alpine-2.10+dfsg/0000700000175000017500000000000012074461275015351 5ustar paulproteuspaulproteusalpine-2.10+dfsg/m4/0000700000175000017500000000000012074150021015651 5ustar paulproteuspaulproteusalpine-2.10+dfsg/m4/visibility.m40000600000175000017500000000413012074052521020310 0ustar paulproteuspaulproteus# visibility.m4 serial 1 (gettext-0.15) dnl Copyright (C) 2005 Free Software Foundation, Inc. dnl This file is free software; the Free Software Foundation dnl gives unlimited permission to copy and/or distribute it, dnl with or without modifications, as long as this notice is preserved. dnl From Bruno Haible. dnl Tests whether the compiler supports the command-line option dnl -fvisibility=hidden and the function and variable attributes dnl __attribute__((__visibility__("hidden"))) and dnl __attribute__((__visibility__("default"))). dnl Does *not* test for __visibility__("protected") - which has tricky dnl semantics (see the 'vismain' test in glibc) and does not exist e.g. on dnl MacOS X. dnl Does *not* test for __visibility__("internal") - which has processor dnl dependent semantics. dnl Does *not* test for #pragma GCC visibility push(hidden) - which is dnl "really only recommended for legacy code". dnl Set the variable CFLAG_VISIBILITY. dnl Defines and sets the variable HAVE_VISIBILITY. AC_DEFUN([gl_VISIBILITY], [ AC_REQUIRE([AC_PROG_CC]) CFLAG_VISIBILITY= HAVE_VISIBILITY=0 if test -n "$GCC"; then AC_MSG_CHECKING([for simple visibility declarations]) AC_CACHE_VAL(gl_cv_cc_visibility, [ gl_save_CFLAGS="$CFLAGS" CFLAGS="$CFLAGS -fvisibility=hidden" AC_TRY_COMPILE( [extern __attribute__((__visibility__("hidden"))) int hiddenvar; extern __attribute__((__visibility__("default"))) int exportedvar; extern __attribute__((__visibility__("hidden"))) int hiddenfunc (void); extern __attribute__((__visibility__("default"))) int exportedfunc (void);], [], gl_cv_cc_visibility=yes, gl_cv_cc_visibility=no) CFLAGS="$gl_save_CFLAGS"]) AC_MSG_RESULT([$gl_cv_cc_visibility]) if test $gl_cv_cc_visibility = yes; then CFLAG_VISIBILITY="-fvisibility=hidden" HAVE_VISIBILITY=1 fi fi AC_SUBST([CFLAG_VISIBILITY]) AC_SUBST([HAVE_VISIBILITY]) AC_DEFINE_UNQUOTED([HAVE_VISIBILITY], [$HAVE_VISIBILITY], [Define to 1 or 0, depending whether the compiler supports simple visibility declarations.]) ]) alpine-2.10+dfsg/m4/inttypes_h.m40000600000175000017500000000164412074052520020315 0ustar paulproteuspaulproteus# inttypes_h.m4 serial 7 dnl Copyright (C) 1997-2004, 2006 Free Software Foundation, Inc. dnl This file is free software; the Free Software Foundation dnl gives unlimited permission to copy and/or distribute it, dnl with or without modifications, as long as this notice is preserved. dnl From Paul Eggert. # Define HAVE_INTTYPES_H_WITH_UINTMAX if exists, # doesn't clash with , and declares uintmax_t. AC_DEFUN([gl_AC_HEADER_INTTYPES_H], [ AC_CACHE_CHECK([for inttypes.h], gl_cv_header_inttypes_h, [AC_TRY_COMPILE( [#include #include ], [uintmax_t i = (uintmax_t) -1; return !i;], gl_cv_header_inttypes_h=yes, gl_cv_header_inttypes_h=no)]) if test $gl_cv_header_inttypes_h = yes; then AC_DEFINE_UNQUOTED(HAVE_INTTYPES_H_WITH_UINTMAX, 1, [Define if exists, doesn't clash with , and declares uintmax_t. ]) fi ]) alpine-2.10+dfsg/m4/lib-link.m40000600000175000017500000006424412074052520017635 0ustar paulproteuspaulproteus# lib-link.m4 serial 9 (gettext-0.16) dnl Copyright (C) 2001-2006 Free Software Foundation, Inc. dnl This file is free software; the Free Software Foundation dnl gives unlimited permission to copy and/or distribute it, dnl with or without modifications, as long as this notice is preserved. dnl From Bruno Haible. AC_PREREQ(2.50) dnl AC_LIB_LINKFLAGS(name [, dependencies]) searches for libname and dnl the libraries corresponding to explicit and implicit dependencies. dnl Sets and AC_SUBSTs the LIB${NAME} and LTLIB${NAME} variables and dnl augments the CPPFLAGS variable. AC_DEFUN([AC_LIB_LINKFLAGS], [ AC_REQUIRE([AC_LIB_PREPARE_PREFIX]) AC_REQUIRE([AC_LIB_RPATH]) define([Name],[translit([$1],[./-], [___])]) define([NAME],[translit([$1],[abcdefghijklmnopqrstuvwxyz./-], [ABCDEFGHIJKLMNOPQRSTUVWXYZ___])]) AC_CACHE_CHECK([how to link with lib[]$1], [ac_cv_lib[]Name[]_libs], [ AC_LIB_LINKFLAGS_BODY([$1], [$2]) ac_cv_lib[]Name[]_libs="$LIB[]NAME" ac_cv_lib[]Name[]_ltlibs="$LTLIB[]NAME" ac_cv_lib[]Name[]_cppflags="$INC[]NAME" ]) LIB[]NAME="$ac_cv_lib[]Name[]_libs" LTLIB[]NAME="$ac_cv_lib[]Name[]_ltlibs" INC[]NAME="$ac_cv_lib[]Name[]_cppflags" AC_LIB_APPENDTOVAR([CPPFLAGS], [$INC]NAME) AC_SUBST([LIB]NAME) AC_SUBST([LTLIB]NAME) dnl Also set HAVE_LIB[]NAME so that AC_LIB_HAVE_LINKFLAGS can reuse the dnl results of this search when this library appears as a dependency. HAVE_LIB[]NAME=yes undefine([Name]) undefine([NAME]) ]) dnl AC_LIB_HAVE_LINKFLAGS(name, dependencies, includes, testcode) dnl searches for libname and the libraries corresponding to explicit and dnl implicit dependencies, together with the specified include files and dnl the ability to compile and link the specified testcode. If found, it dnl sets and AC_SUBSTs HAVE_LIB${NAME}=yes and the LIB${NAME} and dnl LTLIB${NAME} variables and augments the CPPFLAGS variable, and dnl #defines HAVE_LIB${NAME} to 1. Otherwise, it sets and AC_SUBSTs dnl HAVE_LIB${NAME}=no and LIB${NAME} and LTLIB${NAME} to empty. AC_DEFUN([AC_LIB_HAVE_LINKFLAGS], [ AC_REQUIRE([AC_LIB_PREPARE_PREFIX]) AC_REQUIRE([AC_LIB_RPATH]) define([Name],[translit([$1],[./-], [___])]) define([NAME],[translit([$1],[abcdefghijklmnopqrstuvwxyz./-], [ABCDEFGHIJKLMNOPQRSTUVWXYZ___])]) dnl Search for lib[]Name and define LIB[]NAME, LTLIB[]NAME and INC[]NAME dnl accordingly. AC_LIB_LINKFLAGS_BODY([$1], [$2]) dnl Add $INC[]NAME to CPPFLAGS before performing the following checks, dnl because if the user has installed lib[]Name and not disabled its use dnl via --without-lib[]Name-prefix, he wants to use it. ac_save_CPPFLAGS="$CPPFLAGS" AC_LIB_APPENDTOVAR([CPPFLAGS], [$INC]NAME) AC_CACHE_CHECK([for lib[]$1], [ac_cv_lib[]Name], [ ac_save_LIBS="$LIBS" LIBS="$LIBS $LIB[]NAME" AC_TRY_LINK([$3], [$4], [ac_cv_lib[]Name=yes], [ac_cv_lib[]Name=no]) LIBS="$ac_save_LIBS" ]) if test "$ac_cv_lib[]Name" = yes; then HAVE_LIB[]NAME=yes AC_DEFINE([HAVE_LIB]NAME, 1, [Define if you have the $1 library.]) AC_MSG_CHECKING([how to link with lib[]$1]) AC_MSG_RESULT([$LIB[]NAME]) else HAVE_LIB[]NAME=no dnl If $LIB[]NAME didn't lead to a usable library, we don't need dnl $INC[]NAME either. CPPFLAGS="$ac_save_CPPFLAGS" LIB[]NAME= LTLIB[]NAME= fi AC_SUBST([HAVE_LIB]NAME) AC_SUBST([LIB]NAME) AC_SUBST([LTLIB]NAME) undefine([Name]) undefine([NAME]) ]) dnl Determine the platform dependent parameters needed to use rpath: dnl libext, shlibext, hardcode_libdir_flag_spec, hardcode_libdir_separator, dnl hardcode_direct, hardcode_minus_L. AC_DEFUN([AC_LIB_RPATH], [ dnl Tell automake >= 1.10 to complain if config.rpath is missing. m4_ifdef([AC_REQUIRE_AUX_FILE], [AC_REQUIRE_AUX_FILE([config.rpath])]) AC_REQUIRE([AC_PROG_CC]) dnl we use $CC, $GCC, $LDFLAGS AC_REQUIRE([AC_LIB_PROG_LD]) dnl we use $LD, $with_gnu_ld AC_REQUIRE([AC_CANONICAL_HOST]) dnl we use $host AC_REQUIRE([AC_CONFIG_AUX_DIR_DEFAULT]) dnl we use $ac_aux_dir AC_CACHE_CHECK([for shared library run path origin], acl_cv_rpath, [ CC="$CC" GCC="$GCC" LDFLAGS="$LDFLAGS" LD="$LD" with_gnu_ld="$with_gnu_ld" \ ${CONFIG_SHELL-/bin/sh} "$ac_aux_dir/config.rpath" "$host" > conftest.sh . ./conftest.sh rm -f ./conftest.sh acl_cv_rpath=done ]) wl="$acl_cv_wl" libext="$acl_cv_libext" shlibext="$acl_cv_shlibext" hardcode_libdir_flag_spec="$acl_cv_hardcode_libdir_flag_spec" hardcode_libdir_separator="$acl_cv_hardcode_libdir_separator" hardcode_direct="$acl_cv_hardcode_direct" hardcode_minus_L="$acl_cv_hardcode_minus_L" dnl Determine whether the user wants rpath handling at all. AC_ARG_ENABLE(rpath, [ --disable-rpath do not hardcode runtime library paths], :, enable_rpath=yes) ]) dnl AC_LIB_LINKFLAGS_BODY(name [, dependencies]) searches for libname and dnl the libraries corresponding to explicit and implicit dependencies. dnl Sets the LIB${NAME}, LTLIB${NAME} and INC${NAME} variables. AC_DEFUN([AC_LIB_LINKFLAGS_BODY], [ AC_REQUIRE([AC_LIB_PREPARE_MULTILIB]) define([NAME],[translit([$1],[abcdefghijklmnopqrstuvwxyz./-], [ABCDEFGHIJKLMNOPQRSTUVWXYZ___])]) dnl By default, look in $includedir and $libdir. use_additional=yes AC_LIB_WITH_FINAL_PREFIX([ eval additional_includedir=\"$includedir\" eval additional_libdir=\"$libdir\" ]) AC_LIB_ARG_WITH([lib$1-prefix], [ --with-lib$1-prefix[=DIR] search for lib$1 in DIR/include and DIR/lib --without-lib$1-prefix don't search for lib$1 in includedir and libdir], [ if test "X$withval" = "Xno"; then use_additional=no else if test "X$withval" = "X"; then AC_LIB_WITH_FINAL_PREFIX([ eval additional_includedir=\"$includedir\" eval additional_libdir=\"$libdir\" ]) else additional_includedir="$withval/include" additional_libdir="$withval/$acl_libdirstem" fi fi ]) dnl Search the library and its dependencies in $additional_libdir and dnl $LDFLAGS. Using breadth-first-seach. LIB[]NAME= LTLIB[]NAME= INC[]NAME= rpathdirs= ltrpathdirs= names_already_handled= names_next_round='$1 $2' while test -n "$names_next_round"; do names_this_round="$names_next_round" names_next_round= for name in $names_this_round; do already_handled= for n in $names_already_handled; do if test "$n" = "$name"; then already_handled=yes break fi done if test -z "$already_handled"; then names_already_handled="$names_already_handled $name" dnl See if it was already located by an earlier AC_LIB_LINKFLAGS dnl or AC_LIB_HAVE_LINKFLAGS call. uppername=`echo "$name" | sed -e 'y|abcdefghijklmnopqrstuvwxyz./-|ABCDEFGHIJKLMNOPQRSTUVWXYZ___|'` eval value=\"\$HAVE_LIB$uppername\" if test -n "$value"; then if test "$value" = yes; then eval value=\"\$LIB$uppername\" test -z "$value" || LIB[]NAME="${LIB[]NAME}${LIB[]NAME:+ }$value" eval value=\"\$LTLIB$uppername\" test -z "$value" || LTLIB[]NAME="${LTLIB[]NAME}${LTLIB[]NAME:+ }$value" else dnl An earlier call to AC_LIB_HAVE_LINKFLAGS has determined dnl that this library doesn't exist. So just drop it. : fi else dnl Search the library lib$name in $additional_libdir and $LDFLAGS dnl and the already constructed $LIBNAME/$LTLIBNAME. found_dir= found_la= found_so= found_a= if test $use_additional = yes; then if test -n "$shlibext" \ && { test -f "$additional_libdir/lib$name.$shlibext" \ || { test "$shlibext" = dll \ && test -f "$additional_libdir/lib$name.dll.a"; }; }; then found_dir="$additional_libdir" if test -f "$additional_libdir/lib$name.$shlibext"; then found_so="$additional_libdir/lib$name.$shlibext" else found_so="$additional_libdir/lib$name.dll.a" fi if test -f "$additional_libdir/lib$name.la"; then found_la="$additional_libdir/lib$name.la" fi else if test -f "$additional_libdir/lib$name.$libext"; then found_dir="$additional_libdir" found_a="$additional_libdir/lib$name.$libext" if test -f "$additional_libdir/lib$name.la"; then found_la="$additional_libdir/lib$name.la" fi fi fi fi if test "X$found_dir" = "X"; then for x in $LDFLAGS $LTLIB[]NAME; do AC_LIB_WITH_FINAL_PREFIX([eval x=\"$x\"]) case "$x" in -L*) dir=`echo "X$x" | sed -e 's/^X-L//'` if test -n "$shlibext" \ && { test -f "$dir/lib$name.$shlibext" \ || { test "$shlibext" = dll \ && test -f "$dir/lib$name.dll.a"; }; }; then found_dir="$dir" if test -f "$dir/lib$name.$shlibext"; then found_so="$dir/lib$name.$shlibext" else found_so="$dir/lib$name.dll.a" fi if test -f "$dir/lib$name.la"; then found_la="$dir/lib$name.la" fi else if test -f "$dir/lib$name.$libext"; then found_dir="$dir" found_a="$dir/lib$name.$libext" if test -f "$dir/lib$name.la"; then found_la="$dir/lib$name.la" fi fi fi ;; esac if test "X$found_dir" != "X"; then break fi done fi if test "X$found_dir" != "X"; then dnl Found the library. LTLIB[]NAME="${LTLIB[]NAME}${LTLIB[]NAME:+ }-L$found_dir -l$name" if test "X$found_so" != "X"; then dnl Linking with a shared library. We attempt to hardcode its dnl directory into the executable's runpath, unless it's the dnl standard /usr/lib. if test "$enable_rpath" = no || test "X$found_dir" = "X/usr/$acl_libdirstem"; then dnl No hardcoding is needed. LIB[]NAME="${LIB[]NAME}${LIB[]NAME:+ }$found_so" else dnl Use an explicit option to hardcode DIR into the resulting dnl binary. dnl Potentially add DIR to ltrpathdirs. dnl The ltrpathdirs will be appended to $LTLIBNAME at the end. haveit= for x in $ltrpathdirs; do if test "X$x" = "X$found_dir"; then haveit=yes break fi done if test -z "$haveit"; then ltrpathdirs="$ltrpathdirs $found_dir" fi dnl The hardcoding into $LIBNAME is system dependent. if test "$hardcode_direct" = yes; then dnl Using DIR/libNAME.so during linking hardcodes DIR into the dnl resulting binary. LIB[]NAME="${LIB[]NAME}${LIB[]NAME:+ }$found_so" else if test -n "$hardcode_libdir_flag_spec" && test "$hardcode_minus_L" = no; then dnl Use an explicit option to hardcode DIR into the resulting dnl binary. LIB[]NAME="${LIB[]NAME}${LIB[]NAME:+ }$found_so" dnl Potentially add DIR to rpathdirs. dnl The rpathdirs will be appended to $LIBNAME at the end. haveit= for x in $rpathdirs; do if test "X$x" = "X$found_dir"; then haveit=yes break fi done if test -z "$haveit"; then rpathdirs="$rpathdirs $found_dir" fi else dnl Rely on "-L$found_dir". dnl But don't add it if it's already contained in the LDFLAGS dnl or the already constructed $LIBNAME haveit= for x in $LDFLAGS $LIB[]NAME; do AC_LIB_WITH_FINAL_PREFIX([eval x=\"$x\"]) if test "X$x" = "X-L$found_dir"; then haveit=yes break fi done if test -z "$haveit"; then LIB[]NAME="${LIB[]NAME}${LIB[]NAME:+ }-L$found_dir" fi if test "$hardcode_minus_L" != no; then dnl FIXME: Not sure whether we should use dnl "-L$found_dir -l$name" or "-L$found_dir $found_so" dnl here. LIB[]NAME="${LIB[]NAME}${LIB[]NAME:+ }$found_so" else dnl We cannot use $hardcode_runpath_var and LD_RUN_PATH dnl here, because this doesn't fit in flags passed to the dnl compiler. So give up. No hardcoding. This affects only dnl very old systems. dnl FIXME: Not sure whether we should use dnl "-L$found_dir -l$name" or "-L$found_dir $found_so" dnl here. LIB[]NAME="${LIB[]NAME}${LIB[]NAME:+ }-l$name" fi fi fi fi else if test "X$found_a" != "X"; then dnl Linking with a static library. LIB[]NAME="${LIB[]NAME}${LIB[]NAME:+ }$found_a" else dnl We shouldn't come here, but anyway it's good to have a dnl fallback. LIB[]NAME="${LIB[]NAME}${LIB[]NAME:+ }-L$found_dir -l$name" fi fi dnl Assume the include files are nearby. additional_includedir= case "$found_dir" in */$acl_libdirstem | */$acl_libdirstem/) basedir=`echo "X$found_dir" | sed -e 's,^X,,' -e "s,/$acl_libdirstem/"'*$,,'` additional_includedir="$basedir/include" ;; esac if test "X$additional_includedir" != "X"; then dnl Potentially add $additional_includedir to $INCNAME. dnl But don't add it dnl 1. if it's the standard /usr/include, dnl 2. if it's /usr/local/include and we are using GCC on Linux, dnl 3. if it's already present in $CPPFLAGS or the already dnl constructed $INCNAME, dnl 4. if it doesn't exist as a directory. if test "X$additional_includedir" != "X/usr/include"; then haveit= if test "X$additional_includedir" = "X/usr/local/include"; then if test -n "$GCC"; then case $host_os in linux* | gnu* | k*bsd*-gnu) haveit=yes;; esac fi fi if test -z "$haveit"; then for x in $CPPFLAGS $INC[]NAME; do AC_LIB_WITH_FINAL_PREFIX([eval x=\"$x\"]) if test "X$x" = "X-I$additional_includedir"; then haveit=yes break fi done if test -z "$haveit"; then if test -d "$additional_includedir"; then dnl Really add $additional_includedir to $INCNAME. INC[]NAME="${INC[]NAME}${INC[]NAME:+ }-I$additional_includedir" fi fi fi fi fi dnl Look for dependencies. if test -n "$found_la"; then dnl Read the .la file. It defines the variables dnl dlname, library_names, old_library, dependency_libs, current, dnl age, revision, installed, dlopen, dlpreopen, libdir. save_libdir="$libdir" case "$found_la" in */* | *\\*) . "$found_la" ;; *) . "./$found_la" ;; esac libdir="$save_libdir" dnl We use only dependency_libs. for dep in $dependency_libs; do case "$dep" in -L*) additional_libdir=`echo "X$dep" | sed -e 's/^X-L//'` dnl Potentially add $additional_libdir to $LIBNAME and $LTLIBNAME. dnl But don't add it dnl 1. if it's the standard /usr/lib, dnl 2. if it's /usr/local/lib and we are using GCC on Linux, dnl 3. if it's already present in $LDFLAGS or the already dnl constructed $LIBNAME, dnl 4. if it doesn't exist as a directory. if test "X$additional_libdir" != "X/usr/$acl_libdirstem"; then haveit= if test "X$additional_libdir" = "X/usr/local/$acl_libdirstem"; then if test -n "$GCC"; then case $host_os in linux* | gnu* | k*bsd*-gnu) haveit=yes;; esac fi fi if test -z "$haveit"; then haveit= for x in $LDFLAGS $LIB[]NAME; do AC_LIB_WITH_FINAL_PREFIX([eval x=\"$x\"]) if test "X$x" = "X-L$additional_libdir"; then haveit=yes break fi done if test -z "$haveit"; then if test -d "$additional_libdir"; then dnl Really add $additional_libdir to $LIBNAME. LIB[]NAME="${LIB[]NAME}${LIB[]NAME:+ }-L$additional_libdir" fi fi haveit= for x in $LDFLAGS $LTLIB[]NAME; do AC_LIB_WITH_FINAL_PREFIX([eval x=\"$x\"]) if test "X$x" = "X-L$additional_libdir"; then haveit=yes break fi done if test -z "$haveit"; then if test -d "$additional_libdir"; then dnl Really add $additional_libdir to $LTLIBNAME. LTLIB[]NAME="${LTLIB[]NAME}${LTLIB[]NAME:+ }-L$additional_libdir" fi fi fi fi ;; -R*) dir=`echo "X$dep" | sed -e 's/^X-R//'` if test "$enable_rpath" != no; then dnl Potentially add DIR to rpathdirs. dnl The rpathdirs will be appended to $LIBNAME at the end. haveit= for x in $rpathdirs; do if test "X$x" = "X$dir"; then haveit=yes break fi done if test -z "$haveit"; then rpathdirs="$rpathdirs $dir" fi dnl Potentially add DIR to ltrpathdirs. dnl The ltrpathdirs will be appended to $LTLIBNAME at the end. haveit= for x in $ltrpathdirs; do if test "X$x" = "X$dir"; then haveit=yes break fi done if test -z "$haveit"; then ltrpathdirs="$ltrpathdirs $dir" fi fi ;; -l*) dnl Handle this in the next round. names_next_round="$names_next_round "`echo "X$dep" | sed -e 's/^X-l//'` ;; *.la) dnl Handle this in the next round. Throw away the .la's dnl directory; it is already contained in a preceding -L dnl option. names_next_round="$names_next_round "`echo "X$dep" | sed -e 's,^X.*/,,' -e 's,^lib,,' -e 's,\.la$,,'` ;; *) dnl Most likely an immediate library name. LIB[]NAME="${LIB[]NAME}${LIB[]NAME:+ }$dep" LTLIB[]NAME="${LTLIB[]NAME}${LTLIB[]NAME:+ }$dep" ;; esac done fi else dnl Didn't find the library; assume it is in the system directories dnl known to the linker and runtime loader. (All the system dnl directories known to the linker should also be known to the dnl runtime loader, otherwise the system is severely misconfigured.) LIB[]NAME="${LIB[]NAME}${LIB[]NAME:+ }-l$name" LTLIB[]NAME="${LTLIB[]NAME}${LTLIB[]NAME:+ }-l$name" fi fi fi done done if test "X$rpathdirs" != "X"; then if test -n "$hardcode_libdir_separator"; then dnl Weird platform: only the last -rpath option counts, the user must dnl pass all path elements in one option. We can arrange that for a dnl single library, but not when more than one $LIBNAMEs are used. alldirs= for found_dir in $rpathdirs; do alldirs="${alldirs}${alldirs:+$hardcode_libdir_separator}$found_dir" done dnl Note: hardcode_libdir_flag_spec uses $libdir and $wl. acl_save_libdir="$libdir" libdir="$alldirs" eval flag=\"$hardcode_libdir_flag_spec\" libdir="$acl_save_libdir" LIB[]NAME="${LIB[]NAME}${LIB[]NAME:+ }$flag" else dnl The -rpath options are cumulative. for found_dir in $rpathdirs; do acl_save_libdir="$libdir" libdir="$found_dir" eval flag=\"$hardcode_libdir_flag_spec\" libdir="$acl_save_libdir" LIB[]NAME="${LIB[]NAME}${LIB[]NAME:+ }$flag" done fi fi if test "X$ltrpathdirs" != "X"; then dnl When using libtool, the option that works for both libraries and dnl executables is -R. The -R options are cumulative. for found_dir in $ltrpathdirs; do LTLIB[]NAME="${LTLIB[]NAME}${LTLIB[]NAME:+ }-R$found_dir" done fi ]) dnl AC_LIB_APPENDTOVAR(VAR, CONTENTS) appends the elements of CONTENTS to VAR, dnl unless already present in VAR. dnl Works only for CPPFLAGS, not for LIB* variables because that sometimes dnl contains two or three consecutive elements that belong together. AC_DEFUN([AC_LIB_APPENDTOVAR], [ for element in [$2]; do haveit= for x in $[$1]; do AC_LIB_WITH_FINAL_PREFIX([eval x=\"$x\"]) if test "X$x" = "X$element"; then haveit=yes break fi done if test -z "$haveit"; then [$1]="${[$1]}${[$1]:+ }$element" fi done ]) dnl For those cases where a variable contains several -L and -l options dnl referring to unknown libraries and directories, this macro determines the dnl necessary additional linker options for the runtime path. dnl AC_LIB_LINKFLAGS_FROM_LIBS([LDADDVAR], [LIBSVALUE], [USE-LIBTOOL]) dnl sets LDADDVAR to linker options needed together with LIBSVALUE. dnl If USE-LIBTOOL evaluates to non-empty, linking with libtool is assumed, dnl otherwise linking without libtool is assumed. AC_DEFUN([AC_LIB_LINKFLAGS_FROM_LIBS], [ AC_REQUIRE([AC_LIB_RPATH]) AC_REQUIRE([AC_LIB_PREPARE_MULTILIB]) $1= if test "$enable_rpath" != no; then if test -n "$hardcode_libdir_flag_spec" && test "$hardcode_minus_L" = no; then dnl Use an explicit option to hardcode directories into the resulting dnl binary. rpathdirs= next= for opt in $2; do if test -n "$next"; then dir="$next" dnl No need to hardcode the standard /usr/lib. if test "X$dir" != "X/usr/$acl_libdirstem"; then rpathdirs="$rpathdirs $dir" fi next= else case $opt in -L) next=yes ;; -L*) dir=`echo "X$opt" | sed -e 's,^X-L,,'` dnl No need to hardcode the standard /usr/lib. if test "X$dir" != "X/usr/$acl_libdirstem"; then rpathdirs="$rpathdirs $dir" fi next= ;; *) next= ;; esac fi done if test "X$rpathdirs" != "X"; then if test -n ""$3""; then dnl libtool is used for linking. Use -R options. for dir in $rpathdirs; do $1="${$1}${$1:+ }-R$dir" done else dnl The linker is used for linking directly. if test -n "$hardcode_libdir_separator"; then dnl Weird platform: only the last -rpath option counts, the user dnl must pass all path elements in one option. alldirs= for dir in $rpathdirs; do alldirs="${alldirs}${alldirs:+$hardcode_libdir_separator}$dir" done acl_save_libdir="$libdir" libdir="$alldirs" eval flag=\"$hardcode_libdir_flag_spec\" libdir="$acl_save_libdir" $1="$flag" else dnl The -rpath options are cumulative. for dir in $rpathdirs; do acl_save_libdir="$libdir" libdir="$dir" eval flag=\"$hardcode_libdir_flag_spec\" libdir="$acl_save_libdir" $1="${$1}${$1:+ }$flag" done fi fi fi fi fi AC_SUBST([$1]) ]) alpine-2.10+dfsg/m4/ChangeLog0000600000175000017500000000444011512502114017427 0ustar paulproteuspaulproteus2007-10-05 gettextize * codeset.m4: Upgrade to gettext-0.14.6. * gettext.m4: Upgrade to gettext-0.14.6. * glibc2.m4: New file, from gettext-0.14.6. * glibc21.m4: Upgrade to gettext-0.14.6. * iconv.m4: Upgrade to gettext-0.14.6. * intdiv0.m4: Upgrade to gettext-0.14.6. * intmax.m4: New file, from gettext-0.14.6. * inttypes.m4: Upgrade to gettext-0.14.6. * inttypes_h.m4: Upgrade to gettext-0.14.6. * inttypes-pri.m4: Upgrade to gettext-0.14.6. * isc-posix.m4: Upgrade to gettext-0.14.6. * lcmessage.m4: Upgrade to gettext-0.14.6. * lib-ld.m4: Upgrade to gettext-0.14.6. * lib-link.m4: Upgrade to gettext-0.14.6. * lib-prefix.m4: Upgrade to gettext-0.14.6. * longdouble.m4: New file, from gettext-0.14.6. * longlong.m4: New file, from gettext-0.14.6. * nls.m4: Upgrade to gettext-0.14.6. * po.m4: Upgrade to gettext-0.14.6. * printf-posix.m4: New file, from gettext-0.14.6. * progtest.m4: Upgrade to gettext-0.14.6. * signed.m4: New file, from gettext-0.14.6. * size_max.m4: New file, from gettext-0.14.6. * stdint_h.m4: Upgrade to gettext-0.14.6. * uintmax_t.m4: Upgrade to gettext-0.14.6. * ulonglong.m4: Upgrade to gettext-0.14.6. * wchar_t.m4: New file, from gettext-0.14.6. * wint_t.m4: New file, from gettext-0.14.6. * xsize.m4: New file, from gettext-0.14.6. * Makefile.am (EXTRA_DIST): Add the new files. 2006-07-28 gettextize * codeset.m4: New file, from gettext-0.12.1. * gettext.m4: New file, from gettext-0.12.1. * glibc21.m4: New file, from gettext-0.12.1. * iconv.m4: New file, from gettext-0.12.1. * intdiv0.m4: New file, from gettext-0.12.1. * inttypes.m4: New file, from gettext-0.12.1. * inttypes_h.m4: New file, from gettext-0.12.1. * inttypes-pri.m4: New file, from gettext-0.12.1. * isc-posix.m4: New file, from gettext-0.12.1. * lcmessage.m4: New file, from gettext-0.12.1. * lib-ld.m4: New file, from gettext-0.12.1. * lib-link.m4: New file, from gettext-0.12.1. * lib-prefix.m4: New file, from gettext-0.12.1. * nls.m4: New file, from gettext-0.12.1. * po.m4: New file, from gettext-0.12.1. * progtest.m4: New file, from gettext-0.12.1. * stdint_h.m4: New file, from gettext-0.12.1. * uintmax_t.m4: New file, from gettext-0.12.1. * ulonglong.m4: New file, from gettext-0.12.1. * Makefile.am: New file. alpine-2.10+dfsg/m4/inttypes-pri.m40000600000175000017500000000215212074052520020571 0ustar paulproteuspaulproteus# inttypes-pri.m4 serial 4 (gettext-0.16) dnl Copyright (C) 1997-2002, 2006 Free Software Foundation, Inc. dnl This file is free software; the Free Software Foundation dnl gives unlimited permission to copy and/or distribute it, dnl with or without modifications, as long as this notice is preserved. dnl From Bruno Haible. AC_PREREQ(2.52) # Define PRI_MACROS_BROKEN if exists and defines the PRI* # macros to non-string values. This is the case on AIX 4.3.3. AC_DEFUN([gt_INTTYPES_PRI], [ AC_CHECK_HEADERS([inttypes.h]) if test $ac_cv_header_inttypes_h = yes; then AC_CACHE_CHECK([whether the inttypes.h PRIxNN macros are broken], gt_cv_inttypes_pri_broken, [ AC_TRY_COMPILE([#include #ifdef PRId32 char *p = PRId32; #endif ], [], gt_cv_inttypes_pri_broken=no, gt_cv_inttypes_pri_broken=yes) ]) fi if test "$gt_cv_inttypes_pri_broken" = yes; then AC_DEFINE_UNQUOTED(PRI_MACROS_BROKEN, 1, [Define if exists and defines unusable PRI* macros.]) PRI_MACROS_BROKEN=1 else PRI_MACROS_BROKEN=0 fi AC_SUBST([PRI_MACROS_BROKEN]) ]) alpine-2.10+dfsg/m4/glibc21.m40000600000175000017500000000144511512502114017344 0ustar paulproteuspaulproteus# glibc21.m4 serial 3 dnl Copyright (C) 2000-2002, 2004 Free Software Foundation, Inc. dnl This file is free software; the Free Software Foundation dnl gives unlimited permission to copy and/or distribute it, dnl with or without modifications, as long as this notice is preserved. # Test for the GNU C Library, version 2.1 or newer. # From Bruno Haible. AC_DEFUN([gl_GLIBC21], [ AC_CACHE_CHECK(whether we are using the GNU C Library 2.1 or newer, ac_cv_gnu_library_2_1, [AC_EGREP_CPP([Lucky GNU user], [ #include #ifdef __GNU_LIBRARY__ #if (__GLIBC__ == 2 && __GLIBC_MINOR__ >= 1) || (__GLIBC__ > 2) Lucky GNU user #endif #endif ], ac_cv_gnu_library_2_1=yes, ac_cv_gnu_library_2_1=no) ] ) AC_SUBST(GLIBC21) GLIBC21="$ac_cv_gnu_library_2_1" ] ) alpine-2.10+dfsg/m4/printf-posix.m40000600000175000017500000000266112074052520020571 0ustar paulproteuspaulproteus# printf-posix.m4 serial 2 (gettext-0.13.1) dnl Copyright (C) 2003 Free Software Foundation, Inc. dnl This file is free software; the Free Software Foundation dnl gives unlimited permission to copy and/or distribute it, dnl with or without modifications, as long as this notice is preserved. dnl From Bruno Haible. dnl Test whether the printf() function supports POSIX/XSI format strings with dnl positions. AC_DEFUN([gt_PRINTF_POSIX], [ AC_REQUIRE([AC_PROG_CC]) AC_CACHE_CHECK([whether printf() supports POSIX/XSI format strings], gt_cv_func_printf_posix, [ AC_TRY_RUN([ #include #include /* The string "%2$d %1$d", with dollar characters protected from the shell's dollar expansion (possibly an autoconf bug). */ static char format[] = { '%', '2', '$', 'd', ' ', '%', '1', '$', 'd', '\0' }; static char buf[100]; int main () { sprintf (buf, format, 33, 55); return (strcmp (buf, "55 33") != 0); }], gt_cv_func_printf_posix=yes, gt_cv_func_printf_posix=no, [ AC_EGREP_CPP(notposix, [ #if defined __NetBSD__ || defined _MSC_VER || defined __MINGW32__ || defined __CYGWIN__ notposix #endif ], gt_cv_func_printf_posix="guessing no", gt_cv_func_printf_posix="guessing yes") ]) ]) case $gt_cv_func_printf_posix in *yes) AC_DEFINE(HAVE_POSIX_PRINTF, 1, [Define if your printf() function supports format strings with positions.]) ;; esac ]) alpine-2.10+dfsg/m4/Makefile.am0000600000175000017500000000053311512502114017710 0ustar paulproteuspaulproteusEXTRA_DIST = glibc2.m4 intmax.m4 longdouble.m4 longlong.m4 printf-posix.m4 signed.m4 size_max.m4 wchar_t.m4 wint_t.m4 xsize.m4 codeset.m4 gettext.m4 glibc21.m4 iconv.m4 intdiv0.m4 inttypes.m4 inttypes_h.m4 inttypes-pri.m4 isc-posix.m4 lcmessage.m4 lib-ld.m4 lib-link.m4 lib-prefix.m4 nls.m4 po.m4 progtest.m4 stdint_h.m4 uintmax_t.m4 ulonglong.m4 alpine-2.10+dfsg/m4/codeset.m40000600000175000017500000000136612074052520017556 0ustar paulproteuspaulproteus# codeset.m4 serial 2 (gettext-0.16) dnl Copyright (C) 2000-2002, 2006 Free Software Foundation, Inc. dnl This file is free software; the Free Software Foundation dnl gives unlimited permission to copy and/or distribute it, dnl with or without modifications, as long as this notice is preserved. dnl From Bruno Haible. AC_DEFUN([AM_LANGINFO_CODESET], [ AC_CACHE_CHECK([for nl_langinfo and CODESET], am_cv_langinfo_codeset, [AC_TRY_LINK([#include ], [char* cs = nl_langinfo(CODESET); return !cs;], am_cv_langinfo_codeset=yes, am_cv_langinfo_codeset=no) ]) if test $am_cv_langinfo_codeset = yes; then AC_DEFINE(HAVE_LANGINFO_CODESET, 1, [Define if you have and nl_langinfo(CODESET).]) fi ]) alpine-2.10+dfsg/m4/ltsugar.m40000600000175000017500000001042412074110240017576 0ustar paulproteuspaulproteus# ltsugar.m4 -- libtool m4 base layer. -*-Autoconf-*- # # Copyright (C) 2004, 2005, 2007, 2008 Free Software Foundation, Inc. # Written by Gary V. Vaughan, 2004 # # This file is free software; the Free Software Foundation gives # unlimited permission to copy and/or distribute it, with or without # modifications, as long as this notice is preserved. # serial 6 ltsugar.m4 # This is to help aclocal find these macros, as it can't see m4_define. AC_DEFUN([LTSUGAR_VERSION], [m4_if([0.1])]) # lt_join(SEP, ARG1, [ARG2...]) # ----------------------------- # Produce ARG1SEPARG2...SEPARGn, omitting [] arguments and their # associated separator. # Needed until we can rely on m4_join from Autoconf 2.62, since all earlier # versions in m4sugar had bugs. m4_define([lt_join], [m4_if([$#], [1], [], [$#], [2], [[$2]], [m4_if([$2], [], [], [[$2]_])$0([$1], m4_shift(m4_shift($@)))])]) m4_define([_lt_join], [m4_if([$#$2], [2], [], [m4_if([$2], [], [], [[$1$2]])$0([$1], m4_shift(m4_shift($@)))])]) # lt_car(LIST) # lt_cdr(LIST) # ------------ # Manipulate m4 lists. # These macros are necessary as long as will still need to support # Autoconf-2.59 which quotes differently. m4_define([lt_car], [[$1]]) m4_define([lt_cdr], [m4_if([$#], 0, [m4_fatal([$0: cannot be called without arguments])], [$#], 1, [], [m4_dquote(m4_shift($@))])]) m4_define([lt_unquote], $1) # lt_append(MACRO-NAME, STRING, [SEPARATOR]) # ------------------------------------------ # Redefine MACRO-NAME to hold its former content plus `SEPARATOR'`STRING'. # Note that neither SEPARATOR nor STRING are expanded; they are appended # to MACRO-NAME as is (leaving the expansion for when MACRO-NAME is invoked). # No SEPARATOR is output if MACRO-NAME was previously undefined (different # than defined and empty). # # This macro is needed until we can rely on Autoconf 2.62, since earlier # versions of m4sugar mistakenly expanded SEPARATOR but not STRING. m4_define([lt_append], [m4_define([$1], m4_ifdef([$1], [m4_defn([$1])[$3]])[$2])]) # lt_combine(SEP, PREFIX-LIST, INFIX, SUFFIX1, [SUFFIX2...]) # ---------------------------------------------------------- # Produce a SEP delimited list of all paired combinations of elements of # PREFIX-LIST with SUFFIX1 through SUFFIXn. Each element of the list # has the form PREFIXmINFIXSUFFIXn. # Needed until we can rely on m4_combine added in Autoconf 2.62. m4_define([lt_combine], [m4_if(m4_eval([$# > 3]), [1], [m4_pushdef([_Lt_sep], [m4_define([_Lt_sep], m4_defn([lt_car]))])]]dnl [[m4_foreach([_Lt_prefix], [$2], [m4_foreach([_Lt_suffix], ]m4_dquote(m4_dquote(m4_shift(m4_shift(m4_shift($@)))))[, [_Lt_sep([$1])[]m4_defn([_Lt_prefix])[$3]m4_defn([_Lt_suffix])])])])]) # lt_if_append_uniq(MACRO-NAME, VARNAME, [SEPARATOR], [UNIQ], [NOT-UNIQ]) # ----------------------------------------------------------------------- # Iff MACRO-NAME does not yet contain VARNAME, then append it (delimited # by SEPARATOR if supplied) and expand UNIQ, else NOT-UNIQ. m4_define([lt_if_append_uniq], [m4_ifdef([$1], [m4_if(m4_index([$3]m4_defn([$1])[$3], [$3$2$3]), [-1], [lt_append([$1], [$2], [$3])$4], [$5])], [lt_append([$1], [$2], [$3])$4])]) # lt_dict_add(DICT, KEY, VALUE) # ----------------------------- m4_define([lt_dict_add], [m4_define([$1($2)], [$3])]) # lt_dict_add_subkey(DICT, KEY, SUBKEY, VALUE) # -------------------------------------------- m4_define([lt_dict_add_subkey], [m4_define([$1($2:$3)], [$4])]) # lt_dict_fetch(DICT, KEY, [SUBKEY]) # ---------------------------------- m4_define([lt_dict_fetch], [m4_ifval([$3], m4_ifdef([$1($2:$3)], [m4_defn([$1($2:$3)])]), m4_ifdef([$1($2)], [m4_defn([$1($2)])]))]) # lt_if_dict_fetch(DICT, KEY, [SUBKEY], VALUE, IF-TRUE, [IF-FALSE]) # ----------------------------------------------------------------- m4_define([lt_if_dict_fetch], [m4_if(lt_dict_fetch([$1], [$2], [$3]), [$4], [$5], [$6])]) # lt_dict_filter(DICT, [SUBKEY], VALUE, [SEPARATOR], KEY, [...]) # -------------------------------------------------------------- m4_define([lt_dict_filter], [m4_if([$5], [], [], [lt_join(m4_quote(m4_default([$4], [[, ]])), lt_unquote(m4_split(m4_normalize(m4_foreach(_Lt_key, lt_car([m4_shiftn(4, $@)]), [lt_if_dict_fetch([$1], _Lt_key, [$2], [$3], [_Lt_key ])])))))])[]dnl ]) alpine-2.10+dfsg/m4/wchar_t.m40000600000175000017500000000132612074052521017554 0ustar paulproteuspaulproteus# wchar_t.m4 serial 1 (gettext-0.12) dnl Copyright (C) 2002-2003 Free Software Foundation, Inc. dnl This file is free software; the Free Software Foundation dnl gives unlimited permission to copy and/or distribute it, dnl with or without modifications, as long as this notice is preserved. dnl From Bruno Haible. dnl Test whether has the 'wchar_t' type. dnl Prerequisite: AC_PROG_CC AC_DEFUN([gt_TYPE_WCHAR_T], [ AC_CACHE_CHECK([for wchar_t], gt_cv_c_wchar_t, [AC_TRY_COMPILE([#include wchar_t foo = (wchar_t)'\0';], , gt_cv_c_wchar_t=yes, gt_cv_c_wchar_t=no)]) if test $gt_cv_c_wchar_t = yes; then AC_DEFINE(HAVE_WCHAR_T, 1, [Define if you have the 'wchar_t' type.]) fi ]) alpine-2.10+dfsg/m4/acx_pthread.m40000600000175000017500000002237411512502114020407 0ustar paulproteuspaulproteusdnl @synopsis ACX_PTHREAD([ACTION-IF-FOUND[, ACTION-IF-NOT-FOUND]]) dnl dnl @summary figure out how to build C programs using POSIX threads dnl dnl This macro figures out how to build C programs using POSIX threads. dnl It sets the PTHREAD_LIBS output variable to the threads library and dnl linker flags, and the PTHREAD_CFLAGS output variable to any special dnl C compiler flags that are needed. (The user can also force certain dnl compiler flags/libs to be tested by setting these environment dnl variables.) dnl dnl Also sets PTHREAD_CC to any special C compiler that is needed for dnl multi-threaded programs (defaults to the value of CC otherwise). dnl (This is necessary on AIX to use the special cc_r compiler alias.) dnl dnl NOTE: You are assumed to not only compile your program with these dnl flags, but also link it with them as well. e.g. you should link dnl with $PTHREAD_CC $CFLAGS $PTHREAD_CFLAGS $LDFLAGS ... $PTHREAD_LIBS dnl $LIBS dnl dnl If you are only building threads programs, you may wish to use dnl these variables in your default LIBS, CFLAGS, and CC: dnl dnl LIBS="$PTHREAD_LIBS $LIBS" dnl CFLAGS="$CFLAGS $PTHREAD_CFLAGS" dnl CC="$PTHREAD_CC" dnl dnl In addition, if the PTHREAD_CREATE_JOINABLE thread-attribute dnl constant has a nonstandard name, defines PTHREAD_CREATE_JOINABLE to dnl that name (e.g. PTHREAD_CREATE_UNDETACHED on AIX). dnl dnl ACTION-IF-FOUND is a list of shell commands to run if a threads dnl library is found, and ACTION-IF-NOT-FOUND is a list of commands to dnl run it if it is not found. If ACTION-IF-FOUND is not specified, the dnl default action will define HAVE_PTHREAD. dnl dnl Please let the authors know if this macro fails on any platform, or dnl if you have any other suggestions or comments. This macro was based dnl on work by SGJ on autoconf scripts for FFTW (www.fftw.org) (with dnl help from M. Frigo), as well as ac_pthread and hb_pthread macros dnl posted by Alejandro Forero Cuervo to the autoconf macro repository. dnl We are also grateful for the helpful feedback of numerous users. dnl dnl @category InstalledPackages dnl @author Steven G. Johnson dnl @version 2006-05-29 dnl @license GPLWithACException AC_DEFUN([ACX_PTHREAD], [ AC_REQUIRE([AC_CANONICAL_HOST]) AC_LANG_SAVE AC_LANG_C acx_pthread_ok=no # We used to check for pthread.h first, but this fails if pthread.h # requires special compiler flags (e.g. on True64 or Sequent). # It gets checked for in the link test anyway. # First of all, check if the user has set any of the PTHREAD_LIBS, # etcetera environment variables, and if threads linking works using # them: if test x"$PTHREAD_LIBS$PTHREAD_CFLAGS" != x; then save_CFLAGS="$CFLAGS" CFLAGS="$CFLAGS $PTHREAD_CFLAGS" save_LIBS="$LIBS" LIBS="$PTHREAD_LIBS $LIBS" AC_MSG_CHECKING([for pthread_join in LIBS=$PTHREAD_LIBS with CFLAGS=$PTHREAD_CFLAGS]) AC_TRY_LINK_FUNC(pthread_join, acx_pthread_ok=yes) AC_MSG_RESULT($acx_pthread_ok) if test x"$acx_pthread_ok" = xno; then PTHREAD_LIBS="" PTHREAD_CFLAGS="" fi LIBS="$save_LIBS" CFLAGS="$save_CFLAGS" fi # We must check for the threads library under a number of different # names; the ordering is very important because some systems # (e.g. DEC) have both -lpthread and -lpthreads, where one of the # libraries is broken (non-POSIX). # Create a list of thread flags to try. Items starting with a "-" are # C compiler flags, and other items are library names, except for "none" # which indicates that we try without any flags at all, and "pthread-config" # which is a program returning the flags for the Pth emulation library. acx_pthread_flags="pthreads none -Kthread -kthread lthread -pthread -pthreads -mthreads pthread --thread-safe -mt pthread-config" # The ordering *is* (sometimes) important. Some notes on the # individual items follow: # pthreads: AIX (must check this before -lpthread) # none: in case threads are in libc; should be tried before -Kthread and # other compiler flags to prevent continual compiler warnings # -Kthread: Sequent (threads in libc, but -Kthread needed for pthread.h) # -kthread: FreeBSD kernel threads (preferred to -pthread since SMP-able) # lthread: LinuxThreads port on FreeBSD (also preferred to -pthread) # -pthread: Linux/gcc (kernel threads), BSD/gcc (userland threads) # -pthreads: Solaris/gcc # -mthreads: Mingw32/gcc, Lynx/gcc # -mt: Sun Workshop C (may only link SunOS threads [-lthread], but it # doesn't hurt to check since this sometimes defines pthreads too; # also defines -D_REENTRANT) # ... -mt is also the pthreads flag for HP/aCC # pthread: Linux, etcetera # --thread-safe: KAI C++ # pthread-config: use pthread-config program (for GNU Pth library) case "${host_cpu}-${host_os}" in *solaris*) # On Solaris (at least, for some versions), libc contains stubbed # (non-functional) versions of the pthreads routines, so link-based # tests will erroneously succeed. (We need to link with -pthreads/-mt/ # -lpthread.) (The stubs are missing pthread_cleanup_push, or rather # a function called by this macro, so we could check for that, but # who knows whether they'll stub that too in a future libc.) So, # we'll just look for -pthreads and -lpthread first: acx_pthread_flags="-pthreads pthread -mt -pthread $acx_pthread_flags" ;; esac if test x"$acx_pthread_ok" = xno; then for flag in $acx_pthread_flags; do case $flag in none) AC_MSG_CHECKING([whether pthreads work without any flags]) ;; -*) AC_MSG_CHECKING([whether pthreads work with $flag]) PTHREAD_CFLAGS="$flag" ;; pthread-config) AC_CHECK_PROG(acx_pthread_config, pthread-config, yes, no) if test x"$acx_pthread_config" = xno; then continue; fi PTHREAD_CFLAGS="`pthread-config --cflags`" PTHREAD_LIBS="`pthread-config --ldflags` `pthread-config --libs`" ;; *) AC_MSG_CHECKING([for the pthreads library -l$flag]) PTHREAD_LIBS="-l$flag" ;; esac save_LIBS="$LIBS" save_CFLAGS="$CFLAGS" LIBS="$PTHREAD_LIBS $LIBS" CFLAGS="$CFLAGS $PTHREAD_CFLAGS" # Check for various functions. We must include pthread.h, # since some functions may be macros. (On the Sequent, we # need a special flag -Kthread to make this header compile.) # We check for pthread_join because it is in -lpthread on IRIX # while pthread_create is in libc. We check for pthread_attr_init # due to DEC craziness with -lpthreads. We check for # pthread_cleanup_push because it is one of the few pthread # functions on Solaris that doesn't have a non-functional libc stub. # We try pthread_create on general principles. AC_TRY_LINK([#include ], [pthread_t th; pthread_join(th, 0); pthread_attr_init(0); pthread_cleanup_push(0, 0); pthread_create(0,0,0,0); pthread_cleanup_pop(0); ], [acx_pthread_ok=yes]) LIBS="$save_LIBS" CFLAGS="$save_CFLAGS" AC_MSG_RESULT($acx_pthread_ok) if test "x$acx_pthread_ok" = xyes; then break; fi PTHREAD_LIBS="" PTHREAD_CFLAGS="" done fi # Various other checks: if test "x$acx_pthread_ok" = xyes; then save_LIBS="$LIBS" LIBS="$PTHREAD_LIBS $LIBS" save_CFLAGS="$CFLAGS" CFLAGS="$CFLAGS $PTHREAD_CFLAGS" # Detect AIX lossage: JOINABLE attribute is called UNDETACHED. AC_MSG_CHECKING([for joinable pthread attribute]) attr_name=unknown for attr in PTHREAD_CREATE_JOINABLE PTHREAD_CREATE_UNDETACHED; do AC_TRY_LINK([#include ], [int attr=$attr; return attr;], [attr_name=$attr; break]) done AC_MSG_RESULT($attr_name) if test "$attr_name" != PTHREAD_CREATE_JOINABLE; then AC_DEFINE_UNQUOTED(PTHREAD_CREATE_JOINABLE, $attr_name, [Define to necessary symbol if this constant uses a non-standard name on your system.]) fi AC_MSG_CHECKING([if more special flags are required for pthreads]) flag=no case "${host_cpu}-${host_os}" in *-aix* | *-freebsd* | *-darwin*) flag="-D_THREAD_SAFE";; *solaris* | *-osf* | *-hpux*) flag="-D_REENTRANT";; esac AC_MSG_RESULT(${flag}) if test "x$flag" != xno; then PTHREAD_CFLAGS="$flag $PTHREAD_CFLAGS" fi LIBS="$save_LIBS" CFLAGS="$save_CFLAGS" # More AIX lossage: must compile with xlc_r or cc_r if test x"$GCC" != xyes; then AC_CHECK_PROGS(PTHREAD_CC, xlc_r cc_r, ${CC}) else PTHREAD_CC=$CC fi else PTHREAD_CC="$CC" fi AC_SUBST(PTHREAD_LIBS) AC_SUBST(PTHREAD_CFLAGS) AC_SUBST(PTHREAD_CC) # Finally, execute ACTION-IF-FOUND/ACTION-IF-NOT-FOUND: if test x"$acx_pthread_ok" = xyes; then ifelse([$1],,AC_DEFINE(HAVE_PTHREAD,1,[Define if you have POSIX threads libraries and header files.]),[$1]) : else acx_pthread_ok=no $2 fi AC_LANG_RESTORE ])dnl ACX_PTHREAD alpine-2.10+dfsg/m4/glibc2.m40000600000175000017500000000135412074052520017267 0ustar paulproteuspaulproteus# glibc2.m4 serial 1 dnl Copyright (C) 2000-2002, 2004 Free Software Foundation, Inc. dnl This file is free software; the Free Software Foundation dnl gives unlimited permission to copy and/or distribute it, dnl with or without modifications, as long as this notice is preserved. # Test for the GNU C Library, version 2.0 or newer. # From Bruno Haible. AC_DEFUN([gt_GLIBC2], [ AC_CACHE_CHECK(whether we are using the GNU C Library 2 or newer, ac_cv_gnu_library_2, [AC_EGREP_CPP([Lucky GNU user], [ #include #ifdef __GNU_LIBRARY__ #if (__GLIBC__ >= 2) Lucky GNU user #endif #endif ], ac_cv_gnu_library_2=yes, ac_cv_gnu_library_2=no) ] ) AC_SUBST(GLIBC2) GLIBC2="$ac_cv_gnu_library_2" ] ) alpine-2.10+dfsg/m4/xsize.m40000600000175000017500000000064512074052521017272 0ustar paulproteuspaulproteus# xsize.m4 serial 3 dnl Copyright (C) 2003-2004 Free Software Foundation, Inc. dnl This file is free software; the Free Software Foundation dnl gives unlimited permission to copy and/or distribute it, dnl with or without modifications, as long as this notice is preserved. AC_DEFUN([gl_XSIZE], [ dnl Prerequisites of lib/xsize.h. AC_REQUIRE([gl_SIZE_MAX]) AC_REQUIRE([AC_C_INLINE]) AC_CHECK_HEADERS(stdint.h) ]) alpine-2.10+dfsg/m4/progtest.m40000600000175000017500000000555011512502114017771 0ustar paulproteuspaulproteus# progtest.m4 serial 4 (gettext-0.14.2) dnl Copyright (C) 1996-2003, 2005 Free Software Foundation, Inc. dnl This file is free software; the Free Software Foundation dnl gives unlimited permission to copy and/or distribute it, dnl with or without modifications, as long as this notice is preserved. dnl dnl This file can can be used in projects which are not available under dnl the GNU General Public License or the GNU Library General Public dnl License but which still want to provide support for the GNU gettext dnl functionality. dnl Please note that the actual code of the GNU gettext library is covered dnl by the GNU Library General Public License, and the rest of the GNU dnl gettext package package is covered by the GNU General Public License. dnl They are *not* in the public domain. dnl Authors: dnl Ulrich Drepper , 1996. AC_PREREQ(2.50) # Search path for a program which passes the given test. dnl AM_PATH_PROG_WITH_TEST(VARIABLE, PROG-TO-CHECK-FOR, dnl TEST-PERFORMED-ON-FOUND_PROGRAM [, VALUE-IF-NOT-FOUND [, PATH]]) AC_DEFUN([AM_PATH_PROG_WITH_TEST], [ # Prepare PATH_SEPARATOR. # The user is always right. if test "${PATH_SEPARATOR+set}" != set; then echo "#! /bin/sh" >conf$$.sh echo "exit 0" >>conf$$.sh chmod +x conf$$.sh if (PATH="/nonexistent;."; conf$$.sh) >/dev/null 2>&1; then PATH_SEPARATOR=';' else PATH_SEPARATOR=: fi rm -f conf$$.sh fi # Find out how to test for executable files. Don't use a zero-byte file, # as systems may use methods other than mode bits to determine executability. cat >conf$$.file <<_ASEOF #! /bin/sh exit 0 _ASEOF chmod +x conf$$.file if test -x conf$$.file >/dev/null 2>&1; then ac_executable_p="test -x" else ac_executable_p="test -f" fi rm -f conf$$.file # Extract the first word of "$2", so it can be a program name with args. set dummy $2; ac_word=[$]2 AC_MSG_CHECKING([for $ac_word]) AC_CACHE_VAL(ac_cv_path_$1, [case "[$]$1" in [[\\/]]* | ?:[[\\/]]*) ac_cv_path_$1="[$]$1" # Let the user override the test with a path. ;; *) ac_save_IFS="$IFS"; IFS=$PATH_SEPARATOR for ac_dir in ifelse([$5], , $PATH, [$5]); do IFS="$ac_save_IFS" test -z "$ac_dir" && ac_dir=. for ac_exec_ext in '' $ac_executable_extensions; do if $ac_executable_p "$ac_dir/$ac_word$ac_exec_ext"; then echo "$as_me: trying $ac_dir/$ac_word..." >&AS_MESSAGE_LOG_FD if [$3]; then ac_cv_path_$1="$ac_dir/$ac_word$ac_exec_ext" break 2 fi fi done done IFS="$ac_save_IFS" dnl If no 4th arg is given, leave the cache variable unset, dnl so AC_PATH_PROGS will keep looking. ifelse([$4], , , [ test -z "[$]ac_cv_path_$1" && ac_cv_path_$1="$4" ])dnl ;; esac])dnl $1="$ac_cv_path_$1" if test ifelse([$4], , [-n "[$]$1"], ["[$]$1" != "$4"]); then AC_MSG_RESULT([$]$1) else AC_MSG_RESULT(no) fi AC_SUBST($1)dnl ]) alpine-2.10+dfsg/m4/size_max.m40000600000175000017500000000461012074052521017743 0ustar paulproteuspaulproteus# size_max.m4 serial 5 dnl Copyright (C) 2003, 2005-2006 Free Software Foundation, Inc. dnl This file is free software; the Free Software Foundation dnl gives unlimited permission to copy and/or distribute it, dnl with or without modifications, as long as this notice is preserved. dnl From Bruno Haible. AC_DEFUN([gl_SIZE_MAX], [ AC_CHECK_HEADERS(stdint.h) dnl First test whether the system already has SIZE_MAX. AC_MSG_CHECKING([for SIZE_MAX]) AC_CACHE_VAL([gl_cv_size_max], [ gl_cv_size_max= AC_EGREP_CPP([Found it], [ #include #if HAVE_STDINT_H #include #endif #ifdef SIZE_MAX Found it #endif ], gl_cv_size_max=yes) if test -z "$gl_cv_size_max"; then dnl Define it ourselves. Here we assume that the type 'size_t' is not wider dnl than the type 'unsigned long'. Try hard to find a definition that can dnl be used in a preprocessor #if, i.e. doesn't contain a cast. _AC_COMPUTE_INT([sizeof (size_t) * CHAR_BIT - 1], size_t_bits_minus_1, [#include #include ], size_t_bits_minus_1=) _AC_COMPUTE_INT([sizeof (size_t) <= sizeof (unsigned int)], fits_in_uint, [#include ], fits_in_uint=) if test -n "$size_t_bits_minus_1" && test -n "$fits_in_uint"; then if test $fits_in_uint = 1; then dnl Even though SIZE_MAX fits in an unsigned int, it must be of type dnl 'unsigned long' if the type 'size_t' is the same as 'unsigned long'. AC_TRY_COMPILE([#include extern size_t foo; extern unsigned long foo; ], [], fits_in_uint=0) fi dnl We cannot use 'expr' to simplify this expression, because 'expr' dnl works only with 'long' integers in the host environment, while we dnl might be cross-compiling from a 32-bit platform to a 64-bit platform. if test $fits_in_uint = 1; then gl_cv_size_max="(((1U << $size_t_bits_minus_1) - 1) * 2 + 1)" else gl_cv_size_max="(((1UL << $size_t_bits_minus_1) - 1) * 2 + 1)" fi else dnl Shouldn't happen, but who knows... gl_cv_size_max='((size_t)~(size_t)0)' fi fi ]) AC_MSG_RESULT([$gl_cv_size_max]) if test "$gl_cv_size_max" != yes; then AC_DEFINE_UNQUOTED([SIZE_MAX], [$gl_cv_size_max], [Define as the maximum value of type 'size_t', if the system doesn't define it.]) fi ]) alpine-2.10+dfsg/m4/wint_t.m40000600000175000017500000000130412074052521017425 0ustar paulproteuspaulproteus# wint_t.m4 serial 1 (gettext-0.12) dnl Copyright (C) 2003 Free Software Foundation, Inc. dnl This file is free software; the Free Software Foundation dnl gives unlimited permission to copy and/or distribute it, dnl with or without modifications, as long as this notice is preserved. dnl From Bruno Haible. dnl Test whether has the 'wint_t' type. dnl Prerequisite: AC_PROG_CC AC_DEFUN([gt_TYPE_WINT_T], [ AC_CACHE_CHECK([for wint_t], gt_cv_c_wint_t, [AC_TRY_COMPILE([#include wint_t foo = (wchar_t)'\0';], , gt_cv_c_wint_t=yes, gt_cv_c_wint_t=no)]) if test $gt_cv_c_wint_t = yes; then AC_DEFINE(HAVE_WINT_T, 1, [Define if you have the 'wint_t' type.]) fi ]) alpine-2.10+dfsg/m4/lib-ld.m40000600000175000017500000000653111512502114017265 0ustar paulproteuspaulproteus# lib-ld.m4 serial 3 (gettext-0.13) dnl Copyright (C) 1996-2003 Free Software Foundation, Inc. dnl This file is free software; the Free Software Foundation dnl gives unlimited permission to copy and/or distribute it, dnl with or without modifications, as long as this notice is preserved. dnl Subroutines of libtool.m4, dnl with replacements s/AC_/AC_LIB/ and s/lt_cv/acl_cv/ to avoid collision dnl with libtool.m4. dnl From libtool-1.4. Sets the variable with_gnu_ld to yes or no. AC_DEFUN([AC_LIB_PROG_LD_GNU], [AC_CACHE_CHECK([if the linker ($LD) is GNU ld], acl_cv_prog_gnu_ld, [# I'd rather use --version here, but apparently some GNU ld's only accept -v. case `$LD -v 2>&1 conf$$.sh echo "exit 0" >>conf$$.sh chmod +x conf$$.sh if (PATH="/nonexistent;."; conf$$.sh) >/dev/null 2>&1; then PATH_SEPARATOR=';' else PATH_SEPARATOR=: fi rm -f conf$$.sh fi ac_prog=ld if test "$GCC" = yes; then # Check if gcc -print-prog-name=ld gives a path. AC_MSG_CHECKING([for ld used by GCC]) case $host in *-*-mingw*) # gcc leaves a trailing carriage return which upsets mingw ac_prog=`($CC -print-prog-name=ld) 2>&5 | tr -d '\015'` ;; *) ac_prog=`($CC -print-prog-name=ld) 2>&5` ;; esac case $ac_prog in # Accept absolute paths. [[\\/]* | [A-Za-z]:[\\/]*)] [re_direlt='/[^/][^/]*/\.\./'] # Canonicalize the path of ld ac_prog=`echo $ac_prog| sed 's%\\\\%/%g'` while echo $ac_prog | grep "$re_direlt" > /dev/null 2>&1; do ac_prog=`echo $ac_prog| sed "s%$re_direlt%/%"` done test -z "$LD" && LD="$ac_prog" ;; "") # If it fails, then pretend we aren't using GCC. ac_prog=ld ;; *) # If it is relative, then search for the first ld in PATH. with_gnu_ld=unknown ;; esac elif test "$with_gnu_ld" = yes; then AC_MSG_CHECKING([for GNU ld]) else AC_MSG_CHECKING([for non-GNU ld]) fi AC_CACHE_VAL(acl_cv_path_LD, [if test -z "$LD"; then IFS="${IFS= }"; ac_save_ifs="$IFS"; IFS="${IFS}${PATH_SEPARATOR-:}" for ac_dir in $PATH; do test -z "$ac_dir" && ac_dir=. if test -f "$ac_dir/$ac_prog" || test -f "$ac_dir/$ac_prog$ac_exeext"; then acl_cv_path_LD="$ac_dir/$ac_prog" # Check to see if the program is GNU ld. I'd rather use --version, # but apparently some GNU ld's only accept -v. # Break only if it was the GNU/non-GNU ld that we prefer. case `"$acl_cv_path_LD" -v 2>&1 < /dev/null` in *GNU* | *'with BFD'*) test "$with_gnu_ld" != no && break ;; *) test "$with_gnu_ld" != yes && break ;; esac fi done IFS="$ac_save_ifs" else acl_cv_path_LD="$LD" # Let the user override the test with a path. fi]) LD="$acl_cv_path_LD" if test -n "$LD"; then AC_MSG_RESULT($LD) else AC_MSG_RESULT(no) fi test -z "$LD" && AC_MSG_ERROR([no acceptable ld found in \$PATH]) AC_LIB_PROG_LD_GNU ]) alpine-2.10+dfsg/m4/lock.m40000600000175000017500000002770512074052520017065 0ustar paulproteuspaulproteus# lock.m4 serial 6 (gettext-0.16) dnl Copyright (C) 2005-2006 Free Software Foundation, Inc. dnl This file is free software; the Free Software Foundation dnl gives unlimited permission to copy and/or distribute it, dnl with or without modifications, as long as this notice is preserved. dnl From Bruno Haible. dnl Tests for a multithreading library to be used. dnl Defines at most one of the macros USE_POSIX_THREADS, USE_SOLARIS_THREADS, dnl USE_PTH_THREADS, USE_WIN32_THREADS dnl Sets the variables LIBTHREAD and LTLIBTHREAD to the linker options for use dnl in a Makefile (LIBTHREAD for use without libtool, LTLIBTHREAD for use with dnl libtool). dnl Sets the variables LIBMULTITHREAD and LTLIBMULTITHREAD similarly, for dnl programs that really need multithread functionality. The difference dnl between LIBTHREAD and LIBMULTITHREAD is that on platforms supporting weak dnl symbols, typically LIBTHREAD="" whereas LIBMULTITHREAD="-lpthread". dnl Adds to CPPFLAGS the flag -D_REENTRANT or -D_THREAD_SAFE if needed for dnl multithread-safe programs. AC_DEFUN([gl_LOCK_EARLY], [ AC_REQUIRE([gl_LOCK_EARLY_BODY]) ]) dnl The guts of gl_LOCK_EARLY. Needs to be expanded only once. AC_DEFUN([gl_LOCK_EARLY_BODY], [ dnl Ordering constraints: This macro modifies CPPFLAGS in a way that dnl influences the result of the autoconf tests that test for *_unlocked dnl declarations, on AIX 5 at least. Therefore it must come early. AC_BEFORE([$0], [gl_FUNC_GLIBC_UNLOCKED_IO])dnl AC_BEFORE([$0], [gl_ARGP])dnl AC_REQUIRE([AC_CANONICAL_HOST]) AC_REQUIRE([AC_GNU_SOURCE]) dnl needed for pthread_rwlock_t on glibc systems dnl Check for multithreading. AC_ARG_ENABLE(threads, AC_HELP_STRING([--enable-threads={posix|solaris|pth|win32}], [specify multithreading API]) AC_HELP_STRING([--disable-threads], [build without multithread safety]), [gl_use_threads=$enableval], [case "$host_os" in dnl Disable multithreading by default on OSF/1, because it interferes dnl with fork()/exec(): When msgexec is linked with -lpthread, its child dnl process gets an endless segmentation fault inside execvp(). osf*) gl_use_threads=no ;; *) gl_use_threads=yes ;; esac ]) if test "$gl_use_threads" = yes || test "$gl_use_threads" = posix; then # For using : case "$host_os" in osf*) # On OSF/1, the compiler needs the flag -D_REENTRANT so that it # groks . cc also understands the flag -pthread, but # we don't use it because 1. gcc-2.95 doesn't understand -pthread, # 2. putting a flag into CPPFLAGS that has an effect on the linker # causes the AC_TRY_LINK test below to succeed unexpectedly, # leading to wrong values of LIBTHREAD and LTLIBTHREAD. CPPFLAGS="$CPPFLAGS -D_REENTRANT" ;; esac # Some systems optimize for single-threaded programs by default, and # need special flags to disable these optimizations. For example, the # definition of 'errno' in . case "$host_os" in aix* | freebsd*) CPPFLAGS="$CPPFLAGS -D_THREAD_SAFE" ;; solaris*) CPPFLAGS="$CPPFLAGS -D_REENTRANT" ;; esac fi ]) dnl The guts of gl_LOCK. Needs to be expanded only once. AC_DEFUN([gl_LOCK_BODY], [ AC_REQUIRE([gl_LOCK_EARLY_BODY]) gl_threads_api=none LIBTHREAD= LTLIBTHREAD= LIBMULTITHREAD= LTLIBMULTITHREAD= if test "$gl_use_threads" != no; then dnl Check whether the compiler and linker support weak declarations. AC_MSG_CHECKING([whether imported symbols can be declared weak]) gl_have_weak=no AC_TRY_LINK([extern void xyzzy (); #pragma weak xyzzy], [xyzzy();], [gl_have_weak=yes]) AC_MSG_RESULT([$gl_have_weak]) if test "$gl_use_threads" = yes || test "$gl_use_threads" = posix; then # On OSF/1, the compiler needs the flag -pthread or -D_REENTRANT so that # it groks . It's added above, in gl_LOCK_EARLY_BODY. AC_CHECK_HEADER(pthread.h, gl_have_pthread_h=yes, gl_have_pthread_h=no) if test "$gl_have_pthread_h" = yes; then # Other possible tests: # -lpthreads (FSU threads, PCthreads) # -lgthreads gl_have_pthread= # Test whether both pthread_mutex_lock and pthread_mutexattr_init exist # in libc. IRIX 6.5 has the first one in both libc and libpthread, but # the second one only in libpthread, and lock.c needs it. AC_TRY_LINK([#include ], [pthread_mutex_lock((pthread_mutex_t*)0); pthread_mutexattr_init((pthread_mutexattr_t*)0);], [gl_have_pthread=yes]) # Test for libpthread by looking for pthread_kill. (Not pthread_self, # since it is defined as a macro on OSF/1.) if test -n "$gl_have_pthread"; then # The program links fine without libpthread. But it may actually # need to link with libpthread in order to create multiple threads. AC_CHECK_LIB(pthread, pthread_kill, [LIBMULTITHREAD=-lpthread LTLIBMULTITHREAD=-lpthread # On Solaris and HP-UX, most pthread functions exist also in libc. # Therefore pthread_in_use() needs to actually try to create a # thread: pthread_create from libc will fail, whereas # pthread_create will actually create a thread. case "$host_os" in solaris* | hpux*) AC_DEFINE([PTHREAD_IN_USE_DETECTION_HARD], 1, [Define if the pthread_in_use() detection is hard.]) esac ]) else # Some library is needed. Try libpthread and libc_r. AC_CHECK_LIB(pthread, pthread_kill, [gl_have_pthread=yes LIBTHREAD=-lpthread LTLIBTHREAD=-lpthread LIBMULTITHREAD=-lpthread LTLIBMULTITHREAD=-lpthread]) if test -z "$gl_have_pthread"; then # For FreeBSD 4. AC_CHECK_LIB(c_r, pthread_kill, [gl_have_pthread=yes LIBTHREAD=-lc_r LTLIBTHREAD=-lc_r LIBMULTITHREAD=-lc_r LTLIBMULTITHREAD=-lc_r]) fi fi if test -n "$gl_have_pthread"; then gl_threads_api=posix AC_DEFINE([USE_POSIX_THREADS], 1, [Define if the POSIX multithreading library can be used.]) if test -n "$LIBMULTITHREAD" || test -n "$LTLIBMULTITHREAD"; then if test $gl_have_weak = yes; then AC_DEFINE([USE_POSIX_THREADS_WEAK], 1, [Define if references to the POSIX multithreading library should be made weak.]) LIBTHREAD= LTLIBTHREAD= fi fi # OSF/1 4.0 and MacOS X 10.1 lack the pthread_rwlock_t type and the # pthread_rwlock_* functions. AC_CHECK_TYPE([pthread_rwlock_t], [AC_DEFINE([HAVE_PTHREAD_RWLOCK], 1, [Define if the POSIX multithreading library has read/write locks.])], [], [#include ]) # glibc defines PTHREAD_MUTEX_RECURSIVE as enum, not as a macro. AC_TRY_COMPILE([#include ], [#if __FreeBSD__ == 4 error "No, in FreeBSD 4.0 recursive mutexes actually don't work." #else int x = (int)PTHREAD_MUTEX_RECURSIVE; return !x; #endif], [AC_DEFINE([HAVE_PTHREAD_MUTEX_RECURSIVE], 1, [Define if the defines PTHREAD_MUTEX_RECURSIVE.])]) fi fi fi if test -z "$gl_have_pthread"; then if test "$gl_use_threads" = yes || test "$gl_use_threads" = solaris; then gl_have_solaristhread= gl_save_LIBS="$LIBS" LIBS="$LIBS -lthread" AC_TRY_LINK([#include #include ], [thr_self();], [gl_have_solaristhread=yes]) LIBS="$gl_save_LIBS" if test -n "$gl_have_solaristhread"; then gl_threads_api=solaris LIBTHREAD=-lthread LTLIBTHREAD=-lthread LIBMULTITHREAD="$LIBTHREAD" LTLIBMULTITHREAD="$LTLIBTHREAD" AC_DEFINE([USE_SOLARIS_THREADS], 1, [Define if the old Solaris multithreading library can be used.]) if test $gl_have_weak = yes; then AC_DEFINE([USE_SOLARIS_THREADS_WEAK], 1, [Define if references to the old Solaris multithreading library should be made weak.]) LIBTHREAD= LTLIBTHREAD= fi fi fi fi if test "$gl_use_threads" = pth; then gl_save_CPPFLAGS="$CPPFLAGS" AC_LIB_LINKFLAGS(pth) gl_have_pth= gl_save_LIBS="$LIBS" LIBS="$LIBS -lpth" AC_TRY_LINK([#include ], [pth_self();], gl_have_pth=yes) LIBS="$gl_save_LIBS" if test -n "$gl_have_pth"; then gl_threads_api=pth LIBTHREAD="$LIBPTH" LTLIBTHREAD="$LTLIBPTH" LIBMULTITHREAD="$LIBTHREAD" LTLIBMULTITHREAD="$LTLIBTHREAD" AC_DEFINE([USE_PTH_THREADS], 1, [Define if the GNU Pth multithreading library can be used.]) if test -n "$LIBMULTITHREAD" || test -n "$LTLIBMULTITHREAD"; then if test $gl_have_weak = yes; then AC_DEFINE([USE_PTH_THREADS_WEAK], 1, [Define if references to the GNU Pth multithreading library should be made weak.]) LIBTHREAD= LTLIBTHREAD= fi fi else CPPFLAGS="$gl_save_CPPFLAGS" fi fi if test -z "$gl_have_pthread"; then if test "$gl_use_threads" = yes || test "$gl_use_threads" = win32; then if { case "$host_os" in mingw*) true;; *) false;; esac }; then gl_threads_api=win32 AC_DEFINE([USE_WIN32_THREADS], 1, [Define if the Win32 multithreading API can be used.]) fi fi fi fi AC_MSG_CHECKING([for multithread API to use]) AC_MSG_RESULT([$gl_threads_api]) AC_SUBST(LIBTHREAD) AC_SUBST(LTLIBTHREAD) AC_SUBST(LIBMULTITHREAD) AC_SUBST(LTLIBMULTITHREAD) ]) AC_DEFUN([gl_LOCK], [ AC_REQUIRE([gl_LOCK_EARLY]) AC_REQUIRE([gl_LOCK_BODY]) gl_PREREQ_LOCK ]) # Prerequisites of lib/lock.c. AC_DEFUN([gl_PREREQ_LOCK], [ AC_REQUIRE([AC_C_INLINE]) ]) dnl Survey of platforms: dnl dnl Platform Available Compiler Supports test-lock dnl flavours option weak result dnl --------------- --------- --------- -------- --------- dnl Linux 2.4/glibc posix -lpthread Y OK dnl dnl GNU Hurd/glibc posix dnl dnl FreeBSD 5.3 posix -lc_r Y dnl posix -lkse ? Y dnl posix -lpthread ? Y dnl posix -lthr Y dnl dnl FreeBSD 5.2 posix -lc_r Y dnl posix -lkse Y dnl posix -lthr Y dnl dnl FreeBSD 4.0,4.10 posix -lc_r Y OK dnl dnl NetBSD 1.6 -- dnl dnl OpenBSD 3.4 posix -lpthread Y OK dnl dnl MacOS X 10.[123] posix -lpthread Y OK dnl dnl Solaris 7,8,9 posix -lpthread Y Sol 7,8: 0.0; Sol 9: OK dnl solaris -lthread Y Sol 7,8: 0.0; Sol 9: OK dnl dnl HP-UX 11 posix -lpthread N (cc) OK dnl Y (gcc) dnl dnl IRIX 6.5 posix -lpthread Y 0.5 dnl dnl AIX 4.3,5.1 posix -lpthread N AIX 4: 0.5; AIX 5: OK dnl dnl OSF/1 4.0,5.1 posix -pthread (cc) N OK dnl -lpthread (gcc) Y dnl dnl Cygwin posix -lpthread Y OK dnl dnl Any of the above pth -lpth 0.0 dnl dnl Mingw win32 N OK dnl dnl BeOS 5 -- dnl dnl The test-lock result shows what happens if in test-lock.c EXPLICIT_YIELD is dnl turned off: dnl OK if all three tests terminate OK, dnl 0.5 if the first test terminates OK but the second one loops endlessly, dnl 0.0 if the first test already loops endlessly. alpine-2.10+dfsg/m4/lt~obsolete.m40000600000175000017500000001311312074110240020465 0ustar paulproteuspaulproteus# lt~obsolete.m4 -- aclocal satisfying obsolete definitions. -*-Autoconf-*- # # Copyright (C) 2004, 2005, 2007 Free Software Foundation, Inc. # Written by Scott James Remnant, 2004. # # This file is free software; the Free Software Foundation gives # unlimited permission to copy and/or distribute it, with or without # modifications, as long as this notice is preserved. # serial 4 lt~obsolete.m4 # These exist entirely to fool aclocal when bootstrapping libtool. # # In the past libtool.m4 has provided macros via AC_DEFUN (or AU_DEFUN) # which have later been changed to m4_define as they aren't part of the # exported API, or moved to Autoconf or Automake where they belong. # # The trouble is, aclocal is a bit thick. It'll see the old AC_DEFUN # in /usr/share/aclocal/libtool.m4 and remember it, then when it sees us # using a macro with the same name in our local m4/libtool.m4 it'll # pull the old libtool.m4 in (it doesn't see our shiny new m4_define # and doesn't know about Autoconf macros at all.) # # So we provide this file, which has a silly filename so it's always # included after everything else. This provides aclocal with the # AC_DEFUNs it wants, but when m4 processes it, it doesn't do anything # because those macros already exist, or will be overwritten later. # We use AC_DEFUN over AU_DEFUN for compatibility with aclocal-1.6. # # Anytime we withdraw an AC_DEFUN or AU_DEFUN, remember to add it here. # Yes, that means every name once taken will need to remain here until # we give up compatibility with versions before 1.7, at which point # we need to keep only those names which we still refer to. # This is to help aclocal find these macros, as it can't see m4_define. AC_DEFUN([LTOBSOLETE_VERSION], [m4_if([1])]) m4_ifndef([AC_LIBTOOL_LINKER_OPTION], [AC_DEFUN([AC_LIBTOOL_LINKER_OPTION])]) m4_ifndef([AC_PROG_EGREP], [AC_DEFUN([AC_PROG_EGREP])]) m4_ifndef([_LT_AC_PROG_ECHO_BACKSLASH], [AC_DEFUN([_LT_AC_PROG_ECHO_BACKSLASH])]) m4_ifndef([_LT_AC_SHELL_INIT], [AC_DEFUN([_LT_AC_SHELL_INIT])]) m4_ifndef([_LT_AC_SYS_LIBPATH_AIX], [AC_DEFUN([_LT_AC_SYS_LIBPATH_AIX])]) m4_ifndef([_LT_PROG_LTMAIN], [AC_DEFUN([_LT_PROG_LTMAIN])]) m4_ifndef([_LT_AC_TAGVAR], [AC_DEFUN([_LT_AC_TAGVAR])]) m4_ifndef([AC_LTDL_ENABLE_INSTALL], [AC_DEFUN([AC_LTDL_ENABLE_INSTALL])]) m4_ifndef([AC_LTDL_PREOPEN], [AC_DEFUN([AC_LTDL_PREOPEN])]) m4_ifndef([_LT_AC_SYS_COMPILER], [AC_DEFUN([_LT_AC_SYS_COMPILER])]) m4_ifndef([_LT_AC_LOCK], [AC_DEFUN([_LT_AC_LOCK])]) m4_ifndef([AC_LIBTOOL_SYS_OLD_ARCHIVE], [AC_DEFUN([AC_LIBTOOL_SYS_OLD_ARCHIVE])]) m4_ifndef([_LT_AC_TRY_DLOPEN_SELF], [AC_DEFUN([_LT_AC_TRY_DLOPEN_SELF])]) m4_ifndef([AC_LIBTOOL_PROG_CC_C_O], [AC_DEFUN([AC_LIBTOOL_PROG_CC_C_O])]) m4_ifndef([AC_LIBTOOL_SYS_HARD_LINK_LOCKS], [AC_DEFUN([AC_LIBTOOL_SYS_HARD_LINK_LOCKS])]) m4_ifndef([AC_LIBTOOL_OBJDIR], [AC_DEFUN([AC_LIBTOOL_OBJDIR])]) m4_ifndef([AC_LTDL_OBJDIR], [AC_DEFUN([AC_LTDL_OBJDIR])]) m4_ifndef([AC_LIBTOOL_PROG_LD_HARDCODE_LIBPATH], [AC_DEFUN([AC_LIBTOOL_PROG_LD_HARDCODE_LIBPATH])]) m4_ifndef([AC_LIBTOOL_SYS_LIB_STRIP], [AC_DEFUN([AC_LIBTOOL_SYS_LIB_STRIP])]) m4_ifndef([AC_PATH_MAGIC], [AC_DEFUN([AC_PATH_MAGIC])]) m4_ifndef([AC_PROG_LD_GNU], [AC_DEFUN([AC_PROG_LD_GNU])]) m4_ifndef([AC_PROG_LD_RELOAD_FLAG], [AC_DEFUN([AC_PROG_LD_RELOAD_FLAG])]) m4_ifndef([AC_DEPLIBS_CHECK_METHOD], [AC_DEFUN([AC_DEPLIBS_CHECK_METHOD])]) m4_ifndef([AC_LIBTOOL_PROG_COMPILER_NO_RTTI], [AC_DEFUN([AC_LIBTOOL_PROG_COMPILER_NO_RTTI])]) m4_ifndef([AC_LIBTOOL_SYS_GLOBAL_SYMBOL_PIPE], [AC_DEFUN([AC_LIBTOOL_SYS_GLOBAL_SYMBOL_PIPE])]) m4_ifndef([AC_LIBTOOL_PROG_COMPILER_PIC], [AC_DEFUN([AC_LIBTOOL_PROG_COMPILER_PIC])]) m4_ifndef([AC_LIBTOOL_PROG_LD_SHLIBS], [AC_DEFUN([AC_LIBTOOL_PROG_LD_SHLIBS])]) m4_ifndef([AC_LIBTOOL_POSTDEP_PREDEP], [AC_DEFUN([AC_LIBTOOL_POSTDEP_PREDEP])]) m4_ifndef([LT_AC_PROG_EGREP], [AC_DEFUN([LT_AC_PROG_EGREP])]) m4_ifndef([LT_AC_PROG_SED], [AC_DEFUN([LT_AC_PROG_SED])]) m4_ifndef([_LT_CC_BASENAME], [AC_DEFUN([_LT_CC_BASENAME])]) m4_ifndef([_LT_COMPILER_BOILERPLATE], [AC_DEFUN([_LT_COMPILER_BOILERPLATE])]) m4_ifndef([_LT_LINKER_BOILERPLATE], [AC_DEFUN([_LT_LINKER_BOILERPLATE])]) m4_ifndef([_AC_PROG_LIBTOOL], [AC_DEFUN([_AC_PROG_LIBTOOL])]) m4_ifndef([AC_LIBTOOL_SETUP], [AC_DEFUN([AC_LIBTOOL_SETUP])]) m4_ifndef([_LT_AC_CHECK_DLFCN], [AC_DEFUN([_LT_AC_CHECK_DLFCN])]) m4_ifndef([AC_LIBTOOL_SYS_DYNAMIC_LINKER], [AC_DEFUN([AC_LIBTOOL_SYS_DYNAMIC_LINKER])]) m4_ifndef([_LT_AC_TAGCONFIG], [AC_DEFUN([_LT_AC_TAGCONFIG])]) m4_ifndef([AC_DISABLE_FAST_INSTALL], [AC_DEFUN([AC_DISABLE_FAST_INSTALL])]) m4_ifndef([_LT_AC_LANG_CXX], [AC_DEFUN([_LT_AC_LANG_CXX])]) m4_ifndef([_LT_AC_LANG_F77], [AC_DEFUN([_LT_AC_LANG_F77])]) m4_ifndef([_LT_AC_LANG_GCJ], [AC_DEFUN([_LT_AC_LANG_GCJ])]) m4_ifndef([AC_LIBTOOL_RC], [AC_DEFUN([AC_LIBTOOL_RC])]) m4_ifndef([AC_LIBTOOL_LANG_C_CONFIG], [AC_DEFUN([AC_LIBTOOL_LANG_C_CONFIG])]) m4_ifndef([_LT_AC_LANG_C_CONFIG], [AC_DEFUN([_LT_AC_LANG_C_CONFIG])]) m4_ifndef([AC_LIBTOOL_LANG_CXX_CONFIG], [AC_DEFUN([AC_LIBTOOL_LANG_CXX_CONFIG])]) m4_ifndef([_LT_AC_LANG_CXX_CONFIG], [AC_DEFUN([_LT_AC_LANG_CXX_CONFIG])]) m4_ifndef([AC_LIBTOOL_LANG_F77_CONFIG], [AC_DEFUN([AC_LIBTOOL_LANG_F77_CONFIG])]) m4_ifndef([_LT_AC_LANG_F77_CONFIG], [AC_DEFUN([_LT_AC_LANG_F77_CONFIG])]) m4_ifndef([AC_LIBTOOL_LANG_GCJ_CONFIG], [AC_DEFUN([AC_LIBTOOL_LANG_GCJ_CONFIG])]) m4_ifndef([_LT_AC_LANG_GCJ_CONFIG], [AC_DEFUN([_LT_AC_LANG_GCJ_CONFIG])]) m4_ifndef([AC_LIBTOOL_LANG_RC_CONFIG], [AC_DEFUN([AC_LIBTOOL_LANG_RC_CONFIG])]) m4_ifndef([_LT_AC_LANG_RC_CONFIG], [AC_DEFUN([_LT_AC_LANG_RC_CONFIG])]) m4_ifndef([AC_LIBTOOL_CONFIG], [AC_DEFUN([AC_LIBTOOL_CONFIG])]) m4_ifndef([_LT_AC_FILE_LTDLL_C], [AC_DEFUN([_LT_AC_FILE_LTDLL_C])]) alpine-2.10+dfsg/m4/po.m40000600000175000017500000004336712074052520016555 0ustar paulproteuspaulproteus# po.m4 serial 13 (gettext-0.15) dnl Copyright (C) 1995-2006 Free Software Foundation, Inc. dnl This file is free software; the Free Software Foundation dnl gives unlimited permission to copy and/or distribute it, dnl with or without modifications, as long as this notice is preserved. dnl dnl This file can can be used in projects which are not available under dnl the GNU General Public License or the GNU Library General Public dnl License but which still want to provide support for the GNU gettext dnl functionality. dnl Please note that the actual code of the GNU gettext library is covered dnl by the GNU Library General Public License, and the rest of the GNU dnl gettext package package is covered by the GNU General Public License. dnl They are *not* in the public domain. dnl Authors: dnl Ulrich Drepper , 1995-2000. dnl Bruno Haible , 2000-2003. AC_PREREQ(2.50) dnl Checks for all prerequisites of the po subdirectory. AC_DEFUN([AM_PO_SUBDIRS], [ AC_REQUIRE([AC_PROG_MAKE_SET])dnl AC_REQUIRE([AC_PROG_INSTALL])dnl AC_REQUIRE([AM_PROG_MKDIR_P])dnl defined by automake AC_REQUIRE([AM_NLS])dnl dnl Perform the following tests also if --disable-nls has been given, dnl because they are needed for "make dist" to work. dnl Search for GNU msgfmt in the PATH. dnl The first test excludes Solaris msgfmt and early GNU msgfmt versions. dnl The second test excludes FreeBSD msgfmt. AM_PATH_PROG_WITH_TEST(MSGFMT, msgfmt, [$ac_dir/$ac_word --statistics /dev/null >&]AS_MESSAGE_LOG_FD[ 2>&1 && (if $ac_dir/$ac_word --statistics /dev/null 2>&1 >/dev/null | grep usage >/dev/null; then exit 1; else exit 0; fi)], :) AC_PATH_PROG(GMSGFMT, gmsgfmt, $MSGFMT) dnl Test whether it is GNU msgfmt >= 0.15. changequote(,)dnl case `$MSGFMT --version | sed 1q | sed -e 's,^[^0-9]*,,'` in '' | 0.[0-9] | 0.[0-9].* | 0.1[0-4] | 0.1[0-4].*) MSGFMT_015=: ;; *) MSGFMT_015=$MSGFMT ;; esac changequote([,])dnl AC_SUBST([MSGFMT_015]) changequote(,)dnl case `$GMSGFMT --version | sed 1q | sed -e 's,^[^0-9]*,,'` in '' | 0.[0-9] | 0.[0-9].* | 0.1[0-4] | 0.1[0-4].*) GMSGFMT_015=: ;; *) GMSGFMT_015=$GMSGFMT ;; esac changequote([,])dnl AC_SUBST([GMSGFMT_015]) dnl Search for GNU xgettext 0.12 or newer in the PATH. dnl The first test excludes Solaris xgettext and early GNU xgettext versions. dnl The second test excludes FreeBSD xgettext. AM_PATH_PROG_WITH_TEST(XGETTEXT, xgettext, [$ac_dir/$ac_word --omit-header --copyright-holder= --msgid-bugs-address= /dev/null >&]AS_MESSAGE_LOG_FD[ 2>&1 && (if $ac_dir/$ac_word --omit-header --copyright-holder= --msgid-bugs-address= /dev/null 2>&1 >/dev/null | grep usage >/dev/null; then exit 1; else exit 0; fi)], :) dnl Remove leftover from FreeBSD xgettext call. rm -f messages.po dnl Test whether it is GNU xgettext >= 0.15. changequote(,)dnl case `$XGETTEXT --version | sed 1q | sed -e 's,^[^0-9]*,,'` in '' | 0.[0-9] | 0.[0-9].* | 0.1[0-4] | 0.1[0-4].*) XGETTEXT_015=: ;; *) XGETTEXT_015=$XGETTEXT ;; esac changequote([,])dnl AC_SUBST([XGETTEXT_015]) dnl Search for GNU msgmerge 0.11 or newer in the PATH. AM_PATH_PROG_WITH_TEST(MSGMERGE, msgmerge, [$ac_dir/$ac_word --update -q /dev/null /dev/null >&]AS_MESSAGE_LOG_FD[ 2>&1], :) dnl Installation directories. dnl Autoconf >= 2.60 defines localedir. For older versions of autoconf, we dnl have to define it here, so that it can be used in po/Makefile. test -n "$localedir" || localedir='${datadir}/locale' AC_SUBST([localedir]) AC_CONFIG_COMMANDS([po-directories], [[ for ac_file in $CONFIG_FILES; do # Support "outfile[:infile[:infile...]]" case "$ac_file" in *:*) ac_file=`echo "$ac_file"|sed 's%:.*%%'` ;; esac # PO directories have a Makefile.in generated from Makefile.in.in. case "$ac_file" in */Makefile.in) # Adjust a relative srcdir. ac_dir=`echo "$ac_file"|sed 's%/[^/][^/]*$%%'` ac_dir_suffix="/`echo "$ac_dir"|sed 's%^\./%%'`" ac_dots=`echo "$ac_dir_suffix"|sed 's%/[^/]*%../%g'` # In autoconf-2.13 it is called $ac_given_srcdir. # In autoconf-2.50 it is called $srcdir. test -n "$ac_given_srcdir" || ac_given_srcdir="$srcdir" case "$ac_given_srcdir" in .) top_srcdir=`echo $ac_dots|sed 's%/$%%'` ;; /*) top_srcdir="$ac_given_srcdir" ;; *) top_srcdir="$ac_dots$ac_given_srcdir" ;; esac # Treat a directory as a PO directory if and only if it has a # POTFILES.in file. This allows packages to have multiple PO # directories under different names or in different locations. if test -f "$ac_given_srcdir/$ac_dir/POTFILES.in"; then rm -f "$ac_dir/POTFILES" test -n "$as_me" && echo "$as_me: creating $ac_dir/POTFILES" || echo "creating $ac_dir/POTFILES" cat "$ac_given_srcdir/$ac_dir/POTFILES.in" | sed -e "/^#/d" -e "/^[ ]*\$/d" -e "s,.*, $top_srcdir/& \\\\," | sed -e "\$s/\(.*\) \\\\/\1/" > "$ac_dir/POTFILES" POMAKEFILEDEPS="POTFILES.in" # ALL_LINGUAS, POFILES, UPDATEPOFILES, DUMMYPOFILES, GMOFILES depend # on $ac_dir but don't depend on user-specified configuration # parameters. if test -f "$ac_given_srcdir/$ac_dir/LINGUAS"; then # The LINGUAS file contains the set of available languages. if test -n "$OBSOLETE_ALL_LINGUAS"; then test -n "$as_me" && echo "$as_me: setting ALL_LINGUAS in configure.in is obsolete" || echo "setting ALL_LINGUAS in configure.in is obsolete" fi ALL_LINGUAS_=`sed -e "/^#/d" -e "s/#.*//" "$ac_given_srcdir/$ac_dir/LINGUAS"` # Hide the ALL_LINGUAS assigment from automake < 1.5. eval 'ALL_LINGUAS''=$ALL_LINGUAS_' POMAKEFILEDEPS="$POMAKEFILEDEPS LINGUAS" else # The set of available languages was given in configure.in. # Hide the ALL_LINGUAS assigment from automake < 1.5. eval 'ALL_LINGUAS''=$OBSOLETE_ALL_LINGUAS' fi # Compute POFILES # as $(foreach lang, $(ALL_LINGUAS), $(srcdir)/$(lang).po) # Compute UPDATEPOFILES # as $(foreach lang, $(ALL_LINGUAS), $(lang).po-update) # Compute DUMMYPOFILES # as $(foreach lang, $(ALL_LINGUAS), $(lang).nop) # Compute GMOFILES # as $(foreach lang, $(ALL_LINGUAS), $(srcdir)/$(lang).gmo) case "$ac_given_srcdir" in .) srcdirpre= ;; *) srcdirpre='$(srcdir)/' ;; esac POFILES= UPDATEPOFILES= DUMMYPOFILES= GMOFILES= for lang in $ALL_LINGUAS; do POFILES="$POFILES $srcdirpre$lang.po" UPDATEPOFILES="$UPDATEPOFILES $lang.po-update" DUMMYPOFILES="$DUMMYPOFILES $lang.nop" GMOFILES="$GMOFILES $srcdirpre$lang.gmo" done # CATALOGS depends on both $ac_dir and the user's LINGUAS # environment variable. INST_LINGUAS= if test -n "$ALL_LINGUAS"; then for presentlang in $ALL_LINGUAS; do useit=no if test "%UNSET%" != "$LINGUAS"; then desiredlanguages="$LINGUAS" else desiredlanguages="$ALL_LINGUAS" fi for desiredlang in $desiredlanguages; do # Use the presentlang catalog if desiredlang is # a. equal to presentlang, or # b. a variant of presentlang (because in this case, # presentlang can be used as a fallback for messages # which are not translated in the desiredlang catalog). case "$desiredlang" in "$presentlang"*) useit=yes;; esac done if test $useit = yes; then INST_LINGUAS="$INST_LINGUAS $presentlang" fi done fi CATALOGS= if test -n "$INST_LINGUAS"; then for lang in $INST_LINGUAS; do CATALOGS="$CATALOGS $lang.gmo" done fi test -n "$as_me" && echo "$as_me: creating $ac_dir/Makefile" || echo "creating $ac_dir/Makefile" sed -e "/^POTFILES =/r $ac_dir/POTFILES" -e "/^# Makevars/r $ac_given_srcdir/$ac_dir/Makevars" -e "s|@POFILES@|$POFILES|g" -e "s|@UPDATEPOFILES@|$UPDATEPOFILES|g" -e "s|@DUMMYPOFILES@|$DUMMYPOFILES|g" -e "s|@GMOFILES@|$GMOFILES|g" -e "s|@CATALOGS@|$CATALOGS|g" -e "s|@POMAKEFILEDEPS@|$POMAKEFILEDEPS|g" "$ac_dir/Makefile.in" > "$ac_dir/Makefile" for f in "$ac_given_srcdir/$ac_dir"/Rules-*; do if test -f "$f"; then case "$f" in *.orig | *.bak | *~) ;; *) cat "$f" >> "$ac_dir/Makefile" ;; esac fi done fi ;; esac done]], [# Capture the value of obsolete ALL_LINGUAS because we need it to compute # POFILES, UPDATEPOFILES, DUMMYPOFILES, GMOFILES, CATALOGS. But hide it # from automake < 1.5. eval 'OBSOLETE_ALL_LINGUAS''="$ALL_LINGUAS"' # Capture the value of LINGUAS because we need it to compute CATALOGS. LINGUAS="${LINGUAS-%UNSET%}" ]) ]) dnl Postprocesses a Makefile in a directory containing PO files. AC_DEFUN([AM_POSTPROCESS_PO_MAKEFILE], [ # When this code is run, in config.status, two variables have already been # set: # - OBSOLETE_ALL_LINGUAS is the value of LINGUAS set in configure.in, # - LINGUAS is the value of the environment variable LINGUAS at configure # time. changequote(,)dnl # Adjust a relative srcdir. ac_dir=`echo "$ac_file"|sed 's%/[^/][^/]*$%%'` ac_dir_suffix="/`echo "$ac_dir"|sed 's%^\./%%'`" ac_dots=`echo "$ac_dir_suffix"|sed 's%/[^/]*%../%g'` # In autoconf-2.13 it is called $ac_given_srcdir. # In autoconf-2.50 it is called $srcdir. test -n "$ac_given_srcdir" || ac_given_srcdir="$srcdir" case "$ac_given_srcdir" in .) top_srcdir=`echo $ac_dots|sed 's%/$%%'` ;; /*) top_srcdir="$ac_given_srcdir" ;; *) top_srcdir="$ac_dots$ac_given_srcdir" ;; esac # Find a way to echo strings without interpreting backslash. if test "X`(echo '\t') 2>/dev/null`" = 'X\t'; then gt_echo='echo' else if test "X`(printf '%s\n' '\t') 2>/dev/null`" = 'X\t'; then gt_echo='printf %s\n' else echo_func () { cat < "$ac_file.tmp" if grep -l '@TCLCATALOGS@' "$ac_file" > /dev/null; then # Add dependencies that cannot be formulated as a simple suffix rule. for lang in $ALL_LINGUAS; do frobbedlang=`echo $lang | sed -e 's/\..*$//' -e 'y/ABCDEFGHIJKLMNOPQRSTUVWXYZ/abcdefghijklmnopqrstuvwxyz/'` cat >> "$ac_file.tmp" < /dev/null; then # Add dependencies that cannot be formulated as a simple suffix rule. for lang in $ALL_LINGUAS; do frobbedlang=`echo $lang | sed -e 's/_/-/g' -e 's/^sr-CS/sr-SP/' -e 's/@latin$/-Latn/' -e 's/@cyrillic$/-Cyrl/' -e 's/^sr-SP$/sr-SP-Latn/' -e 's/^uz-UZ$/uz-UZ-Latn/'` cat >> "$ac_file.tmp" <> "$ac_file.tmp" < exists, # doesn't clash with , and declares uintmax_t. AC_DEFUN([gl_AC_HEADER_STDINT_H], [ AC_CACHE_CHECK([for stdint.h], gl_cv_header_stdint_h, [AC_TRY_COMPILE( [#include #include ], [uintmax_t i = (uintmax_t) -1; return !i;], gl_cv_header_stdint_h=yes, gl_cv_header_stdint_h=no)]) if test $gl_cv_header_stdint_h = yes; then AC_DEFINE_UNQUOTED(HAVE_STDINT_H_WITH_UINTMAX, 1, [Define if exists, doesn't clash with , and declares uintmax_t. ]) fi ]) alpine-2.10+dfsg/m4/uintmax_t.m40000600000175000017500000000207611512502114020132 0ustar paulproteuspaulproteus# uintmax_t.m4 serial 9 dnl Copyright (C) 1997-2004 Free Software Foundation, Inc. dnl This file is free software; the Free Software Foundation dnl gives unlimited permission to copy and/or distribute it, dnl with or without modifications, as long as this notice is preserved. dnl From Paul Eggert. AC_PREREQ(2.13) # Define uintmax_t to 'unsigned long' or 'unsigned long long' # if it is not already defined in or . AC_DEFUN([gl_AC_TYPE_UINTMAX_T], [ AC_REQUIRE([gl_AC_HEADER_INTTYPES_H]) AC_REQUIRE([gl_AC_HEADER_STDINT_H]) if test $gl_cv_header_inttypes_h = no && test $gl_cv_header_stdint_h = no; then AC_REQUIRE([gl_AC_TYPE_UNSIGNED_LONG_LONG]) test $ac_cv_type_unsigned_long_long = yes \ && ac_type='unsigned long long' \ || ac_type='unsigned long' AC_DEFINE_UNQUOTED(uintmax_t, $ac_type, [Define to unsigned long or unsigned long long if and don't define.]) else AC_DEFINE(HAVE_UINTMAX_T, 1, [Define if you have the 'uintmax_t' type in or .]) fi ]) alpine-2.10+dfsg/m4/intl.m40000600000175000017500000002333012074052520017071 0ustar paulproteuspaulproteus# intl.m4 serial 3 (gettext-0.16) dnl Copyright (C) 1995-2006 Free Software Foundation, Inc. dnl This file is free software; the Free Software Foundation dnl gives unlimited permission to copy and/or distribute it, dnl with or without modifications, as long as this notice is preserved. dnl dnl This file can can be used in projects which are not available under dnl the GNU General Public License or the GNU Library General Public dnl License but which still want to provide support for the GNU gettext dnl functionality. dnl Please note that the actual code of the GNU gettext library is covered dnl by the GNU Library General Public License, and the rest of the GNU dnl gettext package package is covered by the GNU General Public License. dnl They are *not* in the public domain. dnl Authors: dnl Ulrich Drepper , 1995-2000. dnl Bruno Haible , 2000-2006. AC_PREREQ(2.52) dnl Checks for all prerequisites of the intl subdirectory, dnl except for INTL_LIBTOOL_SUFFIX_PREFIX (and possibly LIBTOOL), INTLOBJS, dnl USE_INCLUDED_LIBINTL, BUILD_INCLUDED_LIBINTL. AC_DEFUN([AM_INTL_SUBDIR], [ AC_REQUIRE([AC_PROG_INSTALL])dnl AC_REQUIRE([AM_PROG_MKDIR_P])dnl defined by automake AC_REQUIRE([AC_PROG_CC])dnl AC_REQUIRE([AC_CANONICAL_HOST])dnl AC_REQUIRE([gt_GLIBC2])dnl AC_REQUIRE([AC_PROG_RANLIB])dnl AC_REQUIRE([gl_VISIBILITY])dnl AC_REQUIRE([gt_INTL_SUBDIR_CORE])dnl AC_REQUIRE([AC_TYPE_LONG_LONG_INT])dnl AC_REQUIRE([gt_TYPE_LONGDOUBLE])dnl AC_REQUIRE([gt_TYPE_WCHAR_T])dnl AC_REQUIRE([gt_TYPE_WINT_T])dnl AC_REQUIRE([gl_AC_HEADER_INTTYPES_H]) AC_REQUIRE([gt_TYPE_INTMAX_T]) AC_REQUIRE([gt_PRINTF_POSIX]) AC_REQUIRE([gl_GLIBC21])dnl AC_REQUIRE([gl_XSIZE])dnl AC_REQUIRE([gt_INTL_MACOSX])dnl AC_CHECK_TYPE([ptrdiff_t], , [AC_DEFINE([ptrdiff_t], [long], [Define as the type of the result of subtracting two pointers, if the system doesn't define it.]) ]) AC_CHECK_HEADERS([stddef.h stdlib.h string.h]) AC_CHECK_FUNCS([asprintf fwprintf putenv setenv setlocale snprintf wcslen]) dnl Use the _snprintf function only if it is declared (because on NetBSD it dnl is defined as a weak alias of snprintf; we prefer to use the latter). gt_CHECK_DECL(_snprintf, [#include ]) gt_CHECK_DECL(_snwprintf, [#include ]) dnl Use the *_unlocked functions only if they are declared. dnl (because some of them were defined without being declared in Solaris dnl 2.5.1 but were removed in Solaris 2.6, whereas we want binaries built dnl on Solaris 2.5.1 to run on Solaris 2.6). dnl Don't use AC_CHECK_DECLS because it isn't supported in autoconf-2.13. gt_CHECK_DECL(getc_unlocked, [#include ]) case $gt_cv_func_printf_posix in *yes) HAVE_POSIX_PRINTF=1 ;; *) HAVE_POSIX_PRINTF=0 ;; esac AC_SUBST([HAVE_POSIX_PRINTF]) if test "$ac_cv_func_asprintf" = yes; then HAVE_ASPRINTF=1 else HAVE_ASPRINTF=0 fi AC_SUBST([HAVE_ASPRINTF]) if test "$ac_cv_func_snprintf" = yes; then HAVE_SNPRINTF=1 else HAVE_SNPRINTF=0 fi AC_SUBST([HAVE_SNPRINTF]) if test "$ac_cv_func_wprintf" = yes; then HAVE_WPRINTF=1 else HAVE_WPRINTF=0 fi AC_SUBST([HAVE_WPRINTF]) AM_LANGINFO_CODESET gt_LC_MESSAGES dnl Compilation on mingw and Cygwin needs special Makefile rules, because dnl 1. when we install a shared library, we must arrange to export dnl auxiliary pointer variables for every exported variable, dnl 2. when we install a shared library and a static library simultaneously, dnl the include file specifies __declspec(dllimport) and therefore we dnl must arrange to define the auxiliary pointer variables for the dnl exported variables _also_ in the static library. if test "$enable_shared" = yes; then case "$host_os" in cygwin*) is_woe32dll=yes ;; *) is_woe32dll=no ;; esac else is_woe32dll=no fi WOE32DLL=$is_woe32dll AC_SUBST([WOE32DLL]) dnl Rename some macros and functions used for locking. AH_BOTTOM([ #define __libc_lock_t gl_lock_t #define __libc_lock_define gl_lock_define #define __libc_lock_define_initialized gl_lock_define_initialized #define __libc_lock_init gl_lock_init #define __libc_lock_lock gl_lock_lock #define __libc_lock_unlock gl_lock_unlock #define __libc_lock_recursive_t gl_recursive_lock_t #define __libc_lock_define_recursive gl_recursive_lock_define #define __libc_lock_define_initialized_recursive gl_recursive_lock_define_initialized #define __libc_lock_init_recursive gl_recursive_lock_init #define __libc_lock_lock_recursive gl_recursive_lock_lock #define __libc_lock_unlock_recursive gl_recursive_lock_unlock #define glthread_in_use libintl_thread_in_use #define glthread_lock_init libintl_lock_init #define glthread_lock_lock libintl_lock_lock #define glthread_lock_unlock libintl_lock_unlock #define glthread_lock_destroy libintl_lock_destroy #define glthread_rwlock_init libintl_rwlock_init #define glthread_rwlock_rdlock libintl_rwlock_rdlock #define glthread_rwlock_wrlock libintl_rwlock_wrlock #define glthread_rwlock_unlock libintl_rwlock_unlock #define glthread_rwlock_destroy libintl_rwlock_destroy #define glthread_recursive_lock_init libintl_recursive_lock_init #define glthread_recursive_lock_lock libintl_recursive_lock_lock #define glthread_recursive_lock_unlock libintl_recursive_lock_unlock #define glthread_recursive_lock_destroy libintl_recursive_lock_destroy #define glthread_once libintl_once #define glthread_once_call libintl_once_call #define glthread_once_singlethreaded libintl_once_singlethreaded ]) ]) dnl Checks for the core files of the intl subdirectory: dnl dcigettext.c dnl eval-plural.h dnl explodename.c dnl finddomain.c dnl gettextP.h dnl gmo.h dnl hash-string.h hash-string.c dnl l10nflist.c dnl libgnuintl.h.in (except the *printf stuff) dnl loadinfo.h dnl loadmsgcat.c dnl localealias.c dnl log.c dnl plural-exp.h plural-exp.c dnl plural.y dnl Used by libglocale. AC_DEFUN([gt_INTL_SUBDIR_CORE], [ AC_REQUIRE([AC_C_INLINE])dnl AC_REQUIRE([AC_TYPE_SIZE_T])dnl AC_REQUIRE([gl_AC_HEADER_STDINT_H]) AC_REQUIRE([AC_FUNC_ALLOCA])dnl AC_REQUIRE([AC_FUNC_MMAP])dnl AC_REQUIRE([gt_INTDIV0])dnl AC_REQUIRE([gl_AC_TYPE_UINTMAX_T])dnl AC_REQUIRE([gt_INTTYPES_PRI])dnl AC_REQUIRE([gl_LOCK])dnl AC_TRY_LINK( [int foo (int a) { a = __builtin_expect (a, 10); return a == 10 ? 0 : 1; }], [], [AC_DEFINE([HAVE_BUILTIN_EXPECT], 1, [Define to 1 if the compiler understands __builtin_expect.])]) AC_CHECK_HEADERS([argz.h inttypes.h limits.h unistd.h sys/param.h]) AC_CHECK_FUNCS([getcwd getegid geteuid getgid getuid mempcpy munmap \ stpcpy strcasecmp strdup strtoul tsearch argz_count argz_stringify \ argz_next __fsetlocking]) dnl Use the *_unlocked functions only if they are declared. dnl (because some of them were defined without being declared in Solaris dnl 2.5.1 but were removed in Solaris 2.6, whereas we want binaries built dnl on Solaris 2.5.1 to run on Solaris 2.6). dnl Don't use AC_CHECK_DECLS because it isn't supported in autoconf-2.13. gt_CHECK_DECL(feof_unlocked, [#include ]) gt_CHECK_DECL(fgets_unlocked, [#include ]) AM_ICONV dnl glibc >= 2.4 has a NL_LOCALE_NAME macro when _GNU_SOURCE is defined, dnl and a _NL_LOCALE_NAME macro always. AC_CACHE_CHECK([for NL_LOCALE_NAME macro], gt_cv_nl_locale_name, [AC_TRY_LINK([#include #include ], [char* cs = nl_langinfo(_NL_LOCALE_NAME(LC_MESSAGES));], gt_cv_nl_locale_name=yes, gt_cv_nl_locale_name=no) ]) if test $gt_cv_nl_locale_name = yes; then AC_DEFINE(HAVE_NL_LOCALE_NAME, 1, [Define if you have and it defines the NL_LOCALE_NAME macro if _GNU_SOURCE is defined.]) fi dnl intl/plural.c is generated from intl/plural.y. It requires bison, dnl because plural.y uses bison specific features. It requires at least dnl bison-1.26 because earlier versions generate a plural.c that doesn't dnl compile. dnl bison is only needed for the maintainer (who touches plural.y). But in dnl order to avoid separate Makefiles or --enable-maintainer-mode, we put dnl the rule in general Makefile. Now, some people carelessly touch the dnl files or have a broken "make" program, hence the plural.c rule will dnl sometimes fire. To avoid an error, defines BISON to ":" if it is not dnl present or too old. AC_CHECK_PROGS([INTLBISON], [bison]) if test -z "$INTLBISON"; then ac_verc_fail=yes else dnl Found it, now check the version. AC_MSG_CHECKING([version of bison]) changequote(<<,>>)dnl ac_prog_version=`$INTLBISON --version 2>&1 | sed -n 's/^.*GNU Bison.* \([0-9]*\.[0-9.]*\).*$/\1/p'` case $ac_prog_version in '') ac_prog_version="v. ?.??, bad"; ac_verc_fail=yes;; 1.2[6-9]* | 1.[3-9][0-9]* | [2-9].*) changequote([,])dnl ac_prog_version="$ac_prog_version, ok"; ac_verc_fail=no;; *) ac_prog_version="$ac_prog_version, bad"; ac_verc_fail=yes;; esac AC_MSG_RESULT([$ac_prog_version]) fi if test $ac_verc_fail = yes; then INTLBISON=: fi ]) dnl gt_CHECK_DECL(FUNC, INCLUDES) dnl Check whether a function is declared. AC_DEFUN([gt_CHECK_DECL], [ AC_CACHE_CHECK([whether $1 is declared], ac_cv_have_decl_$1, [AC_TRY_COMPILE([$2], [ #ifndef $1 char *p = (char *) $1; #endif ], ac_cv_have_decl_$1=yes, ac_cv_have_decl_$1=no)]) if test $ac_cv_have_decl_$1 = yes; then gt_value=1 else gt_value=0 fi AC_DEFINE_UNQUOTED([HAVE_DECL_]translit($1, [a-z], [A-Z]), [$gt_value], [Define to 1 if you have the declaration of `$1', and to 0 if you don't.]) ]) alpine-2.10+dfsg/m4/intmax.m40000600000175000017500000000201112074052520017414 0ustar paulproteuspaulproteus# intmax.m4 serial 3 (gettext-0.16) dnl Copyright (C) 2002-2005 Free Software Foundation, Inc. dnl This file is free software; the Free Software Foundation dnl gives unlimited permission to copy and/or distribute it, dnl with or without modifications, as long as this notice is preserved. dnl From Bruno Haible. dnl Test whether the system has the 'intmax_t' type, but don't attempt to dnl find a replacement if it is lacking. AC_DEFUN([gt_TYPE_INTMAX_T], [ AC_REQUIRE([gl_AC_HEADER_INTTYPES_H]) AC_REQUIRE([gl_AC_HEADER_STDINT_H]) AC_CACHE_CHECK(for intmax_t, gt_cv_c_intmax_t, [AC_TRY_COMPILE([ #include #include #if HAVE_STDINT_H_WITH_UINTMAX #include #endif #if HAVE_INTTYPES_H_WITH_UINTMAX #include #endif ], [intmax_t x = -1; return !x;], gt_cv_c_intmax_t=yes, gt_cv_c_intmax_t=no)]) if test $gt_cv_c_intmax_t = yes; then AC_DEFINE(HAVE_INTMAX_T, 1, [Define if you have the 'intmax_t' type in or .]) fi ]) alpine-2.10+dfsg/m4/Makefile.in0000600000175000017500000002623412074110253017732 0ustar paulproteuspaulproteus# Makefile.in generated by automake 1.11.1 from Makefile.am. # @configure_input@ # Copyright (C) 1994, 1995, 1996, 1997, 1998, 1999, 2000, 2001, 2002, # 2003, 2004, 2005, 2006, 2007, 2008, 2009 Free Software Foundation, # Inc. # This Makefile.in is free software; the Free Software Foundation # gives unlimited permission to copy and/or distribute it, # with or without modifications, as long as this notice is preserved. # This program is distributed in the hope that it will be useful, # but WITHOUT ANY WARRANTY, to the extent permitted by law; without # even the implied warranty of MERCHANTABILITY or FITNESS FOR A # PARTICULAR PURPOSE. @SET_MAKE@ VPATH = @srcdir@ pkgdatadir = $(datadir)/@PACKAGE@ pkgincludedir = $(includedir)/@PACKAGE@ pkglibdir = $(libdir)/@PACKAGE@ pkglibexecdir = $(libexecdir)/@PACKAGE@ am__cd = CDPATH="$${ZSH_VERSION+.}$(PATH_SEPARATOR)" && cd install_sh_DATA = $(install_sh) -c -m 644 install_sh_PROGRAM = $(install_sh) -c install_sh_SCRIPT = $(install_sh) -c INSTALL_HEADER = $(INSTALL_DATA) transform = $(program_transform_name) NORMAL_INSTALL = : PRE_INSTALL = : POST_INSTALL = : NORMAL_UNINSTALL = : PRE_UNINSTALL = : POST_UNINSTALL = : build_triplet = @build@ host_triplet = @host@ subdir = m4 DIST_COMMON = $(srcdir)/Makefile.am $(srcdir)/Makefile.in ChangeLog ACLOCAL_M4 = $(top_srcdir)/aclocal.m4 am__aclocal_m4_deps = $(top_srcdir)/m4/acx_pthread.m4 \ $(top_srcdir)/m4/gettext.m4 $(top_srcdir)/m4/iconv.m4 \ $(top_srcdir)/m4/lib-ld.m4 $(top_srcdir)/m4/lib-link.m4 \ $(top_srcdir)/m4/lib-prefix.m4 $(top_srcdir)/m4/libtool.m4 \ $(top_srcdir)/m4/ltoptions.m4 $(top_srcdir)/m4/ltsugar.m4 \ $(top_srcdir)/m4/ltversion.m4 $(top_srcdir)/m4/lt~obsolete.m4 \ $(top_srcdir)/m4/nls.m4 $(top_srcdir)/m4/po.m4 \ $(top_srcdir)/m4/progtest.m4 $(top_srcdir)/VERSION \ $(top_srcdir)/configure.ac am__configure_deps = $(am__aclocal_m4_deps) $(CONFIGURE_DEPENDENCIES) \ $(ACLOCAL_M4) mkinstalldirs = $(SHELL) $(top_srcdir)/mkinstalldirs CONFIG_HEADER = $(top_builddir)/include/config.h CONFIG_CLEAN_FILES = CONFIG_CLEAN_VPATH_FILES = SOURCES = DIST_SOURCES = DISTFILES = $(DIST_COMMON) $(DIST_SOURCES) $(TEXINFOS) $(EXTRA_DIST) ACLOCAL = @ACLOCAL@ AMTAR = @AMTAR@ AM_CFLAGS = @AM_CFLAGS@ AM_LDFLAGS = @AM_LDFLAGS@ AR = @AR@ AUTOCONF = @AUTOCONF@ AUTOHEADER = @AUTOHEADER@ AUTOMAKE = @AUTOMAKE@ AWK = @AWK@ CC = @CC@ CCDEPMODE = @CCDEPMODE@ CFLAGS = @CFLAGS@ CP = @CP@ CPP = @CPP@ CPPFLAGS = @CPPFLAGS@ CYGPATH_W = @CYGPATH_W@ C_CLIENT_CFLAGS = @C_CLIENT_CFLAGS@ C_CLIENT_GCCOPTLEVEL = @C_CLIENT_GCCOPTLEVEL@ C_CLIENT_LDFLAGS = @C_CLIENT_LDFLAGS@ C_CLIENT_SPECIALS = @C_CLIENT_SPECIALS@ C_CLIENT_TARGET = @C_CLIENT_TARGET@ C_CLIENT_WITH_IPV6 = @C_CLIENT_WITH_IPV6@ DEFS = @DEFS@ DEPDIR = @DEPDIR@ DSYMUTIL = @DSYMUTIL@ DUMPBIN = @DUMPBIN@ ECHO_C = @ECHO_C@ ECHO_N = @ECHO_N@ ECHO_T = @ECHO_T@ EGREP = @EGREP@ EXEEXT = @EXEEXT@ FGREP = @FGREP@ GMSGFMT = @GMSGFMT@ GMSGFMT_015 = @GMSGFMT_015@ GREP = @GREP@ INSTALL = @INSTALL@ INSTALL_DATA = @INSTALL_DATA@ INSTALL_PROGRAM = @INSTALL_PROGRAM@ INSTALL_SCRIPT = @INSTALL_SCRIPT@ INSTALL_STRIP_PROGRAM = @INSTALL_STRIP_PROGRAM@ INTLLIBS = @INTLLIBS@ INTL_MACOSX_LIBS = @INTL_MACOSX_LIBS@ ISPELLPROG = @ISPELLPROG@ LD = @LD@ LDFLAGS = @LDFLAGS@ LIBICONV = @LIBICONV@ LIBINTL = @LIBINTL@ LIBOBJS = @LIBOBJS@ LIBS = @LIBS@ LIBTOOL = @LIBTOOL@ LIPO = @LIPO@ LN = @LN@ LN_S = @LN_S@ LTLIBICONV = @LTLIBICONV@ LTLIBINTL = @LTLIBINTL@ LTLIBOBJS = @LTLIBOBJS@ MAINT = @MAINT@ MAKE = @MAKE@ MAKEINFO = @MAKEINFO@ MKDIR_P = @MKDIR_P@ MSGFMT = @MSGFMT@ MSGFMT_015 = @MSGFMT_015@ MSGMERGE = @MSGMERGE@ NM = @NM@ NMEDIT = @NMEDIT@ NPA_PROG = @NPA_PROG@ OBJDUMP = @OBJDUMP@ OBJEXT = @OBJEXT@ OTOOL = @OTOOL@ OTOOL64 = @OTOOL64@ PACKAGE = @PACKAGE@ PACKAGE_BUGREPORT = @PACKAGE_BUGREPORT@ PACKAGE_NAME = @PACKAGE_NAME@ PACKAGE_STRING = @PACKAGE_STRING@ PACKAGE_TARNAME = @PACKAGE_TARNAME@ PACKAGE_URL = @PACKAGE_URL@ PACKAGE_VERSION = @PACKAGE_VERSION@ PATH_SEPARATOR = @PATH_SEPARATOR@ POSUB = @POSUB@ PTHREAD_CC = @PTHREAD_CC@ PTHREAD_CFLAGS = @PTHREAD_CFLAGS@ PTHREAD_LIBS = @PTHREAD_LIBS@ PWPROG = @PWPROG@ RANLIB = @RANLIB@ REGEX_BUILD = @REGEX_BUILD@ RM = @RM@ SED = @SED@ SENDMAIL = @SENDMAIL@ SET_MAKE = @SET_MAKE@ SHELL = @SHELL@ SPELLPROG = @SPELLPROG@ STRIP = @STRIP@ USE_NLS = @USE_NLS@ VERSION = @VERSION@ WEB_BINDIR = @WEB_BINDIR@ WEB_BUILD = @WEB_BUILD@ WEB_PUBCOOKIE_BUILD = @WEB_PUBCOOKIE_BUILD@ WEB_PUBCOOKIE_LIB = @WEB_PUBCOOKIE_LIB@ WEB_PUBCOOKIE_LINK = @WEB_PUBCOOKIE_LINK@ XGETTEXT = @XGETTEXT@ XGETTEXT_015 = @XGETTEXT_015@ abs_builddir = @abs_builddir@ abs_srcdir = @abs_srcdir@ abs_top_builddir = @abs_top_builddir@ abs_top_srcdir = @abs_top_srcdir@ ac_ct_CC = @ac_ct_CC@ ac_ct_DUMPBIN = @ac_ct_DUMPBIN@ acx_pthread_config = @acx_pthread_config@ alpine_interactive_spellcheck = @alpine_interactive_spellcheck@ alpine_simple_spellcheck = @alpine_simple_spellcheck@ am__include = @am__include@ am__leading_dot = @am__leading_dot@ am__quote = @am__quote@ am__tar = @am__tar@ am__untar = @am__untar@ bindir = @bindir@ build = @build@ build_alias = @build_alias@ build_cpu = @build_cpu@ build_os = @build_os@ build_vendor = @build_vendor@ builddir = @builddir@ datadir = @datadir@ datarootdir = @datarootdir@ docdir = @docdir@ dvidir = @dvidir@ exec_prefix = @exec_prefix@ host = @host@ host_alias = @host_alias@ host_cpu = @host_cpu@ host_os = @host_os@ host_vendor = @host_vendor@ htmldir = @htmldir@ includedir = @includedir@ infodir = @infodir@ install_sh = @install_sh@ libdir = @libdir@ libexecdir = @libexecdir@ localedir = @localedir@ localstatedir = @localstatedir@ lt_ECHO = @lt_ECHO@ mandir = @mandir@ mkdir_p = @mkdir_p@ oldincludedir = @oldincludedir@ pdfdir = @pdfdir@ prefix = @prefix@ program_transform_name = @program_transform_name@ psdir = @psdir@ sbindir = @sbindir@ sharedstatedir = @sharedstatedir@ srcdir = @srcdir@ sysconfdir = @sysconfdir@ target_alias = @target_alias@ top_build_prefix = @top_build_prefix@ top_builddir = @top_builddir@ top_srcdir = @top_srcdir@ EXTRA_DIST = glibc2.m4 intmax.m4 longdouble.m4 longlong.m4 printf-posix.m4 signed.m4 size_max.m4 wchar_t.m4 wint_t.m4 xsize.m4 codeset.m4 gettext.m4 glibc21.m4 iconv.m4 intdiv0.m4 inttypes.m4 inttypes_h.m4 inttypes-pri.m4 isc-posix.m4 lcmessage.m4 lib-ld.m4 lib-link.m4 lib-prefix.m4 nls.m4 po.m4 progtest.m4 stdint_h.m4 uintmax_t.m4 ulonglong.m4 all: all-am .SUFFIXES: $(srcdir)/Makefile.in: @MAINTAINER_MODE_TRUE@ $(srcdir)/Makefile.am $(am__configure_deps) @for dep in $?; do \ case '$(am__configure_deps)' in \ *$$dep*) \ ( cd $(top_builddir) && $(MAKE) $(AM_MAKEFLAGS) am--refresh ) \ && { if test -f $@; then exit 0; else break; fi; }; \ exit 1;; \ esac; \ done; \ echo ' cd $(top_srcdir) && $(AUTOMAKE) --foreign m4/Makefile'; \ $(am__cd) $(top_srcdir) && \ $(AUTOMAKE) --foreign m4/Makefile .PRECIOUS: Makefile Makefile: $(srcdir)/Makefile.in $(top_builddir)/config.status @case '$?' in \ *config.status*) \ cd $(top_builddir) && $(MAKE) $(AM_MAKEFLAGS) am--refresh;; \ *) \ echo ' cd $(top_builddir) && $(SHELL) ./config.status $(subdir)/$@ $(am__depfiles_maybe)'; \ cd $(top_builddir) && $(SHELL) ./config.status $(subdir)/$@ $(am__depfiles_maybe);; \ esac; $(top_builddir)/config.status: $(top_srcdir)/configure $(CONFIG_STATUS_DEPENDENCIES) cd $(top_builddir) && $(MAKE) $(AM_MAKEFLAGS) am--refresh $(top_srcdir)/configure: @MAINTAINER_MODE_TRUE@ $(am__configure_deps) cd $(top_builddir) && $(MAKE) $(AM_MAKEFLAGS) am--refresh $(ACLOCAL_M4): @MAINTAINER_MODE_TRUE@ $(am__aclocal_m4_deps) cd $(top_builddir) && $(MAKE) $(AM_MAKEFLAGS) am--refresh $(am__aclocal_m4_deps): mostlyclean-libtool: -rm -f *.lo clean-libtool: -rm -rf .libs _libs tags: TAGS TAGS: ctags: CTAGS CTAGS: distdir: $(DISTFILES) @srcdirstrip=`echo "$(srcdir)" | sed 's/[].[^$$\\*]/\\\\&/g'`; \ topsrcdirstrip=`echo "$(top_srcdir)" | sed 's/[].[^$$\\*]/\\\\&/g'`; \ list='$(DISTFILES)'; \ dist_files=`for file in $$list; do echo $$file; done | \ sed -e "s|^$$srcdirstrip/||;t" \ -e "s|^$$topsrcdirstrip/|$(top_builddir)/|;t"`; \ case $$dist_files in \ */*) $(MKDIR_P) `echo "$$dist_files" | \ sed '/\//!d;s|^|$(distdir)/|;s,/[^/]*$$,,' | \ sort -u` ;; \ esac; \ for file in $$dist_files; do \ if test -f $$file || test -d $$file; then d=.; else d=$(srcdir); fi; \ if test -d $$d/$$file; then \ dir=`echo "/$$file" | sed -e 's,/[^/]*$$,,'`; \ if test -d "$(distdir)/$$file"; then \ find "$(distdir)/$$file" -type d ! -perm -700 -exec chmod u+rwx {} \;; \ fi; \ if test -d $(srcdir)/$$file && test $$d != $(srcdir); then \ cp -fpR $(srcdir)/$$file "$(distdir)$$dir" || exit 1; \ find "$(distdir)/$$file" -type d ! -perm -700 -exec chmod u+rwx {} \;; \ fi; \ cp -fpR $$d/$$file "$(distdir)$$dir" || exit 1; \ else \ test -f "$(distdir)/$$file" \ || cp -p $$d/$$file "$(distdir)/$$file" \ || exit 1; \ fi; \ done check-am: all-am check: check-am all-am: Makefile installdirs: install: install-am install-exec: install-exec-am install-data: install-data-am uninstall: uninstall-am install-am: all-am @$(MAKE) $(AM_MAKEFLAGS) install-exec-am install-data-am installcheck: installcheck-am install-strip: $(MAKE) $(AM_MAKEFLAGS) INSTALL_PROGRAM="$(INSTALL_STRIP_PROGRAM)" \ install_sh_PROGRAM="$(INSTALL_STRIP_PROGRAM)" INSTALL_STRIP_FLAG=-s \ `test -z '$(STRIP)' || \ echo "INSTALL_PROGRAM_ENV=STRIPPROG='$(STRIP)'"` install mostlyclean-generic: clean-generic: distclean-generic: -test -z "$(CONFIG_CLEAN_FILES)" || rm -f $(CONFIG_CLEAN_FILES) -test . = "$(srcdir)" || test -z "$(CONFIG_CLEAN_VPATH_FILES)" || rm -f $(CONFIG_CLEAN_VPATH_FILES) maintainer-clean-generic: @echo "This command is intended for maintainers to use" @echo "it deletes files that may require special tools to rebuild." clean: clean-am clean-am: clean-generic clean-libtool mostlyclean-am distclean: distclean-am -rm -f Makefile distclean-am: clean-am distclean-generic dvi: dvi-am dvi-am: html: html-am html-am: info: info-am info-am: install-data-am: install-dvi: install-dvi-am install-dvi-am: install-exec-am: install-html: install-html-am install-html-am: install-info: install-info-am install-info-am: install-man: install-pdf: install-pdf-am install-pdf-am: install-ps: install-ps-am install-ps-am: installcheck-am: maintainer-clean: maintainer-clean-am -rm -f Makefile maintainer-clean-am: distclean-am maintainer-clean-generic mostlyclean: mostlyclean-am mostlyclean-am: mostlyclean-generic mostlyclean-libtool pdf: pdf-am pdf-am: ps: ps-am ps-am: uninstall-am: .MAKE: install-am install-strip .PHONY: all all-am check check-am clean clean-generic clean-libtool \ distclean distclean-generic distclean-libtool distdir dvi \ dvi-am html html-am info info-am install install-am \ install-data install-data-am install-dvi install-dvi-am \ install-exec install-exec-am install-html install-html-am \ install-info install-info-am install-man install-pdf \ install-pdf-am install-ps install-ps-am install-strip \ installcheck installcheck-am installdirs maintainer-clean \ maintainer-clean-generic mostlyclean mostlyclean-generic \ mostlyclean-libtool pdf pdf-am ps ps-am uninstall uninstall-am # Tell versions [3.59,3.63) of GNU make to not export all variables. # Otherwise a system limit (for SysV at least) may be exceeded. .NOEXPORT: alpine-2.10+dfsg/m4/libtool.m40000600000175000017500000077343612074110240017604 0ustar paulproteuspaulproteus# libtool.m4 - Configure libtool for the host system. -*-Autoconf-*- # # Copyright (C) 1996, 1997, 1998, 1999, 2000, 2001, 2003, 2004, 2005, # 2006, 2007, 2008 Free Software Foundation, Inc. # Written by Gordon Matzigkeit, 1996 # # This file is free software; the Free Software Foundation gives # unlimited permission to copy and/or distribute it, with or without # modifications, as long as this notice is preserved. m4_define([_LT_COPYING], [dnl # Copyright (C) 1996, 1997, 1998, 1999, 2000, 2001, 2003, 2004, 2005, # 2006, 2007, 2008 Free Software Foundation, Inc. # Written by Gordon Matzigkeit, 1996 # # This file is part of GNU Libtool. # # GNU Libtool is free software; you can redistribute it and/or # modify it under the terms of the GNU General Public License as # published by the Free Software Foundation; either version 2 of # the License, or (at your option) any later version. # # As a special exception to the GNU General Public License, # if you distribute this file as part of a program or library that # is built using GNU Libtool, you may include this file under the # same distribution terms that you use for the rest of that program. # # GNU Libtool is distributed in the hope that it will be useful, # but WITHOUT ANY WARRANTY; without even the implied warranty of # MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the # GNU General Public License for more details. # # You should have received a copy of the GNU General Public License # along with GNU Libtool; see the file COPYING. If not, a copy # can be downloaded from http://www.gnu.org/licenses/gpl.html, or # obtained by writing to the Free Software Foundation, Inc., # 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA. ]) # serial 56 LT_INIT # LT_PREREQ(VERSION) # ------------------ # Complain and exit if this libtool version is less that VERSION. m4_defun([LT_PREREQ], [m4_if(m4_version_compare(m4_defn([LT_PACKAGE_VERSION]), [$1]), -1, [m4_default([$3], [m4_fatal([Libtool version $1 or higher is required], 63)])], [$2])]) # _LT_CHECK_BUILDDIR # ------------------ # Complain if the absolute build directory name contains unusual characters m4_defun([_LT_CHECK_BUILDDIR], [case `pwd` in *\ * | *\ *) AC_MSG_WARN([Libtool does not cope well with whitespace in `pwd`]) ;; esac ]) # LT_INIT([OPTIONS]) # ------------------ AC_DEFUN([LT_INIT], [AC_PREREQ([2.58])dnl We use AC_INCLUDES_DEFAULT AC_BEFORE([$0], [LT_LANG])dnl AC_BEFORE([$0], [LT_OUTPUT])dnl AC_BEFORE([$0], [LTDL_INIT])dnl m4_require([_LT_CHECK_BUILDDIR])dnl dnl Autoconf doesn't catch unexpanded LT_ macros by default: m4_pattern_forbid([^_?LT_[A-Z_]+$])dnl m4_pattern_allow([^(_LT_EOF|LT_DLGLOBAL|LT_DLLAZY_OR_NOW|LT_MULTI_MODULE)$])dnl dnl aclocal doesn't pull ltoptions.m4, ltsugar.m4, or ltversion.m4 dnl unless we require an AC_DEFUNed macro: AC_REQUIRE([LTOPTIONS_VERSION])dnl AC_REQUIRE([LTSUGAR_VERSION])dnl AC_REQUIRE([LTVERSION_VERSION])dnl AC_REQUIRE([LTOBSOLETE_VERSION])dnl m4_require([_LT_PROG_LTMAIN])dnl dnl Parse OPTIONS _LT_SET_OPTIONS([$0], [$1]) # This can be used to rebuild libtool when needed LIBTOOL_DEPS="$ltmain" # Always use our own libtool. LIBTOOL='$(SHELL) $(top_builddir)/libtool' AC_SUBST(LIBTOOL)dnl _LT_SETUP # Only expand once: m4_define([LT_INIT]) ])# LT_INIT # Old names: AU_ALIAS([AC_PROG_LIBTOOL], [LT_INIT]) AU_ALIAS([AM_PROG_LIBTOOL], [LT_INIT]) dnl aclocal-1.4 backwards compatibility: dnl AC_DEFUN([AC_PROG_LIBTOOL], []) dnl AC_DEFUN([AM_PROG_LIBTOOL], []) # _LT_CC_BASENAME(CC) # ------------------- # Calculate cc_basename. Skip known compiler wrappers and cross-prefix. m4_defun([_LT_CC_BASENAME], [for cc_temp in $1""; do case $cc_temp in compile | *[[\\/]]compile | ccache | *[[\\/]]ccache ) ;; distcc | *[[\\/]]distcc | purify | *[[\\/]]purify ) ;; \-*) ;; *) break;; esac done cc_basename=`$ECHO "X$cc_temp" | $Xsed -e 's%.*/%%' -e "s%^$host_alias-%%"` ]) # _LT_FILEUTILS_DEFAULTS # ---------------------- # It is okay to use these file commands and assume they have been set # sensibly after `m4_require([_LT_FILEUTILS_DEFAULTS])'. m4_defun([_LT_FILEUTILS_DEFAULTS], [: ${CP="cp -f"} : ${MV="mv -f"} : ${RM="rm -f"} ])# _LT_FILEUTILS_DEFAULTS # _LT_SETUP # --------- m4_defun([_LT_SETUP], [AC_REQUIRE([AC_CANONICAL_HOST])dnl AC_REQUIRE([AC_CANONICAL_BUILD])dnl _LT_DECL([], [host_alias], [0], [The host system])dnl _LT_DECL([], [host], [0])dnl _LT_DECL([], [host_os], [0])dnl dnl _LT_DECL([], [build_alias], [0], [The build system])dnl _LT_DECL([], [build], [0])dnl _LT_DECL([], [build_os], [0])dnl dnl AC_REQUIRE([AC_PROG_CC])dnl AC_REQUIRE([LT_PATH_LD])dnl AC_REQUIRE([LT_PATH_NM])dnl dnl AC_REQUIRE([AC_PROG_LN_S])dnl test -z "$LN_S" && LN_S="ln -s" _LT_DECL([], [LN_S], [1], [Whether we need soft or hard links])dnl dnl AC_REQUIRE([LT_CMD_MAX_LEN])dnl _LT_DECL([objext], [ac_objext], [0], [Object file suffix (normally "o")])dnl _LT_DECL([], [exeext], [0], [Executable file suffix (normally "")])dnl dnl m4_require([_LT_FILEUTILS_DEFAULTS])dnl m4_require([_LT_CHECK_SHELL_FEATURES])dnl m4_require([_LT_CMD_RELOAD])dnl m4_require([_LT_CHECK_MAGIC_METHOD])dnl m4_require([_LT_CMD_OLD_ARCHIVE])dnl m4_require([_LT_CMD_GLOBAL_SYMBOLS])dnl _LT_CONFIG_LIBTOOL_INIT([ # See if we are running on zsh, and set the options which allow our # commands through without removal of \ escapes INIT. if test -n "\${ZSH_VERSION+set}" ; then setopt NO_GLOB_SUBST fi ]) if test -n "${ZSH_VERSION+set}" ; then setopt NO_GLOB_SUBST fi _LT_CHECK_OBJDIR m4_require([_LT_TAG_COMPILER])dnl _LT_PROG_ECHO_BACKSLASH case $host_os in aix3*) # AIX sometimes has problems with the GCC collect2 program. For some # reason, if we set the COLLECT_NAMES environment variable, the problems # vanish in a puff of smoke. if test "X${COLLECT_NAMES+set}" != Xset; then COLLECT_NAMES= export COLLECT_NAMES fi ;; esac # Sed substitution that helps us do robust quoting. It backslashifies # metacharacters that are still active within double-quoted strings. sed_quote_subst='s/\([["`$\\]]\)/\\\1/g' # Same as above, but do not quote variable references. double_quote_subst='s/\([["`\\]]\)/\\\1/g' # Sed substitution to delay expansion of an escaped shell variable in a # double_quote_subst'ed string. delay_variable_subst='s/\\\\\\\\\\\$/\\\\\\$/g' # Sed substitution to delay expansion of an escaped single quote. delay_single_quote_subst='s/'\''/'\'\\\\\\\'\''/g' # Sed substitution to avoid accidental globbing in evaled expressions no_glob_subst='s/\*/\\\*/g' # Global variables: ofile=libtool can_build_shared=yes # All known linkers require a `.a' archive for static linking (except MSVC, # which needs '.lib'). libext=a with_gnu_ld="$lt_cv_prog_gnu_ld" old_CC="$CC" old_CFLAGS="$CFLAGS" # Set sane defaults for various variables test -z "$CC" && CC=cc test -z "$LTCC" && LTCC=$CC test -z "$LTCFLAGS" && LTCFLAGS=$CFLAGS test -z "$LD" && LD=ld test -z "$ac_objext" && ac_objext=o _LT_CC_BASENAME([$compiler]) # Only perform the check for file, if the check method requires it test -z "$MAGIC_CMD" && MAGIC_CMD=file case $deplibs_check_method in file_magic*) if test "$file_magic_cmd" = '$MAGIC_CMD'; then _LT_PATH_MAGIC fi ;; esac # Use C for the default configuration in the libtool script LT_SUPPORTED_TAG([CC]) _LT_LANG_C_CONFIG _LT_LANG_DEFAULT_CONFIG _LT_CONFIG_COMMANDS ])# _LT_SETUP # _LT_PROG_LTMAIN # --------------- # Note that this code is called both from `configure', and `config.status' # now that we use AC_CONFIG_COMMANDS to generate libtool. Notably, # `config.status' has no value for ac_aux_dir unless we are using Automake, # so we pass a copy along to make sure it has a sensible value anyway. m4_defun([_LT_PROG_LTMAIN], [m4_ifdef([AC_REQUIRE_AUX_FILE], [AC_REQUIRE_AUX_FILE([ltmain.sh])])dnl _LT_CONFIG_LIBTOOL_INIT([ac_aux_dir='$ac_aux_dir']) ltmain="$ac_aux_dir/ltmain.sh" ])# _LT_PROG_LTMAIN ## ------------------------------------- ## ## Accumulate code for creating libtool. ## ## ------------------------------------- ## # So that we can recreate a full libtool script including additional # tags, we accumulate the chunks of code to send to AC_CONFIG_COMMANDS # in macros and then make a single call at the end using the `libtool' # label. # _LT_CONFIG_LIBTOOL_INIT([INIT-COMMANDS]) # ---------------------------------------- # Register INIT-COMMANDS to be passed to AC_CONFIG_COMMANDS later. m4_define([_LT_CONFIG_LIBTOOL_INIT], [m4_ifval([$1], [m4_append([_LT_OUTPUT_LIBTOOL_INIT], [$1 ])])]) # Initialize. m4_define([_LT_OUTPUT_LIBTOOL_INIT]) # _LT_CONFIG_LIBTOOL([COMMANDS]) # ------------------------------ # Register COMMANDS to be passed to AC_CONFIG_COMMANDS later. m4_define([_LT_CONFIG_LIBTOOL], [m4_ifval([$1], [m4_append([_LT_OUTPUT_LIBTOOL_COMMANDS], [$1 ])])]) # Initialize. m4_define([_LT_OUTPUT_LIBTOOL_COMMANDS]) # _LT_CONFIG_SAVE_COMMANDS([COMMANDS], [INIT_COMMANDS]) # ----------------------------------------------------- m4_defun([_LT_CONFIG_SAVE_COMMANDS], [_LT_CONFIG_LIBTOOL([$1]) _LT_CONFIG_LIBTOOL_INIT([$2]) ]) # _LT_FORMAT_COMMENT([COMMENT]) # ----------------------------- # Add leading comment marks to the start of each line, and a trailing # full-stop to the whole comment if one is not present already. m4_define([_LT_FORMAT_COMMENT], [m4_ifval([$1], [ m4_bpatsubst([m4_bpatsubst([$1], [^ *], [# ])], [['`$\]], [\\\&])]m4_bmatch([$1], [[!?.]$], [], [.]) )]) ## ------------------------ ## ## FIXME: Eliminate VARNAME ## ## ------------------------ ## # _LT_DECL([CONFIGNAME], VARNAME, VALUE, [DESCRIPTION], [IS-TAGGED?]) # ------------------------------------------------------------------- # CONFIGNAME is the name given to the value in the libtool script. # VARNAME is the (base) name used in the configure script. # VALUE may be 0, 1 or 2 for a computed quote escaped value based on # VARNAME. Any other value will be used directly. m4_define([_LT_DECL], [lt_if_append_uniq([lt_decl_varnames], [$2], [, ], [lt_dict_add_subkey([lt_decl_dict], [$2], [libtool_name], [m4_ifval([$1], [$1], [$2])]) lt_dict_add_subkey([lt_decl_dict], [$2], [value], [$3]) m4_ifval([$4], [lt_dict_add_subkey([lt_decl_dict], [$2], [description], [$4])]) lt_dict_add_subkey([lt_decl_dict], [$2], [tagged?], [m4_ifval([$5], [yes], [no])])]) ]) # _LT_TAGDECL([CONFIGNAME], VARNAME, VALUE, [DESCRIPTION]) # -------------------------------------------------------- m4_define([_LT_TAGDECL], [_LT_DECL([$1], [$2], [$3], [$4], [yes])]) # lt_decl_tag_varnames([SEPARATOR], [VARNAME1...]) # ------------------------------------------------ m4_define([lt_decl_tag_varnames], [_lt_decl_filter([tagged?], [yes], $@)]) # _lt_decl_filter(SUBKEY, VALUE, [SEPARATOR], [VARNAME1..]) # --------------------------------------------------------- m4_define([_lt_decl_filter], [m4_case([$#], [0], [m4_fatal([$0: too few arguments: $#])], [1], [m4_fatal([$0: too few arguments: $#: $1])], [2], [lt_dict_filter([lt_decl_dict], [$1], [$2], [], lt_decl_varnames)], [3], [lt_dict_filter([lt_decl_dict], [$1], [$2], [$3], lt_decl_varnames)], [lt_dict_filter([lt_decl_dict], $@)])[]dnl ]) # lt_decl_quote_varnames([SEPARATOR], [VARNAME1...]) # -------------------------------------------------- m4_define([lt_decl_quote_varnames], [_lt_decl_filter([value], [1], $@)]) # lt_decl_dquote_varnames([SEPARATOR], [VARNAME1...]) # --------------------------------------------------- m4_define([lt_decl_dquote_varnames], [_lt_decl_filter([value], [2], $@)]) # lt_decl_varnames_tagged([SEPARATOR], [VARNAME1...]) # --------------------------------------------------- m4_define([lt_decl_varnames_tagged], [m4_assert([$# <= 2])dnl _$0(m4_quote(m4_default([$1], [[, ]])), m4_ifval([$2], [[$2]], [m4_dquote(lt_decl_tag_varnames)]), m4_split(m4_normalize(m4_quote(_LT_TAGS)), [ ]))]) m4_define([_lt_decl_varnames_tagged], [m4_ifval([$3], [lt_combine([$1], [$2], [_], $3)])]) # lt_decl_all_varnames([SEPARATOR], [VARNAME1...]) # ------------------------------------------------ m4_define([lt_decl_all_varnames], [_$0(m4_quote(m4_default([$1], [[, ]])), m4_if([$2], [], m4_quote(lt_decl_varnames), m4_quote(m4_shift($@))))[]dnl ]) m4_define([_lt_decl_all_varnames], [lt_join($@, lt_decl_varnames_tagged([$1], lt_decl_tag_varnames([[, ]], m4_shift($@))))dnl ]) # _LT_CONFIG_STATUS_DECLARE([VARNAME]) # ------------------------------------ # Quote a variable value, and forward it to `config.status' so that its # declaration there will have the same value as in `configure'. VARNAME # must have a single quote delimited value for this to work. m4_define([_LT_CONFIG_STATUS_DECLARE], [$1='`$ECHO "X$][$1" | $Xsed -e "$delay_single_quote_subst"`']) # _LT_CONFIG_STATUS_DECLARATIONS # ------------------------------ # We delimit libtool config variables with single quotes, so when # we write them to config.status, we have to be sure to quote all # embedded single quotes properly. In configure, this macro expands # each variable declared with _LT_DECL (and _LT_TAGDECL) into: # # ='`$ECHO "X$" | $Xsed -e "$delay_single_quote_subst"`' m4_defun([_LT_CONFIG_STATUS_DECLARATIONS], [m4_foreach([_lt_var], m4_quote(lt_decl_all_varnames), [m4_n([_LT_CONFIG_STATUS_DECLARE(_lt_var)])])]) # _LT_LIBTOOL_TAGS # ---------------- # Output comment and list of tags supported by the script m4_defun([_LT_LIBTOOL_TAGS], [_LT_FORMAT_COMMENT([The names of the tagged configurations supported by this script])dnl available_tags="_LT_TAGS"dnl ]) # _LT_LIBTOOL_DECLARE(VARNAME, [TAG]) # ----------------------------------- # Extract the dictionary values for VARNAME (optionally with TAG) and # expand to a commented shell variable setting: # # # Some comment about what VAR is for. # visible_name=$lt_internal_name m4_define([_LT_LIBTOOL_DECLARE], [_LT_FORMAT_COMMENT(m4_quote(lt_dict_fetch([lt_decl_dict], [$1], [description])))[]dnl m4_pushdef([_libtool_name], m4_quote(lt_dict_fetch([lt_decl_dict], [$1], [libtool_name])))[]dnl m4_case(m4_quote(lt_dict_fetch([lt_decl_dict], [$1], [value])), [0], [_libtool_name=[$]$1], [1], [_libtool_name=$lt_[]$1], [2], [_libtool_name=$lt_[]$1], [_libtool_name=lt_dict_fetch([lt_decl_dict], [$1], [value])])[]dnl m4_ifval([$2], [_$2])[]m4_popdef([_libtool_name])[]dnl ]) # _LT_LIBTOOL_CONFIG_VARS # ----------------------- # Produce commented declarations of non-tagged libtool config variables # suitable for insertion in the LIBTOOL CONFIG section of the `libtool' # script. Tagged libtool config variables (even for the LIBTOOL CONFIG # section) are produced by _LT_LIBTOOL_TAG_VARS. m4_defun([_LT_LIBTOOL_CONFIG_VARS], [m4_foreach([_lt_var], m4_quote(_lt_decl_filter([tagged?], [no], [], lt_decl_varnames)), [m4_n([_LT_LIBTOOL_DECLARE(_lt_var)])])]) # _LT_LIBTOOL_TAG_VARS(TAG) # ------------------------- m4_define([_LT_LIBTOOL_TAG_VARS], [m4_foreach([_lt_var], m4_quote(lt_decl_tag_varnames), [m4_n([_LT_LIBTOOL_DECLARE(_lt_var, [$1])])])]) # _LT_TAGVAR(VARNAME, [TAGNAME]) # ------------------------------ m4_define([_LT_TAGVAR], [m4_ifval([$2], [$1_$2], [$1])]) # _LT_CONFIG_COMMANDS # ------------------- # Send accumulated output to $CONFIG_STATUS. Thanks to the lists of # variables for single and double quote escaping we saved from calls # to _LT_DECL, we can put quote escaped variables declarations # into `config.status', and then the shell code to quote escape them in # for loops in `config.status'. Finally, any additional code accumulated # from calls to _LT_CONFIG_LIBTOOL_INIT is expanded. m4_defun([_LT_CONFIG_COMMANDS], [AC_PROVIDE_IFELSE([LT_OUTPUT], dnl If the libtool generation code has been placed in $CONFIG_LT, dnl instead of duplicating it all over again into config.status, dnl then we will have config.status run $CONFIG_LT later, so it dnl needs to know what name is stored there: [AC_CONFIG_COMMANDS([libtool], [$SHELL $CONFIG_LT || AS_EXIT(1)], [CONFIG_LT='$CONFIG_LT'])], dnl If the libtool generation code is destined for config.status, dnl expand the accumulated commands and init code now: [AC_CONFIG_COMMANDS([libtool], [_LT_OUTPUT_LIBTOOL_COMMANDS], [_LT_OUTPUT_LIBTOOL_COMMANDS_INIT])]) ])#_LT_CONFIG_COMMANDS # Initialize. m4_define([_LT_OUTPUT_LIBTOOL_COMMANDS_INIT], [ # The HP-UX ksh and POSIX shell print the target directory to stdout # if CDPATH is set. (unset CDPATH) >/dev/null 2>&1 && unset CDPATH sed_quote_subst='$sed_quote_subst' double_quote_subst='$double_quote_subst' delay_variable_subst='$delay_variable_subst' _LT_CONFIG_STATUS_DECLARATIONS LTCC='$LTCC' LTCFLAGS='$LTCFLAGS' compiler='$compiler_DEFAULT' # Quote evaled strings. for var in lt_decl_all_varnames([[ \ ]], lt_decl_quote_varnames); do case \`eval \\\\\$ECHO "X\\\\\$\$var"\` in *[[\\\\\\\`\\"\\\$]]*) eval "lt_\$var=\\\\\\"\\\`\\\$ECHO \\"X\\\$\$var\\" | \\\$Xsed -e \\"\\\$sed_quote_subst\\"\\\`\\\\\\"" ;; *) eval "lt_\$var=\\\\\\"\\\$\$var\\\\\\"" ;; esac done # Double-quote double-evaled strings. for var in lt_decl_all_varnames([[ \ ]], lt_decl_dquote_varnames); do case \`eval \\\\\$ECHO "X\\\\\$\$var"\` in *[[\\\\\\\`\\"\\\$]]*) eval "lt_\$var=\\\\\\"\\\`\\\$ECHO \\"X\\\$\$var\\" | \\\$Xsed -e \\"\\\$double_quote_subst\\" -e \\"\\\$sed_quote_subst\\" -e \\"\\\$delay_variable_subst\\"\\\`\\\\\\"" ;; *) eval "lt_\$var=\\\\\\"\\\$\$var\\\\\\"" ;; esac done # Fix-up fallback echo if it was mangled by the above quoting rules. case \$lt_ECHO in *'\\\[$]0 --fallback-echo"')dnl " lt_ECHO=\`\$ECHO "X\$lt_ECHO" | \$Xsed -e 's/\\\\\\\\\\\\\\\[$]0 --fallback-echo"\[$]/\[$]0 --fallback-echo"/'\` ;; esac _LT_OUTPUT_LIBTOOL_INIT ]) # LT_OUTPUT # --------- # This macro allows early generation of the libtool script (before # AC_OUTPUT is called), incase it is used in configure for compilation # tests. AC_DEFUN([LT_OUTPUT], [: ${CONFIG_LT=./config.lt} AC_MSG_NOTICE([creating $CONFIG_LT]) cat >"$CONFIG_LT" <<_LTEOF #! $SHELL # Generated by $as_me. # Run this file to recreate a libtool stub with the current configuration. lt_cl_silent=false SHELL=\${CONFIG_SHELL-$SHELL} _LTEOF cat >>"$CONFIG_LT" <<\_LTEOF AS_SHELL_SANITIZE _AS_PREPARE exec AS_MESSAGE_FD>&1 exec AS_MESSAGE_LOG_FD>>config.log { echo AS_BOX([Running $as_me.]) } >&AS_MESSAGE_LOG_FD lt_cl_help="\ \`$as_me' creates a local libtool stub from the current configuration, for use in further configure time tests before the real libtool is generated. Usage: $[0] [[OPTIONS]] -h, --help print this help, then exit -V, --version print version number, then exit -q, --quiet do not print progress messages -d, --debug don't remove temporary files Report bugs to ." lt_cl_version="\ m4_ifset([AC_PACKAGE_NAME], [AC_PACKAGE_NAME ])config.lt[]dnl m4_ifset([AC_PACKAGE_VERSION], [ AC_PACKAGE_VERSION]) configured by $[0], generated by m4_PACKAGE_STRING. Copyright (C) 2008 Free Software Foundation, Inc. This config.lt script is free software; the Free Software Foundation gives unlimited permision to copy, distribute and modify it." while test $[#] != 0 do case $[1] in --version | --v* | -V ) echo "$lt_cl_version"; exit 0 ;; --help | --h* | -h ) echo "$lt_cl_help"; exit 0 ;; --debug | --d* | -d ) debug=: ;; --quiet | --q* | --silent | --s* | -q ) lt_cl_silent=: ;; -*) AC_MSG_ERROR([unrecognized option: $[1] Try \`$[0] --help' for more information.]) ;; *) AC_MSG_ERROR([unrecognized argument: $[1] Try \`$[0] --help' for more information.]) ;; esac shift done if $lt_cl_silent; then exec AS_MESSAGE_FD>/dev/null fi _LTEOF cat >>"$CONFIG_LT" <<_LTEOF _LT_OUTPUT_LIBTOOL_COMMANDS_INIT _LTEOF cat >>"$CONFIG_LT" <<\_LTEOF AC_MSG_NOTICE([creating $ofile]) _LT_OUTPUT_LIBTOOL_COMMANDS AS_EXIT(0) _LTEOF chmod +x "$CONFIG_LT" # configure is writing to config.log, but config.lt does its own redirection, # appending to config.log, which fails on DOS, as config.log is still kept # open by configure. Here we exec the FD to /dev/null, effectively closing # config.log, so it can be properly (re)opened and appended to by config.lt. if test "$no_create" != yes; then lt_cl_success=: test "$silent" = yes && lt_config_lt_args="$lt_config_lt_args --quiet" exec AS_MESSAGE_LOG_FD>/dev/null $SHELL "$CONFIG_LT" $lt_config_lt_args || lt_cl_success=false exec AS_MESSAGE_LOG_FD>>config.log $lt_cl_success || AS_EXIT(1) fi ])# LT_OUTPUT # _LT_CONFIG(TAG) # --------------- # If TAG is the built-in tag, create an initial libtool script with a # default configuration from the untagged config vars. Otherwise add code # to config.status for appending the configuration named by TAG from the # matching tagged config vars. m4_defun([_LT_CONFIG], [m4_require([_LT_FILEUTILS_DEFAULTS])dnl _LT_CONFIG_SAVE_COMMANDS([ m4_define([_LT_TAG], m4_if([$1], [], [C], [$1]))dnl m4_if(_LT_TAG, [C], [ # See if we are running on zsh, and set the options which allow our # commands through without removal of \ escapes. if test -n "${ZSH_VERSION+set}" ; then setopt NO_GLOB_SUBST fi cfgfile="${ofile}T" trap "$RM \"$cfgfile\"; exit 1" 1 2 15 $RM "$cfgfile" cat <<_LT_EOF >> "$cfgfile" #! $SHELL # `$ECHO "$ofile" | sed 's%^.*/%%'` - Provide generalized library-building support services. # Generated automatically by $as_me ($PACKAGE$TIMESTAMP) $VERSION # NOTE: Changes made to this file will be lost: look at ltmain.sh. # _LT_COPYING _LT_LIBTOOL_TAGS # ### BEGIN LIBTOOL CONFIG _LT_LIBTOOL_CONFIG_VARS _LT_LIBTOOL_TAG_VARS # ### END LIBTOOL CONFIG _LT_EOF case $host_os in aix3*) cat <<\_LT_EOF >> "$cfgfile" # AIX sometimes has problems with the GCC collect2 program. For some # reason, if we set the COLLECT_NAMES environment variable, the problems # vanish in a puff of smoke. if test "X${COLLECT_NAMES+set}" != Xset; then COLLECT_NAMES= export COLLECT_NAMES fi _LT_EOF ;; esac _LT_PROG_LTMAIN # We use sed instead of cat because bash on DJGPP gets confused if # if finds mixed CR/LF and LF-only lines. Since sed operates in # text mode, it properly converts lines to CR/LF. This bash problem # is reportedly fixed, but why not run on old versions too? sed '/^# Generated shell functions inserted here/q' "$ltmain" >> "$cfgfile" \ || (rm -f "$cfgfile"; exit 1) _LT_PROG_XSI_SHELLFNS sed -n '/^# Generated shell functions inserted here/,$p' "$ltmain" >> "$cfgfile" \ || (rm -f "$cfgfile"; exit 1) mv -f "$cfgfile" "$ofile" || (rm -f "$ofile" && cp "$cfgfile" "$ofile" && rm -f "$cfgfile") chmod +x "$ofile" ], [cat <<_LT_EOF >> "$ofile" dnl Unfortunately we have to use $1 here, since _LT_TAG is not expanded dnl in a comment (ie after a #). # ### BEGIN LIBTOOL TAG CONFIG: $1 _LT_LIBTOOL_TAG_VARS(_LT_TAG) # ### END LIBTOOL TAG CONFIG: $1 _LT_EOF ])dnl /m4_if ], [m4_if([$1], [], [ PACKAGE='$PACKAGE' VERSION='$VERSION' TIMESTAMP='$TIMESTAMP' RM='$RM' ofile='$ofile'], []) ])dnl /_LT_CONFIG_SAVE_COMMANDS ])# _LT_CONFIG # LT_SUPPORTED_TAG(TAG) # --------------------- # Trace this macro to discover what tags are supported by the libtool # --tag option, using: # autoconf --trace 'LT_SUPPORTED_TAG:$1' AC_DEFUN([LT_SUPPORTED_TAG], []) # C support is built-in for now m4_define([_LT_LANG_C_enabled], []) m4_define([_LT_TAGS], []) # LT_LANG(LANG) # ------------- # Enable libtool support for the given language if not already enabled. AC_DEFUN([LT_LANG], [AC_BEFORE([$0], [LT_OUTPUT])dnl m4_case([$1], [C], [_LT_LANG(C)], [C++], [_LT_LANG(CXX)], [Java], [_LT_LANG(GCJ)], [Fortran 77], [_LT_LANG(F77)], [Fortran], [_LT_LANG(FC)], [Windows Resource], [_LT_LANG(RC)], [m4_ifdef([_LT_LANG_]$1[_CONFIG], [_LT_LANG($1)], [m4_fatal([$0: unsupported language: "$1"])])])dnl ])# LT_LANG # _LT_LANG(LANGNAME) # ------------------ m4_defun([_LT_LANG], [m4_ifdef([_LT_LANG_]$1[_enabled], [], [LT_SUPPORTED_TAG([$1])dnl m4_append([_LT_TAGS], [$1 ])dnl m4_define([_LT_LANG_]$1[_enabled], [])dnl _LT_LANG_$1_CONFIG($1)])dnl ])# _LT_LANG # _LT_LANG_DEFAULT_CONFIG # ----------------------- m4_defun([_LT_LANG_DEFAULT_CONFIG], [AC_PROVIDE_IFELSE([AC_PROG_CXX], [LT_LANG(CXX)], [m4_define([AC_PROG_CXX], defn([AC_PROG_CXX])[LT_LANG(CXX)])]) AC_PROVIDE_IFELSE([AC_PROG_F77], [LT_LANG(F77)], [m4_define([AC_PROG_F77], defn([AC_PROG_F77])[LT_LANG(F77)])]) AC_PROVIDE_IFELSE([AC_PROG_FC], [LT_LANG(FC)], [m4_define([AC_PROG_FC], defn([AC_PROG_FC])[LT_LANG(FC)])]) dnl The call to [A][M_PROG_GCJ] is quoted like that to stop aclocal dnl pulling things in needlessly. AC_PROVIDE_IFELSE([AC_PROG_GCJ], [LT_LANG(GCJ)], [AC_PROVIDE_IFELSE([A][M_PROG_GCJ], [LT_LANG(GCJ)], [AC_PROVIDE_IFELSE([LT_PROG_GCJ], [LT_LANG(GCJ)], [m4_ifdef([AC_PROG_GCJ], [m4_define([AC_PROG_GCJ], defn([AC_PROG_GCJ])[LT_LANG(GCJ)])]) m4_ifdef([A][M_PROG_GCJ], [m4_define([A][M_PROG_GCJ], defn([A][M_PROG_GCJ])[LT_LANG(GCJ)])]) m4_ifdef([LT_PROG_GCJ], [m4_define([LT_PROG_GCJ], defn([LT_PROG_GCJ])[LT_LANG(GCJ)])])])])]) AC_PROVIDE_IFELSE([LT_PROG_RC], [LT_LANG(RC)], [m4_define([LT_PROG_RC], defn([LT_PROG_RC])[LT_LANG(RC)])]) ])# _LT_LANG_DEFAULT_CONFIG # Obsolete macros: AU_DEFUN([AC_LIBTOOL_CXX], [LT_LANG(C++)]) AU_DEFUN([AC_LIBTOOL_F77], [LT_LANG(Fortran 77)]) AU_DEFUN([AC_LIBTOOL_FC], [LT_LANG(Fortran)]) AU_DEFUN([AC_LIBTOOL_GCJ], [LT_LANG(Java)]) dnl aclocal-1.4 backwards compatibility: dnl AC_DEFUN([AC_LIBTOOL_CXX], []) dnl AC_DEFUN([AC_LIBTOOL_F77], []) dnl AC_DEFUN([AC_LIBTOOL_FC], []) dnl AC_DEFUN([AC_LIBTOOL_GCJ], []) # _LT_TAG_COMPILER # ---------------- m4_defun([_LT_TAG_COMPILER], [AC_REQUIRE([AC_PROG_CC])dnl _LT_DECL([LTCC], [CC], [1], [A C compiler])dnl _LT_DECL([LTCFLAGS], [CFLAGS], [1], [LTCC compiler flags])dnl _LT_TAGDECL([CC], [compiler], [1], [A language specific compiler])dnl _LT_TAGDECL([with_gcc], [GCC], [0], [Is the compiler the GNU compiler?])dnl # If no C compiler was specified, use CC. LTCC=${LTCC-"$CC"} # If no C compiler flags were specified, use CFLAGS. LTCFLAGS=${LTCFLAGS-"$CFLAGS"} # Allow CC to be a program name with arguments. compiler=$CC ])# _LT_TAG_COMPILER # _LT_COMPILER_BOILERPLATE # ------------------------ # Check for compiler boilerplate output or warnings with # the simple compiler test code. m4_defun([_LT_COMPILER_BOILERPLATE], [m4_require([_LT_DECL_SED])dnl ac_outfile=conftest.$ac_objext echo "$lt_simple_compile_test_code" >conftest.$ac_ext eval "$ac_compile" 2>&1 >/dev/null | $SED '/^$/d; /^ *+/d' >conftest.err _lt_compiler_boilerplate=`cat conftest.err` $RM conftest* ])# _LT_COMPILER_BOILERPLATE # _LT_LINKER_BOILERPLATE # ---------------------- # Check for linker boilerplate output or warnings with # the simple link test code. m4_defun([_LT_LINKER_BOILERPLATE], [m4_require([_LT_DECL_SED])dnl ac_outfile=conftest.$ac_objext echo "$lt_simple_link_test_code" >conftest.$ac_ext eval "$ac_link" 2>&1 >/dev/null | $SED '/^$/d; /^ *+/d' >conftest.err _lt_linker_boilerplate=`cat conftest.err` $RM -r conftest* ])# _LT_LINKER_BOILERPLATE # _LT_REQUIRED_DARWIN_CHECKS # ------------------------- m4_defun_once([_LT_REQUIRED_DARWIN_CHECKS],[ case $host_os in rhapsody* | darwin*) AC_CHECK_TOOL([DSYMUTIL], [dsymutil], [:]) AC_CHECK_TOOL([NMEDIT], [nmedit], [:]) AC_CHECK_TOOL([LIPO], [lipo], [:]) AC_CHECK_TOOL([OTOOL], [otool], [:]) AC_CHECK_TOOL([OTOOL64], [otool64], [:]) _LT_DECL([], [DSYMUTIL], [1], [Tool to manipulate archived DWARF debug symbol files on Mac OS X]) _LT_DECL([], [NMEDIT], [1], [Tool to change global to local symbols on Mac OS X]) _LT_DECL([], [LIPO], [1], [Tool to manipulate fat objects and archives on Mac OS X]) _LT_DECL([], [OTOOL], [1], [ldd/readelf like tool for Mach-O binaries on Mac OS X]) _LT_DECL([], [OTOOL64], [1], [ldd/readelf like tool for 64 bit Mach-O binaries on Mac OS X 10.4]) AC_CACHE_CHECK([for -single_module linker flag],[lt_cv_apple_cc_single_mod], [lt_cv_apple_cc_single_mod=no if test -z "${LT_MULTI_MODULE}"; then # By default we will add the -single_module flag. You can override # by either setting the environment variable LT_MULTI_MODULE # non-empty at configure time, or by adding -multi_module to the # link flags. rm -rf libconftest.dylib* echo "int foo(void){return 1;}" > conftest.c echo "$LTCC $LTCFLAGS $LDFLAGS -o libconftest.dylib \ -dynamiclib -Wl,-single_module conftest.c" >&AS_MESSAGE_LOG_FD $LTCC $LTCFLAGS $LDFLAGS -o libconftest.dylib \ -dynamiclib -Wl,-single_module conftest.c 2>conftest.err _lt_result=$? if test -f libconftest.dylib && test ! -s conftest.err && test $_lt_result = 0; then lt_cv_apple_cc_single_mod=yes else cat conftest.err >&AS_MESSAGE_LOG_FD fi rm -rf libconftest.dylib* rm -f conftest.* fi]) AC_CACHE_CHECK([for -exported_symbols_list linker flag], [lt_cv_ld_exported_symbols_list], [lt_cv_ld_exported_symbols_list=no save_LDFLAGS=$LDFLAGS echo "_main" > conftest.sym LDFLAGS="$LDFLAGS -Wl,-exported_symbols_list,conftest.sym" AC_LINK_IFELSE([AC_LANG_PROGRAM([],[])], [lt_cv_ld_exported_symbols_list=yes], [lt_cv_ld_exported_symbols_list=no]) LDFLAGS="$save_LDFLAGS" ]) case $host_os in rhapsody* | darwin1.[[012]]) _lt_dar_allow_undefined='${wl}-undefined ${wl}suppress' ;; darwin1.*) _lt_dar_allow_undefined='${wl}-flat_namespace ${wl}-undefined ${wl}suppress' ;; darwin*) # darwin 5.x on # if running on 10.5 or later, the deployment target defaults # to the OS version, if on x86, and 10.4, the deployment # target defaults to 10.4. Don't you love it? case ${MACOSX_DEPLOYMENT_TARGET-10.0},$host in 10.0,*86*-darwin8*|10.0,*-darwin[[91]]*) _lt_dar_allow_undefined='${wl}-undefined ${wl}dynamic_lookup' ;; 10.[[012]]*) _lt_dar_allow_undefined='${wl}-flat_namespace ${wl}-undefined ${wl}suppress' ;; 10.*) _lt_dar_allow_undefined='${wl}-undefined ${wl}dynamic_lookup' ;; esac ;; esac if test "$lt_cv_apple_cc_single_mod" = "yes"; then _lt_dar_single_mod='$single_module' fi if test "$lt_cv_ld_exported_symbols_list" = "yes"; then _lt_dar_export_syms=' ${wl}-exported_symbols_list,$output_objdir/${libname}-symbols.expsym' else _lt_dar_export_syms='~$NMEDIT -s $output_objdir/${libname}-symbols.expsym ${lib}' fi if test "$DSYMUTIL" != ":"; then _lt_dsymutil='~$DSYMUTIL $lib || :' else _lt_dsymutil= fi ;; esac ]) # _LT_DARWIN_LINKER_FEATURES # -------------------------- # Checks for linker and compiler features on darwin m4_defun([_LT_DARWIN_LINKER_FEATURES], [ m4_require([_LT_REQUIRED_DARWIN_CHECKS]) _LT_TAGVAR(archive_cmds_need_lc, $1)=no _LT_TAGVAR(hardcode_direct, $1)=no _LT_TAGVAR(hardcode_automatic, $1)=yes _LT_TAGVAR(hardcode_shlibpath_var, $1)=unsupported _LT_TAGVAR(whole_archive_flag_spec, $1)='' _LT_TAGVAR(link_all_deplibs, $1)=yes _LT_TAGVAR(allow_undefined_flag, $1)="$_lt_dar_allow_undefined" case $cc_basename in ifort*) _lt_dar_can_shared=yes ;; *) _lt_dar_can_shared=$GCC ;; esac if test "$_lt_dar_can_shared" = "yes"; then output_verbose_link_cmd=echo _LT_TAGVAR(archive_cmds, $1)="\$CC -dynamiclib \$allow_undefined_flag -o \$lib \$libobjs \$deplibs \$compiler_flags -install_name \$rpath/\$soname \$verstring $_lt_dar_single_mod${_lt_dsymutil}" _LT_TAGVAR(module_cmds, $1)="\$CC \$allow_undefined_flag -o \$lib -bundle \$libobjs \$deplibs \$compiler_flags${_lt_dsymutil}" _LT_TAGVAR(archive_expsym_cmds, $1)="sed 's,^,_,' < \$export_symbols > \$output_objdir/\${libname}-symbols.expsym~\$CC -dynamiclib \$allow_undefined_flag -o \$lib \$libobjs \$deplibs \$compiler_flags -install_name \$rpath/\$soname \$verstring ${_lt_dar_single_mod}${_lt_dar_export_syms}${_lt_dsymutil}" _LT_TAGVAR(module_expsym_cmds, $1)="sed -e 's,^,_,' < \$export_symbols > \$output_objdir/\${libname}-symbols.expsym~\$CC \$allow_undefined_flag -o \$lib -bundle \$libobjs \$deplibs \$compiler_flags${_lt_dar_export_syms}${_lt_dsymutil}" m4_if([$1], [CXX], [ if test "$lt_cv_apple_cc_single_mod" != "yes"; then _LT_TAGVAR(archive_cmds, $1)="\$CC -r -keep_private_externs -nostdlib -o \${lib}-master.o \$libobjs~\$CC -dynamiclib \$allow_undefined_flag -o \$lib \${lib}-master.o \$deplibs \$compiler_flags -install_name \$rpath/\$soname \$verstring${_lt_dsymutil}" _LT_TAGVAR(archive_expsym_cmds, $1)="sed 's,^,_,' < \$export_symbols > \$output_objdir/\${libname}-symbols.expsym~\$CC -r -keep_private_externs -nostdlib -o \${lib}-master.o \$libobjs~\$CC -dynamiclib \$allow_undefined_flag -o \$lib \${lib}-master.o \$deplibs \$compiler_flags -install_name \$rpath/\$soname \$verstring${_lt_dar_export_syms}${_lt_dsymutil}" fi ],[]) else _LT_TAGVAR(ld_shlibs, $1)=no fi ]) # _LT_SYS_MODULE_PATH_AIX # ----------------------- # Links a minimal program and checks the executable # for the system default hardcoded library path. In most cases, # this is /usr/lib:/lib, but when the MPI compilers are used # the location of the communication and MPI libs are included too. # If we don't find anything, use the default library path according # to the aix ld manual. m4_defun([_LT_SYS_MODULE_PATH_AIX], [m4_require([_LT_DECL_SED])dnl AC_LINK_IFELSE([AC_LANG_PROGRAM],[ lt_aix_libpath_sed=' /Import File Strings/,/^$/ { /^0/ { s/^0 *\(.*\)$/\1/ p } }' aix_libpath=`dump -H conftest$ac_exeext 2>/dev/null | $SED -n -e "$lt_aix_libpath_sed"` # Check for a 64-bit object if we didn't find anything. if test -z "$aix_libpath"; then aix_libpath=`dump -HX64 conftest$ac_exeext 2>/dev/null | $SED -n -e "$lt_aix_libpath_sed"` fi],[]) if test -z "$aix_libpath"; then aix_libpath="/usr/lib:/lib"; fi ])# _LT_SYS_MODULE_PATH_AIX # _LT_SHELL_INIT(ARG) # ------------------- m4_define([_LT_SHELL_INIT], [ifdef([AC_DIVERSION_NOTICE], [AC_DIVERT_PUSH(AC_DIVERSION_NOTICE)], [AC_DIVERT_PUSH(NOTICE)]) $1 AC_DIVERT_POP ])# _LT_SHELL_INIT # _LT_PROG_ECHO_BACKSLASH # ----------------------- # Add some code to the start of the generated configure script which # will find an echo command which doesn't interpret backslashes. m4_defun([_LT_PROG_ECHO_BACKSLASH], [_LT_SHELL_INIT([ # Check that we are running under the correct shell. SHELL=${CONFIG_SHELL-/bin/sh} case X$lt_ECHO in X*--fallback-echo) # Remove one level of quotation (which was required for Make). ECHO=`echo "$lt_ECHO" | sed 's,\\\\\[$]\\[$]0,'[$]0','` ;; esac ECHO=${lt_ECHO-echo} if test "X[$]1" = X--no-reexec; then # Discard the --no-reexec flag, and continue. shift elif test "X[$]1" = X--fallback-echo; then # Avoid inline document here, it may be left over : elif test "X`{ $ECHO '\t'; } 2>/dev/null`" = 'X\t' ; then # Yippee, $ECHO works! : else # Restart under the correct shell. exec $SHELL "[$]0" --no-reexec ${1+"[$]@"} fi if test "X[$]1" = X--fallback-echo; then # used as fallback echo shift cat <<_LT_EOF [$]* _LT_EOF exit 0 fi # The HP-UX ksh and POSIX shell print the target directory to stdout # if CDPATH is set. (unset CDPATH) >/dev/null 2>&1 && unset CDPATH if test -z "$lt_ECHO"; then if test "X${echo_test_string+set}" != Xset; then # find a string as large as possible, as long as the shell can cope with it for cmd in 'sed 50q "[$]0"' 'sed 20q "[$]0"' 'sed 10q "[$]0"' 'sed 2q "[$]0"' 'echo test'; do # expected sizes: less than 2Kb, 1Kb, 512 bytes, 16 bytes, ... if { echo_test_string=`eval $cmd`; } 2>/dev/null && { test "X$echo_test_string" = "X$echo_test_string"; } 2>/dev/null then break fi done fi if test "X`{ $ECHO '\t'; } 2>/dev/null`" = 'X\t' && echo_testing_string=`{ $ECHO "$echo_test_string"; } 2>/dev/null` && test "X$echo_testing_string" = "X$echo_test_string"; then : else # The Solaris, AIX, and Digital Unix default echo programs unquote # backslashes. This makes it impossible to quote backslashes using # echo "$something" | sed 's/\\/\\\\/g' # # So, first we look for a working echo in the user's PATH. lt_save_ifs="$IFS"; IFS=$PATH_SEPARATOR for dir in $PATH /usr/ucb; do IFS="$lt_save_ifs" if (test -f $dir/echo || test -f $dir/echo$ac_exeext) && test "X`($dir/echo '\t') 2>/dev/null`" = 'X\t' && echo_testing_string=`($dir/echo "$echo_test_string") 2>/dev/null` && test "X$echo_testing_string" = "X$echo_test_string"; then ECHO="$dir/echo" break fi done IFS="$lt_save_ifs" if test "X$ECHO" = Xecho; then # We didn't find a better echo, so look for alternatives. if test "X`{ print -r '\t'; } 2>/dev/null`" = 'X\t' && echo_testing_string=`{ print -r "$echo_test_string"; } 2>/dev/null` && test "X$echo_testing_string" = "X$echo_test_string"; then # This shell has a builtin print -r that does the trick. ECHO='print -r' elif { test -f /bin/ksh || test -f /bin/ksh$ac_exeext; } && test "X$CONFIG_SHELL" != X/bin/ksh; then # If we have ksh, try running configure again with it. ORIGINAL_CONFIG_SHELL=${CONFIG_SHELL-/bin/sh} export ORIGINAL_CONFIG_SHELL CONFIG_SHELL=/bin/ksh export CONFIG_SHELL exec $CONFIG_SHELL "[$]0" --no-reexec ${1+"[$]@"} else # Try using printf. ECHO='printf %s\n' if test "X`{ $ECHO '\t'; } 2>/dev/null`" = 'X\t' && echo_testing_string=`{ $ECHO "$echo_test_string"; } 2>/dev/null` && test "X$echo_testing_string" = "X$echo_test_string"; then # Cool, printf works : elif echo_testing_string=`($ORIGINAL_CONFIG_SHELL "[$]0" --fallback-echo '\t') 2>/dev/null` && test "X$echo_testing_string" = 'X\t' && echo_testing_string=`($ORIGINAL_CONFIG_SHELL "[$]0" --fallback-echo "$echo_test_string") 2>/dev/null` && test "X$echo_testing_string" = "X$echo_test_string"; then CONFIG_SHELL=$ORIGINAL_CONFIG_SHELL export CONFIG_SHELL SHELL="$CONFIG_SHELL" export SHELL ECHO="$CONFIG_SHELL [$]0 --fallback-echo" elif echo_testing_string=`($CONFIG_SHELL "[$]0" --fallback-echo '\t') 2>/dev/null` && test "X$echo_testing_string" = 'X\t' && echo_testing_string=`($CONFIG_SHELL "[$]0" --fallback-echo "$echo_test_string") 2>/dev/null` && test "X$echo_testing_string" = "X$echo_test_string"; then ECHO="$CONFIG_SHELL [$]0 --fallback-echo" else # maybe with a smaller string... prev=: for cmd in 'echo test' 'sed 2q "[$]0"' 'sed 10q "[$]0"' 'sed 20q "[$]0"' 'sed 50q "[$]0"'; do if { test "X$echo_test_string" = "X`eval $cmd`"; } 2>/dev/null then break fi prev="$cmd" done if test "$prev" != 'sed 50q "[$]0"'; then echo_test_string=`eval $prev` export echo_test_string exec ${ORIGINAL_CONFIG_SHELL-${CONFIG_SHELL-/bin/sh}} "[$]0" ${1+"[$]@"} else # Oops. We lost completely, so just stick with echo. ECHO=echo fi fi fi fi fi fi # Copy echo and quote the copy suitably for passing to libtool from # the Makefile, instead of quoting the original, which is used later. lt_ECHO=$ECHO if test "X$lt_ECHO" = "X$CONFIG_SHELL [$]0 --fallback-echo"; then lt_ECHO="$CONFIG_SHELL \\\$\[$]0 --fallback-echo" fi AC_SUBST(lt_ECHO) ]) _LT_DECL([], [SHELL], [1], [Shell to use when invoking shell scripts]) _LT_DECL([], [ECHO], [1], [An echo program that does not interpret backslashes]) ])# _LT_PROG_ECHO_BACKSLASH # _LT_ENABLE_LOCK # --------------- m4_defun([_LT_ENABLE_LOCK], [AC_ARG_ENABLE([libtool-lock], [AS_HELP_STRING([--disable-libtool-lock], [avoid locking (might break parallel builds)])]) test "x$enable_libtool_lock" != xno && enable_libtool_lock=yes # Some flags need to be propagated to the compiler or linker for good # libtool support. case $host in ia64-*-hpux*) # Find out which ABI we are using. echo 'int i;' > conftest.$ac_ext if AC_TRY_EVAL(ac_compile); then case `/usr/bin/file conftest.$ac_objext` in *ELF-32*) HPUX_IA64_MODE="32" ;; *ELF-64*) HPUX_IA64_MODE="64" ;; esac fi rm -rf conftest* ;; *-*-irix6*) # Find out which ABI we are using. echo '[#]line __oline__ "configure"' > conftest.$ac_ext if AC_TRY_EVAL(ac_compile); then if test "$lt_cv_prog_gnu_ld" = yes; then case `/usr/bin/file conftest.$ac_objext` in *32-bit*) LD="${LD-ld} -melf32bsmip" ;; *N32*) LD="${LD-ld} -melf32bmipn32" ;; *64-bit*) LD="${LD-ld} -melf64bmip" ;; esac else case `/usr/bin/file conftest.$ac_objext` in *32-bit*) LD="${LD-ld} -32" ;; *N32*) LD="${LD-ld} -n32" ;; *64-bit*) LD="${LD-ld} -64" ;; esac fi fi rm -rf conftest* ;; x86_64-*kfreebsd*-gnu|x86_64-*linux*|ppc*-*linux*|powerpc*-*linux*| \ s390*-*linux*|s390*-*tpf*|sparc*-*linux*) # Find out which ABI we are using. echo 'int i;' > conftest.$ac_ext if AC_TRY_EVAL(ac_compile); then case `/usr/bin/file conftest.o` in *32-bit*) case $host in x86_64-*kfreebsd*-gnu) LD="${LD-ld} -m elf_i386_fbsd" ;; x86_64-*linux*) LD="${LD-ld} -m elf_i386" ;; ppc64-*linux*|powerpc64-*linux*) LD="${LD-ld} -m elf32ppclinux" ;; s390x-*linux*) LD="${LD-ld} -m elf_s390" ;; sparc64-*linux*) LD="${LD-ld} -m elf32_sparc" ;; esac ;; *64-bit*) case $host in x86_64-*kfreebsd*-gnu) LD="${LD-ld} -m elf_x86_64_fbsd" ;; x86_64-*linux*) LD="${LD-ld} -m elf_x86_64" ;; ppc*-*linux*|powerpc*-*linux*) LD="${LD-ld} -m elf64ppc" ;; s390*-*linux*|s390*-*tpf*) LD="${LD-ld} -m elf64_s390" ;; sparc*-*linux*) LD="${LD-ld} -m elf64_sparc" ;; esac ;; esac fi rm -rf conftest* ;; *-*-sco3.2v5*) # On SCO OpenServer 5, we need -belf to get full-featured binaries. SAVE_CFLAGS="$CFLAGS" CFLAGS="$CFLAGS -belf" AC_CACHE_CHECK([whether the C compiler needs -belf], lt_cv_cc_needs_belf, [AC_LANG_PUSH(C) AC_LINK_IFELSE([AC_LANG_PROGRAM([[]],[[]])],[lt_cv_cc_needs_belf=yes],[lt_cv_cc_needs_belf=no]) AC_LANG_POP]) if test x"$lt_cv_cc_needs_belf" != x"yes"; then # this is probably gcc 2.8.0, egcs 1.0 or newer; no need for -belf CFLAGS="$SAVE_CFLAGS" fi ;; sparc*-*solaris*) # Find out which ABI we are using. echo 'int i;' > conftest.$ac_ext if AC_TRY_EVAL(ac_compile); then case `/usr/bin/file conftest.o` in *64-bit*) case $lt_cv_prog_gnu_ld in yes*) LD="${LD-ld} -m elf64_sparc" ;; *) if ${LD-ld} -64 -r -o conftest2.o conftest.o >/dev/null 2>&1; then LD="${LD-ld} -64" fi ;; esac ;; esac fi rm -rf conftest* ;; esac need_locks="$enable_libtool_lock" ])# _LT_ENABLE_LOCK # _LT_CMD_OLD_ARCHIVE # ------------------- m4_defun([_LT_CMD_OLD_ARCHIVE], [AC_CHECK_TOOL(AR, ar, false) test -z "$AR" && AR=ar test -z "$AR_FLAGS" && AR_FLAGS=cru _LT_DECL([], [AR], [1], [The archiver]) _LT_DECL([], [AR_FLAGS], [1]) AC_CHECK_TOOL(STRIP, strip, :) test -z "$STRIP" && STRIP=: _LT_DECL([], [STRIP], [1], [A symbol stripping program]) AC_CHECK_TOOL(RANLIB, ranlib, :) test -z "$RANLIB" && RANLIB=: _LT_DECL([], [RANLIB], [1], [Commands used to install an old-style archive]) # Determine commands to create old-style static archives. old_archive_cmds='$AR $AR_FLAGS $oldlib$oldobjs' old_postinstall_cmds='chmod 644 $oldlib' old_postuninstall_cmds= if test -n "$RANLIB"; then case $host_os in openbsd*) old_postinstall_cmds="$old_postinstall_cmds~\$RANLIB -t \$oldlib" ;; *) old_postinstall_cmds="$old_postinstall_cmds~\$RANLIB \$oldlib" ;; esac old_archive_cmds="$old_archive_cmds~\$RANLIB \$oldlib" fi _LT_DECL([], [old_postinstall_cmds], [2]) _LT_DECL([], [old_postuninstall_cmds], [2]) _LT_TAGDECL([], [old_archive_cmds], [2], [Commands used to build an old-style archive]) ])# _LT_CMD_OLD_ARCHIVE # _LT_COMPILER_OPTION(MESSAGE, VARIABLE-NAME, FLAGS, # [OUTPUT-FILE], [ACTION-SUCCESS], [ACTION-FAILURE]) # ---------------------------------------------------------------- # Check whether the given compiler option works AC_DEFUN([_LT_COMPILER_OPTION], [m4_require([_LT_FILEUTILS_DEFAULTS])dnl m4_require([_LT_DECL_SED])dnl AC_CACHE_CHECK([$1], [$2], [$2=no m4_if([$4], , [ac_outfile=conftest.$ac_objext], [ac_outfile=$4]) echo "$lt_simple_compile_test_code" > conftest.$ac_ext lt_compiler_flag="$3" # Insert the option either (1) after the last *FLAGS variable, or # (2) before a word containing "conftest.", or (3) at the end. # Note that $ac_compile itself does not contain backslashes and begins # with a dollar sign (not a hyphen), so the echo should work correctly. # The option is referenced via a variable to avoid confusing sed. lt_compile=`echo "$ac_compile" | $SED \ -e 's:.*FLAGS}\{0,1\} :&$lt_compiler_flag :; t' \ -e 's: [[^ ]]*conftest\.: $lt_compiler_flag&:; t' \ -e 's:$: $lt_compiler_flag:'` (eval echo "\"\$as_me:__oline__: $lt_compile\"" >&AS_MESSAGE_LOG_FD) (eval "$lt_compile" 2>conftest.err) ac_status=$? cat conftest.err >&AS_MESSAGE_LOG_FD echo "$as_me:__oline__: \$? = $ac_status" >&AS_MESSAGE_LOG_FD if (exit $ac_status) && test -s "$ac_outfile"; then # The compiler can only warn and ignore the option if not recognized # So say no if there are warnings other than the usual output. $ECHO "X$_lt_compiler_boilerplate" | $Xsed -e '/^$/d' >conftest.exp $SED '/^$/d; /^ *+/d' conftest.err >conftest.er2 if test ! -s conftest.er2 || diff conftest.exp conftest.er2 >/dev/null; then $2=yes fi fi $RM conftest* ]) if test x"[$]$2" = xyes; then m4_if([$5], , :, [$5]) else m4_if([$6], , :, [$6]) fi ])# _LT_COMPILER_OPTION # Old name: AU_ALIAS([AC_LIBTOOL_COMPILER_OPTION], [_LT_COMPILER_OPTION]) dnl aclocal-1.4 backwards compatibility: dnl AC_DEFUN([AC_LIBTOOL_COMPILER_OPTION], []) # _LT_LINKER_OPTION(MESSAGE, VARIABLE-NAME, FLAGS, # [ACTION-SUCCESS], [ACTION-FAILURE]) # ---------------------------------------------------- # Check whether the given linker option works AC_DEFUN([_LT_LINKER_OPTION], [m4_require([_LT_FILEUTILS_DEFAULTS])dnl m4_require([_LT_DECL_SED])dnl AC_CACHE_CHECK([$1], [$2], [$2=no save_LDFLAGS="$LDFLAGS" LDFLAGS="$LDFLAGS $3" echo "$lt_simple_link_test_code" > conftest.$ac_ext if (eval $ac_link 2>conftest.err) && test -s conftest$ac_exeext; then # The linker can only warn and ignore the option if not recognized # So say no if there are warnings if test -s conftest.err; then # Append any errors to the config.log. cat conftest.err 1>&AS_MESSAGE_LOG_FD $ECHO "X$_lt_linker_boilerplate" | $Xsed -e '/^$/d' > conftest.exp $SED '/^$/d; /^ *+/d' conftest.err >conftest.er2 if diff conftest.exp conftest.er2 >/dev/null; then $2=yes fi else $2=yes fi fi $RM -r conftest* LDFLAGS="$save_LDFLAGS" ]) if test x"[$]$2" = xyes; then m4_if([$4], , :, [$4]) else m4_if([$5], , :, [$5]) fi ])# _LT_LINKER_OPTION # Old name: AU_ALIAS([AC_LIBTOOL_LINKER_OPTION], [_LT_LINKER_OPTION]) dnl aclocal-1.4 backwards compatibility: dnl AC_DEFUN([AC_LIBTOOL_LINKER_OPTION], []) # LT_CMD_MAX_LEN #--------------- AC_DEFUN([LT_CMD_MAX_LEN], [AC_REQUIRE([AC_CANONICAL_HOST])dnl # find the maximum length of command line arguments AC_MSG_CHECKING([the maximum length of command line arguments]) AC_CACHE_VAL([lt_cv_sys_max_cmd_len], [dnl i=0 teststring="ABCD" case $build_os in msdosdjgpp*) # On DJGPP, this test can blow up pretty badly due to problems in libc # (any single argument exceeding 2000 bytes causes a buffer overrun # during glob expansion). Even if it were fixed, the result of this # check would be larger than it should be. lt_cv_sys_max_cmd_len=12288; # 12K is about right ;; gnu*) # Under GNU Hurd, this test is not required because there is # no limit to the length of command line arguments. # Libtool will interpret -1 as no limit whatsoever lt_cv_sys_max_cmd_len=-1; ;; cygwin* | mingw* | cegcc*) # On Win9x/ME, this test blows up -- it succeeds, but takes # about 5 minutes as the teststring grows exponentially. # Worse, since 9x/ME are not pre-emptively multitasking, # you end up with a "frozen" computer, even though with patience # the test eventually succeeds (with a max line length of 256k). # Instead, let's just punt: use the minimum linelength reported by # all of the supported platforms: 8192 (on NT/2K/XP). lt_cv_sys_max_cmd_len=8192; ;; amigaos*) # On AmigaOS with pdksh, this test takes hours, literally. # So we just punt and use a minimum line length of 8192. lt_cv_sys_max_cmd_len=8192; ;; netbsd* | freebsd* | openbsd* | darwin* | dragonfly*) # This has been around since 386BSD, at least. Likely further. if test -x /sbin/sysctl; then lt_cv_sys_max_cmd_len=`/sbin/sysctl -n kern.argmax` elif test -x /usr/sbin/sysctl; then lt_cv_sys_max_cmd_len=`/usr/sbin/sysctl -n kern.argmax` else lt_cv_sys_max_cmd_len=65536 # usable default for all BSDs fi # And add a safety zone lt_cv_sys_max_cmd_len=`expr $lt_cv_sys_max_cmd_len \/ 4` lt_cv_sys_max_cmd_len=`expr $lt_cv_sys_max_cmd_len \* 3` ;; interix*) # We know the value 262144 and hardcode it with a safety zone (like BSD) lt_cv_sys_max_cmd_len=196608 ;; osf*) # Dr. Hans Ekkehard Plesser reports seeing a kernel panic running configure # due to this test when exec_disable_arg_limit is 1 on Tru64. It is not # nice to cause kernel panics so lets avoid the loop below. # First set a reasonable default. lt_cv_sys_max_cmd_len=16384 # if test -x /sbin/sysconfig; then case `/sbin/sysconfig -q proc exec_disable_arg_limit` in *1*) lt_cv_sys_max_cmd_len=-1 ;; esac fi ;; sco3.2v5*) lt_cv_sys_max_cmd_len=102400 ;; sysv5* | sco5v6* | sysv4.2uw2*) kargmax=`grep ARG_MAX /etc/conf/cf.d/stune 2>/dev/null` if test -n "$kargmax"; then lt_cv_sys_max_cmd_len=`echo $kargmax | sed 's/.*[[ ]]//'` else lt_cv_sys_max_cmd_len=32768 fi ;; *) lt_cv_sys_max_cmd_len=`(getconf ARG_MAX) 2> /dev/null` if test -n "$lt_cv_sys_max_cmd_len"; then lt_cv_sys_max_cmd_len=`expr $lt_cv_sys_max_cmd_len \/ 4` lt_cv_sys_max_cmd_len=`expr $lt_cv_sys_max_cmd_len \* 3` else # Make teststring a little bigger before we do anything with it. # a 1K string should be a reasonable start. for i in 1 2 3 4 5 6 7 8 ; do teststring=$teststring$teststring done SHELL=${SHELL-${CONFIG_SHELL-/bin/sh}} # If test is not a shell built-in, we'll probably end up computing a # maximum length that is only half of the actual maximum length, but # we can't tell. while { test "X"`$SHELL [$]0 --fallback-echo "X$teststring$teststring" 2>/dev/null` \ = "XX$teststring$teststring"; } >/dev/null 2>&1 && test $i != 17 # 1/2 MB should be enough do i=`expr $i + 1` teststring=$teststring$teststring done # Only check the string length outside the loop. lt_cv_sys_max_cmd_len=`expr "X$teststring" : ".*" 2>&1` teststring= # Add a significant safety factor because C++ compilers can tack on # massive amounts of additional arguments before passing them to the # linker. It appears as though 1/2 is a usable value. lt_cv_sys_max_cmd_len=`expr $lt_cv_sys_max_cmd_len \/ 2` fi ;; esac ]) if test -n $lt_cv_sys_max_cmd_len ; then AC_MSG_RESULT($lt_cv_sys_max_cmd_len) else AC_MSG_RESULT(none) fi max_cmd_len=$lt_cv_sys_max_cmd_len _LT_DECL([], [max_cmd_len], [0], [What is the maximum length of a command?]) ])# LT_CMD_MAX_LEN # Old name: AU_ALIAS([AC_LIBTOOL_SYS_MAX_CMD_LEN], [LT_CMD_MAX_LEN]) dnl aclocal-1.4 backwards compatibility: dnl AC_DEFUN([AC_LIBTOOL_SYS_MAX_CMD_LEN], []) # _LT_HEADER_DLFCN # ---------------- m4_defun([_LT_HEADER_DLFCN], [AC_CHECK_HEADERS([dlfcn.h], [], [], [AC_INCLUDES_DEFAULT])dnl ])# _LT_HEADER_DLFCN # _LT_TRY_DLOPEN_SELF (ACTION-IF-TRUE, ACTION-IF-TRUE-W-USCORE, # ACTION-IF-FALSE, ACTION-IF-CROSS-COMPILING) # ---------------------------------------------------------------- m4_defun([_LT_TRY_DLOPEN_SELF], [m4_require([_LT_HEADER_DLFCN])dnl if test "$cross_compiling" = yes; then : [$4] else lt_dlunknown=0; lt_dlno_uscore=1; lt_dlneed_uscore=2 lt_status=$lt_dlunknown cat > conftest.$ac_ext <<_LT_EOF [#line __oline__ "configure" #include "confdefs.h" #if HAVE_DLFCN_H #include #endif #include #ifdef RTLD_GLOBAL # define LT_DLGLOBAL RTLD_GLOBAL #else # ifdef DL_GLOBAL # define LT_DLGLOBAL DL_GLOBAL # else # define LT_DLGLOBAL 0 # endif #endif /* We may have to define LT_DLLAZY_OR_NOW in the command line if we find out it does not work in some platform. */ #ifndef LT_DLLAZY_OR_NOW # ifdef RTLD_LAZY # define LT_DLLAZY_OR_NOW RTLD_LAZY # else # ifdef DL_LAZY # define LT_DLLAZY_OR_NOW DL_LAZY # else # ifdef RTLD_NOW # define LT_DLLAZY_OR_NOW RTLD_NOW # else # ifdef DL_NOW # define LT_DLLAZY_OR_NOW DL_NOW # else # define LT_DLLAZY_OR_NOW 0 # endif # endif # endif # endif #endif void fnord() { int i=42;} int main () { void *self = dlopen (0, LT_DLGLOBAL|LT_DLLAZY_OR_NOW); int status = $lt_dlunknown; if (self) { if (dlsym (self,"fnord")) status = $lt_dlno_uscore; else if (dlsym( self,"_fnord")) status = $lt_dlneed_uscore; /* dlclose (self); */ } else puts (dlerror ()); return status; }] _LT_EOF if AC_TRY_EVAL(ac_link) && test -s conftest${ac_exeext} 2>/dev/null; then (./conftest; exit; ) >&AS_MESSAGE_LOG_FD 2>/dev/null lt_status=$? case x$lt_status in x$lt_dlno_uscore) $1 ;; x$lt_dlneed_uscore) $2 ;; x$lt_dlunknown|x*) $3 ;; esac else : # compilation failed $3 fi fi rm -fr conftest* ])# _LT_TRY_DLOPEN_SELF # LT_SYS_DLOPEN_SELF # ------------------ AC_DEFUN([LT_SYS_DLOPEN_SELF], [m4_require([_LT_HEADER_DLFCN])dnl if test "x$enable_dlopen" != xyes; then enable_dlopen=unknown enable_dlopen_self=unknown enable_dlopen_self_static=unknown else lt_cv_dlopen=no lt_cv_dlopen_libs= case $host_os in beos*) lt_cv_dlopen="load_add_on" lt_cv_dlopen_libs= lt_cv_dlopen_self=yes ;; mingw* | pw32* | cegcc*) lt_cv_dlopen="LoadLibrary" lt_cv_dlopen_libs= ;; cygwin*) lt_cv_dlopen="dlopen" lt_cv_dlopen_libs= ;; darwin*) # if libdl is installed we need to link against it AC_CHECK_LIB([dl], [dlopen], [lt_cv_dlopen="dlopen" lt_cv_dlopen_libs="-ldl"],[ lt_cv_dlopen="dyld" lt_cv_dlopen_libs= lt_cv_dlopen_self=yes ]) ;; *) AC_CHECK_FUNC([shl_load], [lt_cv_dlopen="shl_load"], [AC_CHECK_LIB([dld], [shl_load], [lt_cv_dlopen="shl_load" lt_cv_dlopen_libs="-ldld"], [AC_CHECK_FUNC([dlopen], [lt_cv_dlopen="dlopen"], [AC_CHECK_LIB([dl], [dlopen], [lt_cv_dlopen="dlopen" lt_cv_dlopen_libs="-ldl"], [AC_CHECK_LIB([svld], [dlopen], [lt_cv_dlopen="dlopen" lt_cv_dlopen_libs="-lsvld"], [AC_CHECK_LIB([dld], [dld_link], [lt_cv_dlopen="dld_link" lt_cv_dlopen_libs="-ldld"]) ]) ]) ]) ]) ]) ;; esac if test "x$lt_cv_dlopen" != xno; then enable_dlopen=yes else enable_dlopen=no fi case $lt_cv_dlopen in dlopen) save_CPPFLAGS="$CPPFLAGS" test "x$ac_cv_header_dlfcn_h" = xyes && CPPFLAGS="$CPPFLAGS -DHAVE_DLFCN_H" save_LDFLAGS="$LDFLAGS" wl=$lt_prog_compiler_wl eval LDFLAGS=\"\$LDFLAGS $export_dynamic_flag_spec\" save_LIBS="$LIBS" LIBS="$lt_cv_dlopen_libs $LIBS" AC_CACHE_CHECK([whether a program can dlopen itself], lt_cv_dlopen_self, [dnl _LT_TRY_DLOPEN_SELF( lt_cv_dlopen_self=yes, lt_cv_dlopen_self=yes, lt_cv_dlopen_self=no, lt_cv_dlopen_self=cross) ]) if test "x$lt_cv_dlopen_self" = xyes; then wl=$lt_prog_compiler_wl eval LDFLAGS=\"\$LDFLAGS $lt_prog_compiler_static\" AC_CACHE_CHECK([whether a statically linked program can dlopen itself], lt_cv_dlopen_self_static, [dnl _LT_TRY_DLOPEN_SELF( lt_cv_dlopen_self_static=yes, lt_cv_dlopen_self_static=yes, lt_cv_dlopen_self_static=no, lt_cv_dlopen_self_static=cross) ]) fi CPPFLAGS="$save_CPPFLAGS" LDFLAGS="$save_LDFLAGS" LIBS="$save_LIBS" ;; esac case $lt_cv_dlopen_self in yes|no) enable_dlopen_self=$lt_cv_dlopen_self ;; *) enable_dlopen_self=unknown ;; esac case $lt_cv_dlopen_self_static in yes|no) enable_dlopen_self_static=$lt_cv_dlopen_self_static ;; *) enable_dlopen_self_static=unknown ;; esac fi _LT_DECL([dlopen_support], [enable_dlopen], [0], [Whether dlopen is supported]) _LT_DECL([dlopen_self], [enable_dlopen_self], [0], [Whether dlopen of programs is supported]) _LT_DECL([dlopen_self_static], [enable_dlopen_self_static], [0], [Whether dlopen of statically linked programs is supported]) ])# LT_SYS_DLOPEN_SELF # Old name: AU_ALIAS([AC_LIBTOOL_DLOPEN_SELF], [LT_SYS_DLOPEN_SELF]) dnl aclocal-1.4 backwards compatibility: dnl AC_DEFUN([AC_LIBTOOL_DLOPEN_SELF], []) # _LT_COMPILER_C_O([TAGNAME]) # --------------------------- # Check to see if options -c and -o are simultaneously supported by compiler. # This macro does not hard code the compiler like AC_PROG_CC_C_O. m4_defun([_LT_COMPILER_C_O], [m4_require([_LT_DECL_SED])dnl m4_require([_LT_FILEUTILS_DEFAULTS])dnl m4_require([_LT_TAG_COMPILER])dnl AC_CACHE_CHECK([if $compiler supports -c -o file.$ac_objext], [_LT_TAGVAR(lt_cv_prog_compiler_c_o, $1)], [_LT_TAGVAR(lt_cv_prog_compiler_c_o, $1)=no $RM -r conftest 2>/dev/null mkdir conftest cd conftest mkdir out echo "$lt_simple_compile_test_code" > conftest.$ac_ext lt_compiler_flag="-o out/conftest2.$ac_objext" # Insert the option either (1) after the last *FLAGS variable, or # (2) before a word containing "conftest.", or (3) at the end. # Note that $ac_compile itself does not contain backslashes and begins # with a dollar sign (not a hyphen), so the echo should work correctly. lt_compile=`echo "$ac_compile" | $SED \ -e 's:.*FLAGS}\{0,1\} :&$lt_compiler_flag :; t' \ -e 's: [[^ ]]*conftest\.: $lt_compiler_flag&:; t' \ -e 's:$: $lt_compiler_flag:'` (eval echo "\"\$as_me:__oline__: $lt_compile\"" >&AS_MESSAGE_LOG_FD) (eval "$lt_compile" 2>out/conftest.err) ac_status=$? cat out/conftest.err >&AS_MESSAGE_LOG_FD echo "$as_me:__oline__: \$? = $ac_status" >&AS_MESSAGE_LOG_FD if (exit $ac_status) && test -s out/conftest2.$ac_objext then # The compiler can only warn and ignore the option if not recognized # So say no if there are warnings $ECHO "X$_lt_compiler_boilerplate" | $Xsed -e '/^$/d' > out/conftest.exp $SED '/^$/d; /^ *+/d' out/conftest.err >out/conftest.er2 if test ! -s out/conftest.er2 || diff out/conftest.exp out/conftest.er2 >/dev/null; then _LT_TAGVAR(lt_cv_prog_compiler_c_o, $1)=yes fi fi chmod u+w . 2>&AS_MESSAGE_LOG_FD $RM conftest* # SGI C++ compiler will create directory out/ii_files/ for # template instantiation test -d out/ii_files && $RM out/ii_files/* && rmdir out/ii_files $RM out/* && rmdir out cd .. $RM -r conftest $RM conftest* ]) _LT_TAGDECL([compiler_c_o], [lt_cv_prog_compiler_c_o], [1], [Does compiler simultaneously support -c and -o options?]) ])# _LT_COMPILER_C_O # _LT_COMPILER_FILE_LOCKS([TAGNAME]) # ---------------------------------- # Check to see if we can do hard links to lock some files if needed m4_defun([_LT_COMPILER_FILE_LOCKS], [m4_require([_LT_ENABLE_LOCK])dnl m4_require([_LT_FILEUTILS_DEFAULTS])dnl _LT_COMPILER_C_O([$1]) hard_links="nottested" if test "$_LT_TAGVAR(lt_cv_prog_compiler_c_o, $1)" = no && test "$need_locks" != no; then # do not overwrite the value of need_locks provided by the user AC_MSG_CHECKING([if we can lock with hard links]) hard_links=yes $RM conftest* ln conftest.a conftest.b 2>/dev/null && hard_links=no touch conftest.a ln conftest.a conftest.b 2>&5 || hard_links=no ln conftest.a conftest.b 2>/dev/null && hard_links=no AC_MSG_RESULT([$hard_links]) if test "$hard_links" = no; then AC_MSG_WARN([`$CC' does not support `-c -o', so `make -j' may be unsafe]) need_locks=warn fi else need_locks=no fi _LT_DECL([], [need_locks], [1], [Must we lock files when doing compilation?]) ])# _LT_COMPILER_FILE_LOCKS # _LT_CHECK_OBJDIR # ---------------- m4_defun([_LT_CHECK_OBJDIR], [AC_CACHE_CHECK([for objdir], [lt_cv_objdir], [rm -f .libs 2>/dev/null mkdir .libs 2>/dev/null if test -d .libs; then lt_cv_objdir=.libs else # MS-DOS does not allow filenames that begin with a dot. lt_cv_objdir=_libs fi rmdir .libs 2>/dev/null]) objdir=$lt_cv_objdir _LT_DECL([], [objdir], [0], [The name of the directory that contains temporary libtool files])dnl m4_pattern_allow([LT_OBJDIR])dnl AC_DEFINE_UNQUOTED(LT_OBJDIR, "$lt_cv_objdir/", [Define to the sub-directory in which libtool stores uninstalled libraries.]) ])# _LT_CHECK_OBJDIR # _LT_LINKER_HARDCODE_LIBPATH([TAGNAME]) # -------------------------------------- # Check hardcoding attributes. m4_defun([_LT_LINKER_HARDCODE_LIBPATH], [AC_MSG_CHECKING([how to hardcode library paths into programs]) _LT_TAGVAR(hardcode_action, $1)= if test -n "$_LT_TAGVAR(hardcode_libdir_flag_spec, $1)" || test -n "$_LT_TAGVAR(runpath_var, $1)" || test "X$_LT_TAGVAR(hardcode_automatic, $1)" = "Xyes" ; then # We can hardcode non-existent directories. if test "$_LT_TAGVAR(hardcode_direct, $1)" != no && # If the only mechanism to avoid hardcoding is shlibpath_var, we # have to relink, otherwise we might link with an installed library # when we should be linking with a yet-to-be-installed one ## test "$_LT_TAGVAR(hardcode_shlibpath_var, $1)" != no && test "$_LT_TAGVAR(hardcode_minus_L, $1)" != no; then # Linking always hardcodes the temporary library directory. _LT_TAGVAR(hardcode_action, $1)=relink else # We can link without hardcoding, and we can hardcode nonexisting dirs. _LT_TAGVAR(hardcode_action, $1)=immediate fi else # We cannot hardcode anything, or else we can only hardcode existing # directories. _LT_TAGVAR(hardcode_action, $1)=unsupported fi AC_MSG_RESULT([$_LT_TAGVAR(hardcode_action, $1)]) if test "$_LT_TAGVAR(hardcode_action, $1)" = relink || test "$_LT_TAGVAR(inherit_rpath, $1)" = yes; then # Fast installation is not supported enable_fast_install=no elif test "$shlibpath_overrides_runpath" = yes || test "$enable_shared" = no; then # Fast installation is not necessary enable_fast_install=needless fi _LT_TAGDECL([], [hardcode_action], [0], [How to hardcode a shared library path into an executable]) ])# _LT_LINKER_HARDCODE_LIBPATH # _LT_CMD_STRIPLIB # ---------------- m4_defun([_LT_CMD_STRIPLIB], [m4_require([_LT_DECL_EGREP]) striplib= old_striplib= AC_MSG_CHECKING([whether stripping libraries is possible]) if test -n "$STRIP" && $STRIP -V 2>&1 | $GREP "GNU strip" >/dev/null; then test -z "$old_striplib" && old_striplib="$STRIP --strip-debug" test -z "$striplib" && striplib="$STRIP --strip-unneeded" AC_MSG_RESULT([yes]) else # FIXME - insert some real tests, host_os isn't really good enough case $host_os in darwin*) if test -n "$STRIP" ; then striplib="$STRIP -x" old_striplib="$STRIP -S" AC_MSG_RESULT([yes]) else AC_MSG_RESULT([no]) fi ;; *) AC_MSG_RESULT([no]) ;; esac fi _LT_DECL([], [old_striplib], [1], [Commands to strip libraries]) _LT_DECL([], [striplib], [1]) ])# _LT_CMD_STRIPLIB # _LT_SYS_DYNAMIC_LINKER([TAG]) # ----------------------------- # PORTME Fill in your ld.so characteristics m4_defun([_LT_SYS_DYNAMIC_LINKER], [AC_REQUIRE([AC_CANONICAL_HOST])dnl m4_require([_LT_DECL_EGREP])dnl m4_require([_LT_FILEUTILS_DEFAULTS])dnl m4_require([_LT_DECL_OBJDUMP])dnl m4_require([_LT_DECL_SED])dnl AC_MSG_CHECKING([dynamic linker characteristics]) m4_if([$1], [], [ if test "$GCC" = yes; then case $host_os in darwin*) lt_awk_arg="/^libraries:/,/LR/" ;; *) lt_awk_arg="/^libraries:/" ;; esac lt_search_path_spec=`$CC -print-search-dirs | awk $lt_awk_arg | $SED -e "s/^libraries://" -e "s,=/,/,g"` if $ECHO "$lt_search_path_spec" | $GREP ';' >/dev/null ; then # if the path contains ";" then we assume it to be the separator # otherwise default to the standard path separator (i.e. ":") - it is # assumed that no part of a normal pathname contains ";" but that should # okay in the real world where ";" in dirpaths is itself problematic. lt_search_path_spec=`$ECHO "$lt_search_path_spec" | $SED -e 's/;/ /g'` else lt_search_path_spec=`$ECHO "$lt_search_path_spec" | $SED -e "s/$PATH_SEPARATOR/ /g"` fi # Ok, now we have the path, separated by spaces, we can step through it # and add multilib dir if necessary. lt_tmp_lt_search_path_spec= lt_multi_os_dir=`$CC $CPPFLAGS $CFLAGS $LDFLAGS -print-multi-os-directory 2>/dev/null` for lt_sys_path in $lt_search_path_spec; do if test -d "$lt_sys_path/$lt_multi_os_dir"; then lt_tmp_lt_search_path_spec="$lt_tmp_lt_search_path_spec $lt_sys_path/$lt_multi_os_dir" else test -d "$lt_sys_path" && \ lt_tmp_lt_search_path_spec="$lt_tmp_lt_search_path_spec $lt_sys_path" fi done lt_search_path_spec=`$ECHO $lt_tmp_lt_search_path_spec | awk ' BEGIN {RS=" "; FS="/|\n";} { lt_foo=""; lt_count=0; for (lt_i = NF; lt_i > 0; lt_i--) { if ($lt_i != "" && $lt_i != ".") { if ($lt_i == "..") { lt_count++; } else { if (lt_count == 0) { lt_foo="/" $lt_i lt_foo; } else { lt_count--; } } } } if (lt_foo != "") { lt_freq[[lt_foo]]++; } if (lt_freq[[lt_foo]] == 1) { print lt_foo; } }'` sys_lib_search_path_spec=`$ECHO $lt_search_path_spec` else sys_lib_search_path_spec="/lib /usr/lib /usr/local/lib" fi]) library_names_spec= libname_spec='lib$name' soname_spec= shrext_cmds=".so" postinstall_cmds= postuninstall_cmds= finish_cmds= finish_eval= shlibpath_var= shlibpath_overrides_runpath=unknown version_type=none dynamic_linker="$host_os ld.so" sys_lib_dlsearch_path_spec="/lib /usr/lib" need_lib_prefix=unknown hardcode_into_libs=no # when you set need_version to no, make sure it does not cause -set_version # flags to be left without arguments need_version=unknown case $host_os in aix3*) version_type=linux library_names_spec='${libname}${release}${shared_ext}$versuffix $libname.a' shlibpath_var=LIBPATH # AIX 3 has no versioning support, so we append a major version to the name. soname_spec='${libname}${release}${shared_ext}$major' ;; aix[[4-9]]*) version_type=linux need_lib_prefix=no need_version=no hardcode_into_libs=yes if test "$host_cpu" = ia64; then # AIX 5 supports IA64 library_names_spec='${libname}${release}${shared_ext}$major ${libname}${release}${shared_ext}$versuffix $libname${shared_ext}' shlibpath_var=LD_LIBRARY_PATH else # With GCC up to 2.95.x, collect2 would create an import file # for dependence libraries. The import file would start with # the line `#! .'. This would cause the generated library to # depend on `.', always an invalid library. This was fixed in # development snapshots of GCC prior to 3.0. case $host_os in aix4 | aix4.[[01]] | aix4.[[01]].*) if { echo '#if __GNUC__ > 2 || (__GNUC__ == 2 && __GNUC_MINOR__ >= 97)' echo ' yes ' echo '#endif'; } | ${CC} -E - | $GREP yes > /dev/null; then : else can_build_shared=no fi ;; esac # AIX (on Power*) has no versioning support, so currently we can not hardcode correct # soname into executable. Probably we can add versioning support to # collect2, so additional links can be useful in future. if test "$aix_use_runtimelinking" = yes; then # If using run time linking (on AIX 4.2 or later) use lib.so # instead of lib.a to let people know that these are not # typical AIX shared libraries. library_names_spec='${libname}${release}${shared_ext}$versuffix ${libname}${release}${shared_ext}$major $libname${shared_ext}' else # We preserve .a as extension for shared libraries through AIX4.2 # and later when we are not doing run time linking. library_names_spec='${libname}${release}.a $libname.a' soname_spec='${libname}${release}${shared_ext}$major' fi shlibpath_var=LIBPATH fi ;; amigaos*) case $host_cpu in powerpc) # Since July 2007 AmigaOS4 officially supports .so libraries. # When compiling the executable, add -use-dynld -Lsobjs: to the compileline. library_names_spec='${libname}${release}${shared_ext}$versuffix ${libname}${release}${shared_ext}$major $libname${shared_ext}' ;; m68k) library_names_spec='$libname.ixlibrary $libname.a' # Create ${libname}_ixlibrary.a entries in /sys/libs. finish_eval='for lib in `ls $libdir/*.ixlibrary 2>/dev/null`; do libname=`$ECHO "X$lib" | $Xsed -e '\''s%^.*/\([[^/]]*\)\.ixlibrary$%\1%'\''`; test $RM /sys/libs/${libname}_ixlibrary.a; $show "cd /sys/libs && $LN_S $lib ${libname}_ixlibrary.a"; cd /sys/libs && $LN_S $lib ${libname}_ixlibrary.a || exit 1; done' ;; esac ;; beos*) library_names_spec='${libname}${shared_ext}' dynamic_linker="$host_os ld.so" shlibpath_var=LIBRARY_PATH ;; bsdi[[45]]*) version_type=linux need_version=no library_names_spec='${libname}${release}${shared_ext}$versuffix ${libname}${release}${shared_ext}$major $libname${shared_ext}' soname_spec='${libname}${release}${shared_ext}$major' finish_cmds='PATH="\$PATH:/sbin" ldconfig $libdir' shlibpath_var=LD_LIBRARY_PATH sys_lib_search_path_spec="/shlib /usr/lib /usr/X11/lib /usr/contrib/lib /lib /usr/local/lib" sys_lib_dlsearch_path_spec="/shlib /usr/lib /usr/local/lib" # the default ld.so.conf also contains /usr/contrib/lib and # /usr/X11R6/lib (/usr/X11 is a link to /usr/X11R6), but let us allow # libtool to hard-code these into programs ;; cygwin* | mingw* | pw32* | cegcc*) version_type=windows shrext_cmds=".dll" need_version=no need_lib_prefix=no case $GCC,$host_os in yes,cygwin* | yes,mingw* | yes,pw32* | yes,cegcc*) library_names_spec='$libname.dll.a' # DLL is installed to $(libdir)/../bin by postinstall_cmds postinstall_cmds='base_file=`basename \${file}`~ dlpath=`$SHELL 2>&1 -c '\''. $dir/'\''\${base_file}'\''i; echo \$dlname'\''`~ dldir=$destdir/`dirname \$dlpath`~ test -d \$dldir || mkdir -p \$dldir~ $install_prog $dir/$dlname \$dldir/$dlname~ chmod a+x \$dldir/$dlname~ if test -n '\''$stripme'\'' && test -n '\''$striplib'\''; then eval '\''$striplib \$dldir/$dlname'\'' || exit \$?; fi' postuninstall_cmds='dldll=`$SHELL 2>&1 -c '\''. $file; echo \$dlname'\''`~ dlpath=$dir/\$dldll~ $RM \$dlpath' shlibpath_overrides_runpath=yes case $host_os in cygwin*) # Cygwin DLLs use 'cyg' prefix rather than 'lib' soname_spec='`echo ${libname} | sed -e 's/^lib/cyg/'``echo ${release} | $SED -e 's/[[.]]/-/g'`${versuffix}${shared_ext}' sys_lib_search_path_spec="/usr/lib /lib/w32api /lib /usr/local/lib" ;; mingw* | cegcc*) # MinGW DLLs use traditional 'lib' prefix soname_spec='${libname}`echo ${release} | $SED -e 's/[[.]]/-/g'`${versuffix}${shared_ext}' sys_lib_search_path_spec=`$CC -print-search-dirs | $GREP "^libraries:" | $SED -e "s/^libraries://" -e "s,=/,/,g"` if $ECHO "$sys_lib_search_path_spec" | [$GREP ';[c-zC-Z]:/' >/dev/null]; then # It is most probably a Windows format PATH printed by # mingw gcc, but we are running on Cygwin. Gcc prints its search # path with ; separators, and with drive letters. We can handle the # drive letters (cygwin fileutils understands them), so leave them, # especially as we might pass files found there to a mingw objdump, # which wouldn't understand a cygwinified path. Ahh. sys_lib_search_path_spec=`$ECHO "$sys_lib_search_path_spec" | $SED -e 's/;/ /g'` else sys_lib_search_path_spec=`$ECHO "$sys_lib_search_path_spec" | $SED -e "s/$PATH_SEPARATOR/ /g"` fi ;; pw32*) # pw32 DLLs use 'pw' prefix rather than 'lib' library_names_spec='`echo ${libname} | sed -e 's/^lib/pw/'``echo ${release} | $SED -e 's/[[.]]/-/g'`${versuffix}${shared_ext}' ;; esac ;; *) library_names_spec='${libname}`echo ${release} | $SED -e 's/[[.]]/-/g'`${versuffix}${shared_ext} $libname.lib' ;; esac dynamic_linker='Win32 ld.exe' # FIXME: first we should search . and the directory the executable is in shlibpath_var=PATH ;; darwin* | rhapsody*) dynamic_linker="$host_os dyld" version_type=darwin need_lib_prefix=no need_version=no library_names_spec='${libname}${release}${major}$shared_ext ${libname}$shared_ext' soname_spec='${libname}${release}${major}$shared_ext' shlibpath_overrides_runpath=yes shlibpath_var=DYLD_LIBRARY_PATH shrext_cmds='`test .$module = .yes && echo .so || echo .dylib`' m4_if([$1], [],[ sys_lib_search_path_spec="$sys_lib_search_path_spec /usr/local/lib"]) sys_lib_dlsearch_path_spec='/usr/local/lib /lib /usr/lib' ;; dgux*) version_type=linux need_lib_prefix=no need_version=no library_names_spec='${libname}${release}${shared_ext}$versuffix ${libname}${release}${shared_ext}$major $libname$shared_ext' soname_spec='${libname}${release}${shared_ext}$major' shlibpath_var=LD_LIBRARY_PATH ;; freebsd1*) dynamic_linker=no ;; freebsd* | dragonfly*) # DragonFly does not have aout. When/if they implement a new # versioning mechanism, adjust this. if test -x /usr/bin/objformat; then objformat=`/usr/bin/objformat` else case $host_os in freebsd[[123]]*) objformat=aout ;; *) objformat=elf ;; esac fi version_type=freebsd-$objformat case $version_type in freebsd-elf*) library_names_spec='${libname}${release}${shared_ext}$versuffix ${libname}${release}${shared_ext} $libname${shared_ext}' need_version=no need_lib_prefix=no ;; freebsd-*) library_names_spec='${libname}${release}${shared_ext}$versuffix $libname${shared_ext}$versuffix' need_version=yes ;; esac shlibpath_var=LD_LIBRARY_PATH case $host_os in freebsd2*) shlibpath_overrides_runpath=yes ;; freebsd3.[[01]]* | freebsdelf3.[[01]]*) shlibpath_overrides_runpath=yes hardcode_into_libs=yes ;; freebsd3.[[2-9]]* | freebsdelf3.[[2-9]]* | \ freebsd4.[[0-5]] | freebsdelf4.[[0-5]] | freebsd4.1.1 | freebsdelf4.1.1) shlibpath_overrides_runpath=no hardcode_into_libs=yes ;; *) # from 4.6 on, and DragonFly shlibpath_overrides_runpath=yes hardcode_into_libs=yes ;; esac ;; gnu*) version_type=linux need_lib_prefix=no need_version=no library_names_spec='${libname}${release}${shared_ext}$versuffix ${libname}${release}${shared_ext}${major} ${libname}${shared_ext}' soname_spec='${libname}${release}${shared_ext}$major' shlibpath_var=LD_LIBRARY_PATH hardcode_into_libs=yes ;; hpux9* | hpux10* | hpux11*) # Give a soname corresponding to the major version so that dld.sl refuses to # link against other versions. version_type=sunos need_lib_prefix=no need_version=no case $host_cpu in ia64*) shrext_cmds='.so' hardcode_into_libs=yes dynamic_linker="$host_os dld.so" shlibpath_var=LD_LIBRARY_PATH shlibpath_overrides_runpath=yes # Unless +noenvvar is specified. library_names_spec='${libname}${release}${shared_ext}$versuffix ${libname}${release}${shared_ext}$major $libname${shared_ext}' soname_spec='${libname}${release}${shared_ext}$major' if test "X$HPUX_IA64_MODE" = X32; then sys_lib_search_path_spec="/usr/lib/hpux32 /usr/local/lib/hpux32 /usr/local/lib" else sys_lib_search_path_spec="/usr/lib/hpux64 /usr/local/lib/hpux64" fi sys_lib_dlsearch_path_spec=$sys_lib_search_path_spec ;; hppa*64*) shrext_cmds='.sl' hardcode_into_libs=yes dynamic_linker="$host_os dld.sl" shlibpath_var=LD_LIBRARY_PATH # How should we handle SHLIB_PATH shlibpath_overrides_runpath=yes # Unless +noenvvar is specified. library_names_spec='${libname}${release}${shared_ext}$versuffix ${libname}${release}${shared_ext}$major $libname${shared_ext}' soname_spec='${libname}${release}${shared_ext}$major' sys_lib_search_path_spec="/usr/lib/pa20_64 /usr/ccs/lib/pa20_64" sys_lib_dlsearch_path_spec=$sys_lib_search_path_spec ;; *) shrext_cmds='.sl' dynamic_linker="$host_os dld.sl" shlibpath_var=SHLIB_PATH shlibpath_overrides_runpath=no # +s is required to enable SHLIB_PATH library_names_spec='${libname}${release}${shared_ext}$versuffix ${libname}${release}${shared_ext}$major $libname${shared_ext}' soname_spec='${libname}${release}${shared_ext}$major' ;; esac # HP-UX runs *really* slowly unless shared libraries are mode 555. postinstall_cmds='chmod 555 $lib' ;; interix[[3-9]]*) version_type=linux need_lib_prefix=no need_version=no library_names_spec='${libname}${release}${shared_ext}$versuffix ${libname}${release}${shared_ext}$major ${libname}${shared_ext}' soname_spec='${libname}${release}${shared_ext}$major' dynamic_linker='Interix 3.x ld.so.1 (PE, like ELF)' shlibpath_var=LD_LIBRARY_PATH shlibpath_overrides_runpath=no hardcode_into_libs=yes ;; irix5* | irix6* | nonstopux*) case $host_os in nonstopux*) version_type=nonstopux ;; *) if test "$lt_cv_prog_gnu_ld" = yes; then version_type=linux else version_type=irix fi ;; esac need_lib_prefix=no need_version=no soname_spec='${libname}${release}${shared_ext}$major' library_names_spec='${libname}${release}${shared_ext}$versuffix ${libname}${release}${shared_ext}$major ${libname}${release}${shared_ext} $libname${shared_ext}' case $host_os in irix5* | nonstopux*) libsuff= shlibsuff= ;; *) case $LD in # libtool.m4 will add one of these switches to LD *-32|*"-32 "|*-melf32bsmip|*"-melf32bsmip ") libsuff= shlibsuff= libmagic=32-bit;; *-n32|*"-n32 "|*-melf32bmipn32|*"-melf32bmipn32 ") libsuff=32 shlibsuff=N32 libmagic=N32;; *-64|*"-64 "|*-melf64bmip|*"-melf64bmip ") libsuff=64 shlibsuff=64 libmagic=64-bit;; *) libsuff= shlibsuff= libmagic=never-match;; esac ;; esac shlibpath_var=LD_LIBRARY${shlibsuff}_PATH shlibpath_overrides_runpath=no sys_lib_search_path_spec="/usr/lib${libsuff} /lib${libsuff} /usr/local/lib${libsuff}" sys_lib_dlsearch_path_spec="/usr/lib${libsuff} /lib${libsuff}" hardcode_into_libs=yes ;; # No shared lib support for Linux oldld, aout, or coff. linux*oldld* | linux*aout* | linux*coff*) dynamic_linker=no ;; # This must be Linux ELF. linux* | k*bsd*-gnu) version_type=linux need_lib_prefix=no need_version=no library_names_spec='${libname}${release}${shared_ext}$versuffix ${libname}${release}${shared_ext}$major $libname${shared_ext}' soname_spec='${libname}${release}${shared_ext}$major' finish_cmds='PATH="\$PATH:/sbin" ldconfig -n $libdir' shlibpath_var=LD_LIBRARY_PATH shlibpath_overrides_runpath=no # Some binutils ld are patched to set DT_RUNPATH save_LDFLAGS=$LDFLAGS save_libdir=$libdir eval "libdir=/foo; wl=\"$_LT_TAGVAR(lt_prog_compiler_wl, $1)\"; \ LDFLAGS=\"\$LDFLAGS $_LT_TAGVAR(hardcode_libdir_flag_spec, $1)\"" AC_LINK_IFELSE([AC_LANG_PROGRAM([],[])], [AS_IF([ ($OBJDUMP -p conftest$ac_exeext) 2>/dev/null | grep "RUNPATH.*$libdir" >/dev/null], [shlibpath_overrides_runpath=yes])]) LDFLAGS=$save_LDFLAGS libdir=$save_libdir # This implies no fast_install, which is unacceptable. # Some rework will be needed to allow for fast_install # before this can be enabled. hardcode_into_libs=yes # Append ld.so.conf contents to the search path if test -f /etc/ld.so.conf; then lt_ld_extra=`awk '/^include / { system(sprintf("cd /etc; cat %s 2>/dev/null", \[$]2)); skip = 1; } { if (!skip) print \[$]0; skip = 0; }' < /etc/ld.so.conf | $SED -e 's/#.*//;/^[ ]*hwcap[ ]/d;s/[:, ]/ /g;s/=[^=]*$//;s/=[^= ]* / /g;/^$/d' | tr '\n' ' '` sys_lib_dlsearch_path_spec="/lib /usr/lib $lt_ld_extra" fi # We used to test for /lib/ld.so.1 and disable shared libraries on # powerpc, because MkLinux only supported shared libraries with the # GNU dynamic linker. Since this was broken with cross compilers, # most powerpc-linux boxes support dynamic linking these days and # people can always --disable-shared, the test was removed, and we # assume the GNU/Linux dynamic linker is in use. dynamic_linker='GNU/Linux ld.so' ;; netbsd*) version_type=sunos need_lib_prefix=no need_version=no if echo __ELF__ | $CC -E - | $GREP __ELF__ >/dev/null; then library_names_spec='${libname}${release}${shared_ext}$versuffix ${libname}${shared_ext}$versuffix' finish_cmds='PATH="\$PATH:/sbin" ldconfig -m $libdir' dynamic_linker='NetBSD (a.out) ld.so' else library_names_spec='${libname}${release}${shared_ext}$versuffix ${libname}${release}${shared_ext}$major ${libname}${shared_ext}' soname_spec='${libname}${release}${shared_ext}$major' dynamic_linker='NetBSD ld.elf_so' fi shlibpath_var=LD_LIBRARY_PATH shlibpath_overrides_runpath=yes hardcode_into_libs=yes ;; newsos6) version_type=linux library_names_spec='${libname}${release}${shared_ext}$versuffix ${libname}${release}${shared_ext}$major $libname${shared_ext}' shlibpath_var=LD_LIBRARY_PATH shlibpath_overrides_runpath=yes ;; *nto* | *qnx*) version_type=qnx need_lib_prefix=no need_version=no library_names_spec='${libname}${release}${shared_ext}$versuffix ${libname}${release}${shared_ext}$major $libname${shared_ext}' soname_spec='${libname}${release}${shared_ext}$major' shlibpath_var=LD_LIBRARY_PATH shlibpath_overrides_runpath=no hardcode_into_libs=yes dynamic_linker='ldqnx.so' ;; openbsd*) version_type=sunos sys_lib_dlsearch_path_spec="/usr/lib" need_lib_prefix=no # Some older versions of OpenBSD (3.3 at least) *do* need versioned libs. case $host_os in openbsd3.3 | openbsd3.3.*) need_version=yes ;; *) need_version=no ;; esac library_names_spec='${libname}${release}${shared_ext}$versuffix ${libname}${shared_ext}$versuffix' finish_cmds='PATH="\$PATH:/sbin" ldconfig -m $libdir' shlibpath_var=LD_LIBRARY_PATH if test -z "`echo __ELF__ | $CC -E - | $GREP __ELF__`" || test "$host_os-$host_cpu" = "openbsd2.8-powerpc"; then case $host_os in openbsd2.[[89]] | openbsd2.[[89]].*) shlibpath_overrides_runpath=no ;; *) shlibpath_overrides_runpath=yes ;; esac else shlibpath_overrides_runpath=yes fi ;; os2*) libname_spec='$name' shrext_cmds=".dll" need_lib_prefix=no library_names_spec='$libname${shared_ext} $libname.a' dynamic_linker='OS/2 ld.exe' shlibpath_var=LIBPATH ;; osf3* | osf4* | osf5*) version_type=osf need_lib_prefix=no need_version=no soname_spec='${libname}${release}${shared_ext}$major' library_names_spec='${libname}${release}${shared_ext}$versuffix ${libname}${release}${shared_ext}$major $libname${shared_ext}' shlibpath_var=LD_LIBRARY_PATH sys_lib_search_path_spec="/usr/shlib /usr/ccs/lib /usr/lib/cmplrs/cc /usr/lib /usr/local/lib /var/shlib" sys_lib_dlsearch_path_spec="$sys_lib_search_path_spec" ;; rdos*) dynamic_linker=no ;; solaris*) version_type=linux need_lib_prefix=no need_version=no library_names_spec='${libname}${release}${shared_ext}$versuffix ${libname}${release}${shared_ext}$major $libname${shared_ext}' soname_spec='${libname}${release}${shared_ext}$major' shlibpath_var=LD_LIBRARY_PATH shlibpath_overrides_runpath=yes hardcode_into_libs=yes # ldd complains unless libraries are executable postinstall_cmds='chmod +x $lib' ;; sunos4*) version_type=sunos library_names_spec='${libname}${release}${shared_ext}$versuffix ${libname}${shared_ext}$versuffix' finish_cmds='PATH="\$PATH:/usr/etc" ldconfig $libdir' shlibpath_var=LD_LIBRARY_PATH shlibpath_overrides_runpath=yes if test "$with_gnu_ld" = yes; then need_lib_prefix=no fi need_version=yes ;; sysv4 | sysv4.3*) version_type=linux library_names_spec='${libname}${release}${shared_ext}$versuffix ${libname}${release}${shared_ext}$major $libname${shared_ext}' soname_spec='${libname}${release}${shared_ext}$major' shlibpath_var=LD_LIBRARY_PATH case $host_vendor in sni) shlibpath_overrides_runpath=no need_lib_prefix=no runpath_var=LD_RUN_PATH ;; siemens) need_lib_prefix=no ;; motorola) need_lib_prefix=no need_version=no shlibpath_overrides_runpath=no sys_lib_search_path_spec='/lib /usr/lib /usr/ccs/lib' ;; esac ;; sysv4*MP*) if test -d /usr/nec ;then version_type=linux library_names_spec='$libname${shared_ext}.$versuffix $libname${shared_ext}.$major $libname${shared_ext}' soname_spec='$libname${shared_ext}.$major' shlibpath_var=LD_LIBRARY_PATH fi ;; sysv5* | sco3.2v5* | sco5v6* | unixware* | OpenUNIX* | sysv4*uw2*) version_type=freebsd-elf need_lib_prefix=no need_version=no library_names_spec='${libname}${release}${shared_ext}$versuffix ${libname}${release}${shared_ext} $libname${shared_ext}' soname_spec='${libname}${release}${shared_ext}$major' shlibpath_var=LD_LIBRARY_PATH shlibpath_overrides_runpath=yes hardcode_into_libs=yes if test "$with_gnu_ld" = yes; then sys_lib_search_path_spec='/usr/local/lib /usr/gnu/lib /usr/ccs/lib /usr/lib /lib' else sys_lib_search_path_spec='/usr/ccs/lib /usr/lib' case $host_os in sco3.2v5*) sys_lib_search_path_spec="$sys_lib_search_path_spec /lib" ;; esac fi sys_lib_dlsearch_path_spec='/usr/lib' ;; tpf*) # TPF is a cross-target only. Preferred cross-host = GNU/Linux. version_type=linux need_lib_prefix=no need_version=no library_names_spec='${libname}${release}${shared_ext}$versuffix ${libname}${release}${shared_ext}$major $libname${shared_ext}' shlibpath_var=LD_LIBRARY_PATH shlibpath_overrides_runpath=no hardcode_into_libs=yes ;; uts4*) version_type=linux library_names_spec='${libname}${release}${shared_ext}$versuffix ${libname}${release}${shared_ext}$major $libname${shared_ext}' soname_spec='${libname}${release}${shared_ext}$major' shlibpath_var=LD_LIBRARY_PATH ;; *) dynamic_linker=no ;; esac AC_MSG_RESULT([$dynamic_linker]) test "$dynamic_linker" = no && can_build_shared=no variables_saved_for_relink="PATH $shlibpath_var $runpath_var" if test "$GCC" = yes; then variables_saved_for_relink="$variables_saved_for_relink GCC_EXEC_PREFIX COMPILER_PATH LIBRARY_PATH" fi if test "${lt_cv_sys_lib_search_path_spec+set}" = set; then sys_lib_search_path_spec="$lt_cv_sys_lib_search_path_spec" fi if test "${lt_cv_sys_lib_dlsearch_path_spec+set}" = set; then sys_lib_dlsearch_path_spec="$lt_cv_sys_lib_dlsearch_path_spec" fi _LT_DECL([], [variables_saved_for_relink], [1], [Variables whose values should be saved in libtool wrapper scripts and restored at link time]) _LT_DECL([], [need_lib_prefix], [0], [Do we need the "lib" prefix for modules?]) _LT_DECL([], [need_version], [0], [Do we need a version for libraries?]) _LT_DECL([], [version_type], [0], [Library versioning type]) _LT_DECL([], [runpath_var], [0], [Shared library runtime path variable]) _LT_DECL([], [shlibpath_var], [0],[Shared library path variable]) _LT_DECL([], [shlibpath_overrides_runpath], [0], [Is shlibpath searched before the hard-coded library search path?]) _LT_DECL([], [libname_spec], [1], [Format of library name prefix]) _LT_DECL([], [library_names_spec], [1], [[List of archive names. First name is the real one, the rest are links. The last name is the one that the linker finds with -lNAME]]) _LT_DECL([], [soname_spec], [1], [[The coded name of the library, if different from the real name]]) _LT_DECL([], [postinstall_cmds], [2], [Command to use after installation of a shared archive]) _LT_DECL([], [postuninstall_cmds], [2], [Command to use after uninstallation of a shared archive]) _LT_DECL([], [finish_cmds], [2], [Commands used to finish a libtool library installation in a directory]) _LT_DECL([], [finish_eval], [1], [[As "finish_cmds", except a single script fragment to be evaled but not shown]]) _LT_DECL([], [hardcode_into_libs], [0], [Whether we should hardcode library paths into libraries]) _LT_DECL([], [sys_lib_search_path_spec], [2], [Compile-time system search path for libraries]) _LT_DECL([], [sys_lib_dlsearch_path_spec], [2], [Run-time system search path for libraries]) ])# _LT_SYS_DYNAMIC_LINKER # _LT_PATH_TOOL_PREFIX(TOOL) # -------------------------- # find a file program which can recognize shared library AC_DEFUN([_LT_PATH_TOOL_PREFIX], [m4_require([_LT_DECL_EGREP])dnl AC_MSG_CHECKING([for $1]) AC_CACHE_VAL(lt_cv_path_MAGIC_CMD, [case $MAGIC_CMD in [[\\/*] | ?:[\\/]*]) lt_cv_path_MAGIC_CMD="$MAGIC_CMD" # Let the user override the test with a path. ;; *) lt_save_MAGIC_CMD="$MAGIC_CMD" lt_save_ifs="$IFS"; IFS=$PATH_SEPARATOR dnl $ac_dummy forces splitting on constant user-supplied paths. dnl POSIX.2 word splitting is done only on the output of word expansions, dnl not every word. This closes a longstanding sh security hole. ac_dummy="m4_if([$2], , $PATH, [$2])" for ac_dir in $ac_dummy; do IFS="$lt_save_ifs" test -z "$ac_dir" && ac_dir=. if test -f $ac_dir/$1; then lt_cv_path_MAGIC_CMD="$ac_dir/$1" if test -n "$file_magic_test_file"; then case $deplibs_check_method in "file_magic "*) file_magic_regex=`expr "$deplibs_check_method" : "file_magic \(.*\)"` MAGIC_CMD="$lt_cv_path_MAGIC_CMD" if eval $file_magic_cmd \$file_magic_test_file 2> /dev/null | $EGREP "$file_magic_regex" > /dev/null; then : else cat <<_LT_EOF 1>&2 *** Warning: the command libtool uses to detect shared libraries, *** $file_magic_cmd, produces output that libtool cannot recognize. *** The result is that libtool may fail to recognize shared libraries *** as such. This will affect the creation of libtool libraries that *** depend on shared libraries, but programs linked with such libtool *** libraries will work regardless of this problem. Nevertheless, you *** may want to report the problem to your system manager and/or to *** bug-libtool@gnu.org _LT_EOF fi ;; esac fi break fi done IFS="$lt_save_ifs" MAGIC_CMD="$lt_save_MAGIC_CMD" ;; esac]) MAGIC_CMD="$lt_cv_path_MAGIC_CMD" if test -n "$MAGIC_CMD"; then AC_MSG_RESULT($MAGIC_CMD) else AC_MSG_RESULT(no) fi _LT_DECL([], [MAGIC_CMD], [0], [Used to examine libraries when file_magic_cmd begins with "file"])dnl ])# _LT_PATH_TOOL_PREFIX # Old name: AU_ALIAS([AC_PATH_TOOL_PREFIX], [_LT_PATH_TOOL_PREFIX]) dnl aclocal-1.4 backwards compatibility: dnl AC_DEFUN([AC_PATH_TOOL_PREFIX], []) # _LT_PATH_MAGIC # -------------- # find a file program which can recognize a shared library m4_defun([_LT_PATH_MAGIC], [_LT_PATH_TOOL_PREFIX(${ac_tool_prefix}file, /usr/bin$PATH_SEPARATOR$PATH) if test -z "$lt_cv_path_MAGIC_CMD"; then if test -n "$ac_tool_prefix"; then _LT_PATH_TOOL_PREFIX(file, /usr/bin$PATH_SEPARATOR$PATH) else MAGIC_CMD=: fi fi ])# _LT_PATH_MAGIC # LT_PATH_LD # ---------- # find the pathname to the GNU or non-GNU linker AC_DEFUN([LT_PATH_LD], [AC_REQUIRE([AC_PROG_CC])dnl AC_REQUIRE([AC_CANONICAL_HOST])dnl AC_REQUIRE([AC_CANONICAL_BUILD])dnl m4_require([_LT_DECL_SED])dnl m4_require([_LT_DECL_EGREP])dnl AC_ARG_WITH([gnu-ld], [AS_HELP_STRING([--with-gnu-ld], [assume the C compiler uses GNU ld @<:@default=no@:>@])], [test "$withval" = no || with_gnu_ld=yes], [with_gnu_ld=no])dnl ac_prog=ld if test "$GCC" = yes; then # Check if gcc -print-prog-name=ld gives a path. AC_MSG_CHECKING([for ld used by $CC]) case $host in *-*-mingw*) # gcc leaves a trailing carriage return which upsets mingw ac_prog=`($CC -print-prog-name=ld) 2>&5 | tr -d '\015'` ;; *) ac_prog=`($CC -print-prog-name=ld) 2>&5` ;; esac case $ac_prog in # Accept absolute paths. [[\\/]]* | ?:[[\\/]]*) re_direlt='/[[^/]][[^/]]*/\.\./' # Canonicalize the pathname of ld ac_prog=`$ECHO "$ac_prog"| $SED 's%\\\\%/%g'` while $ECHO "$ac_prog" | $GREP "$re_direlt" > /dev/null 2>&1; do ac_prog=`$ECHO $ac_prog| $SED "s%$re_direlt%/%"` done test -z "$LD" && LD="$ac_prog" ;; "") # If it fails, then pretend we aren't using GCC. ac_prog=ld ;; *) # If it is relative, then search for the first ld in PATH. with_gnu_ld=unknown ;; esac elif test "$with_gnu_ld" = yes; then AC_MSG_CHECKING([for GNU ld]) else AC_MSG_CHECKING([for non-GNU ld]) fi AC_CACHE_VAL(lt_cv_path_LD, [if test -z "$LD"; then lt_save_ifs="$IFS"; IFS=$PATH_SEPARATOR for ac_dir in $PATH; do IFS="$lt_save_ifs" test -z "$ac_dir" && ac_dir=. if test -f "$ac_dir/$ac_prog" || test -f "$ac_dir/$ac_prog$ac_exeext"; then lt_cv_path_LD="$ac_dir/$ac_prog" # Check to see if the program is GNU ld. I'd rather use --version, # but apparently some variants of GNU ld only accept -v. # Break only if it was the GNU/non-GNU ld that we prefer. case `"$lt_cv_path_LD" -v 2>&1 &1 /dev/null 2>&1; then lt_cv_deplibs_check_method='file_magic ^x86 archive import|^x86 DLL' lt_cv_file_magic_cmd='func_win32_libid' else lt_cv_deplibs_check_method='file_magic file format pei*-i386(.*architecture: i386)?' lt_cv_file_magic_cmd='$OBJDUMP -f' fi ;; cegcc) # use the weaker test based on 'objdump'. See mingw*. lt_cv_deplibs_check_method='file_magic file format pe-arm-.*little(.*architecture: arm)?' lt_cv_file_magic_cmd='$OBJDUMP -f' ;; darwin* | rhapsody*) lt_cv_deplibs_check_method=pass_all ;; freebsd* | dragonfly*) if echo __ELF__ | $CC -E - | $GREP __ELF__ > /dev/null; then case $host_cpu in i*86 ) # Not sure whether the presence of OpenBSD here was a mistake. # Let's accept both of them until this is cleared up. lt_cv_deplibs_check_method='file_magic (FreeBSD|OpenBSD|DragonFly)/i[[3-9]]86 (compact )?demand paged shared library' lt_cv_file_magic_cmd=/usr/bin/file lt_cv_file_magic_test_file=`echo /usr/lib/libc.so.*` ;; esac else lt_cv_deplibs_check_method=pass_all fi ;; gnu*) lt_cv_deplibs_check_method=pass_all ;; hpux10.20* | hpux11*) lt_cv_file_magic_cmd=/usr/bin/file case $host_cpu in ia64*) lt_cv_deplibs_check_method='file_magic (s[[0-9]][[0-9]][[0-9]]|ELF-[[0-9]][[0-9]]) shared object file - IA64' lt_cv_file_magic_test_file=/usr/lib/hpux32/libc.so ;; hppa*64*) [lt_cv_deplibs_check_method='file_magic (s[0-9][0-9][0-9]|ELF-[0-9][0-9]) shared object file - PA-RISC [0-9].[0-9]'] lt_cv_file_magic_test_file=/usr/lib/pa20_64/libc.sl ;; *) lt_cv_deplibs_check_method='file_magic (s[[0-9]][[0-9]][[0-9]]|PA-RISC[[0-9]].[[0-9]]) shared library' lt_cv_file_magic_test_file=/usr/lib/libc.sl ;; esac ;; interix[[3-9]]*) # PIC code is broken on Interix 3.x, that's why |\.a not |_pic\.a here lt_cv_deplibs_check_method='match_pattern /lib[[^/]]+(\.so|\.a)$' ;; irix5* | irix6* | nonstopux*) case $LD in *-32|*"-32 ") libmagic=32-bit;; *-n32|*"-n32 ") libmagic=N32;; *-64|*"-64 ") libmagic=64-bit;; *) libmagic=never-match;; esac lt_cv_deplibs_check_method=pass_all ;; # This must be Linux ELF. linux* | k*bsd*-gnu) lt_cv_deplibs_check_method=pass_all ;; netbsd*) if echo __ELF__ | $CC -E - | $GREP __ELF__ > /dev/null; then lt_cv_deplibs_check_method='match_pattern /lib[[^/]]+(\.so\.[[0-9]]+\.[[0-9]]+|_pic\.a)$' else lt_cv_deplibs_check_method='match_pattern /lib[[^/]]+(\.so|_pic\.a)$' fi ;; newos6*) lt_cv_deplibs_check_method='file_magic ELF [[0-9]][[0-9]]*-bit [[ML]]SB (executable|dynamic lib)' lt_cv_file_magic_cmd=/usr/bin/file lt_cv_file_magic_test_file=/usr/lib/libnls.so ;; *nto* | *qnx*) lt_cv_deplibs_check_method=pass_all ;; openbsd*) if test -z "`echo __ELF__ | $CC -E - | $GREP __ELF__`" || test "$host_os-$host_cpu" = "openbsd2.8-powerpc"; then lt_cv_deplibs_check_method='match_pattern /lib[[^/]]+(\.so\.[[0-9]]+\.[[0-9]]+|\.so|_pic\.a)$' else lt_cv_deplibs_check_method='match_pattern /lib[[^/]]+(\.so\.[[0-9]]+\.[[0-9]]+|_pic\.a)$' fi ;; osf3* | osf4* | osf5*) lt_cv_deplibs_check_method=pass_all ;; rdos*) lt_cv_deplibs_check_method=pass_all ;; solaris*) lt_cv_deplibs_check_method=pass_all ;; sysv5* | sco3.2v5* | sco5v6* | unixware* | OpenUNIX* | sysv4*uw2*) lt_cv_deplibs_check_method=pass_all ;; sysv4 | sysv4.3*) case $host_vendor in motorola) lt_cv_deplibs_check_method='file_magic ELF [[0-9]][[0-9]]*-bit [[ML]]SB (shared object|dynamic lib) M[[0-9]][[0-9]]* Version [[0-9]]' lt_cv_file_magic_test_file=`echo /usr/lib/libc.so*` ;; ncr) lt_cv_deplibs_check_method=pass_all ;; sequent) lt_cv_file_magic_cmd='/bin/file' lt_cv_deplibs_check_method='file_magic ELF [[0-9]][[0-9]]*-bit [[LM]]SB (shared object|dynamic lib )' ;; sni) lt_cv_file_magic_cmd='/bin/file' lt_cv_deplibs_check_method="file_magic ELF [[0-9]][[0-9]]*-bit [[LM]]SB dynamic lib" lt_cv_file_magic_test_file=/lib/libc.so ;; siemens) lt_cv_deplibs_check_method=pass_all ;; pc) lt_cv_deplibs_check_method=pass_all ;; esac ;; tpf*) lt_cv_deplibs_check_method=pass_all ;; esac ]) file_magic_cmd=$lt_cv_file_magic_cmd deplibs_check_method=$lt_cv_deplibs_check_method test -z "$deplibs_check_method" && deplibs_check_method=unknown _LT_DECL([], [deplibs_check_method], [1], [Method to check whether dependent libraries are shared objects]) _LT_DECL([], [file_magic_cmd], [1], [Command to use when deplibs_check_method == "file_magic"]) ])# _LT_CHECK_MAGIC_METHOD # LT_PATH_NM # ---------- # find the pathname to a BSD- or MS-compatible name lister AC_DEFUN([LT_PATH_NM], [AC_REQUIRE([AC_PROG_CC])dnl AC_CACHE_CHECK([for BSD- or MS-compatible name lister (nm)], lt_cv_path_NM, [if test -n "$NM"; then # Let the user override the test. lt_cv_path_NM="$NM" else lt_nm_to_check="${ac_tool_prefix}nm" if test -n "$ac_tool_prefix" && test "$build" = "$host"; then lt_nm_to_check="$lt_nm_to_check nm" fi for lt_tmp_nm in $lt_nm_to_check; do lt_save_ifs="$IFS"; IFS=$PATH_SEPARATOR for ac_dir in $PATH /usr/ccs/bin/elf /usr/ccs/bin /usr/ucb /bin; do IFS="$lt_save_ifs" test -z "$ac_dir" && ac_dir=. tmp_nm="$ac_dir/$lt_tmp_nm" if test -f "$tmp_nm" || test -f "$tmp_nm$ac_exeext" ; then # Check to see if the nm accepts a BSD-compat flag. # Adding the `sed 1q' prevents false positives on HP-UX, which says: # nm: unknown option "B" ignored # Tru64's nm complains that /dev/null is an invalid object file case `"$tmp_nm" -B /dev/null 2>&1 | sed '1q'` in */dev/null* | *'Invalid file or object type'*) lt_cv_path_NM="$tmp_nm -B" break ;; *) case `"$tmp_nm" -p /dev/null 2>&1 | sed '1q'` in */dev/null*) lt_cv_path_NM="$tmp_nm -p" break ;; *) lt_cv_path_NM=${lt_cv_path_NM="$tmp_nm"} # keep the first match, but continue # so that we can try to find one that supports BSD flags ;; esac ;; esac fi done IFS="$lt_save_ifs" done : ${lt_cv_path_NM=no} fi]) if test "$lt_cv_path_NM" != "no"; then NM="$lt_cv_path_NM" else # Didn't find any BSD compatible name lister, look for dumpbin. AC_CHECK_TOOLS(DUMPBIN, ["dumpbin -symbols" "link -dump -symbols"], :) AC_SUBST([DUMPBIN]) if test "$DUMPBIN" != ":"; then NM="$DUMPBIN" fi fi test -z "$NM" && NM=nm AC_SUBST([NM]) _LT_DECL([], [NM], [1], [A BSD- or MS-compatible name lister])dnl AC_CACHE_CHECK([the name lister ($NM) interface], [lt_cv_nm_interface], [lt_cv_nm_interface="BSD nm" echo "int some_variable = 0;" > conftest.$ac_ext (eval echo "\"\$as_me:__oline__: $ac_compile\"" >&AS_MESSAGE_LOG_FD) (eval "$ac_compile" 2>conftest.err) cat conftest.err >&AS_MESSAGE_LOG_FD (eval echo "\"\$as_me:__oline__: $NM \\\"conftest.$ac_objext\\\"\"" >&AS_MESSAGE_LOG_FD) (eval "$NM \"conftest.$ac_objext\"" 2>conftest.err > conftest.out) cat conftest.err >&AS_MESSAGE_LOG_FD (eval echo "\"\$as_me:__oline__: output\"" >&AS_MESSAGE_LOG_FD) cat conftest.out >&AS_MESSAGE_LOG_FD if $GREP 'External.*some_variable' conftest.out > /dev/null; then lt_cv_nm_interface="MS dumpbin" fi rm -f conftest*]) ])# LT_PATH_NM # Old names: AU_ALIAS([AM_PROG_NM], [LT_PATH_NM]) AU_ALIAS([AC_PROG_NM], [LT_PATH_NM]) dnl aclocal-1.4 backwards compatibility: dnl AC_DEFUN([AM_PROG_NM], []) dnl AC_DEFUN([AC_PROG_NM], []) # LT_LIB_M # -------- # check for math library AC_DEFUN([LT_LIB_M], [AC_REQUIRE([AC_CANONICAL_HOST])dnl LIBM= case $host in *-*-beos* | *-*-cygwin* | *-*-pw32* | *-*-darwin*) # These system don't have libm, or don't need it ;; *-ncr-sysv4.3*) AC_CHECK_LIB(mw, _mwvalidcheckl, LIBM="-lmw") AC_CHECK_LIB(m, cos, LIBM="$LIBM -lm") ;; *) AC_CHECK_LIB(m, cos, LIBM="-lm") ;; esac AC_SUBST([LIBM]) ])# LT_LIB_M # Old name: AU_ALIAS([AC_CHECK_LIBM], [LT_LIB_M]) dnl aclocal-1.4 backwards compatibility: dnl AC_DEFUN([AC_CHECK_LIBM], []) # _LT_COMPILER_NO_RTTI([TAGNAME]) # ------------------------------- m4_defun([_LT_COMPILER_NO_RTTI], [m4_require([_LT_TAG_COMPILER])dnl _LT_TAGVAR(lt_prog_compiler_no_builtin_flag, $1)= if test "$GCC" = yes; then _LT_TAGVAR(lt_prog_compiler_no_builtin_flag, $1)=' -fno-builtin' _LT_COMPILER_OPTION([if $compiler supports -fno-rtti -fno-exceptions], lt_cv_prog_compiler_rtti_exceptions, [-fno-rtti -fno-exceptions], [], [_LT_TAGVAR(lt_prog_compiler_no_builtin_flag, $1)="$_LT_TAGVAR(lt_prog_compiler_no_builtin_flag, $1) -fno-rtti -fno-exceptions"]) fi _LT_TAGDECL([no_builtin_flag], [lt_prog_compiler_no_builtin_flag], [1], [Compiler flag to turn off builtin functions]) ])# _LT_COMPILER_NO_RTTI # _LT_CMD_GLOBAL_SYMBOLS # ---------------------- m4_defun([_LT_CMD_GLOBAL_SYMBOLS], [AC_REQUIRE([AC_CANONICAL_HOST])dnl AC_REQUIRE([AC_PROG_CC])dnl AC_REQUIRE([LT_PATH_NM])dnl AC_REQUIRE([LT_PATH_LD])dnl m4_require([_LT_DECL_SED])dnl m4_require([_LT_DECL_EGREP])dnl m4_require([_LT_TAG_COMPILER])dnl # Check for command to grab the raw symbol name followed by C symbol from nm. AC_MSG_CHECKING([command to parse $NM output from $compiler object]) AC_CACHE_VAL([lt_cv_sys_global_symbol_pipe], [ # These are sane defaults that work on at least a few old systems. # [They come from Ultrix. What could be older than Ultrix?!! ;)] # Character class describing NM global symbol codes. symcode='[[BCDEGRST]]' # Regexp to match symbols that can be accessed directly from C. sympat='\([[_A-Za-z]][[_A-Za-z0-9]]*\)' # Define system-specific variables. case $host_os in aix*) symcode='[[BCDT]]' ;; cygwin* | mingw* | pw32* | cegcc*) symcode='[[ABCDGISTW]]' ;; hpux*) if test "$host_cpu" = ia64; then symcode='[[ABCDEGRST]]' fi ;; irix* | nonstopux*) symcode='[[BCDEGRST]]' ;; osf*) symcode='[[BCDEGQRST]]' ;; solaris*) symcode='[[BDRT]]' ;; sco3.2v5*) symcode='[[DT]]' ;; sysv4.2uw2*) symcode='[[DT]]' ;; sysv5* | sco5v6* | unixware* | OpenUNIX*) symcode='[[ABDT]]' ;; sysv4) symcode='[[DFNSTU]]' ;; esac # If we're using GNU nm, then use its standard symbol codes. case `$NM -V 2>&1` in *GNU* | *'with BFD'*) symcode='[[ABCDGIRSTW]]' ;; esac # Transform an extracted symbol line into a proper C declaration. # Some systems (esp. on ia64) link data and code symbols differently, # so use this general approach. lt_cv_sys_global_symbol_to_cdecl="sed -n -e 's/^T .* \(.*\)$/extern int \1();/p' -e 's/^$symcode* .* \(.*\)$/extern char \1;/p'" # Transform an extracted symbol line into symbol name and symbol address lt_cv_sys_global_symbol_to_c_name_address="sed -n -e 's/^: \([[^ ]]*\) $/ {\\\"\1\\\", (void *) 0},/p' -e 's/^$symcode* \([[^ ]]*\) \([[^ ]]*\)$/ {\"\2\", (void *) \&\2},/p'" lt_cv_sys_global_symbol_to_c_name_address_lib_prefix="sed -n -e 's/^: \([[^ ]]*\) $/ {\\\"\1\\\", (void *) 0},/p' -e 's/^$symcode* \([[^ ]]*\) \(lib[[^ ]]*\)$/ {\"\2\", (void *) \&\2},/p' -e 's/^$symcode* \([[^ ]]*\) \([[^ ]]*\)$/ {\"lib\2\", (void *) \&\2},/p'" # Handle CRLF in mingw tool chain opt_cr= case $build_os in mingw*) opt_cr=`$ECHO 'x\{0,1\}' | tr x '\015'` # option cr in regexp ;; esac # Try without a prefix underscore, then with it. for ac_symprfx in "" "_"; do # Transform symcode, sympat, and symprfx into a raw symbol and a C symbol. symxfrm="\\1 $ac_symprfx\\2 \\2" # Write the raw and C identifiers. if test "$lt_cv_nm_interface" = "MS dumpbin"; then # Fake it for dumpbin and say T for any non-static function # and D for any global variable. # Also find C++ and __fastcall symbols from MSVC++, # which start with @ or ?. lt_cv_sys_global_symbol_pipe="$AWK ['"\ " {last_section=section; section=\$ 3};"\ " /Section length .*#relocs.*(pick any)/{hide[last_section]=1};"\ " \$ 0!~/External *\|/{next};"\ " / 0+ UNDEF /{next}; / UNDEF \([^|]\)*()/{next};"\ " {if(hide[section]) next};"\ " {f=0}; \$ 0~/\(\).*\|/{f=1}; {printf f ? \"T \" : \"D \"};"\ " {split(\$ 0, a, /\||\r/); split(a[2], s)};"\ " s[1]~/^[@?]/{print s[1], s[1]; next};"\ " s[1]~prfx {split(s[1],t,\"@\"); print t[1], substr(t[1],length(prfx))}"\ " ' prfx=^$ac_symprfx]" else lt_cv_sys_global_symbol_pipe="sed -n -e 's/^.*[[ ]]\($symcode$symcode*\)[[ ]][[ ]]*$ac_symprfx$sympat$opt_cr$/$symxfrm/p'" fi # Check to see that the pipe works correctly. pipe_works=no rm -f conftest* cat > conftest.$ac_ext <<_LT_EOF #ifdef __cplusplus extern "C" { #endif char nm_test_var; void nm_test_func(void); void nm_test_func(void){} #ifdef __cplusplus } #endif int main(){nm_test_var='a';nm_test_func();return(0);} _LT_EOF if AC_TRY_EVAL(ac_compile); then # Now try to grab the symbols. nlist=conftest.nm if AC_TRY_EVAL(NM conftest.$ac_objext \| $lt_cv_sys_global_symbol_pipe \> $nlist) && test -s "$nlist"; then # Try sorting and uniquifying the output. if sort "$nlist" | uniq > "$nlist"T; then mv -f "$nlist"T "$nlist" else rm -f "$nlist"T fi # Make sure that we snagged all the symbols we need. if $GREP ' nm_test_var$' "$nlist" >/dev/null; then if $GREP ' nm_test_func$' "$nlist" >/dev/null; then cat <<_LT_EOF > conftest.$ac_ext #ifdef __cplusplus extern "C" { #endif _LT_EOF # Now generate the symbol file. eval "$lt_cv_sys_global_symbol_to_cdecl"' < "$nlist" | $GREP -v main >> conftest.$ac_ext' cat <<_LT_EOF >> conftest.$ac_ext /* The mapping between symbol names and symbols. */ const struct { const char *name; void *address; } lt__PROGRAM__LTX_preloaded_symbols[[]] = { { "@PROGRAM@", (void *) 0 }, _LT_EOF $SED "s/^$symcode$symcode* \(.*\) \(.*\)$/ {\"\2\", (void *) \&\2},/" < "$nlist" | $GREP -v main >> conftest.$ac_ext cat <<\_LT_EOF >> conftest.$ac_ext {0, (void *) 0} }; /* This works around a problem in FreeBSD linker */ #ifdef FREEBSD_WORKAROUND static const void *lt_preloaded_setup() { return lt__PROGRAM__LTX_preloaded_symbols; } #endif #ifdef __cplusplus } #endif _LT_EOF # Now try linking the two files. mv conftest.$ac_objext conftstm.$ac_objext lt_save_LIBS="$LIBS" lt_save_CFLAGS="$CFLAGS" LIBS="conftstm.$ac_objext" CFLAGS="$CFLAGS$_LT_TAGVAR(lt_prog_compiler_no_builtin_flag, $1)" if AC_TRY_EVAL(ac_link) && test -s conftest${ac_exeext}; then pipe_works=yes fi LIBS="$lt_save_LIBS" CFLAGS="$lt_save_CFLAGS" else echo "cannot find nm_test_func in $nlist" >&AS_MESSAGE_LOG_FD fi else echo "cannot find nm_test_var in $nlist" >&AS_MESSAGE_LOG_FD fi else echo "cannot run $lt_cv_sys_global_symbol_pipe" >&AS_MESSAGE_LOG_FD fi else echo "$progname: failed program was:" >&AS_MESSAGE_LOG_FD cat conftest.$ac_ext >&5 fi rm -rf conftest* conftst* # Do not use the global_symbol_pipe unless it works. if test "$pipe_works" = yes; then break else lt_cv_sys_global_symbol_pipe= fi done ]) if test -z "$lt_cv_sys_global_symbol_pipe"; then lt_cv_sys_global_symbol_to_cdecl= fi if test -z "$lt_cv_sys_global_symbol_pipe$lt_cv_sys_global_symbol_to_cdecl"; then AC_MSG_RESULT(failed) else AC_MSG_RESULT(ok) fi _LT_DECL([global_symbol_pipe], [lt_cv_sys_global_symbol_pipe], [1], [Take the output of nm and produce a listing of raw symbols and C names]) _LT_DECL([global_symbol_to_cdecl], [lt_cv_sys_global_symbol_to_cdecl], [1], [Transform the output of nm in a proper C declaration]) _LT_DECL([global_symbol_to_c_name_address], [lt_cv_sys_global_symbol_to_c_name_address], [1], [Transform the output of nm in a C name address pair]) _LT_DECL([global_symbol_to_c_name_address_lib_prefix], [lt_cv_sys_global_symbol_to_c_name_address_lib_prefix], [1], [Transform the output of nm in a C name address pair when lib prefix is needed]) ]) # _LT_CMD_GLOBAL_SYMBOLS # _LT_COMPILER_PIC([TAGNAME]) # --------------------------- m4_defun([_LT_COMPILER_PIC], [m4_require([_LT_TAG_COMPILER])dnl _LT_TAGVAR(lt_prog_compiler_wl, $1)= _LT_TAGVAR(lt_prog_compiler_pic, $1)= _LT_TAGVAR(lt_prog_compiler_static, $1)= AC_MSG_CHECKING([for $compiler option to produce PIC]) m4_if([$1], [CXX], [ # C++ specific cases for pic, static, wl, etc. if test "$GXX" = yes; then _LT_TAGVAR(lt_prog_compiler_wl, $1)='-Wl,' _LT_TAGVAR(lt_prog_compiler_static, $1)='-static' case $host_os in aix*) # All AIX code is PIC. if test "$host_cpu" = ia64; then # AIX 5 now supports IA64 processor _LT_TAGVAR(lt_prog_compiler_static, $1)='-Bstatic' fi ;; amigaos*) case $host_cpu in powerpc) # see comment about AmigaOS4 .so support _LT_TAGVAR(lt_prog_compiler_pic, $1)='-fPIC' ;; m68k) # FIXME: we need at least 68020 code to build shared libraries, but # adding the `-m68020' flag to GCC prevents building anything better, # like `-m68040'. _LT_TAGVAR(lt_prog_compiler_pic, $1)='-m68020 -resident32 -malways-restore-a4' ;; esac ;; beos* | irix5* | irix6* | nonstopux* | osf3* | osf4* | osf5*) # PIC is the default for these OSes. ;; mingw* | cygwin* | os2* | pw32* | cegcc*) # This hack is so that the source file can tell whether it is being # built for inclusion in a dll (and should export symbols for example). # Although the cygwin gcc ignores -fPIC, still need this for old-style # (--disable-auto-import) libraries m4_if([$1], [GCJ], [], [_LT_TAGVAR(lt_prog_compiler_pic, $1)='-DDLL_EXPORT']) ;; darwin* | rhapsody*) # PIC is the default on this platform # Common symbols not allowed in MH_DYLIB files _LT_TAGVAR(lt_prog_compiler_pic, $1)='-fno-common' ;; *djgpp*) # DJGPP does not support shared libraries at all _LT_TAGVAR(lt_prog_compiler_pic, $1)= ;; interix[[3-9]]*) # Interix 3.x gcc -fpic/-fPIC options generate broken code. # Instead, we relocate shared libraries at runtime. ;; sysv4*MP*) if test -d /usr/nec; then _LT_TAGVAR(lt_prog_compiler_pic, $1)=-Kconform_pic fi ;; hpux*) # PIC is the default for 64-bit PA HP-UX, but not for 32-bit # PA HP-UX. On IA64 HP-UX, PIC is the default but the pic flag # sets the default TLS model and affects inlining. case $host_cpu in hppa*64*) ;; *) _LT_TAGVAR(lt_prog_compiler_pic, $1)='-fPIC' ;; esac ;; *qnx* | *nto*) # QNX uses GNU C++, but need to define -shared option too, otherwise # it will coredump. _LT_TAGVAR(lt_prog_compiler_pic, $1)='-fPIC -shared' ;; *) _LT_TAGVAR(lt_prog_compiler_pic, $1)='-fPIC' ;; esac else case $host_os in aix[[4-9]]*) # All AIX code is PIC. if test "$host_cpu" = ia64; then # AIX 5 now supports IA64 processor _LT_TAGVAR(lt_prog_compiler_static, $1)='-Bstatic' else _LT_TAGVAR(lt_prog_compiler_static, $1)='-bnso -bI:/lib/syscalls.exp' fi ;; chorus*) case $cc_basename in cxch68*) # Green Hills C++ Compiler # _LT_TAGVAR(lt_prog_compiler_static, $1)="--no_auto_instantiation -u __main -u __premain -u _abort -r $COOL_DIR/lib/libOrb.a $MVME_DIR/lib/CC/libC.a $MVME_DIR/lib/classix/libcx.s.a" ;; esac ;; dgux*) case $cc_basename in ec++*) _LT_TAGVAR(lt_prog_compiler_pic, $1)='-KPIC' ;; ghcx*) # Green Hills C++ Compiler _LT_TAGVAR(lt_prog_compiler_pic, $1)='-pic' ;; *) ;; esac ;; freebsd* | dragonfly*) # FreeBSD uses GNU C++ ;; hpux9* | hpux10* | hpux11*) case $cc_basename in CC*) _LT_TAGVAR(lt_prog_compiler_wl, $1)='-Wl,' _LT_TAGVAR(lt_prog_compiler_static, $1)='${wl}-a ${wl}archive' if test "$host_cpu" != ia64; then _LT_TAGVAR(lt_prog_compiler_pic, $1)='+Z' fi ;; aCC*) _LT_TAGVAR(lt_prog_compiler_wl, $1)='-Wl,' _LT_TAGVAR(lt_prog_compiler_static, $1)='${wl}-a ${wl}archive' case $host_cpu in hppa*64*|ia64*) # +Z the default ;; *) _LT_TAGVAR(lt_prog_compiler_pic, $1)='+Z' ;; esac ;; *) ;; esac ;; interix*) # This is c89, which is MS Visual C++ (no shared libs) # Anyone wants to do a port? ;; irix5* | irix6* | nonstopux*) case $cc_basename in CC*) _LT_TAGVAR(lt_prog_compiler_wl, $1)='-Wl,' _LT_TAGVAR(lt_prog_compiler_static, $1)='-non_shared' # CC pic flag -KPIC is the default. ;; *) ;; esac ;; linux* | k*bsd*-gnu) case $cc_basename in KCC*) # KAI C++ Compiler _LT_TAGVAR(lt_prog_compiler_wl, $1)='--backend -Wl,' _LT_TAGVAR(lt_prog_compiler_pic, $1)='-fPIC' ;; ecpc* ) # old Intel C++ for x86_64 which still supported -KPIC. _LT_TAGVAR(lt_prog_compiler_wl, $1)='-Wl,' _LT_TAGVAR(lt_prog_compiler_pic, $1)='-KPIC' _LT_TAGVAR(lt_prog_compiler_static, $1)='-static' ;; icpc* ) # Intel C++, used to be incompatible with GCC. # ICC 10 doesn't accept -KPIC any more. _LT_TAGVAR(lt_prog_compiler_wl, $1)='-Wl,' _LT_TAGVAR(lt_prog_compiler_pic, $1)='-fPIC' _LT_TAGVAR(lt_prog_compiler_static, $1)='-static' ;; pgCC* | pgcpp*) # Portland Group C++ compiler _LT_TAGVAR(lt_prog_compiler_wl, $1)='-Wl,' _LT_TAGVAR(lt_prog_compiler_pic, $1)='-fpic' _LT_TAGVAR(lt_prog_compiler_static, $1)='-Bstatic' ;; cxx*) # Compaq C++ # Make sure the PIC flag is empty. It appears that all Alpha # Linux and Compaq Tru64 Unix objects are PIC. _LT_TAGVAR(lt_prog_compiler_pic, $1)= _LT_TAGVAR(lt_prog_compiler_static, $1)='-non_shared' ;; xlc* | xlC*) # IBM XL 8.0 on PPC _LT_TAGVAR(lt_prog_compiler_wl, $1)='-Wl,' _LT_TAGVAR(lt_prog_compiler_pic, $1)='-qpic' _LT_TAGVAR(lt_prog_compiler_static, $1)='-qstaticlink' ;; *) case `$CC -V 2>&1 | sed 5q` in *Sun\ C*) # Sun C++ 5.9 _LT_TAGVAR(lt_prog_compiler_pic, $1)='-KPIC' _LT_TAGVAR(lt_prog_compiler_static, $1)='-Bstatic' _LT_TAGVAR(lt_prog_compiler_wl, $1)='-Qoption ld ' ;; esac ;; esac ;; lynxos*) ;; m88k*) ;; mvs*) case $cc_basename in cxx*) _LT_TAGVAR(lt_prog_compiler_pic, $1)='-W c,exportall' ;; *) ;; esac ;; netbsd*) ;; *qnx* | *nto*) # QNX uses GNU C++, but need to define -shared option too, otherwise # it will coredump. _LT_TAGVAR(lt_prog_compiler_pic, $1)='-fPIC -shared' ;; osf3* | osf4* | osf5*) case $cc_basename in KCC*) _LT_TAGVAR(lt_prog_compiler_wl, $1)='--backend -Wl,' ;; RCC*) # Rational C++ 2.4.1 _LT_TAGVAR(lt_prog_compiler_pic, $1)='-pic' ;; cxx*) # Digital/Compaq C++ _LT_TAGVAR(lt_prog_compiler_wl, $1)='-Wl,' # Make sure the PIC flag is empty. It appears that all Alpha # Linux and Compaq Tru64 Unix objects are PIC. _LT_TAGVAR(lt_prog_compiler_pic, $1)= _LT_TAGVAR(lt_prog_compiler_static, $1)='-non_shared' ;; *) ;; esac ;; psos*) ;; solaris*) case $cc_basename in CC*) # Sun C++ 4.2, 5.x and Centerline C++ _LT_TAGVAR(lt_prog_compiler_pic, $1)='-KPIC' _LT_TAGVAR(lt_prog_compiler_static, $1)='-Bstatic' _LT_TAGVAR(lt_prog_compiler_wl, $1)='-Qoption ld ' ;; gcx*) # Green Hills C++ Compiler _LT_TAGVAR(lt_prog_compiler_pic, $1)='-PIC' ;; *) ;; esac ;; sunos4*) case $cc_basename in CC*) # Sun C++ 4.x _LT_TAGVAR(lt_prog_compiler_pic, $1)='-pic' _LT_TAGVAR(lt_prog_compiler_static, $1)='-Bstatic' ;; lcc*) # Lucid _LT_TAGVAR(lt_prog_compiler_pic, $1)='-pic' ;; *) ;; esac ;; sysv5* | unixware* | sco3.2v5* | sco5v6* | OpenUNIX*) case $cc_basename in CC*) _LT_TAGVAR(lt_prog_compiler_wl, $1)='-Wl,' _LT_TAGVAR(lt_prog_compiler_pic, $1)='-KPIC' _LT_TAGVAR(lt_prog_compiler_static, $1)='-Bstatic' ;; esac ;; tandem*) case $cc_basename in NCC*) # NonStop-UX NCC 3.20 _LT_TAGVAR(lt_prog_compiler_pic, $1)='-KPIC' ;; *) ;; esac ;; vxworks*) ;; *) _LT_TAGVAR(lt_prog_compiler_can_build_shared, $1)=no ;; esac fi ], [ if test "$GCC" = yes; then _LT_TAGVAR(lt_prog_compiler_wl, $1)='-Wl,' _LT_TAGVAR(lt_prog_compiler_static, $1)='-static' case $host_os in aix*) # All AIX code is PIC. if test "$host_cpu" = ia64; then # AIX 5 now supports IA64 processor _LT_TAGVAR(lt_prog_compiler_static, $1)='-Bstatic' fi ;; amigaos*) case $host_cpu in powerpc) # see comment about AmigaOS4 .so support _LT_TAGVAR(lt_prog_compiler_pic, $1)='-fPIC' ;; m68k) # FIXME: we need at least 68020 code to build shared libraries, but # adding the `-m68020' flag to GCC prevents building anything better, # like `-m68040'. _LT_TAGVAR(lt_prog_compiler_pic, $1)='-m68020 -resident32 -malways-restore-a4' ;; esac ;; beos* | irix5* | irix6* | nonstopux* | osf3* | osf4* | osf5*) # PIC is the default for these OSes. ;; mingw* | cygwin* | pw32* | os2* | cegcc*) # This hack is so that the source file can tell whether it is being # built for inclusion in a dll (and should export symbols for example). # Although the cygwin gcc ignores -fPIC, still need this for old-style # (--disable-auto-import) libraries m4_if([$1], [GCJ], [], [_LT_TAGVAR(lt_prog_compiler_pic, $1)='-DDLL_EXPORT']) ;; darwin* | rhapsody*) # PIC is the default on this platform # Common symbols not allowed in MH_DYLIB files _LT_TAGVAR(lt_prog_compiler_pic, $1)='-fno-common' ;; hpux*) # PIC is the default for 64-bit PA HP-UX, but not for 32-bit # PA HP-UX. On IA64 HP-UX, PIC is the default but the pic flag # sets the default TLS model and affects inlining. case $host_cpu in hppa*64*) # +Z the default ;; *) _LT_TAGVAR(lt_prog_compiler_pic, $1)='-fPIC' ;; esac ;; interix[[3-9]]*) # Interix 3.x gcc -fpic/-fPIC options generate broken code. # Instead, we relocate shared libraries at runtime. ;; msdosdjgpp*) # Just because we use GCC doesn't mean we suddenly get shared libraries # on systems that don't support them. _LT_TAGVAR(lt_prog_compiler_can_build_shared, $1)=no enable_shared=no ;; *nto* | *qnx*) # QNX uses GNU C++, but need to define -shared option too, otherwise # it will coredump. _LT_TAGVAR(lt_prog_compiler_pic, $1)='-fPIC -shared' ;; sysv4*MP*) if test -d /usr/nec; then _LT_TAGVAR(lt_prog_compiler_pic, $1)=-Kconform_pic fi ;; *) _LT_TAGVAR(lt_prog_compiler_pic, $1)='-fPIC' ;; esac else # PORTME Check for flag to pass linker flags through the system compiler. case $host_os in aix*) _LT_TAGVAR(lt_prog_compiler_wl, $1)='-Wl,' if test "$host_cpu" = ia64; then # AIX 5 now supports IA64 processor _LT_TAGVAR(lt_prog_compiler_static, $1)='-Bstatic' else _LT_TAGVAR(lt_prog_compiler_static, $1)='-bnso -bI:/lib/syscalls.exp' fi ;; mingw* | cygwin* | pw32* | os2* | cegcc*) # This hack is so that the source file can tell whether it is being # built for inclusion in a dll (and should export symbols for example). m4_if([$1], [GCJ], [], [_LT_TAGVAR(lt_prog_compiler_pic, $1)='-DDLL_EXPORT']) ;; hpux9* | hpux10* | hpux11*) _LT_TAGVAR(lt_prog_compiler_wl, $1)='-Wl,' # PIC is the default for IA64 HP-UX and 64-bit HP-UX, but # not for PA HP-UX. case $host_cpu in hppa*64*|ia64*) # +Z the default ;; *) _LT_TAGVAR(lt_prog_compiler_pic, $1)='+Z' ;; esac # Is there a better lt_prog_compiler_static that works with the bundled CC? _LT_TAGVAR(lt_prog_compiler_static, $1)='${wl}-a ${wl}archive' ;; irix5* | irix6* | nonstopux*) _LT_TAGVAR(lt_prog_compiler_wl, $1)='-Wl,' # PIC (with -KPIC) is the default. _LT_TAGVAR(lt_prog_compiler_static, $1)='-non_shared' ;; linux* | k*bsd*-gnu) case $cc_basename in # old Intel for x86_64 which still supported -KPIC. ecc*) _LT_TAGVAR(lt_prog_compiler_wl, $1)='-Wl,' _LT_TAGVAR(lt_prog_compiler_pic, $1)='-KPIC' _LT_TAGVAR(lt_prog_compiler_static, $1)='-static' ;; # icc used to be incompatible with GCC. # ICC 10 doesn't accept -KPIC any more. icc* | ifort*) _LT_TAGVAR(lt_prog_compiler_wl, $1)='-Wl,' _LT_TAGVAR(lt_prog_compiler_pic, $1)='-fPIC' _LT_TAGVAR(lt_prog_compiler_static, $1)='-static' ;; # Lahey Fortran 8.1. lf95*) _LT_TAGVAR(lt_prog_compiler_wl, $1)='-Wl,' _LT_TAGVAR(lt_prog_compiler_pic, $1)='--shared' _LT_TAGVAR(lt_prog_compiler_static, $1)='--static' ;; pgcc* | pgf77* | pgf90* | pgf95*) # Portland Group compilers (*not* the Pentium gcc compiler, # which looks to be a dead project) _LT_TAGVAR(lt_prog_compiler_wl, $1)='-Wl,' _LT_TAGVAR(lt_prog_compiler_pic, $1)='-fpic' _LT_TAGVAR(lt_prog_compiler_static, $1)='-Bstatic' ;; ccc*) _LT_TAGVAR(lt_prog_compiler_wl, $1)='-Wl,' # All Alpha code is PIC. _LT_TAGVAR(lt_prog_compiler_static, $1)='-non_shared' ;; xl*) # IBM XL C 8.0/Fortran 10.1 on PPC _LT_TAGVAR(lt_prog_compiler_wl, $1)='-Wl,' _LT_TAGVAR(lt_prog_compiler_pic, $1)='-qpic' _LT_TAGVAR(lt_prog_compiler_static, $1)='-qstaticlink' ;; *) case `$CC -V 2>&1 | sed 5q` in *Sun\ C*) # Sun C 5.9 _LT_TAGVAR(lt_prog_compiler_pic, $1)='-KPIC' _LT_TAGVAR(lt_prog_compiler_static, $1)='-Bstatic' _LT_TAGVAR(lt_prog_compiler_wl, $1)='-Wl,' ;; *Sun\ F*) # Sun Fortran 8.3 passes all unrecognized flags to the linker _LT_TAGVAR(lt_prog_compiler_pic, $1)='-KPIC' _LT_TAGVAR(lt_prog_compiler_static, $1)='-Bstatic' _LT_TAGVAR(lt_prog_compiler_wl, $1)='' ;; esac ;; esac ;; newsos6) _LT_TAGVAR(lt_prog_compiler_pic, $1)='-KPIC' _LT_TAGVAR(lt_prog_compiler_static, $1)='-Bstatic' ;; *nto* | *qnx*) # QNX uses GNU C++, but need to define -shared option too, otherwise # it will coredump. _LT_TAGVAR(lt_prog_compiler_pic, $1)='-fPIC -shared' ;; osf3* | osf4* | osf5*) _LT_TAGVAR(lt_prog_compiler_wl, $1)='-Wl,' # All OSF/1 code is PIC. _LT_TAGVAR(lt_prog_compiler_static, $1)='-non_shared' ;; rdos*) _LT_TAGVAR(lt_prog_compiler_static, $1)='-non_shared' ;; solaris*) _LT_TAGVAR(lt_prog_compiler_pic, $1)='-KPIC' _LT_TAGVAR(lt_prog_compiler_static, $1)='-Bstatic' case $cc_basename in f77* | f90* | f95*) _LT_TAGVAR(lt_prog_compiler_wl, $1)='-Qoption ld ';; *) _LT_TAGVAR(lt_prog_compiler_wl, $1)='-Wl,';; esac ;; sunos4*) _LT_TAGVAR(lt_prog_compiler_wl, $1)='-Qoption ld ' _LT_TAGVAR(lt_prog_compiler_pic, $1)='-PIC' _LT_TAGVAR(lt_prog_compiler_static, $1)='-Bstatic' ;; sysv4 | sysv4.2uw2* | sysv4.3*) _LT_TAGVAR(lt_prog_compiler_wl, $1)='-Wl,' _LT_TAGVAR(lt_prog_compiler_pic, $1)='-KPIC' _LT_TAGVAR(lt_prog_compiler_static, $1)='-Bstatic' ;; sysv4*MP*) if test -d /usr/nec ;then _LT_TAGVAR(lt_prog_compiler_pic, $1)='-Kconform_pic' _LT_TAGVAR(lt_prog_compiler_static, $1)='-Bstatic' fi ;; sysv5* | unixware* | sco3.2v5* | sco5v6* | OpenUNIX*) _LT_TAGVAR(lt_prog_compiler_wl, $1)='-Wl,' _LT_TAGVAR(lt_prog_compiler_pic, $1)='-KPIC' _LT_TAGVAR(lt_prog_compiler_static, $1)='-Bstatic' ;; unicos*) _LT_TAGVAR(lt_prog_compiler_wl, $1)='-Wl,' _LT_TAGVAR(lt_prog_compiler_can_build_shared, $1)=no ;; uts4*) _LT_TAGVAR(lt_prog_compiler_pic, $1)='-pic' _LT_TAGVAR(lt_prog_compiler_static, $1)='-Bstatic' ;; *) _LT_TAGVAR(lt_prog_compiler_can_build_shared, $1)=no ;; esac fi ]) case $host_os in # For platforms which do not support PIC, -DPIC is meaningless: *djgpp*) _LT_TAGVAR(lt_prog_compiler_pic, $1)= ;; *) _LT_TAGVAR(lt_prog_compiler_pic, $1)="$_LT_TAGVAR(lt_prog_compiler_pic, $1)@&t@m4_if([$1],[],[ -DPIC],[m4_if([$1],[CXX],[ -DPIC],[])])" ;; esac AC_MSG_RESULT([$_LT_TAGVAR(lt_prog_compiler_pic, $1)]) _LT_TAGDECL([wl], [lt_prog_compiler_wl], [1], [How to pass a linker flag through the compiler]) # # Check to make sure the PIC flag actually works. # if test -n "$_LT_TAGVAR(lt_prog_compiler_pic, $1)"; then _LT_COMPILER_OPTION([if $compiler PIC flag $_LT_TAGVAR(lt_prog_compiler_pic, $1) works], [_LT_TAGVAR(lt_cv_prog_compiler_pic_works, $1)], [$_LT_TAGVAR(lt_prog_compiler_pic, $1)@&t@m4_if([$1],[],[ -DPIC],[m4_if([$1],[CXX],[ -DPIC],[])])], [], [case $_LT_TAGVAR(lt_prog_compiler_pic, $1) in "" | " "*) ;; *) _LT_TAGVAR(lt_prog_compiler_pic, $1)=" $_LT_TAGVAR(lt_prog_compiler_pic, $1)" ;; esac], [_LT_TAGVAR(lt_prog_compiler_pic, $1)= _LT_TAGVAR(lt_prog_compiler_can_build_shared, $1)=no]) fi _LT_TAGDECL([pic_flag], [lt_prog_compiler_pic], [1], [Additional compiler flags for building library objects]) # # Check to make sure the static flag actually works. # wl=$_LT_TAGVAR(lt_prog_compiler_wl, $1) eval lt_tmp_static_flag=\"$_LT_TAGVAR(lt_prog_compiler_static, $1)\" _LT_LINKER_OPTION([if $compiler static flag $lt_tmp_static_flag works], _LT_TAGVAR(lt_cv_prog_compiler_static_works, $1), $lt_tmp_static_flag, [], [_LT_TAGVAR(lt_prog_compiler_static, $1)=]) _LT_TAGDECL([link_static_flag], [lt_prog_compiler_static], [1], [Compiler flag to prevent dynamic linking]) ])# _LT_COMPILER_PIC # _LT_LINKER_SHLIBS([TAGNAME]) # ---------------------------- # See if the linker supports building shared libraries. m4_defun([_LT_LINKER_SHLIBS], [AC_REQUIRE([LT_PATH_LD])dnl AC_REQUIRE([LT_PATH_NM])dnl m4_require([_LT_FILEUTILS_DEFAULTS])dnl m4_require([_LT_DECL_EGREP])dnl m4_require([_LT_DECL_SED])dnl m4_require([_LT_CMD_GLOBAL_SYMBOLS])dnl m4_require([_LT_TAG_COMPILER])dnl AC_MSG_CHECKING([whether the $compiler linker ($LD) supports shared libraries]) m4_if([$1], [CXX], [ _LT_TAGVAR(export_symbols_cmds, $1)='$NM $libobjs $convenience | $global_symbol_pipe | $SED '\''s/.* //'\'' | sort | uniq > $export_symbols' case $host_os in aix[[4-9]]*) # If we're using GNU nm, then we don't want the "-C" option. # -C means demangle to AIX nm, but means don't demangle with GNU nm if $NM -V 2>&1 | $GREP 'GNU' > /dev/null; then _LT_TAGVAR(export_symbols_cmds, $1)='$NM -Bpg $libobjs $convenience | awk '\''{ if (((\$ 2 == "T") || (\$ 2 == "D") || (\$ 2 == "B")) && ([substr](\$ 3,1,1) != ".")) { print \$ 3 } }'\'' | sort -u > $export_symbols' else _LT_TAGVAR(export_symbols_cmds, $1)='$NM -BCpg $libobjs $convenience | awk '\''{ if (((\$ 2 == "T") || (\$ 2 == "D") || (\$ 2 == "B")) && ([substr](\$ 3,1,1) != ".")) { print \$ 3 } }'\'' | sort -u > $export_symbols' fi ;; pw32*) _LT_TAGVAR(export_symbols_cmds, $1)="$ltdll_cmds" ;; cygwin* | mingw* | cegcc*) _LT_TAGVAR(export_symbols_cmds, $1)='$NM $libobjs $convenience | $global_symbol_pipe | $SED -e '\''/^[[BCDGRS]][[ ]]/s/.*[[ ]]\([[^ ]]*\)/\1 DATA/;/^.*[[ ]]__nm__/s/^.*[[ ]]__nm__\([[^ ]]*\)[[ ]][[^ ]]*/\1 DATA/;/^I[[ ]]/d;/^[[AITW]][[ ]]/s/.* //'\'' | sort | uniq > $export_symbols' ;; *) _LT_TAGVAR(export_symbols_cmds, $1)='$NM $libobjs $convenience | $global_symbol_pipe | $SED '\''s/.* //'\'' | sort | uniq > $export_symbols' ;; esac _LT_TAGVAR(exclude_expsyms, $1)=['_GLOBAL_OFFSET_TABLE_|_GLOBAL__F[ID]_.*'] ], [ runpath_var= _LT_TAGVAR(allow_undefined_flag, $1)= _LT_TAGVAR(always_export_symbols, $1)=no _LT_TAGVAR(archive_cmds, $1)= _LT_TAGVAR(archive_expsym_cmds, $1)= _LT_TAGVAR(compiler_needs_object, $1)=no _LT_TAGVAR(enable_shared_with_static_runtimes, $1)=no _LT_TAGVAR(export_dynamic_flag_spec, $1)= _LT_TAGVAR(export_symbols_cmds, $1)='$NM $libobjs $convenience | $global_symbol_pipe | $SED '\''s/.* //'\'' | sort | uniq > $export_symbols' _LT_TAGVAR(hardcode_automatic, $1)=no _LT_TAGVAR(hardcode_direct, $1)=no _LT_TAGVAR(hardcode_direct_absolute, $1)=no _LT_TAGVAR(hardcode_libdir_flag_spec, $1)= _LT_TAGVAR(hardcode_libdir_flag_spec_ld, $1)= _LT_TAGVAR(hardcode_libdir_separator, $1)= _LT_TAGVAR(hardcode_minus_L, $1)=no _LT_TAGVAR(hardcode_shlibpath_var, $1)=unsupported _LT_TAGVAR(inherit_rpath, $1)=no _LT_TAGVAR(link_all_deplibs, $1)=unknown _LT_TAGVAR(module_cmds, $1)= _LT_TAGVAR(module_expsym_cmds, $1)= _LT_TAGVAR(old_archive_from_new_cmds, $1)= _LT_TAGVAR(old_archive_from_expsyms_cmds, $1)= _LT_TAGVAR(thread_safe_flag_spec, $1)= _LT_TAGVAR(whole_archive_flag_spec, $1)= # include_expsyms should be a list of space-separated symbols to be *always* # included in the symbol list _LT_TAGVAR(include_expsyms, $1)= # exclude_expsyms can be an extended regexp of symbols to exclude # it will be wrapped by ` (' and `)$', so one must not match beginning or # end of line. Example: `a|bc|.*d.*' will exclude the symbols `a' and `bc', # as well as any symbol that contains `d'. _LT_TAGVAR(exclude_expsyms, $1)=['_GLOBAL_OFFSET_TABLE_|_GLOBAL__F[ID]_.*'] # Although _GLOBAL_OFFSET_TABLE_ is a valid symbol C name, most a.out # platforms (ab)use it in PIC code, but their linkers get confused if # the symbol is explicitly referenced. Since portable code cannot # rely on this symbol name, it's probably fine to never include it in # preloaded symbol tables. # Exclude shared library initialization/finalization symbols. dnl Note also adjust exclude_expsyms for C++ above. extract_expsyms_cmds= case $host_os in cygwin* | mingw* | pw32* | cegcc*) # FIXME: the MSVC++ port hasn't been tested in a loooong time # When not using gcc, we currently assume that we are using # Microsoft Visual C++. if test "$GCC" != yes; then with_gnu_ld=no fi ;; interix*) # we just hope/assume this is gcc and not c89 (= MSVC++) with_gnu_ld=yes ;; openbsd*) with_gnu_ld=no ;; esac _LT_TAGVAR(ld_shlibs, $1)=yes if test "$with_gnu_ld" = yes; then # If archive_cmds runs LD, not CC, wlarc should be empty wlarc='${wl}' # Set some defaults for GNU ld with shared library support. These # are reset later if shared libraries are not supported. Putting them # here allows them to be overridden if necessary. runpath_var=LD_RUN_PATH _LT_TAGVAR(hardcode_libdir_flag_spec, $1)='${wl}-rpath ${wl}$libdir' _LT_TAGVAR(export_dynamic_flag_spec, $1)='${wl}--export-dynamic' # ancient GNU ld didn't support --whole-archive et. al. if $LD --help 2>&1 | $GREP 'no-whole-archive' > /dev/null; then _LT_TAGVAR(whole_archive_flag_spec, $1)="$wlarc"'--whole-archive$convenience '"$wlarc"'--no-whole-archive' else _LT_TAGVAR(whole_archive_flag_spec, $1)= fi supports_anon_versioning=no case `$LD -v 2>&1` in *\ [[01]].* | *\ 2.[[0-9]].* | *\ 2.10.*) ;; # catch versions < 2.11 *\ 2.11.93.0.2\ *) supports_anon_versioning=yes ;; # RH7.3 ... *\ 2.11.92.0.12\ *) supports_anon_versioning=yes ;; # Mandrake 8.2 ... *\ 2.11.*) ;; # other 2.11 versions *) supports_anon_versioning=yes ;; esac # See if GNU ld supports shared libraries. case $host_os in aix[[3-9]]*) # On AIX/PPC, the GNU linker is very broken if test "$host_cpu" != ia64; then _LT_TAGVAR(ld_shlibs, $1)=no cat <<_LT_EOF 1>&2 *** Warning: the GNU linker, at least up to release 2.9.1, is reported *** to be unable to reliably create shared libraries on AIX. *** Therefore, libtool is disabling shared libraries support. If you *** really care for shared libraries, you may want to modify your PATH *** so that a non-GNU linker is found, and then restart. _LT_EOF fi ;; amigaos*) case $host_cpu in powerpc) # see comment about AmigaOS4 .so support _LT_TAGVAR(archive_cmds, $1)='$CC -shared $libobjs $deplibs $compiler_flags ${wl}-soname $wl$soname -o $lib' _LT_TAGVAR(archive_expsym_cmds, $1)='' ;; m68k) _LT_TAGVAR(archive_cmds, $1)='$RM $output_objdir/a2ixlibrary.data~$ECHO "#define NAME $libname" > $output_objdir/a2ixlibrary.data~$ECHO "#define LIBRARY_ID 1" >> $output_objdir/a2ixlibrary.data~$ECHO "#define VERSION $major" >> $output_objdir/a2ixlibrary.data~$ECHO "#define REVISION $revision" >> $output_objdir/a2ixlibrary.data~$AR $AR_FLAGS $lib $libobjs~$RANLIB $lib~(cd $output_objdir && a2ixlibrary -32)' _LT_TAGVAR(hardcode_libdir_flag_spec, $1)='-L$libdir' _LT_TAGVAR(hardcode_minus_L, $1)=yes ;; esac ;; beos*) if $LD --help 2>&1 | $GREP ': supported targets:.* elf' > /dev/null; then _LT_TAGVAR(allow_undefined_flag, $1)=unsupported # Joseph Beckenbach says some releases of gcc # support --undefined. This deserves some investigation. FIXME _LT_TAGVAR(archive_cmds, $1)='$CC -nostart $libobjs $deplibs $compiler_flags ${wl}-soname $wl$soname -o $lib' else _LT_TAGVAR(ld_shlibs, $1)=no fi ;; cygwin* | mingw* | pw32* | cegcc*) # _LT_TAGVAR(hardcode_libdir_flag_spec, $1) is actually meaningless, # as there is no search path for DLLs. _LT_TAGVAR(hardcode_libdir_flag_spec, $1)='-L$libdir' _LT_TAGVAR(allow_undefined_flag, $1)=unsupported _LT_TAGVAR(always_export_symbols, $1)=no _LT_TAGVAR(enable_shared_with_static_runtimes, $1)=yes _LT_TAGVAR(export_symbols_cmds, $1)='$NM $libobjs $convenience | $global_symbol_pipe | $SED -e '\''/^[[BCDGRS]][[ ]]/s/.*[[ ]]\([[^ ]]*\)/\1 DATA/'\'' | $SED -e '\''/^[[AITW]][[ ]]/s/.*[[ ]]//'\'' | sort | uniq > $export_symbols' if $LD --help 2>&1 | $GREP 'auto-import' > /dev/null; then _LT_TAGVAR(archive_cmds, $1)='$CC -shared $libobjs $deplibs $compiler_flags -o $output_objdir/$soname ${wl}--enable-auto-image-base -Xlinker --out-implib -Xlinker $lib' # If the export-symbols file already is a .def file (1st line # is EXPORTS), use it as is; otherwise, prepend... _LT_TAGVAR(archive_expsym_cmds, $1)='if test "x`$SED 1q $export_symbols`" = xEXPORTS; then cp $export_symbols $output_objdir/$soname.def; else echo EXPORTS > $output_objdir/$soname.def; cat $export_symbols >> $output_objdir/$soname.def; fi~ $CC -shared $output_objdir/$soname.def $libobjs $deplibs $compiler_flags -o $output_objdir/$soname ${wl}--enable-auto-image-base -Xlinker --out-implib -Xlinker $lib' else _LT_TAGVAR(ld_shlibs, $1)=no fi ;; interix[[3-9]]*) _LT_TAGVAR(hardcode_direct, $1)=no _LT_TAGVAR(hardcode_shlibpath_var, $1)=no _LT_TAGVAR(hardcode_libdir_flag_spec, $1)='${wl}-rpath,$libdir' _LT_TAGVAR(export_dynamic_flag_spec, $1)='${wl}-E' # Hack: On Interix 3.x, we cannot compile PIC because of a broken gcc. # Instead, shared libraries are loaded at an image base (0x10000000 by # default) and relocated if they conflict, which is a slow very memory # consuming and fragmenting process. To avoid this, we pick a random, # 256 KiB-aligned image base between 0x50000000 and 0x6FFC0000 at link # time. Moving up from 0x10000000 also allows more sbrk(2) space. _LT_TAGVAR(archive_cmds, $1)='$CC -shared $pic_flag $libobjs $deplibs $compiler_flags ${wl}-h,$soname ${wl}--image-base,`expr ${RANDOM-$$} % 4096 / 2 \* 262144 + 1342177280` -o $lib' _LT_TAGVAR(archive_expsym_cmds, $1)='sed "s,^,_," $export_symbols >$output_objdir/$soname.expsym~$CC -shared $pic_flag $libobjs $deplibs $compiler_flags ${wl}-h,$soname ${wl}--retain-symbols-file,$output_objdir/$soname.expsym ${wl}--image-base,`expr ${RANDOM-$$} % 4096 / 2 \* 262144 + 1342177280` -o $lib' ;; gnu* | linux* | tpf* | k*bsd*-gnu) tmp_diet=no if test "$host_os" = linux-dietlibc; then case $cc_basename in diet\ *) tmp_diet=yes;; # linux-dietlibc with static linking (!diet-dyn) esac fi if $LD --help 2>&1 | $EGREP ': supported targets:.* elf' > /dev/null \ && test "$tmp_diet" = no then tmp_addflag= tmp_sharedflag='-shared' case $cc_basename,$host_cpu in pgcc*) # Portland Group C compiler _LT_TAGVAR(whole_archive_flag_spec, $1)='${wl}--whole-archive`for conv in $convenience\"\"; do test -n \"$conv\" && new_convenience=\"$new_convenience,$conv\"; done; $ECHO \"$new_convenience\"` ${wl}--no-whole-archive' tmp_addflag=' $pic_flag' ;; pgf77* | pgf90* | pgf95*) # Portland Group f77 and f90 compilers _LT_TAGVAR(whole_archive_flag_spec, $1)='${wl}--whole-archive`for conv in $convenience\"\"; do test -n \"$conv\" && new_convenience=\"$new_convenience,$conv\"; done; $ECHO \"$new_convenience\"` ${wl}--no-whole-archive' tmp_addflag=' $pic_flag -Mnomain' ;; ecc*,ia64* | icc*,ia64*) # Intel C compiler on ia64 tmp_addflag=' -i_dynamic' ;; efc*,ia64* | ifort*,ia64*) # Intel Fortran compiler on ia64 tmp_addflag=' -i_dynamic -nofor_main' ;; ifc* | ifort*) # Intel Fortran compiler tmp_addflag=' -nofor_main' ;; lf95*) # Lahey Fortran 8.1 _LT_TAGVAR(whole_archive_flag_spec, $1)= tmp_sharedflag='--shared' ;; xl[[cC]]*) # IBM XL C 8.0 on PPC (deal with xlf below) tmp_sharedflag='-qmkshrobj' tmp_addflag= ;; esac case `$CC -V 2>&1 | sed 5q` in *Sun\ C*) # Sun C 5.9 _LT_TAGVAR(whole_archive_flag_spec, $1)='${wl}--whole-archive`new_convenience=; for conv in $convenience\"\"; do test -z \"$conv\" || new_convenience=\"$new_convenience,$conv\"; done; $ECHO \"$new_convenience\"` ${wl}--no-whole-archive' _LT_TAGVAR(compiler_needs_object, $1)=yes tmp_sharedflag='-G' ;; *Sun\ F*) # Sun Fortran 8.3 tmp_sharedflag='-G' ;; esac _LT_TAGVAR(archive_cmds, $1)='$CC '"$tmp_sharedflag""$tmp_addflag"' $libobjs $deplibs $compiler_flags ${wl}-soname $wl$soname -o $lib' if test "x$supports_anon_versioning" = xyes; then _LT_TAGVAR(archive_expsym_cmds, $1)='echo "{ global:" > $output_objdir/$libname.ver~ cat $export_symbols | sed -e "s/\(.*\)/\1;/" >> $output_objdir/$libname.ver~ echo "local: *; };" >> $output_objdir/$libname.ver~ $CC '"$tmp_sharedflag""$tmp_addflag"' $libobjs $deplibs $compiler_flags ${wl}-soname $wl$soname ${wl}-version-script ${wl}$output_objdir/$libname.ver -o $lib' fi case $cc_basename in xlf*) # IBM XL Fortran 10.1 on PPC cannot create shared libs itself _LT_TAGVAR(whole_archive_flag_spec, $1)='--whole-archive$convenience --no-whole-archive' _LT_TAGVAR(hardcode_libdir_flag_spec, $1)= _LT_TAGVAR(hardcode_libdir_flag_spec_ld, $1)='-rpath $libdir' _LT_TAGVAR(archive_cmds, $1)='$LD -shared $libobjs $deplibs $compiler_flags -soname $soname -o $lib' if test "x$supports_anon_versioning" = xyes; then _LT_TAGVAR(archive_expsym_cmds, $1)='echo "{ global:" > $output_objdir/$libname.ver~ cat $export_symbols | sed -e "s/\(.*\)/\1;/" >> $output_objdir/$libname.ver~ echo "local: *; };" >> $output_objdir/$libname.ver~ $LD -shared $libobjs $deplibs $compiler_flags -soname $soname -version-script $output_objdir/$libname.ver -o $lib' fi ;; esac else _LT_TAGVAR(ld_shlibs, $1)=no fi ;; netbsd*) if echo __ELF__ | $CC -E - | $GREP __ELF__ >/dev/null; then _LT_TAGVAR(archive_cmds, $1)='$LD -Bshareable $libobjs $deplibs $linker_flags -o $lib' wlarc= else _LT_TAGVAR(archive_cmds, $1)='$CC -shared $libobjs $deplibs $compiler_flags ${wl}-soname $wl$soname -o $lib' _LT_TAGVAR(archive_expsym_cmds, $1)='$CC -shared $libobjs $deplibs $compiler_flags ${wl}-soname $wl$soname ${wl}-retain-symbols-file $wl$export_symbols -o $lib' fi ;; solaris*) if $LD -v 2>&1 | $GREP 'BFD 2\.8' > /dev/null; then _LT_TAGVAR(ld_shlibs, $1)=no cat <<_LT_EOF 1>&2 *** Warning: The releases 2.8.* of the GNU linker cannot reliably *** create shared libraries on Solaris systems. Therefore, libtool *** is disabling shared libraries support. We urge you to upgrade GNU *** binutils to release 2.9.1 or newer. Another option is to modify *** your PATH or compiler configuration so that the native linker is *** used, and then restart. _LT_EOF elif $LD --help 2>&1 | $GREP ': supported targets:.* elf' > /dev/null; then _LT_TAGVAR(archive_cmds, $1)='$CC -shared $libobjs $deplibs $compiler_flags ${wl}-soname $wl$soname -o $lib' _LT_TAGVAR(archive_expsym_cmds, $1)='$CC -shared $libobjs $deplibs $compiler_flags ${wl}-soname $wl$soname ${wl}-retain-symbols-file $wl$export_symbols -o $lib' else _LT_TAGVAR(ld_shlibs, $1)=no fi ;; sysv5* | sco3.2v5* | sco5v6* | unixware* | OpenUNIX*) case `$LD -v 2>&1` in *\ [[01]].* | *\ 2.[[0-9]].* | *\ 2.1[[0-5]].*) _LT_TAGVAR(ld_shlibs, $1)=no cat <<_LT_EOF 1>&2 *** Warning: Releases of the GNU linker prior to 2.16.91.0.3 can not *** reliably create shared libraries on SCO systems. Therefore, libtool *** is disabling shared libraries support. We urge you to upgrade GNU *** binutils to release 2.16.91.0.3 or newer. Another option is to modify *** your PATH or compiler configuration so that the native linker is *** used, and then restart. _LT_EOF ;; *) # For security reasons, it is highly recommended that you always # use absolute paths for naming shared libraries, and exclude the # DT_RUNPATH tag from executables and libraries. But doing so # requires that you compile everything twice, which is a pain. if $LD --help 2>&1 | $GREP ': supported targets:.* elf' > /dev/null; then _LT_TAGVAR(hardcode_libdir_flag_spec, $1)='${wl}-rpath ${wl}$libdir' _LT_TAGVAR(archive_cmds, $1)='$CC -shared $libobjs $deplibs $compiler_flags ${wl}-soname $wl$soname -o $lib' _LT_TAGVAR(archive_expsym_cmds, $1)='$CC -shared $libobjs $deplibs $compiler_flags ${wl}-soname $wl$soname ${wl}-retain-symbols-file $wl$export_symbols -o $lib' else _LT_TAGVAR(ld_shlibs, $1)=no fi ;; esac ;; sunos4*) _LT_TAGVAR(archive_cmds, $1)='$LD -assert pure-text -Bshareable -o $lib $libobjs $deplibs $linker_flags' wlarc= _LT_TAGVAR(hardcode_direct, $1)=yes _LT_TAGVAR(hardcode_shlibpath_var, $1)=no ;; *) if $LD --help 2>&1 | $GREP ': supported targets:.* elf' > /dev/null; then _LT_TAGVAR(archive_cmds, $1)='$CC -shared $libobjs $deplibs $compiler_flags ${wl}-soname $wl$soname -o $lib' _LT_TAGVAR(archive_expsym_cmds, $1)='$CC -shared $libobjs $deplibs $compiler_flags ${wl}-soname $wl$soname ${wl}-retain-symbols-file $wl$export_symbols -o $lib' else _LT_TAGVAR(ld_shlibs, $1)=no fi ;; esac if test "$_LT_TAGVAR(ld_shlibs, $1)" = no; then runpath_var= _LT_TAGVAR(hardcode_libdir_flag_spec, $1)= _LT_TAGVAR(export_dynamic_flag_spec, $1)= _LT_TAGVAR(whole_archive_flag_spec, $1)= fi else # PORTME fill in a description of your system's linker (not GNU ld) case $host_os in aix3*) _LT_TAGVAR(allow_undefined_flag, $1)=unsupported _LT_TAGVAR(always_export_symbols, $1)=yes _LT_TAGVAR(archive_expsym_cmds, $1)='$LD -o $output_objdir/$soname $libobjs $deplibs $linker_flags -bE:$export_symbols -T512 -H512 -bM:SRE~$AR $AR_FLAGS $lib $output_objdir/$soname' # Note: this linker hardcodes the directories in LIBPATH if there # are no directories specified by -L. _LT_TAGVAR(hardcode_minus_L, $1)=yes if test "$GCC" = yes && test -z "$lt_prog_compiler_static"; then # Neither direct hardcoding nor static linking is supported with a # broken collect2. _LT_TAGVAR(hardcode_direct, $1)=unsupported fi ;; aix[[4-9]]*) if test "$host_cpu" = ia64; then # On IA64, the linker does run time linking by default, so we don't # have to do anything special. aix_use_runtimelinking=no exp_sym_flag='-Bexport' no_entry_flag="" else # If we're using GNU nm, then we don't want the "-C" option. # -C means demangle to AIX nm, but means don't demangle with GNU nm if $NM -V 2>&1 | $GREP 'GNU' > /dev/null; then _LT_TAGVAR(export_symbols_cmds, $1)='$NM -Bpg $libobjs $convenience | awk '\''{ if (((\$ 2 == "T") || (\$ 2 == "D") || (\$ 2 == "B")) && ([substr](\$ 3,1,1) != ".")) { print \$ 3 } }'\'' | sort -u > $export_symbols' else _LT_TAGVAR(export_symbols_cmds, $1)='$NM -BCpg $libobjs $convenience | awk '\''{ if (((\$ 2 == "T") || (\$ 2 == "D") || (\$ 2 == "B")) && ([substr](\$ 3,1,1) != ".")) { print \$ 3 } }'\'' | sort -u > $export_symbols' fi aix_use_runtimelinking=no # Test if we are trying to use run time linking or normal # AIX style linking. If -brtl is somewhere in LDFLAGS, we # need to do runtime linking. case $host_os in aix4.[[23]]|aix4.[[23]].*|aix[[5-9]]*) for ld_flag in $LDFLAGS; do if (test $ld_flag = "-brtl" || test $ld_flag = "-Wl,-brtl"); then aix_use_runtimelinking=yes break fi done ;; esac exp_sym_flag='-bexport' no_entry_flag='-bnoentry' fi # When large executables or shared objects are built, AIX ld can # have problems creating the table of contents. If linking a library # or program results in "error TOC overflow" add -mminimal-toc to # CXXFLAGS/CFLAGS for g++/gcc. In the cases where that is not # enough to fix the problem, add -Wl,-bbigtoc to LDFLAGS. _LT_TAGVAR(archive_cmds, $1)='' _LT_TAGVAR(hardcode_direct, $1)=yes _LT_TAGVAR(hardcode_direct_absolute, $1)=yes _LT_TAGVAR(hardcode_libdir_separator, $1)=':' _LT_TAGVAR(link_all_deplibs, $1)=yes _LT_TAGVAR(file_list_spec, $1)='${wl}-f,' if test "$GCC" = yes; then case $host_os in aix4.[[012]]|aix4.[[012]].*) # We only want to do this on AIX 4.2 and lower, the check # below for broken collect2 doesn't work under 4.3+ collect2name=`${CC} -print-prog-name=collect2` if test -f "$collect2name" && strings "$collect2name" | $GREP resolve_lib_name >/dev/null then # We have reworked collect2 : else # We have old collect2 _LT_TAGVAR(hardcode_direct, $1)=unsupported # It fails to find uninstalled libraries when the uninstalled # path is not listed in the libpath. Setting hardcode_minus_L # to unsupported forces relinking _LT_TAGVAR(hardcode_minus_L, $1)=yes _LT_TAGVAR(hardcode_libdir_flag_spec, $1)='-L$libdir' _LT_TAGVAR(hardcode_libdir_separator, $1)= fi ;; esac shared_flag='-shared' if test "$aix_use_runtimelinking" = yes; then shared_flag="$shared_flag "'${wl}-G' fi else # not using gcc if test "$host_cpu" = ia64; then # VisualAge C++, Version 5.5 for AIX 5L for IA-64, Beta 3 Release # chokes on -Wl,-G. The following line is correct: shared_flag='-G' else if test "$aix_use_runtimelinking" = yes; then shared_flag='${wl}-G' else shared_flag='${wl}-bM:SRE' fi fi fi _LT_TAGVAR(export_dynamic_flag_spec, $1)='${wl}-bexpall' # It seems that -bexpall does not export symbols beginning with # underscore (_), so it is better to generate a list of symbols to export. _LT_TAGVAR(always_export_symbols, $1)=yes if test "$aix_use_runtimelinking" = yes; then # Warning - without using the other runtime loading flags (-brtl), # -berok will link without error, but may produce a broken library. _LT_TAGVAR(allow_undefined_flag, $1)='-berok' # Determine the default libpath from the value encoded in an # empty executable. _LT_SYS_MODULE_PATH_AIX _LT_TAGVAR(hardcode_libdir_flag_spec, $1)='${wl}-blibpath:$libdir:'"$aix_libpath" _LT_TAGVAR(archive_expsym_cmds, $1)='$CC -o $output_objdir/$soname $libobjs $deplibs '"\${wl}$no_entry_flag"' $compiler_flags `if test "x${allow_undefined_flag}" != "x"; then $ECHO "X${wl}${allow_undefined_flag}" | $Xsed; else :; fi` '"\${wl}$exp_sym_flag:\$export_symbols $shared_flag" else if test "$host_cpu" = ia64; then _LT_TAGVAR(hardcode_libdir_flag_spec, $1)='${wl}-R $libdir:/usr/lib:/lib' _LT_TAGVAR(allow_undefined_flag, $1)="-z nodefs" _LT_TAGVAR(archive_expsym_cmds, $1)="\$CC $shared_flag"' -o $output_objdir/$soname $libobjs $deplibs '"\${wl}$no_entry_flag"' $compiler_flags ${wl}${allow_undefined_flag} '"\${wl}$exp_sym_flag:\$export_symbols" else # Determine the default libpath from the value encoded in an # empty executable. _LT_SYS_MODULE_PATH_AIX _LT_TAGVAR(hardcode_libdir_flag_spec, $1)='${wl}-blibpath:$libdir:'"$aix_libpath" # Warning - without using the other run time loading flags, # -berok will link without error, but may produce a broken library. _LT_TAGVAR(no_undefined_flag, $1)=' ${wl}-bernotok' _LT_TAGVAR(allow_undefined_flag, $1)=' ${wl}-berok' # Exported symbols can be pulled into shared objects from archives _LT_TAGVAR(whole_archive_flag_spec, $1)='$convenience' _LT_TAGVAR(archive_cmds_need_lc, $1)=yes # This is similar to how AIX traditionally builds its shared libraries. _LT_TAGVAR(archive_expsym_cmds, $1)="\$CC $shared_flag"' -o $output_objdir/$soname $libobjs $deplibs ${wl}-bnoentry $compiler_flags ${wl}-bE:$export_symbols${allow_undefined_flag}~$AR $AR_FLAGS $output_objdir/$libname$release.a $output_objdir/$soname' fi fi ;; amigaos*) case $host_cpu in powerpc) # see comment about AmigaOS4 .so support _LT_TAGVAR(archive_cmds, $1)='$CC -shared $libobjs $deplibs $compiler_flags ${wl}-soname $wl$soname -o $lib' _LT_TAGVAR(archive_expsym_cmds, $1)='' ;; m68k) _LT_TAGVAR(archive_cmds, $1)='$RM $output_objdir/a2ixlibrary.data~$ECHO "#define NAME $libname" > $output_objdir/a2ixlibrary.data~$ECHO "#define LIBRARY_ID 1" >> $output_objdir/a2ixlibrary.data~$ECHO "#define VERSION $major" >> $output_objdir/a2ixlibrary.data~$ECHO "#define REVISION $revision" >> $output_objdir/a2ixlibrary.data~$AR $AR_FLAGS $lib $libobjs~$RANLIB $lib~(cd $output_objdir && a2ixlibrary -32)' _LT_TAGVAR(hardcode_libdir_flag_spec, $1)='-L$libdir' _LT_TAGVAR(hardcode_minus_L, $1)=yes ;; esac ;; bsdi[[45]]*) _LT_TAGVAR(export_dynamic_flag_spec, $1)=-rdynamic ;; cygwin* | mingw* | pw32* | cegcc*) # When not using gcc, we currently assume that we are using # Microsoft Visual C++. # hardcode_libdir_flag_spec is actually meaningless, as there is # no search path for DLLs. _LT_TAGVAR(hardcode_libdir_flag_spec, $1)=' ' _LT_TAGVAR(allow_undefined_flag, $1)=unsupported # Tell ltmain to make .lib files, not .a files. libext=lib # Tell ltmain to make .dll files, not .so files. shrext_cmds=".dll" # FIXME: Setting linknames here is a bad hack. _LT_TAGVAR(archive_cmds, $1)='$CC -o $lib $libobjs $compiler_flags `$ECHO "X$deplibs" | $Xsed -e '\''s/ -lc$//'\''` -link -dll~linknames=' # The linker will automatically build a .lib file if we build a DLL. _LT_TAGVAR(old_archive_from_new_cmds, $1)='true' # FIXME: Should let the user specify the lib program. _LT_TAGVAR(old_archive_cmds, $1)='lib -OUT:$oldlib$oldobjs$old_deplibs' _LT_TAGVAR(fix_srcfile_path, $1)='`cygpath -w "$srcfile"`' _LT_TAGVAR(enable_shared_with_static_runtimes, $1)=yes ;; darwin* | rhapsody*) _LT_DARWIN_LINKER_FEATURES($1) ;; dgux*) _LT_TAGVAR(archive_cmds, $1)='$LD -G -h $soname -o $lib $libobjs $deplibs $linker_flags' _LT_TAGVAR(hardcode_libdir_flag_spec, $1)='-L$libdir' _LT_TAGVAR(hardcode_shlibpath_var, $1)=no ;; freebsd1*) _LT_TAGVAR(ld_shlibs, $1)=no ;; # FreeBSD 2.2.[012] allows us to include c++rt0.o to get C++ constructor # support. Future versions do this automatically, but an explicit c++rt0.o # does not break anything, and helps significantly (at the cost of a little # extra space). freebsd2.2*) _LT_TAGVAR(archive_cmds, $1)='$LD -Bshareable -o $lib $libobjs $deplibs $linker_flags /usr/lib/c++rt0.o' _LT_TAGVAR(hardcode_libdir_flag_spec, $1)='-R$libdir' _LT_TAGVAR(hardcode_direct, $1)=yes _LT_TAGVAR(hardcode_shlibpath_var, $1)=no ;; # Unfortunately, older versions of FreeBSD 2 do not have this feature. freebsd2*) _LT_TAGVAR(archive_cmds, $1)='$LD -Bshareable -o $lib $libobjs $deplibs $linker_flags' _LT_TAGVAR(hardcode_direct, $1)=yes _LT_TAGVAR(hardcode_minus_L, $1)=yes _LT_TAGVAR(hardcode_shlibpath_var, $1)=no ;; # FreeBSD 3 and greater uses gcc -shared to do shared libraries. freebsd* | dragonfly*) _LT_TAGVAR(archive_cmds, $1)='$CC -shared -o $lib $libobjs $deplibs $compiler_flags' _LT_TAGVAR(hardcode_libdir_flag_spec, $1)='-R$libdir' _LT_TAGVAR(hardcode_direct, $1)=yes _LT_TAGVAR(hardcode_shlibpath_var, $1)=no ;; hpux9*) if test "$GCC" = yes; then _LT_TAGVAR(archive_cmds, $1)='$RM $output_objdir/$soname~$CC -shared -fPIC ${wl}+b ${wl}$install_libdir -o $output_objdir/$soname $libobjs $deplibs $compiler_flags~test $output_objdir/$soname = $lib || mv $output_objdir/$soname $lib' else _LT_TAGVAR(archive_cmds, $1)='$RM $output_objdir/$soname~$LD -b +b $install_libdir -o $output_objdir/$soname $libobjs $deplibs $linker_flags~test $output_objdir/$soname = $lib || mv $output_objdir/$soname $lib' fi _LT_TAGVAR(hardcode_libdir_flag_spec, $1)='${wl}+b ${wl}$libdir' _LT_TAGVAR(hardcode_libdir_separator, $1)=: _LT_TAGVAR(hardcode_direct, $1)=yes # hardcode_minus_L: Not really in the search PATH, # but as the default location of the library. _LT_TAGVAR(hardcode_minus_L, $1)=yes _LT_TAGVAR(export_dynamic_flag_spec, $1)='${wl}-E' ;; hpux10*) if test "$GCC" = yes -a "$with_gnu_ld" = no; then _LT_TAGVAR(archive_cmds, $1)='$CC -shared -fPIC ${wl}+h ${wl}$soname ${wl}+b ${wl}$install_libdir -o $lib $libobjs $deplibs $compiler_flags' else _LT_TAGVAR(archive_cmds, $1)='$LD -b +h $soname +b $install_libdir -o $lib $libobjs $deplibs $linker_flags' fi if test "$with_gnu_ld" = no; then _LT_TAGVAR(hardcode_libdir_flag_spec, $1)='${wl}+b ${wl}$libdir' _LT_TAGVAR(hardcode_libdir_flag_spec_ld, $1)='+b $libdir' _LT_TAGVAR(hardcode_libdir_separator, $1)=: _LT_TAGVAR(hardcode_direct, $1)=yes _LT_TAGVAR(hardcode_direct_absolute, $1)=yes _LT_TAGVAR(export_dynamic_flag_spec, $1)='${wl}-E' # hardcode_minus_L: Not really in the search PATH, # but as the default location of the library. _LT_TAGVAR(hardcode_minus_L, $1)=yes fi ;; hpux11*) if test "$GCC" = yes -a "$with_gnu_ld" = no; then case $host_cpu in hppa*64*) _LT_TAGVAR(archive_cmds, $1)='$CC -shared ${wl}+h ${wl}$soname -o $lib $libobjs $deplibs $compiler_flags' ;; ia64*) _LT_TAGVAR(archive_cmds, $1)='$CC -shared -fPIC ${wl}+h ${wl}$soname ${wl}+nodefaultrpath -o $lib $libobjs $deplibs $compiler_flags' ;; *) _LT_TAGVAR(archive_cmds, $1)='$CC -shared -fPIC ${wl}+h ${wl}$soname ${wl}+b ${wl}$install_libdir -o $lib $libobjs $deplibs $compiler_flags' ;; esac else case $host_cpu in hppa*64*) _LT_TAGVAR(archive_cmds, $1)='$CC -b ${wl}+h ${wl}$soname -o $lib $libobjs $deplibs $compiler_flags' ;; ia64*) _LT_TAGVAR(archive_cmds, $1)='$CC -b ${wl}+h ${wl}$soname ${wl}+nodefaultrpath -o $lib $libobjs $deplibs $compiler_flags' ;; *) _LT_TAGVAR(archive_cmds, $1)='$CC -b ${wl}+h ${wl}$soname ${wl}+b ${wl}$install_libdir -o $lib $libobjs $deplibs $compiler_flags' ;; esac fi if test "$with_gnu_ld" = no; then _LT_TAGVAR(hardcode_libdir_flag_spec, $1)='${wl}+b ${wl}$libdir' _LT_TAGVAR(hardcode_libdir_separator, $1)=: case $host_cpu in hppa*64*|ia64*) _LT_TAGVAR(hardcode_direct, $1)=no _LT_TAGVAR(hardcode_shlibpath_var, $1)=no ;; *) _LT_TAGVAR(hardcode_direct, $1)=yes _LT_TAGVAR(hardcode_direct_absolute, $1)=yes _LT_TAGVAR(export_dynamic_flag_spec, $1)='${wl}-E' # hardcode_minus_L: Not really in the search PATH, # but as the default location of the library. _LT_TAGVAR(hardcode_minus_L, $1)=yes ;; esac fi ;; irix5* | irix6* | nonstopux*) if test "$GCC" = yes; then _LT_TAGVAR(archive_cmds, $1)='$CC -shared $libobjs $deplibs $compiler_flags ${wl}-soname ${wl}$soname `test -n "$verstring" && $ECHO "X${wl}-set_version ${wl}$verstring" | $Xsed` ${wl}-update_registry ${wl}${output_objdir}/so_locations -o $lib' # Try to use the -exported_symbol ld option, if it does not # work, assume that -exports_file does not work either and # implicitly export all symbols. save_LDFLAGS="$LDFLAGS" LDFLAGS="$LDFLAGS -shared ${wl}-exported_symbol ${wl}foo ${wl}-update_registry ${wl}/dev/null" AC_LINK_IFELSE( [AC_LANG_SOURCE( [AC_LANG_CASE([C], [[int foo (void) { return 0; }]], [C++], [[int foo (void) { return 0; }]], [Fortran 77], [[ subroutine foo end]], [Fortran], [[ subroutine foo end]])])], [ _LT_TAGVAR(archive_expsym_cmds, $1)='$CC -shared $libobjs $deplibs $compiler_flags ${wl}-soname ${wl}$soname `test -n "$verstring" && $ECHO "X${wl}-set_version ${wl}$verstring" | $Xsed` ${wl}-update_registry ${wl}${output_objdir}/so_locations ${wl}-exports_file ${wl}$export_symbols -o $lib' ]) LDFLAGS="$save_LDFLAGS" else _LT_TAGVAR(archive_cmds, $1)='$CC -shared $libobjs $deplibs $compiler_flags -soname $soname `test -n "$verstring" && $ECHO "X-set_version $verstring" | $Xsed` -update_registry ${output_objdir}/so_locations -o $lib' _LT_TAGVAR(archive_expsym_cmds, $1)='$CC -shared $libobjs $deplibs $compiler_flags -soname $soname `test -n "$verstring" && $ECHO "X-set_version $verstring" | $Xsed` -update_registry ${output_objdir}/so_locations -exports_file $export_symbols -o $lib' fi _LT_TAGVAR(archive_cmds_need_lc, $1)='no' _LT_TAGVAR(hardcode_libdir_flag_spec, $1)='${wl}-rpath ${wl}$libdir' _LT_TAGVAR(hardcode_libdir_separator, $1)=: _LT_TAGVAR(inherit_rpath, $1)=yes _LT_TAGVAR(link_all_deplibs, $1)=yes ;; netbsd*) if echo __ELF__ | $CC -E - | $GREP __ELF__ >/dev/null; then _LT_TAGVAR(archive_cmds, $1)='$LD -Bshareable -o $lib $libobjs $deplibs $linker_flags' # a.out else _LT_TAGVAR(archive_cmds, $1)='$LD -shared -o $lib $libobjs $deplibs $linker_flags' # ELF fi _LT_TAGVAR(hardcode_libdir_flag_spec, $1)='-R$libdir' _LT_TAGVAR(hardcode_direct, $1)=yes _LT_TAGVAR(hardcode_shlibpath_var, $1)=no ;; newsos6) _LT_TAGVAR(archive_cmds, $1)='$LD -G -h $soname -o $lib $libobjs $deplibs $linker_flags' _LT_TAGVAR(hardcode_direct, $1)=yes _LT_TAGVAR(hardcode_libdir_flag_spec, $1)='${wl}-rpath ${wl}$libdir' _LT_TAGVAR(hardcode_libdir_separator, $1)=: _LT_TAGVAR(hardcode_shlibpath_var, $1)=no ;; *nto* | *qnx*) ;; openbsd*) if test -f /usr/libexec/ld.so; then _LT_TAGVAR(hardcode_direct, $1)=yes _LT_TAGVAR(hardcode_shlibpath_var, $1)=no _LT_TAGVAR(hardcode_direct_absolute, $1)=yes if test -z "`echo __ELF__ | $CC -E - | $GREP __ELF__`" || test "$host_os-$host_cpu" = "openbsd2.8-powerpc"; then _LT_TAGVAR(archive_cmds, $1)='$CC -shared $pic_flag -o $lib $libobjs $deplibs $compiler_flags' _LT_TAGVAR(archive_expsym_cmds, $1)='$CC -shared $pic_flag -o $lib $libobjs $deplibs $compiler_flags ${wl}-retain-symbols-file,$export_symbols' _LT_TAGVAR(hardcode_libdir_flag_spec, $1)='${wl}-rpath,$libdir' _LT_TAGVAR(export_dynamic_flag_spec, $1)='${wl}-E' else case $host_os in openbsd[[01]].* | openbsd2.[[0-7]] | openbsd2.[[0-7]].*) _LT_TAGVAR(archive_cmds, $1)='$LD -Bshareable -o $lib $libobjs $deplibs $linker_flags' _LT_TAGVAR(hardcode_libdir_flag_spec, $1)='-R$libdir' ;; *) _LT_TAGVAR(archive_cmds, $1)='$CC -shared $pic_flag -o $lib $libobjs $deplibs $compiler_flags' _LT_TAGVAR(hardcode_libdir_flag_spec, $1)='${wl}-rpath,$libdir' ;; esac fi else _LT_TAGVAR(ld_shlibs, $1)=no fi ;; os2*) _LT_TAGVAR(hardcode_libdir_flag_spec, $1)='-L$libdir' _LT_TAGVAR(hardcode_minus_L, $1)=yes _LT_TAGVAR(allow_undefined_flag, $1)=unsupported _LT_TAGVAR(archive_cmds, $1)='$ECHO "LIBRARY $libname INITINSTANCE" > $output_objdir/$libname.def~$ECHO "DESCRIPTION \"$libname\"" >> $output_objdir/$libname.def~$ECHO DATA >> $output_objdir/$libname.def~$ECHO " SINGLE NONSHARED" >> $output_objdir/$libname.def~$ECHO EXPORTS >> $output_objdir/$libname.def~emxexp $libobjs >> $output_objdir/$libname.def~$CC -Zdll -Zcrtdll -o $lib $libobjs $deplibs $compiler_flags $output_objdir/$libname.def' _LT_TAGVAR(old_archive_from_new_cmds, $1)='emximp -o $output_objdir/$libname.a $output_objdir/$libname.def' ;; osf3*) if test "$GCC" = yes; then _LT_TAGVAR(allow_undefined_flag, $1)=' ${wl}-expect_unresolved ${wl}\*' _LT_TAGVAR(archive_cmds, $1)='$CC -shared${allow_undefined_flag} $libobjs $deplibs $compiler_flags ${wl}-soname ${wl}$soname `test -n "$verstring" && $ECHO "X${wl}-set_version ${wl}$verstring" | $Xsed` ${wl}-update_registry ${wl}${output_objdir}/so_locations -o $lib' else _LT_TAGVAR(allow_undefined_flag, $1)=' -expect_unresolved \*' _LT_TAGVAR(archive_cmds, $1)='$CC -shared${allow_undefined_flag} $libobjs $deplibs $compiler_flags -soname $soname `test -n "$verstring" && $ECHO "X-set_version $verstring" | $Xsed` -update_registry ${output_objdir}/so_locations -o $lib' fi _LT_TAGVAR(archive_cmds_need_lc, $1)='no' _LT_TAGVAR(hardcode_libdir_flag_spec, $1)='${wl}-rpath ${wl}$libdir' _LT_TAGVAR(hardcode_libdir_separator, $1)=: ;; osf4* | osf5*) # as osf3* with the addition of -msym flag if test "$GCC" = yes; then _LT_TAGVAR(allow_undefined_flag, $1)=' ${wl}-expect_unresolved ${wl}\*' _LT_TAGVAR(archive_cmds, $1)='$CC -shared${allow_undefined_flag} $libobjs $deplibs $compiler_flags ${wl}-msym ${wl}-soname ${wl}$soname `test -n "$verstring" && $ECHO "X${wl}-set_version ${wl}$verstring" | $Xsed` ${wl}-update_registry ${wl}${output_objdir}/so_locations -o $lib' _LT_TAGVAR(hardcode_libdir_flag_spec, $1)='${wl}-rpath ${wl}$libdir' else _LT_TAGVAR(allow_undefined_flag, $1)=' -expect_unresolved \*' _LT_TAGVAR(archive_cmds, $1)='$CC -shared${allow_undefined_flag} $libobjs $deplibs $compiler_flags -msym -soname $soname `test -n "$verstring" && $ECHO "X-set_version $verstring" | $Xsed` -update_registry ${output_objdir}/so_locations -o $lib' _LT_TAGVAR(archive_expsym_cmds, $1)='for i in `cat $export_symbols`; do printf "%s %s\\n" -exported_symbol "\$i" >> $lib.exp; done; printf "%s\\n" "-hidden">> $lib.exp~ $CC -shared${allow_undefined_flag} ${wl}-input ${wl}$lib.exp $compiler_flags $libobjs $deplibs -soname $soname `test -n "$verstring" && $ECHO "X-set_version $verstring" | $Xsed` -update_registry ${output_objdir}/so_locations -o $lib~$RM $lib.exp' # Both c and cxx compiler support -rpath directly _LT_TAGVAR(hardcode_libdir_flag_spec, $1)='-rpath $libdir' fi _LT_TAGVAR(archive_cmds_need_lc, $1)='no' _LT_TAGVAR(hardcode_libdir_separator, $1)=: ;; solaris*) _LT_TAGVAR(no_undefined_flag, $1)=' -z defs' if test "$GCC" = yes; then wlarc='${wl}' _LT_TAGVAR(archive_cmds, $1)='$CC -shared ${wl}-z ${wl}text ${wl}-h ${wl}$soname -o $lib $libobjs $deplibs $compiler_flags' _LT_TAGVAR(archive_expsym_cmds, $1)='echo "{ global:" > $lib.exp~cat $export_symbols | $SED -e "s/\(.*\)/\1;/" >> $lib.exp~echo "local: *; };" >> $lib.exp~ $CC -shared ${wl}-z ${wl}text ${wl}-M ${wl}$lib.exp ${wl}-h ${wl}$soname -o $lib $libobjs $deplibs $compiler_flags~$RM $lib.exp' else case `$CC -V 2>&1` in *"Compilers 5.0"*) wlarc='' _LT_TAGVAR(archive_cmds, $1)='$LD -G${allow_undefined_flag} -h $soname -o $lib $libobjs $deplibs $linker_flags' _LT_TAGVAR(archive_expsym_cmds, $1)='echo "{ global:" > $lib.exp~cat $export_symbols | $SED -e "s/\(.*\)/\1;/" >> $lib.exp~echo "local: *; };" >> $lib.exp~ $LD -G${allow_undefined_flag} -M $lib.exp -h $soname -o $lib $libobjs $deplibs $linker_flags~$RM $lib.exp' ;; *) wlarc='${wl}' _LT_TAGVAR(archive_cmds, $1)='$CC -G${allow_undefined_flag} -h $soname -o $lib $libobjs $deplibs $compiler_flags' _LT_TAGVAR(archive_expsym_cmds, $1)='echo "{ global:" > $lib.exp~cat $export_symbols | $SED -e "s/\(.*\)/\1;/" >> $lib.exp~echo "local: *; };" >> $lib.exp~ $CC -G${allow_undefined_flag} -M $lib.exp -h $soname -o $lib $libobjs $deplibs $compiler_flags~$RM $lib.exp' ;; esac fi _LT_TAGVAR(hardcode_libdir_flag_spec, $1)='-R$libdir' _LT_TAGVAR(hardcode_shlibpath_var, $1)=no case $host_os in solaris2.[[0-5]] | solaris2.[[0-5]].*) ;; *) # The compiler driver will combine and reorder linker options, # but understands `-z linker_flag'. GCC discards it without `$wl', # but is careful enough not to reorder. # Supported since Solaris 2.6 (maybe 2.5.1?) if test "$GCC" = yes; then _LT_TAGVAR(whole_archive_flag_spec, $1)='${wl}-z ${wl}allextract$convenience ${wl}-z ${wl}defaultextract' else _LT_TAGVAR(whole_archive_flag_spec, $1)='-z allextract$convenience -z defaultextract' fi ;; esac _LT_TAGVAR(link_all_deplibs, $1)=yes ;; sunos4*) if test "x$host_vendor" = xsequent; then # Use $CC to link under sequent, because it throws in some extra .o # files that make .init and .fini sections work. _LT_TAGVAR(archive_cmds, $1)='$CC -G ${wl}-h $soname -o $lib $libobjs $deplibs $compiler_flags' else _LT_TAGVAR(archive_cmds, $1)='$LD -assert pure-text -Bstatic -o $lib $libobjs $deplibs $linker_flags' fi _LT_TAGVAR(hardcode_libdir_flag_spec, $1)='-L$libdir' _LT_TAGVAR(hardcode_direct, $1)=yes _LT_TAGVAR(hardcode_minus_L, $1)=yes _LT_TAGVAR(hardcode_shlibpath_var, $1)=no ;; sysv4) case $host_vendor in sni) _LT_TAGVAR(archive_cmds, $1)='$LD -G -h $soname -o $lib $libobjs $deplibs $linker_flags' _LT_TAGVAR(hardcode_direct, $1)=yes # is this really true??? ;; siemens) ## LD is ld it makes a PLAMLIB ## CC just makes a GrossModule. _LT_TAGVAR(archive_cmds, $1)='$LD -G -o $lib $libobjs $deplibs $linker_flags' _LT_TAGVAR(reload_cmds, $1)='$CC -r -o $output$reload_objs' _LT_TAGVAR(hardcode_direct, $1)=no ;; motorola) _LT_TAGVAR(archive_cmds, $1)='$LD -G -h $soname -o $lib $libobjs $deplibs $linker_flags' _LT_TAGVAR(hardcode_direct, $1)=no #Motorola manual says yes, but my tests say they lie ;; esac runpath_var='LD_RUN_PATH' _LT_TAGVAR(hardcode_shlibpath_var, $1)=no ;; sysv4.3*) _LT_TAGVAR(archive_cmds, $1)='$LD -G -h $soname -o $lib $libobjs $deplibs $linker_flags' _LT_TAGVAR(hardcode_shlibpath_var, $1)=no _LT_TAGVAR(export_dynamic_flag_spec, $1)='-Bexport' ;; sysv4*MP*) if test -d /usr/nec; then _LT_TAGVAR(archive_cmds, $1)='$LD -G -h $soname -o $lib $libobjs $deplibs $linker_flags' _LT_TAGVAR(hardcode_shlibpath_var, $1)=no runpath_var=LD_RUN_PATH hardcode_runpath_var=yes _LT_TAGVAR(ld_shlibs, $1)=yes fi ;; sysv4*uw2* | sysv5OpenUNIX* | sysv5UnixWare7.[[01]].[[10]]* | unixware7* | sco3.2v5.0.[[024]]*) _LT_TAGVAR(no_undefined_flag, $1)='${wl}-z,text' _LT_TAGVAR(archive_cmds_need_lc, $1)=no _LT_TAGVAR(hardcode_shlibpath_var, $1)=no runpath_var='LD_RUN_PATH' if test "$GCC" = yes; then _LT_TAGVAR(archive_cmds, $1)='$CC -shared ${wl}-h,$soname -o $lib $libobjs $deplibs $compiler_flags' _LT_TAGVAR(archive_expsym_cmds, $1)='$CC -shared ${wl}-Bexport:$export_symbols ${wl}-h,$soname -o $lib $libobjs $deplibs $compiler_flags' else _LT_TAGVAR(archive_cmds, $1)='$CC -G ${wl}-h,$soname -o $lib $libobjs $deplibs $compiler_flags' _LT_TAGVAR(archive_expsym_cmds, $1)='$CC -G ${wl}-Bexport:$export_symbols ${wl}-h,$soname -o $lib $libobjs $deplibs $compiler_flags' fi ;; sysv5* | sco3.2v5* | sco5v6*) # Note: We can NOT use -z defs as we might desire, because we do not # link with -lc, and that would cause any symbols used from libc to # always be unresolved, which means just about no library would # ever link correctly. If we're not using GNU ld we use -z text # though, which does catch some bad symbols but isn't as heavy-handed # as -z defs. _LT_TAGVAR(no_undefined_flag, $1)='${wl}-z,text' _LT_TAGVAR(allow_undefined_flag, $1)='${wl}-z,nodefs' _LT_TAGVAR(archive_cmds_need_lc, $1)=no _LT_TAGVAR(hardcode_shlibpath_var, $1)=no _LT_TAGVAR(hardcode_libdir_flag_spec, $1)='${wl}-R,$libdir' _LT_TAGVAR(hardcode_libdir_separator, $1)=':' _LT_TAGVAR(link_all_deplibs, $1)=yes _LT_TAGVAR(export_dynamic_flag_spec, $1)='${wl}-Bexport' runpath_var='LD_RUN_PATH' if test "$GCC" = yes; then _LT_TAGVAR(archive_cmds, $1)='$CC -shared ${wl}-h,$soname -o $lib $libobjs $deplibs $compiler_flags' _LT_TAGVAR(archive_expsym_cmds, $1)='$CC -shared ${wl}-Bexport:$export_symbols ${wl}-h,$soname -o $lib $libobjs $deplibs $compiler_flags' else _LT_TAGVAR(archive_cmds, $1)='$CC -G ${wl}-h,$soname -o $lib $libobjs $deplibs $compiler_flags' _LT_TAGVAR(archive_expsym_cmds, $1)='$CC -G ${wl}-Bexport:$export_symbols ${wl}-h,$soname -o $lib $libobjs $deplibs $compiler_flags' fi ;; uts4*) _LT_TAGVAR(archive_cmds, $1)='$LD -G -h $soname -o $lib $libobjs $deplibs $linker_flags' _LT_TAGVAR(hardcode_libdir_flag_spec, $1)='-L$libdir' _LT_TAGVAR(hardcode_shlibpath_var, $1)=no ;; *) _LT_TAGVAR(ld_shlibs, $1)=no ;; esac if test x$host_vendor = xsni; then case $host in sysv4 | sysv4.2uw2* | sysv4.3* | sysv5*) _LT_TAGVAR(export_dynamic_flag_spec, $1)='${wl}-Blargedynsym' ;; esac fi fi ]) AC_MSG_RESULT([$_LT_TAGVAR(ld_shlibs, $1)]) test "$_LT_TAGVAR(ld_shlibs, $1)" = no && can_build_shared=no _LT_TAGVAR(with_gnu_ld, $1)=$with_gnu_ld _LT_DECL([], [libext], [0], [Old archive suffix (normally "a")])dnl _LT_DECL([], [shrext_cmds], [1], [Shared library suffix (normally ".so")])dnl _LT_DECL([], [extract_expsyms_cmds], [2], [The commands to extract the exported symbol list from a shared archive]) # # Do we need to explicitly link libc? # case "x$_LT_TAGVAR(archive_cmds_need_lc, $1)" in x|xyes) # Assume -lc should be added _LT_TAGVAR(archive_cmds_need_lc, $1)=yes if test "$enable_shared" = yes && test "$GCC" = yes; then case $_LT_TAGVAR(archive_cmds, $1) in *'~'*) # FIXME: we may have to deal with multi-command sequences. ;; '$CC '*) # Test whether the compiler implicitly links with -lc since on some # systems, -lgcc has to come before -lc. If gcc already passes -lc # to ld, don't add -lc before -lgcc. AC_MSG_CHECKING([whether -lc should be explicitly linked in]) $RM conftest* echo "$lt_simple_compile_test_code" > conftest.$ac_ext if AC_TRY_EVAL(ac_compile) 2>conftest.err; then soname=conftest lib=conftest libobjs=conftest.$ac_objext deplibs= wl=$_LT_TAGVAR(lt_prog_compiler_wl, $1) pic_flag=$_LT_TAGVAR(lt_prog_compiler_pic, $1) compiler_flags=-v linker_flags=-v verstring= output_objdir=. libname=conftest lt_save_allow_undefined_flag=$_LT_TAGVAR(allow_undefined_flag, $1) _LT_TAGVAR(allow_undefined_flag, $1)= if AC_TRY_EVAL(_LT_TAGVAR(archive_cmds, $1) 2\>\&1 \| $GREP \" -lc \" \>/dev/null 2\>\&1) then _LT_TAGVAR(archive_cmds_need_lc, $1)=no else _LT_TAGVAR(archive_cmds_need_lc, $1)=yes fi _LT_TAGVAR(allow_undefined_flag, $1)=$lt_save_allow_undefined_flag else cat conftest.err 1>&5 fi $RM conftest* AC_MSG_RESULT([$_LT_TAGVAR(archive_cmds_need_lc, $1)]) ;; esac fi ;; esac _LT_TAGDECL([build_libtool_need_lc], [archive_cmds_need_lc], [0], [Whether or not to add -lc for building shared libraries]) _LT_TAGDECL([allow_libtool_libs_with_static_runtimes], [enable_shared_with_static_runtimes], [0], [Whether or not to disallow shared libs when runtime libs are static]) _LT_TAGDECL([], [export_dynamic_flag_spec], [1], [Compiler flag to allow reflexive dlopens]) _LT_TAGDECL([], [whole_archive_flag_spec], [1], [Compiler flag to generate shared objects directly from archives]) _LT_TAGDECL([], [compiler_needs_object], [1], [Whether the compiler copes with passing no objects directly]) _LT_TAGDECL([], [old_archive_from_new_cmds], [2], [Create an old-style archive from a shared archive]) _LT_TAGDECL([], [old_archive_from_expsyms_cmds], [2], [Create a temporary old-style archive to link instead of a shared archive]) _LT_TAGDECL([], [archive_cmds], [2], [Commands used to build a shared archive]) _LT_TAGDECL([], [archive_expsym_cmds], [2]) _LT_TAGDECL([], [module_cmds], [2], [Commands used to build a loadable module if different from building a shared archive.]) _LT_TAGDECL([], [module_expsym_cmds], [2]) _LT_TAGDECL([], [with_gnu_ld], [1], [Whether we are building with GNU ld or not]) _LT_TAGDECL([], [allow_undefined_flag], [1], [Flag that allows shared libraries with undefined symbols to be built]) _LT_TAGDECL([], [no_undefined_flag], [1], [Flag that enforces no undefined symbols]) _LT_TAGDECL([], [hardcode_libdir_flag_spec], [1], [Flag to hardcode $libdir into a binary during linking. This must work even if $libdir does not exist]) _LT_TAGDECL([], [hardcode_libdir_flag_spec_ld], [1], [[If ld is used when linking, flag to hardcode $libdir into a binary during linking. This must work even if $libdir does not exist]]) _LT_TAGDECL([], [hardcode_libdir_separator], [1], [Whether we need a single "-rpath" flag with a separated argument]) _LT_TAGDECL([], [hardcode_direct], [0], [Set to "yes" if using DIR/libNAME${shared_ext} during linking hardcodes DIR into the resulting binary]) _LT_TAGDECL([], [hardcode_direct_absolute], [0], [Set to "yes" if using DIR/libNAME${shared_ext} during linking hardcodes DIR into the resulting binary and the resulting library dependency is "absolute", i.e impossible to change by setting ${shlibpath_var} if the library is relocated]) _LT_TAGDECL([], [hardcode_minus_L], [0], [Set to "yes" if using the -LDIR flag during linking hardcodes DIR into the resulting binary]) _LT_TAGDECL([], [hardcode_shlibpath_var], [0], [Set to "yes" if using SHLIBPATH_VAR=DIR during linking hardcodes DIR into the resulting binary]) _LT_TAGDECL([], [hardcode_automatic], [0], [Set to "yes" if building a shared library automatically hardcodes DIR into the library and all subsequent libraries and executables linked against it]) _LT_TAGDECL([], [inherit_rpath], [0], [Set to yes if linker adds runtime paths of dependent libraries to runtime path list]) _LT_TAGDECL([], [link_all_deplibs], [0], [Whether libtool must link a program against all its dependency libraries]) _LT_TAGDECL([], [fix_srcfile_path], [1], [Fix the shell variable $srcfile for the compiler]) _LT_TAGDECL([], [always_export_symbols], [0], [Set to "yes" if exported symbols are required]) _LT_TAGDECL([], [export_symbols_cmds], [2], [The commands to list exported symbols]) _LT_TAGDECL([], [exclude_expsyms], [1], [Symbols that should not be listed in the preloaded symbols]) _LT_TAGDECL([], [include_expsyms], [1], [Symbols that must always be exported]) _LT_TAGDECL([], [prelink_cmds], [2], [Commands necessary for linking programs (against libraries) with templates]) _LT_TAGDECL([], [file_list_spec], [1], [Specify filename containing input files]) dnl FIXME: Not yet implemented dnl _LT_TAGDECL([], [thread_safe_flag_spec], [1], dnl [Compiler flag to generate thread safe objects]) ])# _LT_LINKER_SHLIBS # _LT_LANG_C_CONFIG([TAG]) # ------------------------ # Ensure that the configuration variables for a C compiler are suitably # defined. These variables are subsequently used by _LT_CONFIG to write # the compiler configuration to `libtool'. m4_defun([_LT_LANG_C_CONFIG], [m4_require([_LT_DECL_EGREP])dnl lt_save_CC="$CC" AC_LANG_PUSH(C) # Source file extension for C test sources. ac_ext=c # Object file extension for compiled C test sources. objext=o _LT_TAGVAR(objext, $1)=$objext # Code to be used in simple compile tests lt_simple_compile_test_code="int some_variable = 0;" # Code to be used in simple link tests lt_simple_link_test_code='int main(){return(0);}' _LT_TAG_COMPILER # Save the default compiler, since it gets overwritten when the other # tags are being tested, and _LT_TAGVAR(compiler, []) is a NOP. compiler_DEFAULT=$CC # save warnings/boilerplate of simple test code _LT_COMPILER_BOILERPLATE _LT_LINKER_BOILERPLATE ## CAVEAT EMPTOR: ## There is no encapsulation within the following macros, do not change ## the running order or otherwise move them around unless you know exactly ## what you are doing... if test -n "$compiler"; then _LT_COMPILER_NO_RTTI($1) _LT_COMPILER_PIC($1) _LT_COMPILER_C_O($1) _LT_COMPILER_FILE_LOCKS($1) _LT_LINKER_SHLIBS($1) _LT_SYS_DYNAMIC_LINKER($1) _LT_LINKER_HARDCODE_LIBPATH($1) LT_SYS_DLOPEN_SELF _LT_CMD_STRIPLIB # Report which library types will actually be built AC_MSG_CHECKING([if libtool supports shared libraries]) AC_MSG_RESULT([$can_build_shared]) AC_MSG_CHECKING([whether to build shared libraries]) test "$can_build_shared" = "no" && enable_shared=no # On AIX, shared libraries and static libraries use the same namespace, and # are all built from PIC. case $host_os in aix3*) test "$enable_shared" = yes && enable_static=no if test -n "$RANLIB"; then archive_cmds="$archive_cmds~\$RANLIB \$lib" postinstall_cmds='$RANLIB $lib' fi ;; aix[[4-9]]*) if test "$host_cpu" != ia64 && test "$aix_use_runtimelinking" = no ; then test "$enable_shared" = yes && enable_static=no fi ;; esac AC_MSG_RESULT([$enable_shared]) AC_MSG_CHECKING([whether to build static libraries]) # Make sure either enable_shared or enable_static is yes. test "$enable_shared" = yes || enable_static=yes AC_MSG_RESULT([$enable_static]) _LT_CONFIG($1) fi AC_LANG_POP CC="$lt_save_CC" ])# _LT_LANG_C_CONFIG # _LT_PROG_CXX # ------------ # Since AC_PROG_CXX is broken, in that it returns g++ if there is no c++ # compiler, we have our own version here. m4_defun([_LT_PROG_CXX], [ pushdef([AC_MSG_ERROR], [_lt_caught_CXX_error=yes]) AC_PROG_CXX if test -n "$CXX" && ( test "X$CXX" != "Xno" && ( (test "X$CXX" = "Xg++" && `g++ -v >/dev/null 2>&1` ) || (test "X$CXX" != "Xg++"))) ; then AC_PROG_CXXCPP else _lt_caught_CXX_error=yes fi popdef([AC_MSG_ERROR]) ])# _LT_PROG_CXX dnl aclocal-1.4 backwards compatibility: dnl AC_DEFUN([_LT_PROG_CXX], []) # _LT_LANG_CXX_CONFIG([TAG]) # -------------------------- # Ensure that the configuration variables for a C++ compiler are suitably # defined. These variables are subsequently used by _LT_CONFIG to write # the compiler configuration to `libtool'. m4_defun([_LT_LANG_CXX_CONFIG], [AC_REQUIRE([_LT_PROG_CXX])dnl m4_require([_LT_FILEUTILS_DEFAULTS])dnl m4_require([_LT_DECL_EGREP])dnl AC_LANG_PUSH(C++) _LT_TAGVAR(archive_cmds_need_lc, $1)=no _LT_TAGVAR(allow_undefined_flag, $1)= _LT_TAGVAR(always_export_symbols, $1)=no _LT_TAGVAR(archive_expsym_cmds, $1)= _LT_TAGVAR(compiler_needs_object, $1)=no _LT_TAGVAR(export_dynamic_flag_spec, $1)= _LT_TAGVAR(hardcode_direct, $1)=no _LT_TAGVAR(hardcode_direct_absolute, $1)=no _LT_TAGVAR(hardcode_libdir_flag_spec, $1)= _LT_TAGVAR(hardcode_libdir_flag_spec_ld, $1)= _LT_TAGVAR(hardcode_libdir_separator, $1)= _LT_TAGVAR(hardcode_minus_L, $1)=no _LT_TAGVAR(hardcode_shlibpath_var, $1)=unsupported _LT_TAGVAR(hardcode_automatic, $1)=no _LT_TAGVAR(inherit_rpath, $1)=no _LT_TAGVAR(module_cmds, $1)= _LT_TAGVAR(module_expsym_cmds, $1)= _LT_TAGVAR(link_all_deplibs, $1)=unknown _LT_TAGVAR(old_archive_cmds, $1)=$old_archive_cmds _LT_TAGVAR(no_undefined_flag, $1)= _LT_TAGVAR(whole_archive_flag_spec, $1)= _LT_TAGVAR(enable_shared_with_static_runtimes, $1)=no # Source file extension for C++ test sources. ac_ext=cpp # Object file extension for compiled C++ test sources. objext=o _LT_TAGVAR(objext, $1)=$objext # No sense in running all these tests if we already determined that # the CXX compiler isn't working. Some variables (like enable_shared) # are currently assumed to apply to all compilers on this platform, # and will be corrupted by setting them based on a non-working compiler. if test "$_lt_caught_CXX_error" != yes; then # Code to be used in simple compile tests lt_simple_compile_test_code="int some_variable = 0;" # Code to be used in simple link tests lt_simple_link_test_code='int main(int, char *[[]]) { return(0); }' # ltmain only uses $CC for tagged configurations so make sure $CC is set. _LT_TAG_COMPILER # save warnings/boilerplate of simple test code _LT_COMPILER_BOILERPLATE _LT_LINKER_BOILERPLATE # Allow CC to be a program name with arguments. lt_save_CC=$CC lt_save_LD=$LD lt_save_GCC=$GCC GCC=$GXX lt_save_with_gnu_ld=$with_gnu_ld lt_save_path_LD=$lt_cv_path_LD if test -n "${lt_cv_prog_gnu_ldcxx+set}"; then lt_cv_prog_gnu_ld=$lt_cv_prog_gnu_ldcxx else $as_unset lt_cv_prog_gnu_ld fi if test -n "${lt_cv_path_LDCXX+set}"; then lt_cv_path_LD=$lt_cv_path_LDCXX else $as_unset lt_cv_path_LD fi test -z "${LDCXX+set}" || LD=$LDCXX CC=${CXX-"c++"} compiler=$CC _LT_TAGVAR(compiler, $1)=$CC _LT_CC_BASENAME([$compiler]) if test -n "$compiler"; then # We don't want -fno-exception when compiling C++ code, so set the # no_builtin_flag separately if test "$GXX" = yes; then _LT_TAGVAR(lt_prog_compiler_no_builtin_flag, $1)=' -fno-builtin' else _LT_TAGVAR(lt_prog_compiler_no_builtin_flag, $1)= fi if test "$GXX" = yes; then # Set up default GNU C++ configuration LT_PATH_LD # Check if GNU C++ uses GNU ld as the underlying linker, since the # archiving commands below assume that GNU ld is being used. if test "$with_gnu_ld" = yes; then _LT_TAGVAR(archive_cmds, $1)='$CC -shared -nostdlib $predep_objects $libobjs $deplibs $postdep_objects $compiler_flags ${wl}-soname $wl$soname -o $lib' _LT_TAGVAR(archive_expsym_cmds, $1)='$CC -shared -nostdlib $predep_objects $libobjs $deplibs $postdep_objects $compiler_flags ${wl}-soname $wl$soname ${wl}-retain-symbols-file $wl$export_symbols -o $lib' _LT_TAGVAR(hardcode_libdir_flag_spec, $1)='${wl}-rpath ${wl}$libdir' _LT_TAGVAR(export_dynamic_flag_spec, $1)='${wl}--export-dynamic' # If archive_cmds runs LD, not CC, wlarc should be empty # XXX I think wlarc can be eliminated in ltcf-cxx, but I need to # investigate it a little bit more. (MM) wlarc='${wl}' # ancient GNU ld didn't support --whole-archive et. al. if eval "`$CC -print-prog-name=ld` --help 2>&1" | $GREP 'no-whole-archive' > /dev/null; then _LT_TAGVAR(whole_archive_flag_spec, $1)="$wlarc"'--whole-archive$convenience '"$wlarc"'--no-whole-archive' else _LT_TAGVAR(whole_archive_flag_spec, $1)= fi else with_gnu_ld=no wlarc= # A generic and very simple default shared library creation # command for GNU C++ for the case where it uses the native # linker, instead of GNU ld. If possible, this setting should # overridden to take advantage of the native linker features on # the platform it is being used on. _LT_TAGVAR(archive_cmds, $1)='$CC -shared -nostdlib $predep_objects $libobjs $deplibs $postdep_objects $compiler_flags -o $lib' fi # Commands to make compiler produce verbose output that lists # what "hidden" libraries, object files and flags are used when # linking a shared library. output_verbose_link_cmd='$CC -shared $CFLAGS -v conftest.$objext 2>&1 | $GREP "\-L"' else GXX=no with_gnu_ld=no wlarc= fi # PORTME: fill in a description of your system's C++ link characteristics AC_MSG_CHECKING([whether the $compiler linker ($LD) supports shared libraries]) _LT_TAGVAR(ld_shlibs, $1)=yes case $host_os in aix3*) # FIXME: insert proper C++ library support _LT_TAGVAR(ld_shlibs, $1)=no ;; aix[[4-9]]*) if test "$host_cpu" = ia64; then # On IA64, the linker does run time linking by default, so we don't # have to do anything special. aix_use_runtimelinking=no exp_sym_flag='-Bexport' no_entry_flag="" else aix_use_runtimelinking=no # Test if we are trying to use run time linking or normal # AIX style linking. If -brtl is somewhere in LDFLAGS, we # need to do runtime linking. case $host_os in aix4.[[23]]|aix4.[[23]].*|aix[[5-9]]*) for ld_flag in $LDFLAGS; do case $ld_flag in *-brtl*) aix_use_runtimelinking=yes break ;; esac done ;; esac exp_sym_flag='-bexport' no_entry_flag='-bnoentry' fi # When large executables or shared objects are built, AIX ld can # have problems creating the table of contents. If linking a library # or program results in "error TOC overflow" add -mminimal-toc to # CXXFLAGS/CFLAGS for g++/gcc. In the cases where that is not # enough to fix the problem, add -Wl,-bbigtoc to LDFLAGS. _LT_TAGVAR(archive_cmds, $1)='' _LT_TAGVAR(hardcode_direct, $1)=yes _LT_TAGVAR(hardcode_direct_absolute, $1)=yes _LT_TAGVAR(hardcode_libdir_separator, $1)=':' _LT_TAGVAR(link_all_deplibs, $1)=yes _LT_TAGVAR(file_list_spec, $1)='${wl}-f,' if test "$GXX" = yes; then case $host_os in aix4.[[012]]|aix4.[[012]].*) # We only want to do this on AIX 4.2 and lower, the check # below for broken collect2 doesn't work under 4.3+ collect2name=`${CC} -print-prog-name=collect2` if test -f "$collect2name" && strings "$collect2name" | $GREP resolve_lib_name >/dev/null then # We have reworked collect2 : else # We have old collect2 _LT_TAGVAR(hardcode_direct, $1)=unsupported # It fails to find uninstalled libraries when the uninstalled # path is not listed in the libpath. Setting hardcode_minus_L # to unsupported forces relinking _LT_TAGVAR(hardcode_minus_L, $1)=yes _LT_TAGVAR(hardcode_libdir_flag_spec, $1)='-L$libdir' _LT_TAGVAR(hardcode_libdir_separator, $1)= fi esac shared_flag='-shared' if test "$aix_use_runtimelinking" = yes; then shared_flag="$shared_flag "'${wl}-G' fi else # not using gcc if test "$host_cpu" = ia64; then # VisualAge C++, Version 5.5 for AIX 5L for IA-64, Beta 3 Release # chokes on -Wl,-G. The following line is correct: shared_flag='-G' else if test "$aix_use_runtimelinking" = yes; then shared_flag='${wl}-G' else shared_flag='${wl}-bM:SRE' fi fi fi _LT_TAGVAR(export_dynamic_flag_spec, $1)='${wl}-bexpall' # It seems that -bexpall does not export symbols beginning with # underscore (_), so it is better to generate a list of symbols to # export. _LT_TAGVAR(always_export_symbols, $1)=yes if test "$aix_use_runtimelinking" = yes; then # Warning - without using the other runtime loading flags (-brtl), # -berok will link without error, but may produce a broken library. _LT_TAGVAR(allow_undefined_flag, $1)='-berok' # Determine the default libpath from the value encoded in an empty # executable. _LT_SYS_MODULE_PATH_AIX _LT_TAGVAR(hardcode_libdir_flag_spec, $1)='${wl}-blibpath:$libdir:'"$aix_libpath" _LT_TAGVAR(archive_expsym_cmds, $1)='$CC -o $output_objdir/$soname $libobjs $deplibs '"\${wl}$no_entry_flag"' $compiler_flags `if test "x${allow_undefined_flag}" != "x"; then $ECHO "X${wl}${allow_undefined_flag}" | $Xsed; else :; fi` '"\${wl}$exp_sym_flag:\$export_symbols $shared_flag" else if test "$host_cpu" = ia64; then _LT_TAGVAR(hardcode_libdir_flag_spec, $1)='${wl}-R $libdir:/usr/lib:/lib' _LT_TAGVAR(allow_undefined_flag, $1)="-z nodefs" _LT_TAGVAR(archive_expsym_cmds, $1)="\$CC $shared_flag"' -o $output_objdir/$soname $libobjs $deplibs '"\${wl}$no_entry_flag"' $compiler_flags ${wl}${allow_undefined_flag} '"\${wl}$exp_sym_flag:\$export_symbols" else # Determine the default libpath from the value encoded in an # empty executable. _LT_SYS_MODULE_PATH_AIX _LT_TAGVAR(hardcode_libdir_flag_spec, $1)='${wl}-blibpath:$libdir:'"$aix_libpath" # Warning - without using the other run time loading flags, # -berok will link without error, but may produce a broken library. _LT_TAGVAR(no_undefined_flag, $1)=' ${wl}-bernotok' _LT_TAGVAR(allow_undefined_flag, $1)=' ${wl}-berok' # Exported symbols can be pulled into shared objects from archives _LT_TAGVAR(whole_archive_flag_spec, $1)='$convenience' _LT_TAGVAR(archive_cmds_need_lc, $1)=yes # This is similar to how AIX traditionally builds its shared # libraries. _LT_TAGVAR(archive_expsym_cmds, $1)="\$CC $shared_flag"' -o $output_objdir/$soname $libobjs $deplibs ${wl}-bnoentry $compiler_flags ${wl}-bE:$export_symbols${allow_undefined_flag}~$AR $AR_FLAGS $output_objdir/$libname$release.a $output_objdir/$soname' fi fi ;; beos*) if $LD --help 2>&1 | $GREP ': supported targets:.* elf' > /dev/null; then _LT_TAGVAR(allow_undefined_flag, $1)=unsupported # Joseph Beckenbach says some releases of gcc # support --undefined. This deserves some investigation. FIXME _LT_TAGVAR(archive_cmds, $1)='$CC -nostart $libobjs $deplibs $compiler_flags ${wl}-soname $wl$soname -o $lib' else _LT_TAGVAR(ld_shlibs, $1)=no fi ;; chorus*) case $cc_basename in *) # FIXME: insert proper C++ library support _LT_TAGVAR(ld_shlibs, $1)=no ;; esac ;; cygwin* | mingw* | pw32* | cegcc*) # _LT_TAGVAR(hardcode_libdir_flag_spec, $1) is actually meaningless, # as there is no search path for DLLs. _LT_TAGVAR(hardcode_libdir_flag_spec, $1)='-L$libdir' _LT_TAGVAR(allow_undefined_flag, $1)=unsupported _LT_TAGVAR(always_export_symbols, $1)=no _LT_TAGVAR(enable_shared_with_static_runtimes, $1)=yes if $LD --help 2>&1 | $GREP 'auto-import' > /dev/null; then _LT_TAGVAR(archive_cmds, $1)='$CC -shared -nostdlib $predep_objects $libobjs $deplibs $postdep_objects $compiler_flags -o $output_objdir/$soname ${wl}--enable-auto-image-base -Xlinker --out-implib -Xlinker $lib' # If the export-symbols file already is a .def file (1st line # is EXPORTS), use it as is; otherwise, prepend... _LT_TAGVAR(archive_expsym_cmds, $1)='if test "x`$SED 1q $export_symbols`" = xEXPORTS; then cp $export_symbols $output_objdir/$soname.def; else echo EXPORTS > $output_objdir/$soname.def; cat $export_symbols >> $output_objdir/$soname.def; fi~ $CC -shared -nostdlib $output_objdir/$soname.def $predep_objects $libobjs $deplibs $postdep_objects $compiler_flags -o $output_objdir/$soname ${wl}--enable-auto-image-base -Xlinker --out-implib -Xlinker $lib' else _LT_TAGVAR(ld_shlibs, $1)=no fi ;; darwin* | rhapsody*) _LT_DARWIN_LINKER_FEATURES($1) ;; dgux*) case $cc_basename in ec++*) # FIXME: insert proper C++ library support _LT_TAGVAR(ld_shlibs, $1)=no ;; ghcx*) # Green Hills C++ Compiler # FIXME: insert proper C++ library support _LT_TAGVAR(ld_shlibs, $1)=no ;; *) # FIXME: insert proper C++ library support _LT_TAGVAR(ld_shlibs, $1)=no ;; esac ;; freebsd[[12]]*) # C++ shared libraries reported to be fairly broken before # switch to ELF _LT_TAGVAR(ld_shlibs, $1)=no ;; freebsd-elf*) _LT_TAGVAR(archive_cmds_need_lc, $1)=no ;; freebsd* | dragonfly*) # FreeBSD 3 and later use GNU C++ and GNU ld with standard ELF # conventions _LT_TAGVAR(ld_shlibs, $1)=yes ;; gnu*) ;; hpux9*) _LT_TAGVAR(hardcode_libdir_flag_spec, $1)='${wl}+b ${wl}$libdir' _LT_TAGVAR(hardcode_libdir_separator, $1)=: _LT_TAGVAR(export_dynamic_flag_spec, $1)='${wl}-E' _LT_TAGVAR(hardcode_direct, $1)=yes _LT_TAGVAR(hardcode_minus_L, $1)=yes # Not in the search PATH, # but as the default # location of the library. case $cc_basename in CC*) # FIXME: insert proper C++ library support _LT_TAGVAR(ld_shlibs, $1)=no ;; aCC*) _LT_TAGVAR(archive_cmds, $1)='$RM $output_objdir/$soname~$CC -b ${wl}+b ${wl}$install_libdir -o $output_objdir/$soname $predep_objects $libobjs $deplibs $postdep_objects $compiler_flags~test $output_objdir/$soname = $lib || mv $output_objdir/$soname $lib' # Commands to make compiler produce verbose output that lists # what "hidden" libraries, object files and flags are used when # linking a shared library. # # There doesn't appear to be a way to prevent this compiler from # explicitly linking system object files so we need to strip them # from the output so that they don't get included in the library # dependencies. output_verbose_link_cmd='templist=`($CC -b $CFLAGS -v conftest.$objext 2>&1) | $EGREP "\-L"`; list=""; for z in $templist; do case $z in conftest.$objext) list="$list $z";; *.$objext);; *) list="$list $z";;esac; done; $ECHO "X$list" | $Xsed' ;; *) if test "$GXX" = yes; then _LT_TAGVAR(archive_cmds, $1)='$RM $output_objdir/$soname~$CC -shared -nostdlib -fPIC ${wl}+b ${wl}$install_libdir -o $output_objdir/$soname $predep_objects $libobjs $deplibs $postdep_objects $compiler_flags~test $output_objdir/$soname = $lib || mv $output_objdir/$soname $lib' else # FIXME: insert proper C++ library support _LT_TAGVAR(ld_shlibs, $1)=no fi ;; esac ;; hpux10*|hpux11*) if test $with_gnu_ld = no; then _LT_TAGVAR(hardcode_libdir_flag_spec, $1)='${wl}+b ${wl}$libdir' _LT_TAGVAR(hardcode_libdir_separator, $1)=: case $host_cpu in hppa*64*|ia64*) ;; *) _LT_TAGVAR(export_dynamic_flag_spec, $1)='${wl}-E' ;; esac fi case $host_cpu in hppa*64*|ia64*) _LT_TAGVAR(hardcode_direct, $1)=no _LT_TAGVAR(hardcode_shlibpath_var, $1)=no ;; *) _LT_TAGVAR(hardcode_direct, $1)=yes _LT_TAGVAR(hardcode_direct_absolute, $1)=yes _LT_TAGVAR(hardcode_minus_L, $1)=yes # Not in the search PATH, # but as the default # location of the library. ;; esac case $cc_basename in CC*) # FIXME: insert proper C++ library support _LT_TAGVAR(ld_shlibs, $1)=no ;; aCC*) case $host_cpu in hppa*64*) _LT_TAGVAR(archive_cmds, $1)='$CC -b ${wl}+h ${wl}$soname -o $lib $predep_objects $libobjs $deplibs $postdep_objects $compiler_flags' ;; ia64*) _LT_TAGVAR(archive_cmds, $1)='$CC -b ${wl}+h ${wl}$soname ${wl}+nodefaultrpath -o $lib $predep_objects $libobjs $deplibs $postdep_objects $compiler_flags' ;; *) _LT_TAGVAR(archive_cmds, $1)='$CC -b ${wl}+h ${wl}$soname ${wl}+b ${wl}$install_libdir -o $lib $predep_objects $libobjs $deplibs $postdep_objects $compiler_flags' ;; esac # Commands to make compiler produce verbose output that lists # what "hidden" libraries, object files and flags are used when # linking a shared library. # # There doesn't appear to be a way to prevent this compiler from # explicitly linking system object files so we need to strip them # from the output so that they don't get included in the library # dependencies. output_verbose_link_cmd='templist=`($CC -b $CFLAGS -v conftest.$objext 2>&1) | $GREP "\-L"`; list=""; for z in $templist; do case $z in conftest.$objext) list="$list $z";; *.$objext);; *) list="$list $z";;esac; done; $ECHO "X$list" | $Xsed' ;; *) if test "$GXX" = yes; then if test $with_gnu_ld = no; then case $host_cpu in hppa*64*) _LT_TAGVAR(archive_cmds, $1)='$CC -shared -nostdlib -fPIC ${wl}+h ${wl}$soname -o $lib $predep_objects $libobjs $deplibs $postdep_objects $compiler_flags' ;; ia64*) _LT_TAGVAR(archive_cmds, $1)='$CC -shared -nostdlib -fPIC ${wl}+h ${wl}$soname ${wl}+nodefaultrpath -o $lib $predep_objects $libobjs $deplibs $postdep_objects $compiler_flags' ;; *) _LT_TAGVAR(archive_cmds, $1)='$CC -shared -nostdlib -fPIC ${wl}+h ${wl}$soname ${wl}+b ${wl}$install_libdir -o $lib $predep_objects $libobjs $deplibs $postdep_objects $compiler_flags' ;; esac fi else # FIXME: insert proper C++ library support _LT_TAGVAR(ld_shlibs, $1)=no fi ;; esac ;; interix[[3-9]]*) _LT_TAGVAR(hardcode_direct, $1)=no _LT_TAGVAR(hardcode_shlibpath_var, $1)=no _LT_TAGVAR(hardcode_libdir_flag_spec, $1)='${wl}-rpath,$libdir' _LT_TAGVAR(export_dynamic_flag_spec, $1)='${wl}-E' # Hack: On Interix 3.x, we cannot compile PIC because of a broken gcc. # Instead, shared libraries are loaded at an image base (0x10000000 by # default) and relocated if they conflict, which is a slow very memory # consuming and fragmenting process. To avoid this, we pick a random, # 256 KiB-aligned image base between 0x50000000 and 0x6FFC0000 at link # time. Moving up from 0x10000000 also allows more sbrk(2) space. _LT_TAGVAR(archive_cmds, $1)='$CC -shared $pic_flag $libobjs $deplibs $compiler_flags ${wl}-h,$soname ${wl}--image-base,`expr ${RANDOM-$$} % 4096 / 2 \* 262144 + 1342177280` -o $lib' _LT_TAGVAR(archive_expsym_cmds, $1)='sed "s,^,_," $export_symbols >$output_objdir/$soname.expsym~$CC -shared $pic_flag $libobjs $deplibs $compiler_flags ${wl}-h,$soname ${wl}--retain-symbols-file,$output_objdir/$soname.expsym ${wl}--image-base,`expr ${RANDOM-$$} % 4096 / 2 \* 262144 + 1342177280` -o $lib' ;; irix5* | irix6*) case $cc_basename in CC*) # SGI C++ _LT_TAGVAR(archive_cmds, $1)='$CC -shared -all -multigot $predep_objects $libobjs $deplibs $postdep_objects $compiler_flags -soname $soname `test -n "$verstring" && $ECHO "X-set_version $verstring" | $Xsed` -update_registry ${output_objdir}/so_locations -o $lib' # Archives containing C++ object files must be created using # "CC -ar", where "CC" is the IRIX C++ compiler. This is # necessary to make sure instantiated templates are included # in the archive. _LT_TAGVAR(old_archive_cmds, $1)='$CC -ar -WR,-u -o $oldlib $oldobjs' ;; *) if test "$GXX" = yes; then if test "$with_gnu_ld" = no; then _LT_TAGVAR(archive_cmds, $1)='$CC -shared -nostdlib $predep_objects $libobjs $deplibs $postdep_objects $compiler_flags ${wl}-soname ${wl}$soname `test -n "$verstring" && $ECHO "X${wl}-set_version ${wl}$verstring" | $Xsed` ${wl}-update_registry ${wl}${output_objdir}/so_locations -o $lib' else _LT_TAGVAR(archive_cmds, $1)='$CC -shared -nostdlib $predep_objects $libobjs $deplibs $postdep_objects $compiler_flags ${wl}-soname ${wl}$soname `test -n "$verstring" && $ECHO "X${wl}-set_version ${wl}$verstring" | $Xsed` -o $lib' fi fi _LT_TAGVAR(link_all_deplibs, $1)=yes ;; esac _LT_TAGVAR(hardcode_libdir_flag_spec, $1)='${wl}-rpath ${wl}$libdir' _LT_TAGVAR(hardcode_libdir_separator, $1)=: _LT_TAGVAR(inherit_rpath, $1)=yes ;; linux* | k*bsd*-gnu) case $cc_basename in KCC*) # Kuck and Associates, Inc. (KAI) C++ Compiler # KCC will only create a shared library if the output file # ends with ".so" (or ".sl" for HP-UX), so rename the library # to its proper name (with version) after linking. _LT_TAGVAR(archive_cmds, $1)='tempext=`echo $shared_ext | $SED -e '\''s/\([[^()0-9A-Za-z{}]]\)/\\\\\1/g'\''`; templib=`echo $lib | $SED -e "s/\${tempext}\..*/.so/"`; $CC $predep_objects $libobjs $deplibs $postdep_objects $compiler_flags --soname $soname -o \$templib; mv \$templib $lib' _LT_TAGVAR(archive_expsym_cmds, $1)='tempext=`echo $shared_ext | $SED -e '\''s/\([[^()0-9A-Za-z{}]]\)/\\\\\1/g'\''`; templib=`echo $lib | $SED -e "s/\${tempext}\..*/.so/"`; $CC $predep_objects $libobjs $deplibs $postdep_objects $compiler_flags --soname $soname -o \$templib ${wl}-retain-symbols-file,$export_symbols; mv \$templib $lib' # Commands to make compiler produce verbose output that lists # what "hidden" libraries, object files and flags are used when # linking a shared library. # # There doesn't appear to be a way to prevent this compiler from # explicitly linking system object files so we need to strip them # from the output so that they don't get included in the library # dependencies. output_verbose_link_cmd='templist=`$CC $CFLAGS -v conftest.$objext -o libconftest$shared_ext 2>&1 | $GREP "ld"`; rm -f libconftest$shared_ext; list=""; for z in $templist; do case $z in conftest.$objext) list="$list $z";; *.$objext);; *) list="$list $z";;esac; done; $ECHO "X$list" | $Xsed' _LT_TAGVAR(hardcode_libdir_flag_spec, $1)='${wl}-rpath,$libdir' _LT_TAGVAR(export_dynamic_flag_spec, $1)='${wl}--export-dynamic' # Archives containing C++ object files must be created using # "CC -Bstatic", where "CC" is the KAI C++ compiler. _LT_TAGVAR(old_archive_cmds, $1)='$CC -Bstatic -o $oldlib $oldobjs' ;; icpc* | ecpc* ) # Intel C++ with_gnu_ld=yes # version 8.0 and above of icpc choke on multiply defined symbols # if we add $predep_objects and $postdep_objects, however 7.1 and # earlier do not add the objects themselves. case `$CC -V 2>&1` in *"Version 7."*) _LT_TAGVAR(archive_cmds, $1)='$CC -shared $predep_objects $libobjs $deplibs $postdep_objects $compiler_flags ${wl}-soname $wl$soname -o $lib' _LT_TAGVAR(archive_expsym_cmds, $1)='$CC -shared $predep_objects $libobjs $deplibs $postdep_objects $compiler_flags ${wl}-soname $wl$soname ${wl}-retain-symbols-file $wl$export_symbols -o $lib' ;; *) # Version 8.0 or newer tmp_idyn= case $host_cpu in ia64*) tmp_idyn=' -i_dynamic';; esac _LT_TAGVAR(archive_cmds, $1)='$CC -shared'"$tmp_idyn"' $libobjs $deplibs $compiler_flags ${wl}-soname $wl$soname -o $lib' _LT_TAGVAR(archive_expsym_cmds, $1)='$CC -shared'"$tmp_idyn"' $libobjs $deplibs $compiler_flags ${wl}-soname $wl$soname ${wl}-retain-symbols-file $wl$export_symbols -o $lib' ;; esac _LT_TAGVAR(archive_cmds_need_lc, $1)=no _LT_TAGVAR(hardcode_libdir_flag_spec, $1)='${wl}-rpath,$libdir' _LT_TAGVAR(export_dynamic_flag_spec, $1)='${wl}--export-dynamic' _LT_TAGVAR(whole_archive_flag_spec, $1)='${wl}--whole-archive$convenience ${wl}--no-whole-archive' ;; pgCC* | pgcpp*) # Portland Group C++ compiler case `$CC -V` in *pgCC\ [[1-5]]* | *pgcpp\ [[1-5]]*) _LT_TAGVAR(prelink_cmds, $1)='tpldir=Template.dir~ rm -rf $tpldir~ $CC --prelink_objects --instantiation_dir $tpldir $objs $libobjs $compile_deplibs~ compile_command="$compile_command `find $tpldir -name \*.o | $NL2SP`"' _LT_TAGVAR(old_archive_cmds, $1)='tpldir=Template.dir~ rm -rf $tpldir~ $CC --prelink_objects --instantiation_dir $tpldir $oldobjs$old_deplibs~ $AR $AR_FLAGS $oldlib$oldobjs$old_deplibs `find $tpldir -name \*.o | $NL2SP`~ $RANLIB $oldlib' _LT_TAGVAR(archive_cmds, $1)='tpldir=Template.dir~ rm -rf $tpldir~ $CC --prelink_objects --instantiation_dir $tpldir $predep_objects $libobjs $deplibs $convenience $postdep_objects~ $CC -shared $pic_flag $predep_objects $libobjs $deplibs `find $tpldir -name \*.o | $NL2SP` $postdep_objects $compiler_flags ${wl}-soname ${wl}$soname -o $lib' _LT_TAGVAR(archive_expsym_cmds, $1)='tpldir=Template.dir~ rm -rf $tpldir~ $CC --prelink_objects --instantiation_dir $tpldir $predep_objects $libobjs $deplibs $convenience $postdep_objects~ $CC -shared $pic_flag $predep_objects $libobjs $deplibs `find $tpldir -name \*.o | $NL2SP` $postdep_objects $compiler_flags ${wl}-soname ${wl}$soname ${wl}-retain-symbols-file ${wl}$export_symbols -o $lib' ;; *) # Version 6 will use weak symbols _LT_TAGVAR(archive_cmds, $1)='$CC -shared $pic_flag $predep_objects $libobjs $deplibs $postdep_objects $compiler_flags ${wl}-soname ${wl}$soname -o $lib' _LT_TAGVAR(archive_expsym_cmds, $1)='$CC -shared $pic_flag $predep_objects $libobjs $deplibs $postdep_objects $compiler_flags ${wl}-soname ${wl}$soname ${wl}-retain-symbols-file ${wl}$export_symbols -o $lib' ;; esac _LT_TAGVAR(hardcode_libdir_flag_spec, $1)='${wl}--rpath ${wl}$libdir' _LT_TAGVAR(export_dynamic_flag_spec, $1)='${wl}--export-dynamic' _LT_TAGVAR(whole_archive_flag_spec, $1)='${wl}--whole-archive`for conv in $convenience\"\"; do test -n \"$conv\" && new_convenience=\"$new_convenience,$conv\"; done; $ECHO \"$new_convenience\"` ${wl}--no-whole-archive' ;; cxx*) # Compaq C++ _LT_TAGVAR(archive_cmds, $1)='$CC -shared $predep_objects $libobjs $deplibs $postdep_objects $compiler_flags ${wl}-soname $wl$soname -o $lib' _LT_TAGVAR(archive_expsym_cmds, $1)='$CC -shared $predep_objects $libobjs $deplibs $postdep_objects $compiler_flags ${wl}-soname $wl$soname -o $lib ${wl}-retain-symbols-file $wl$export_symbols' runpath_var=LD_RUN_PATH _LT_TAGVAR(hardcode_libdir_flag_spec, $1)='-rpath $libdir' _LT_TAGVAR(hardcode_libdir_separator, $1)=: # Commands to make compiler produce verbose output that lists # what "hidden" libraries, object files and flags are used when # linking a shared library. # # There doesn't appear to be a way to prevent this compiler from # explicitly linking system object files so we need to strip them # from the output so that they don't get included in the library # dependencies. output_verbose_link_cmd='templist=`$CC -shared $CFLAGS -v conftest.$objext 2>&1 | $GREP "ld"`; templist=`$ECHO "X$templist" | $Xsed -e "s/\(^.*ld.*\)\( .*ld .*$\)/\1/"`; list=""; for z in $templist; do case $z in conftest.$objext) list="$list $z";; *.$objext);; *) list="$list $z";;esac; done; $ECHO "X$list" | $Xsed' ;; xl*) # IBM XL 8.0 on PPC, with GNU ld _LT_TAGVAR(hardcode_libdir_flag_spec, $1)='${wl}-rpath ${wl}$libdir' _LT_TAGVAR(export_dynamic_flag_spec, $1)='${wl}--export-dynamic' _LT_TAGVAR(archive_cmds, $1)='$CC -qmkshrobj $libobjs $deplibs $compiler_flags ${wl}-soname $wl$soname -o $lib' if test "x$supports_anon_versioning" = xyes; then _LT_TAGVAR(archive_expsym_cmds, $1)='echo "{ global:" > $output_objdir/$libname.ver~ cat $export_symbols | sed -e "s/\(.*\)/\1;/" >> $output_objdir/$libname.ver~ echo "local: *; };" >> $output_objdir/$libname.ver~ $CC -qmkshrobj $libobjs $deplibs $compiler_flags ${wl}-soname $wl$soname ${wl}-version-script ${wl}$output_objdir/$libname.ver -o $lib' fi ;; *) case `$CC -V 2>&1 | sed 5q` in *Sun\ C*) # Sun C++ 5.9 _LT_TAGVAR(no_undefined_flag, $1)=' -zdefs' _LT_TAGVAR(archive_cmds, $1)='$CC -G${allow_undefined_flag} -h$soname -o $lib $predep_objects $libobjs $deplibs $postdep_objects $compiler_flags' _LT_TAGVAR(archive_expsym_cmds, $1)='$CC -G${allow_undefined_flag} -h$soname -o $lib $predep_objects $libobjs $deplibs $postdep_objects $compiler_flags ${wl}-retain-symbols-file ${wl}$export_symbols' _LT_TAGVAR(hardcode_libdir_flag_spec, $1)='-R$libdir' _LT_TAGVAR(whole_archive_flag_spec, $1)='${wl}--whole-archive`new_convenience=; for conv in $convenience\"\"; do test -z \"$conv\" || new_convenience=\"$new_convenience,$conv\"; done; $ECHO \"$new_convenience\"` ${wl}--no-whole-archive' _LT_TAGVAR(compiler_needs_object, $1)=yes # Not sure whether something based on # $CC $CFLAGS -v conftest.$objext -o libconftest$shared_ext 2>&1 # would be better. output_verbose_link_cmd='echo' # Archives containing C++ object files must be created using # "CC -xar", where "CC" is the Sun C++ compiler. This is # necessary to make sure instantiated templates are included # in the archive. _LT_TAGVAR(old_archive_cmds, $1)='$CC -xar -o $oldlib $oldobjs' ;; esac ;; esac ;; lynxos*) # FIXME: insert proper C++ library support _LT_TAGVAR(ld_shlibs, $1)=no ;; m88k*) # FIXME: insert proper C++ library support _LT_TAGVAR(ld_shlibs, $1)=no ;; mvs*) case $cc_basename in cxx*) # FIXME: insert proper C++ library support _LT_TAGVAR(ld_shlibs, $1)=no ;; *) # FIXME: insert proper C++ library support _LT_TAGVAR(ld_shlibs, $1)=no ;; esac ;; netbsd*) if echo __ELF__ | $CC -E - | $GREP __ELF__ >/dev/null; then _LT_TAGVAR(archive_cmds, $1)='$LD -Bshareable -o $lib $predep_objects $libobjs $deplibs $postdep_objects $linker_flags' wlarc= _LT_TAGVAR(hardcode_libdir_flag_spec, $1)='-R$libdir' _LT_TAGVAR(hardcode_direct, $1)=yes _LT_TAGVAR(hardcode_shlibpath_var, $1)=no fi # Workaround some broken pre-1.5 toolchains output_verbose_link_cmd='$CC -shared $CFLAGS -v conftest.$objext 2>&1 | $GREP conftest.$objext | $SED -e "s:-lgcc -lc -lgcc::"' ;; *nto* | *qnx*) _LT_TAGVAR(ld_shlibs, $1)=yes ;; openbsd2*) # C++ shared libraries are fairly broken _LT_TAGVAR(ld_shlibs, $1)=no ;; openbsd*) if test -f /usr/libexec/ld.so; then _LT_TAGVAR(hardcode_direct, $1)=yes _LT_TAGVAR(hardcode_shlibpath_var, $1)=no _LT_TAGVAR(hardcode_direct_absolute, $1)=yes _LT_TAGVAR(archive_cmds, $1)='$CC -shared $pic_flag $predep_objects $libobjs $deplibs $postdep_objects $compiler_flags -o $lib' _LT_TAGVAR(hardcode_libdir_flag_spec, $1)='${wl}-rpath,$libdir' if test -z "`echo __ELF__ | $CC -E - | grep __ELF__`" || test "$host_os-$host_cpu" = "openbsd2.8-powerpc"; then _LT_TAGVAR(archive_expsym_cmds, $1)='$CC -shared $pic_flag $predep_objects $libobjs $deplibs $postdep_objects $compiler_flags ${wl}-retain-symbols-file,$export_symbols -o $lib' _LT_TAGVAR(export_dynamic_flag_spec, $1)='${wl}-E' _LT_TAGVAR(whole_archive_flag_spec, $1)="$wlarc"'--whole-archive$convenience '"$wlarc"'--no-whole-archive' fi output_verbose_link_cmd=echo else _LT_TAGVAR(ld_shlibs, $1)=no fi ;; osf3* | osf4* | osf5*) case $cc_basename in KCC*) # Kuck and Associates, Inc. (KAI) C++ Compiler # KCC will only create a shared library if the output file # ends with ".so" (or ".sl" for HP-UX), so rename the library # to its proper name (with version) after linking. _LT_TAGVAR(archive_cmds, $1)='tempext=`echo $shared_ext | $SED -e '\''s/\([[^()0-9A-Za-z{}]]\)/\\\\\1/g'\''`; templib=`echo "$lib" | $SED -e "s/\${tempext}\..*/.so/"`; $CC $predep_objects $libobjs $deplibs $postdep_objects $compiler_flags --soname $soname -o \$templib; mv \$templib $lib' _LT_TAGVAR(hardcode_libdir_flag_spec, $1)='${wl}-rpath,$libdir' _LT_TAGVAR(hardcode_libdir_separator, $1)=: # Archives containing C++ object files must be created using # the KAI C++ compiler. case $host in osf3*) _LT_TAGVAR(old_archive_cmds, $1)='$CC -Bstatic -o $oldlib $oldobjs' ;; *) _LT_TAGVAR(old_archive_cmds, $1)='$CC -o $oldlib $oldobjs' ;; esac ;; RCC*) # Rational C++ 2.4.1 # FIXME: insert proper C++ library support _LT_TAGVAR(ld_shlibs, $1)=no ;; cxx*) case $host in osf3*) _LT_TAGVAR(allow_undefined_flag, $1)=' ${wl}-expect_unresolved ${wl}\*' _LT_TAGVAR(archive_cmds, $1)='$CC -shared${allow_undefined_flag} $predep_objects $libobjs $deplibs $postdep_objects $compiler_flags ${wl}-soname $soname `test -n "$verstring" && $ECHO "X${wl}-set_version $verstring" | $Xsed` -update_registry ${output_objdir}/so_locations -o $lib' _LT_TAGVAR(hardcode_libdir_flag_spec, $1)='${wl}-rpath ${wl}$libdir' ;; *) _LT_TAGVAR(allow_undefined_flag, $1)=' -expect_unresolved \*' _LT_TAGVAR(archive_cmds, $1)='$CC -shared${allow_undefined_flag} $predep_objects $libobjs $deplibs $postdep_objects $compiler_flags -msym -soname $soname `test -n "$verstring" && $ECHO "X-set_version $verstring" | $Xsed` -update_registry ${output_objdir}/so_locations -o $lib' _LT_TAGVAR(archive_expsym_cmds, $1)='for i in `cat $export_symbols`; do printf "%s %s\\n" -exported_symbol "\$i" >> $lib.exp; done~ echo "-hidden">> $lib.exp~ $CC -shared$allow_undefined_flag $predep_objects $libobjs $deplibs $postdep_objects $compiler_flags -msym -soname $soname ${wl}-input ${wl}$lib.exp `test -n "$verstring" && $ECHO "X-set_version $verstring" | $Xsed` -update_registry ${output_objdir}/so_locations -o $lib~ $RM $lib.exp' _LT_TAGVAR(hardcode_libdir_flag_spec, $1)='-rpath $libdir' ;; esac _LT_TAGVAR(hardcode_libdir_separator, $1)=: # Commands to make compiler produce verbose output that lists # what "hidden" libraries, object files and flags are used when # linking a shared library. # # There doesn't appear to be a way to prevent this compiler from # explicitly linking system object files so we need to strip them # from the output so that they don't get included in the library # dependencies. output_verbose_link_cmd='templist=`$CC -shared $CFLAGS -v conftest.$objext 2>&1 | $GREP "ld" | $GREP -v "ld:"`; templist=`$ECHO "X$templist" | $Xsed -e "s/\(^.*ld.*\)\( .*ld.*$\)/\1/"`; list=""; for z in $templist; do case $z in conftest.$objext) list="$list $z";; *.$objext);; *) list="$list $z";;esac; done; $ECHO "X$list" | $Xsed' ;; *) if test "$GXX" = yes && test "$with_gnu_ld" = no; then _LT_TAGVAR(allow_undefined_flag, $1)=' ${wl}-expect_unresolved ${wl}\*' case $host in osf3*) _LT_TAGVAR(archive_cmds, $1)='$CC -shared -nostdlib ${allow_undefined_flag} $predep_objects $libobjs $deplibs $postdep_objects $compiler_flags ${wl}-soname ${wl}$soname `test -n "$verstring" && $ECHO "X${wl}-set_version ${wl}$verstring" | $Xsed` ${wl}-update_registry ${wl}${output_objdir}/so_locations -o $lib' ;; *) _LT_TAGVAR(archive_cmds, $1)='$CC -shared -nostdlib ${allow_undefined_flag} $predep_objects $libobjs $deplibs $postdep_objects $compiler_flags ${wl}-msym ${wl}-soname ${wl}$soname `test -n "$verstring" && $ECHO "${wl}-set_version ${wl}$verstring" | $Xsed` ${wl}-update_registry ${wl}${output_objdir}/so_locations -o $lib' ;; esac _LT_TAGVAR(hardcode_libdir_flag_spec, $1)='${wl}-rpath ${wl}$libdir' _LT_TAGVAR(hardcode_libdir_separator, $1)=: # Commands to make compiler produce verbose output that lists # what "hidden" libraries, object files and flags are used when # linking a shared library. output_verbose_link_cmd='$CC -shared $CFLAGS -v conftest.$objext 2>&1 | $GREP "\-L"' else # FIXME: insert proper C++ library support _LT_TAGVAR(ld_shlibs, $1)=no fi ;; esac ;; psos*) # FIXME: insert proper C++ library support _LT_TAGVAR(ld_shlibs, $1)=no ;; sunos4*) case $cc_basename in CC*) # Sun C++ 4.x # FIXME: insert proper C++ library support _LT_TAGVAR(ld_shlibs, $1)=no ;; lcc*) # Lucid # FIXME: insert proper C++ library support _LT_TAGVAR(ld_shlibs, $1)=no ;; *) # FIXME: insert proper C++ library support _LT_TAGVAR(ld_shlibs, $1)=no ;; esac ;; solaris*) case $cc_basename in CC*) # Sun C++ 4.2, 5.x and Centerline C++ _LT_TAGVAR(archive_cmds_need_lc,$1)=yes _LT_TAGVAR(no_undefined_flag, $1)=' -zdefs' _LT_TAGVAR(archive_cmds, $1)='$CC -G${allow_undefined_flag} -h$soname -o $lib $predep_objects $libobjs $deplibs $postdep_objects $compiler_flags' _LT_TAGVAR(archive_expsym_cmds, $1)='echo "{ global:" > $lib.exp~cat $export_symbols | $SED -e "s/\(.*\)/\1;/" >> $lib.exp~echo "local: *; };" >> $lib.exp~ $CC -G${allow_undefined_flag} ${wl}-M ${wl}$lib.exp -h$soname -o $lib $predep_objects $libobjs $deplibs $postdep_objects $compiler_flags~$RM $lib.exp' _LT_TAGVAR(hardcode_libdir_flag_spec, $1)='-R$libdir' _LT_TAGVAR(hardcode_shlibpath_var, $1)=no case $host_os in solaris2.[[0-5]] | solaris2.[[0-5]].*) ;; *) # The compiler driver will combine and reorder linker options, # but understands `-z linker_flag'. # Supported since Solaris 2.6 (maybe 2.5.1?) _LT_TAGVAR(whole_archive_flag_spec, $1)='-z allextract$convenience -z defaultextract' ;; esac _LT_TAGVAR(link_all_deplibs, $1)=yes output_verbose_link_cmd='echo' # Archives containing C++ object files must be created using # "CC -xar", where "CC" is the Sun C++ compiler. This is # necessary to make sure instantiated templates are included # in the archive. _LT_TAGVAR(old_archive_cmds, $1)='$CC -xar -o $oldlib $oldobjs' ;; gcx*) # Green Hills C++ Compiler _LT_TAGVAR(archive_cmds, $1)='$CC -shared $predep_objects $libobjs $deplibs $postdep_objects $compiler_flags ${wl}-h $wl$soname -o $lib' # The C++ compiler must be used to create the archive. _LT_TAGVAR(old_archive_cmds, $1)='$CC $LDFLAGS -archive -o $oldlib $oldobjs' ;; *) # GNU C++ compiler with Solaris linker if test "$GXX" = yes && test "$with_gnu_ld" = no; then _LT_TAGVAR(no_undefined_flag, $1)=' ${wl}-z ${wl}defs' if $CC --version | $GREP -v '^2\.7' > /dev/null; then _LT_TAGVAR(archive_cmds, $1)='$CC -shared -nostdlib $LDFLAGS $predep_objects $libobjs $deplibs $postdep_objects $compiler_flags ${wl}-h $wl$soname -o $lib' _LT_TAGVAR(archive_expsym_cmds, $1)='echo "{ global:" > $lib.exp~cat $export_symbols | $SED -e "s/\(.*\)/\1;/" >> $lib.exp~echo "local: *; };" >> $lib.exp~ $CC -shared -nostdlib ${wl}-M $wl$lib.exp -o $lib $predep_objects $libobjs $deplibs $postdep_objects $compiler_flags~$RM $lib.exp' # Commands to make compiler produce verbose output that lists # what "hidden" libraries, object files and flags are used when # linking a shared library. output_verbose_link_cmd='$CC -shared $CFLAGS -v conftest.$objext 2>&1 | $GREP "\-L"' else # g++ 2.7 appears to require `-G' NOT `-shared' on this # platform. _LT_TAGVAR(archive_cmds, $1)='$CC -G -nostdlib $LDFLAGS $predep_objects $libobjs $deplibs $postdep_objects $compiler_flags ${wl}-h $wl$soname -o $lib' _LT_TAGVAR(archive_expsym_cmds, $1)='echo "{ global:" > $lib.exp~cat $export_symbols | $SED -e "s/\(.*\)/\1;/" >> $lib.exp~echo "local: *; };" >> $lib.exp~ $CC -G -nostdlib ${wl}-M $wl$lib.exp -o $lib $predep_objects $libobjs $deplibs $postdep_objects $compiler_flags~$RM $lib.exp' # Commands to make compiler produce verbose output that lists # what "hidden" libraries, object files and flags are used when # linking a shared library. output_verbose_link_cmd='$CC -G $CFLAGS -v conftest.$objext 2>&1 | $GREP "\-L"' fi _LT_TAGVAR(hardcode_libdir_flag_spec, $1)='${wl}-R $wl$libdir' case $host_os in solaris2.[[0-5]] | solaris2.[[0-5]].*) ;; *) _LT_TAGVAR(whole_archive_flag_spec, $1)='${wl}-z ${wl}allextract$convenience ${wl}-z ${wl}defaultextract' ;; esac fi ;; esac ;; sysv4*uw2* | sysv5OpenUNIX* | sysv5UnixWare7.[[01]].[[10]]* | unixware7* | sco3.2v5.0.[[024]]*) _LT_TAGVAR(no_undefined_flag, $1)='${wl}-z,text' _LT_TAGVAR(archive_cmds_need_lc, $1)=no _LT_TAGVAR(hardcode_shlibpath_var, $1)=no runpath_var='LD_RUN_PATH' case $cc_basename in CC*) _LT_TAGVAR(archive_cmds, $1)='$CC -G ${wl}-h,$soname -o $lib $libobjs $deplibs $compiler_flags' _LT_TAGVAR(archive_expsym_cmds, $1)='$CC -G ${wl}-Bexport:$export_symbols ${wl}-h,$soname -o $lib $libobjs $deplibs $compiler_flags' ;; *) _LT_TAGVAR(archive_cmds, $1)='$CC -shared ${wl}-h,$soname -o $lib $libobjs $deplibs $compiler_flags' _LT_TAGVAR(archive_expsym_cmds, $1)='$CC -shared ${wl}-Bexport:$export_symbols ${wl}-h,$soname -o $lib $libobjs $deplibs $compiler_flags' ;; esac ;; sysv5* | sco3.2v5* | sco5v6*) # Note: We can NOT use -z defs as we might desire, because we do not # link with -lc, and that would cause any symbols used from libc to # always be unresolved, which means just about no library would # ever link correctly. If we're not using GNU ld we use -z text # though, which does catch some bad symbols but isn't as heavy-handed # as -z defs. _LT_TAGVAR(no_undefined_flag, $1)='${wl}-z,text' _LT_TAGVAR(allow_undefined_flag, $1)='${wl}-z,nodefs' _LT_TAGVAR(archive_cmds_need_lc, $1)=no _LT_TAGVAR(hardcode_shlibpath_var, $1)=no _LT_TAGVAR(hardcode_libdir_flag_spec, $1)='${wl}-R,$libdir' _LT_TAGVAR(hardcode_libdir_separator, $1)=':' _LT_TAGVAR(link_all_deplibs, $1)=yes _LT_TAGVAR(export_dynamic_flag_spec, $1)='${wl}-Bexport' runpath_var='LD_RUN_PATH' case $cc_basename in CC*) _LT_TAGVAR(archive_cmds, $1)='$CC -G ${wl}-h,$soname -o $lib $libobjs $deplibs $compiler_flags' _LT_TAGVAR(archive_expsym_cmds, $1)='$CC -G ${wl}-Bexport:$export_symbols ${wl}-h,$soname -o $lib $libobjs $deplibs $compiler_flags' ;; *) _LT_TAGVAR(archive_cmds, $1)='$CC -shared ${wl}-h,$soname -o $lib $libobjs $deplibs $compiler_flags' _LT_TAGVAR(archive_expsym_cmds, $1)='$CC -shared ${wl}-Bexport:$export_symbols ${wl}-h,$soname -o $lib $libobjs $deplibs $compiler_flags' ;; esac ;; tandem*) case $cc_basename in NCC*) # NonStop-UX NCC 3.20 # FIXME: insert proper C++ library support _LT_TAGVAR(ld_shlibs, $1)=no ;; *) # FIXME: insert proper C++ library support _LT_TAGVAR(ld_shlibs, $1)=no ;; esac ;; vxworks*) # FIXME: insert proper C++ library support _LT_TAGVAR(ld_shlibs, $1)=no ;; *) # FIXME: insert proper C++ library support _LT_TAGVAR(ld_shlibs, $1)=no ;; esac AC_MSG_RESULT([$_LT_TAGVAR(ld_shlibs, $1)]) test "$_LT_TAGVAR(ld_shlibs, $1)" = no && can_build_shared=no _LT_TAGVAR(GCC, $1)="$GXX" _LT_TAGVAR(LD, $1)="$LD" ## CAVEAT EMPTOR: ## There is no encapsulation within the following macros, do not change ## the running order or otherwise move them around unless you know exactly ## what you are doing... _LT_SYS_HIDDEN_LIBDEPS($1) _LT_COMPILER_PIC($1) _LT_COMPILER_C_O($1) _LT_COMPILER_FILE_LOCKS($1) _LT_LINKER_SHLIBS($1) _LT_SYS_DYNAMIC_LINKER($1) _LT_LINKER_HARDCODE_LIBPATH($1) _LT_CONFIG($1) fi # test -n "$compiler" CC=$lt_save_CC LDCXX=$LD LD=$lt_save_LD GCC=$lt_save_GCC with_gnu_ld=$lt_save_with_gnu_ld lt_cv_path_LDCXX=$lt_cv_path_LD lt_cv_path_LD=$lt_save_path_LD lt_cv_prog_gnu_ldcxx=$lt_cv_prog_gnu_ld lt_cv_prog_gnu_ld=$lt_save_with_gnu_ld fi # test "$_lt_caught_CXX_error" != yes AC_LANG_POP ])# _LT_LANG_CXX_CONFIG # _LT_SYS_HIDDEN_LIBDEPS([TAGNAME]) # --------------------------------- # Figure out "hidden" library dependencies from verbose # compiler output when linking a shared library. # Parse the compiler output and extract the necessary # objects, libraries and library flags. m4_defun([_LT_SYS_HIDDEN_LIBDEPS], [m4_require([_LT_FILEUTILS_DEFAULTS])dnl # Dependencies to place before and after the object being linked: _LT_TAGVAR(predep_objects, $1)= _LT_TAGVAR(postdep_objects, $1)= _LT_TAGVAR(predeps, $1)= _LT_TAGVAR(postdeps, $1)= _LT_TAGVAR(compiler_lib_search_path, $1)= dnl we can't use the lt_simple_compile_test_code here, dnl because it contains code intended for an executable, dnl not a library. It's possible we should let each dnl tag define a new lt_????_link_test_code variable, dnl but it's only used here... m4_if([$1], [], [cat > conftest.$ac_ext <<_LT_EOF int a; void foo (void) { a = 0; } _LT_EOF ], [$1], [CXX], [cat > conftest.$ac_ext <<_LT_EOF class Foo { public: Foo (void) { a = 0; } private: int a; }; _LT_EOF ], [$1], [F77], [cat > conftest.$ac_ext <<_LT_EOF subroutine foo implicit none integer*4 a a=0 return end _LT_EOF ], [$1], [FC], [cat > conftest.$ac_ext <<_LT_EOF subroutine foo implicit none integer a a=0 return end _LT_EOF ], [$1], [GCJ], [cat > conftest.$ac_ext <<_LT_EOF public class foo { private int a; public void bar (void) { a = 0; } }; _LT_EOF ]) dnl Parse the compiler output and extract the necessary dnl objects, libraries and library flags. if AC_TRY_EVAL(ac_compile); then # Parse the compiler output and extract the necessary # objects, libraries and library flags. # Sentinel used to keep track of whether or not we are before # the conftest object file. pre_test_object_deps_done=no for p in `eval "$output_verbose_link_cmd"`; do case $p in -L* | -R* | -l*) # Some compilers place space between "-{L,R}" and the path. # Remove the space. if test $p = "-L" || test $p = "-R"; then prev=$p continue else prev= fi if test "$pre_test_object_deps_done" = no; then case $p in -L* | -R*) # Internal compiler library paths should come after those # provided the user. The postdeps already come after the # user supplied libs so there is no need to process them. if test -z "$_LT_TAGVAR(compiler_lib_search_path, $1)"; then _LT_TAGVAR(compiler_lib_search_path, $1)="${prev}${p}" else _LT_TAGVAR(compiler_lib_search_path, $1)="${_LT_TAGVAR(compiler_lib_search_path, $1)} ${prev}${p}" fi ;; # The "-l" case would never come before the object being # linked, so don't bother handling this case. esac else if test -z "$_LT_TAGVAR(postdeps, $1)"; then _LT_TAGVAR(postdeps, $1)="${prev}${p}" else _LT_TAGVAR(postdeps, $1)="${_LT_TAGVAR(postdeps, $1)} ${prev}${p}" fi fi ;; *.$objext) # This assumes that the test object file only shows up # once in the compiler output. if test "$p" = "conftest.$objext"; then pre_test_object_deps_done=yes continue fi if test "$pre_test_object_deps_done" = no; then if test -z "$_LT_TAGVAR(predep_objects, $1)"; then _LT_TAGVAR(predep_objects, $1)="$p" else _LT_TAGVAR(predep_objects, $1)="$_LT_TAGVAR(predep_objects, $1) $p" fi else if test -z "$_LT_TAGVAR(postdep_objects, $1)"; then _LT_TAGVAR(postdep_objects, $1)="$p" else _LT_TAGVAR(postdep_objects, $1)="$_LT_TAGVAR(postdep_objects, $1) $p" fi fi ;; *) ;; # Ignore the rest. esac done # Clean up. rm -f a.out a.exe else echo "libtool.m4: error: problem compiling $1 test program" fi $RM -f confest.$objext # PORTME: override above test on systems where it is broken m4_if([$1], [CXX], [case $host_os in interix[[3-9]]*) # Interix 3.5 installs completely hosed .la files for C++, so rather than # hack all around it, let's just trust "g++" to DTRT. _LT_TAGVAR(predep_objects,$1)= _LT_TAGVAR(postdep_objects,$1)= _LT_TAGVAR(postdeps,$1)= ;; linux*) case `$CC -V 2>&1 | sed 5q` in *Sun\ C*) # Sun C++ 5.9 # The more standards-conforming stlport4 library is # incompatible with the Cstd library. Avoid specifying # it if it's in CXXFLAGS. Ignore libCrun as # -library=stlport4 depends on it. case " $CXX $CXXFLAGS " in *" -library=stlport4 "*) solaris_use_stlport4=yes ;; esac if test "$solaris_use_stlport4" != yes; then _LT_TAGVAR(postdeps,$1)='-library=Cstd -library=Crun' fi ;; esac ;; solaris*) case $cc_basename in CC*) # The more standards-conforming stlport4 library is # incompatible with the Cstd library. Avoid specifying # it if it's in CXXFLAGS. Ignore libCrun as # -library=stlport4 depends on it. case " $CXX $CXXFLAGS " in *" -library=stlport4 "*) solaris_use_stlport4=yes ;; esac # Adding this requires a known-good setup of shared libraries for # Sun compiler versions before 5.6, else PIC objects from an old # archive will be linked into the output, leading to subtle bugs. if test "$solaris_use_stlport4" != yes; then _LT_TAGVAR(postdeps,$1)='-library=Cstd -library=Crun' fi ;; esac ;; esac ]) case " $_LT_TAGVAR(postdeps, $1) " in *" -lc "*) _LT_TAGVAR(archive_cmds_need_lc, $1)=no ;; esac _LT_TAGVAR(compiler_lib_search_dirs, $1)= if test -n "${_LT_TAGVAR(compiler_lib_search_path, $1)}"; then _LT_TAGVAR(compiler_lib_search_dirs, $1)=`echo " ${_LT_TAGVAR(compiler_lib_search_path, $1)}" | ${SED} -e 's! -L! !g' -e 's!^ !!'` fi _LT_TAGDECL([], [compiler_lib_search_dirs], [1], [The directories searched by this compiler when creating a shared library]) _LT_TAGDECL([], [predep_objects], [1], [Dependencies to place before and after the objects being linked to create a shared library]) _LT_TAGDECL([], [postdep_objects], [1]) _LT_TAGDECL([], [predeps], [1]) _LT_TAGDECL([], [postdeps], [1]) _LT_TAGDECL([], [compiler_lib_search_path], [1], [The library search path used internally by the compiler when linking a shared library]) ])# _LT_SYS_HIDDEN_LIBDEPS # _LT_PROG_F77 # ------------ # Since AC_PROG_F77 is broken, in that it returns the empty string # if there is no fortran compiler, we have our own version here. m4_defun([_LT_PROG_F77], [ pushdef([AC_MSG_ERROR], [_lt_disable_F77=yes]) AC_PROG_F77 if test -z "$F77" || test "X$F77" = "Xno"; then _lt_disable_F77=yes fi popdef([AC_MSG_ERROR]) ])# _LT_PROG_F77 dnl aclocal-1.4 backwards compatibility: dnl AC_DEFUN([_LT_PROG_F77], []) # _LT_LANG_F77_CONFIG([TAG]) # -------------------------- # Ensure that the configuration variables for a Fortran 77 compiler are # suitably defined. These variables are subsequently used by _LT_CONFIG # to write the compiler configuration to `libtool'. m4_defun([_LT_LANG_F77_CONFIG], [AC_REQUIRE([_LT_PROG_F77])dnl AC_LANG_PUSH(Fortran 77) _LT_TAGVAR(archive_cmds_need_lc, $1)=no _LT_TAGVAR(allow_undefined_flag, $1)= _LT_TAGVAR(always_export_symbols, $1)=no _LT_TAGVAR(archive_expsym_cmds, $1)= _LT_TAGVAR(export_dynamic_flag_spec, $1)= _LT_TAGVAR(hardcode_direct, $1)=no _LT_TAGVAR(hardcode_direct_absolute, $1)=no _LT_TAGVAR(hardcode_libdir_flag_spec, $1)= _LT_TAGVAR(hardcode_libdir_flag_spec_ld, $1)= _LT_TAGVAR(hardcode_libdir_separator, $1)= _LT_TAGVAR(hardcode_minus_L, $1)=no _LT_TAGVAR(hardcode_automatic, $1)=no _LT_TAGVAR(inherit_rpath, $1)=no _LT_TAGVAR(module_cmds, $1)= _LT_TAGVAR(module_expsym_cmds, $1)= _LT_TAGVAR(link_all_deplibs, $1)=unknown _LT_TAGVAR(old_archive_cmds, $1)=$old_archive_cmds _LT_TAGVAR(no_undefined_flag, $1)= _LT_TAGVAR(whole_archive_flag_spec, $1)= _LT_TAGVAR(enable_shared_with_static_runtimes, $1)=no # Source file extension for f77 test sources. ac_ext=f # Object file extension for compiled f77 test sources. objext=o _LT_TAGVAR(objext, $1)=$objext # No sense in running all these tests if we already determined that # the F77 compiler isn't working. Some variables (like enable_shared) # are currently assumed to apply to all compilers on this platform, # and will be corrupted by setting them based on a non-working compiler. if test "$_lt_disable_F77" != yes; then # Code to be used in simple compile tests lt_simple_compile_test_code="\ subroutine t return end " # Code to be used in simple link tests lt_simple_link_test_code="\ program t end " # ltmain only uses $CC for tagged configurations so make sure $CC is set. _LT_TAG_COMPILER # save warnings/boilerplate of simple test code _LT_COMPILER_BOILERPLATE _LT_LINKER_BOILERPLATE # Allow CC to be a program name with arguments. lt_save_CC="$CC" lt_save_GCC=$GCC CC=${F77-"f77"} compiler=$CC _LT_TAGVAR(compiler, $1)=$CC _LT_CC_BASENAME([$compiler]) GCC=$G77 if test -n "$compiler"; then AC_MSG_CHECKING([if libtool supports shared libraries]) AC_MSG_RESULT([$can_build_shared]) AC_MSG_CHECKING([whether to build shared libraries]) test "$can_build_shared" = "no" && enable_shared=no # On AIX, shared libraries and static libraries use the same namespace, and # are all built from PIC. case $host_os in aix3*) test "$enable_shared" = yes && enable_static=no if test -n "$RANLIB"; then archive_cmds="$archive_cmds~\$RANLIB \$lib" postinstall_cmds='$RANLIB $lib' fi ;; aix[[4-9]]*) if test "$host_cpu" != ia64 && test "$aix_use_runtimelinking" = no ; then test "$enable_shared" = yes && enable_static=no fi ;; esac AC_MSG_RESULT([$enable_shared]) AC_MSG_CHECKING([whether to build static libraries]) # Make sure either enable_shared or enable_static is yes. test "$enable_shared" = yes || enable_static=yes AC_MSG_RESULT([$enable_static]) _LT_TAGVAR(GCC, $1)="$G77" _LT_TAGVAR(LD, $1)="$LD" ## CAVEAT EMPTOR: ## There is no encapsulation within the following macros, do not change ## the running order or otherwise move them around unless you know exactly ## what you are doing... _LT_COMPILER_PIC($1) _LT_COMPILER_C_O($1) _LT_COMPILER_FILE_LOCKS($1) _LT_LINKER_SHLIBS($1) _LT_SYS_DYNAMIC_LINKER($1) _LT_LINKER_HARDCODE_LIBPATH($1) _LT_CONFIG($1) fi # test -n "$compiler" GCC=$lt_save_GCC CC="$lt_save_CC" fi # test "$_lt_disable_F77" != yes AC_LANG_POP ])# _LT_LANG_F77_CONFIG # _LT_PROG_FC # ----------- # Since AC_PROG_FC is broken, in that it returns the empty string # if there is no fortran compiler, we have our own version here. m4_defun([_LT_PROG_FC], [ pushdef([AC_MSG_ERROR], [_lt_disable_FC=yes]) AC_PROG_FC if test -z "$FC" || test "X$FC" = "Xno"; then _lt_disable_FC=yes fi popdef([AC_MSG_ERROR]) ])# _LT_PROG_FC dnl aclocal-1.4 backwards compatibility: dnl AC_DEFUN([_LT_PROG_FC], []) # _LT_LANG_FC_CONFIG([TAG]) # ------------------------- # Ensure that the configuration variables for a Fortran compiler are # suitably defined. These variables are subsequently used by _LT_CONFIG # to write the compiler configuration to `libtool'. m4_defun([_LT_LANG_FC_CONFIG], [AC_REQUIRE([_LT_PROG_FC])dnl AC_LANG_PUSH(Fortran) _LT_TAGVAR(archive_cmds_need_lc, $1)=no _LT_TAGVAR(allow_undefined_flag, $1)= _LT_TAGVAR(always_export_symbols, $1)=no _LT_TAGVAR(archive_expsym_cmds, $1)= _LT_TAGVAR(export_dynamic_flag_spec, $1)= _LT_TAGVAR(hardcode_direct, $1)=no _LT_TAGVAR(hardcode_direct_absolute, $1)=no _LT_TAGVAR(hardcode_libdir_flag_spec, $1)= _LT_TAGVAR(hardcode_libdir_flag_spec_ld, $1)= _LT_TAGVAR(hardcode_libdir_separator, $1)= _LT_TAGVAR(hardcode_minus_L, $1)=no _LT_TAGVAR(hardcode_automatic, $1)=no _LT_TAGVAR(inherit_rpath, $1)=no _LT_TAGVAR(module_cmds, $1)= _LT_TAGVAR(module_expsym_cmds, $1)= _LT_TAGVAR(link_all_deplibs, $1)=unknown _LT_TAGVAR(old_archive_cmds, $1)=$old_archive_cmds _LT_TAGVAR(no_undefined_flag, $1)= _LT_TAGVAR(whole_archive_flag_spec, $1)= _LT_TAGVAR(enable_shared_with_static_runtimes, $1)=no # Source file extension for fc test sources. ac_ext=${ac_fc_srcext-f} # Object file extension for compiled fc test sources. objext=o _LT_TAGVAR(objext, $1)=$objext # No sense in running all these tests if we already determined that # the FC compiler isn't working. Some variables (like enable_shared) # are currently assumed to apply to all compilers on this platform, # and will be corrupted by setting them based on a non-working compiler. if test "$_lt_disable_FC" != yes; then # Code to be used in simple compile tests lt_simple_compile_test_code="\ subroutine t return end " # Code to be used in simple link tests lt_simple_link_test_code="\ program t end " # ltmain only uses $CC for tagged configurations so make sure $CC is set. _LT_TAG_COMPILER # save warnings/boilerplate of simple test code _LT_COMPILER_BOILERPLATE _LT_LINKER_BOILERPLATE # Allow CC to be a program name with arguments. lt_save_CC="$CC" lt_save_GCC=$GCC CC=${FC-"f95"} compiler=$CC GCC=$ac_cv_fc_compiler_gnu _LT_TAGVAR(compiler, $1)=$CC _LT_CC_BASENAME([$compiler]) if test -n "$compiler"; then AC_MSG_CHECKING([if libtool supports shared libraries]) AC_MSG_RESULT([$can_build_shared]) AC_MSG_CHECKING([whether to build shared libraries]) test "$can_build_shared" = "no" && enable_shared=no # On AIX, shared libraries and static libraries use the same namespace, and # are all built from PIC. case $host_os in aix3*) test "$enable_shared" = yes && enable_static=no if test -n "$RANLIB"; then archive_cmds="$archive_cmds~\$RANLIB \$lib" postinstall_cmds='$RANLIB $lib' fi ;; aix[[4-9]]*) if test "$host_cpu" != ia64 && test "$aix_use_runtimelinking" = no ; then test "$enable_shared" = yes && enable_static=no fi ;; esac AC_MSG_RESULT([$enable_shared]) AC_MSG_CHECKING([whether to build static libraries]) # Make sure either enable_shared or enable_static is yes. test "$enable_shared" = yes || enable_static=yes AC_MSG_RESULT([$enable_static]) _LT_TAGVAR(GCC, $1)="$ac_cv_fc_compiler_gnu" _LT_TAGVAR(LD, $1)="$LD" ## CAVEAT EMPTOR: ## There is no encapsulation within the following macros, do not change ## the running order or otherwise move them around unless you know exactly ## what you are doing... _LT_SYS_HIDDEN_LIBDEPS($1) _LT_COMPILER_PIC($1) _LT_COMPILER_C_O($1) _LT_COMPILER_FILE_LOCKS($1) _LT_LINKER_SHLIBS($1) _LT_SYS_DYNAMIC_LINKER($1) _LT_LINKER_HARDCODE_LIBPATH($1) _LT_CONFIG($1) fi # test -n "$compiler" GCC=$lt_save_GCC CC="$lt_save_CC" fi # test "$_lt_disable_FC" != yes AC_LANG_POP ])# _LT_LANG_FC_CONFIG # _LT_LANG_GCJ_CONFIG([TAG]) # -------------------------- # Ensure that the configuration variables for the GNU Java Compiler compiler # are suitably defined. These variables are subsequently used by _LT_CONFIG # to write the compiler configuration to `libtool'. m4_defun([_LT_LANG_GCJ_CONFIG], [AC_REQUIRE([LT_PROG_GCJ])dnl AC_LANG_SAVE # Source file extension for Java test sources. ac_ext=java # Object file extension for compiled Java test sources. objext=o _LT_TAGVAR(objext, $1)=$objext # Code to be used in simple compile tests lt_simple_compile_test_code="class foo {}" # Code to be used in simple link tests lt_simple_link_test_code='public class conftest { public static void main(String[[]] argv) {}; }' # ltmain only uses $CC for tagged configurations so make sure $CC is set. _LT_TAG_COMPILER # save warnings/boilerplate of simple test code _LT_COMPILER_BOILERPLATE _LT_LINKER_BOILERPLATE # Allow CC to be a program name with arguments. lt_save_CC="$CC" lt_save_GCC=$GCC GCC=yes CC=${GCJ-"gcj"} compiler=$CC _LT_TAGVAR(compiler, $1)=$CC _LT_TAGVAR(LD, $1)="$LD" _LT_CC_BASENAME([$compiler]) # GCJ did not exist at the time GCC didn't implicitly link libc in. _LT_TAGVAR(archive_cmds_need_lc, $1)=no _LT_TAGVAR(old_archive_cmds, $1)=$old_archive_cmds ## CAVEAT EMPTOR: ## There is no encapsulation within the following macros, do not change ## the running order or otherwise move them around unless you know exactly ## what you are doing... if test -n "$compiler"; then _LT_COMPILER_NO_RTTI($1) _LT_COMPILER_PIC($1) _LT_COMPILER_C_O($1) _LT_COMPILER_FILE_LOCKS($1) _LT_LINKER_SHLIBS($1) _LT_LINKER_HARDCODE_LIBPATH($1) _LT_CONFIG($1) fi AC_LANG_RESTORE GCC=$lt_save_GCC CC="$lt_save_CC" ])# _LT_LANG_GCJ_CONFIG # _LT_LANG_RC_CONFIG([TAG]) # ------------------------- # Ensure that the configuration variables for the Windows resource compiler # are suitably defined. These variables are subsequently used by _LT_CONFIG # to write the compiler configuration to `libtool'. m4_defun([_LT_LANG_RC_CONFIG], [AC_REQUIRE([LT_PROG_RC])dnl AC_LANG_SAVE # Source file extension for RC test sources. ac_ext=rc # Object file extension for compiled RC test sources. objext=o _LT_TAGVAR(objext, $1)=$objext # Code to be used in simple compile tests lt_simple_compile_test_code='sample MENU { MENUITEM "&Soup", 100, CHECKED }' # Code to be used in simple link tests lt_simple_link_test_code="$lt_simple_compile_test_code" # ltmain only uses $CC for tagged configurations so make sure $CC is set. _LT_TAG_COMPILER # save warnings/boilerplate of simple test code _LT_COMPILER_BOILERPLATE _LT_LINKER_BOILERPLATE # Allow CC to be a program name with arguments. lt_save_CC="$CC" lt_save_GCC=$GCC GCC= CC=${RC-"windres"} compiler=$CC _LT_TAGVAR(compiler, $1)=$CC _LT_CC_BASENAME([$compiler]) _LT_TAGVAR(lt_cv_prog_compiler_c_o, $1)=yes if test -n "$compiler"; then : _LT_CONFIG($1) fi GCC=$lt_save_GCC AC_LANG_RESTORE CC="$lt_save_CC" ])# _LT_LANG_RC_CONFIG # LT_PROG_GCJ # ----------- AC_DEFUN([LT_PROG_GCJ], [m4_ifdef([AC_PROG_GCJ], [AC_PROG_GCJ], [m4_ifdef([A][M_PROG_GCJ], [A][M_PROG_GCJ], [AC_CHECK_TOOL(GCJ, gcj,) test "x${GCJFLAGS+set}" = xset || GCJFLAGS="-g -O2" AC_SUBST(GCJFLAGS)])])[]dnl ]) # Old name: AU_ALIAS([LT_AC_PROG_GCJ], [LT_PROG_GCJ]) dnl aclocal-1.4 backwards compatibility: dnl AC_DEFUN([LT_AC_PROG_GCJ], []) # LT_PROG_RC # ---------- AC_DEFUN([LT_PROG_RC], [AC_CHECK_TOOL(RC, windres,) ]) # Old name: AU_ALIAS([LT_AC_PROG_RC], [LT_PROG_RC]) dnl aclocal-1.4 backwards compatibility: dnl AC_DEFUN([LT_AC_PROG_RC], []) # _LT_DECL_EGREP # -------------- # If we don't have a new enough Autoconf to choose the best grep # available, choose the one first in the user's PATH. m4_defun([_LT_DECL_EGREP], [AC_REQUIRE([AC_PROG_EGREP])dnl AC_REQUIRE([AC_PROG_FGREP])dnl test -z "$GREP" && GREP=grep _LT_DECL([], [GREP], [1], [A grep program that handles long lines]) _LT_DECL([], [EGREP], [1], [An ERE matcher]) _LT_DECL([], [FGREP], [1], [A literal string matcher]) dnl Non-bleeding-edge autoconf doesn't subst GREP, so do it here too AC_SUBST([GREP]) ]) # _LT_DECL_OBJDUMP # -------------- # If we don't have a new enough Autoconf to choose the best objdump # available, choose the one first in the user's PATH. m4_defun([_LT_DECL_OBJDUMP], [AC_CHECK_TOOL(OBJDUMP, objdump, false) test -z "$OBJDUMP" && OBJDUMP=objdump _LT_DECL([], [OBJDUMP], [1], [An object symbol dumper]) AC_SUBST([OBJDUMP]) ]) # _LT_DECL_SED # ------------ # Check for a fully-functional sed program, that truncates # as few characters as possible. Prefer GNU sed if found. m4_defun([_LT_DECL_SED], [AC_PROG_SED test -z "$SED" && SED=sed Xsed="$SED -e 1s/^X//" _LT_DECL([], [SED], [1], [A sed program that does not truncate output]) _LT_DECL([], [Xsed], ["\$SED -e 1s/^X//"], [Sed that helps us avoid accidentally triggering echo(1) options like -n]) ])# _LT_DECL_SED m4_ifndef([AC_PROG_SED], [ ############################################################ # NOTE: This macro has been submitted for inclusion into # # GNU Autoconf as AC_PROG_SED. When it is available in # # a released version of Autoconf we should remove this # # macro and use it instead. # ############################################################ m4_defun([AC_PROG_SED], [AC_MSG_CHECKING([for a sed that does not truncate output]) AC_CACHE_VAL(lt_cv_path_SED, [# Loop through the user's path and test for sed and gsed. # Then use that list of sed's as ones to test for truncation. as_save_IFS=$IFS; IFS=$PATH_SEPARATOR for as_dir in $PATH do IFS=$as_save_IFS test -z "$as_dir" && as_dir=. for lt_ac_prog in sed gsed; do for ac_exec_ext in '' $ac_executable_extensions; do if $as_executable_p "$as_dir/$lt_ac_prog$ac_exec_ext"; then lt_ac_sed_list="$lt_ac_sed_list $as_dir/$lt_ac_prog$ac_exec_ext" fi done done done IFS=$as_save_IFS lt_ac_max=0 lt_ac_count=0 # Add /usr/xpg4/bin/sed as it is typically found on Solaris # along with /bin/sed that truncates output. for lt_ac_sed in $lt_ac_sed_list /usr/xpg4/bin/sed; do test ! -f $lt_ac_sed && continue cat /dev/null > conftest.in lt_ac_count=0 echo $ECHO_N "0123456789$ECHO_C" >conftest.in # Check for GNU sed and select it if it is found. if "$lt_ac_sed" --version 2>&1 < /dev/null | grep 'GNU' > /dev/null; then lt_cv_path_SED=$lt_ac_sed break fi while true; do cat conftest.in conftest.in >conftest.tmp mv conftest.tmp conftest.in cp conftest.in conftest.nl echo >>conftest.nl $lt_ac_sed -e 's/a$//' < conftest.nl >conftest.out || break cmp -s conftest.out conftest.nl || break # 10000 chars as input seems more than enough test $lt_ac_count -gt 10 && break lt_ac_count=`expr $lt_ac_count + 1` if test $lt_ac_count -gt $lt_ac_max; then lt_ac_max=$lt_ac_count lt_cv_path_SED=$lt_ac_sed fi done done ]) SED=$lt_cv_path_SED AC_SUBST([SED]) AC_MSG_RESULT([$SED]) ])#AC_PROG_SED ])#m4_ifndef # Old name: AU_ALIAS([LT_AC_PROG_SED], [AC_PROG_SED]) dnl aclocal-1.4 backwards compatibility: dnl AC_DEFUN([LT_AC_PROG_SED], []) # _LT_CHECK_SHELL_FEATURES # ------------------------ # Find out whether the shell is Bourne or XSI compatible, # or has some other useful features. m4_defun([_LT_CHECK_SHELL_FEATURES], [AC_MSG_CHECKING([whether the shell understands some XSI constructs]) # Try some XSI features xsi_shell=no ( _lt_dummy="a/b/c" test "${_lt_dummy##*/},${_lt_dummy%/*},"${_lt_dummy%"$_lt_dummy"}, \ = c,a/b,, \ && eval 'test $(( 1 + 1 )) -eq 2 \ && test "${#_lt_dummy}" -eq 5' ) >/dev/null 2>&1 \ && xsi_shell=yes AC_MSG_RESULT([$xsi_shell]) _LT_CONFIG_LIBTOOL_INIT([xsi_shell='$xsi_shell']) AC_MSG_CHECKING([whether the shell understands "+="]) lt_shell_append=no ( foo=bar; set foo baz; eval "$[1]+=\$[2]" && test "$foo" = barbaz ) \ >/dev/null 2>&1 \ && lt_shell_append=yes AC_MSG_RESULT([$lt_shell_append]) _LT_CONFIG_LIBTOOL_INIT([lt_shell_append='$lt_shell_append']) if ( (MAIL=60; unset MAIL) || exit) >/dev/null 2>&1; then lt_unset=unset else lt_unset=false fi _LT_DECL([], [lt_unset], [0], [whether the shell understands "unset"])dnl # test EBCDIC or ASCII case `echo X|tr X '\101'` in A) # ASCII based system # \n is not interpreted correctly by Solaris 8 /usr/ucb/tr lt_SP2NL='tr \040 \012' lt_NL2SP='tr \015\012 \040\040' ;; *) # EBCDIC based system lt_SP2NL='tr \100 \n' lt_NL2SP='tr \r\n \100\100' ;; esac _LT_DECL([SP2NL], [lt_SP2NL], [1], [turn spaces into newlines])dnl _LT_DECL([NL2SP], [lt_NL2SP], [1], [turn newlines into spaces])dnl ])# _LT_CHECK_SHELL_FEATURES # _LT_PROG_XSI_SHELLFNS # --------------------- # Bourne and XSI compatible variants of some useful shell functions. m4_defun([_LT_PROG_XSI_SHELLFNS], [case $xsi_shell in yes) cat << \_LT_EOF >> "$cfgfile" # func_dirname file append nondir_replacement # Compute the dirname of FILE. If nonempty, add APPEND to the result, # otherwise set result to NONDIR_REPLACEMENT. func_dirname () { case ${1} in */*) func_dirname_result="${1%/*}${2}" ;; * ) func_dirname_result="${3}" ;; esac } # func_basename file func_basename () { func_basename_result="${1##*/}" } # func_dirname_and_basename file append nondir_replacement # perform func_basename and func_dirname in a single function # call: # dirname: Compute the dirname of FILE. If nonempty, # add APPEND to the result, otherwise set result # to NONDIR_REPLACEMENT. # value returned in "$func_dirname_result" # basename: Compute filename of FILE. # value retuned in "$func_basename_result" # Implementation must be kept synchronized with func_dirname # and func_basename. For efficiency, we do not delegate to # those functions but instead duplicate the functionality here. func_dirname_and_basename () { case ${1} in */*) func_dirname_result="${1%/*}${2}" ;; * ) func_dirname_result="${3}" ;; esac func_basename_result="${1##*/}" } # func_stripname prefix suffix name # strip PREFIX and SUFFIX off of NAME. # PREFIX and SUFFIX must not contain globbing or regex special # characters, hashes, percent signs, but SUFFIX may contain a leading # dot (in which case that matches only a dot). func_stripname () { # pdksh 5.2.14 does not do ${X%$Y} correctly if both X and Y are # positional parameters, so assign one to ordinary parameter first. func_stripname_result=${3} func_stripname_result=${func_stripname_result#"${1}"} func_stripname_result=${func_stripname_result%"${2}"} } # func_opt_split func_opt_split () { func_opt_split_opt=${1%%=*} func_opt_split_arg=${1#*=} } # func_lo2o object func_lo2o () { case ${1} in *.lo) func_lo2o_result=${1%.lo}.${objext} ;; *) func_lo2o_result=${1} ;; esac } # func_xform libobj-or-source func_xform () { func_xform_result=${1%.*}.lo } # func_arith arithmetic-term... func_arith () { func_arith_result=$(( $[*] )) } # func_len string # STRING may not start with a hyphen. func_len () { func_len_result=${#1} } _LT_EOF ;; *) # Bourne compatible functions. cat << \_LT_EOF >> "$cfgfile" # func_dirname file append nondir_replacement # Compute the dirname of FILE. If nonempty, add APPEND to the result, # otherwise set result to NONDIR_REPLACEMENT. func_dirname () { # Extract subdirectory from the argument. func_dirname_result=`$ECHO "X${1}" | $Xsed -e "$dirname"` if test "X$func_dirname_result" = "X${1}"; then func_dirname_result="${3}" else func_dirname_result="$func_dirname_result${2}" fi } # func_basename file func_basename () { func_basename_result=`$ECHO "X${1}" | $Xsed -e "$basename"` } dnl func_dirname_and_basename dnl A portable version of this function is already defined in general.m4sh dnl so there is no need for it here. # func_stripname prefix suffix name # strip PREFIX and SUFFIX off of NAME. # PREFIX and SUFFIX must not contain globbing or regex special # characters, hashes, percent signs, but SUFFIX may contain a leading # dot (in which case that matches only a dot). # func_strip_suffix prefix name func_stripname () { case ${2} in .*) func_stripname_result=`$ECHO "X${3}" \ | $Xsed -e "s%^${1}%%" -e "s%\\\\${2}\$%%"`;; *) func_stripname_result=`$ECHO "X${3}" \ | $Xsed -e "s%^${1}%%" -e "s%${2}\$%%"`;; esac } # sed scripts: my_sed_long_opt='1s/^\(-[[^=]]*\)=.*/\1/;q' my_sed_long_arg='1s/^-[[^=]]*=//' # func_opt_split func_opt_split () { func_opt_split_opt=`$ECHO "X${1}" | $Xsed -e "$my_sed_long_opt"` func_opt_split_arg=`$ECHO "X${1}" | $Xsed -e "$my_sed_long_arg"` } # func_lo2o object func_lo2o () { func_lo2o_result=`$ECHO "X${1}" | $Xsed -e "$lo2o"` } # func_xform libobj-or-source func_xform () { func_xform_result=`$ECHO "X${1}" | $Xsed -e 's/\.[[^.]]*$/.lo/'` } # func_arith arithmetic-term... func_arith () { func_arith_result=`expr "$[@]"` } # func_len string # STRING may not start with a hyphen. func_len () { func_len_result=`expr "$[1]" : ".*" 2>/dev/null || echo $max_cmd_len` } _LT_EOF esac case $lt_shell_append in yes) cat << \_LT_EOF >> "$cfgfile" # func_append var value # Append VALUE to the end of shell variable VAR. func_append () { eval "$[1]+=\$[2]" } _LT_EOF ;; *) cat << \_LT_EOF >> "$cfgfile" # func_append var value # Append VALUE to the end of shell variable VAR. func_append () { eval "$[1]=\$$[1]\$[2]" } _LT_EOF ;; esac ]) alpine-2.10+dfsg/m4/ulonglong.m40000600000175000017500000000353212074052521020132 0ustar paulproteuspaulproteus# ulonglong.m4 serial 6 dnl Copyright (C) 1999-2006 Free Software Foundation, Inc. dnl This file is free software; the Free Software Foundation dnl gives unlimited permission to copy and/or distribute it, dnl with or without modifications, as long as this notice is preserved. dnl From Paul Eggert. # Define HAVE_UNSIGNED_LONG_LONG_INT if 'unsigned long long int' works. # This fixes a bug in Autoconf 2.60, but can be removed once we # assume 2.61 everywhere. # Note: If the type 'unsigned long long int' exists but is only 32 bits # large (as on some very old compilers), AC_TYPE_UNSIGNED_LONG_LONG_INT # will not be defined. In this case you can treat 'unsigned long long int' # like 'unsigned long int'. AC_DEFUN([AC_TYPE_UNSIGNED_LONG_LONG_INT], [ AC_CACHE_CHECK([for unsigned long long int], [ac_cv_type_unsigned_long_long_int], [AC_LINK_IFELSE( [AC_LANG_PROGRAM( [[unsigned long long int ull = 18446744073709551615ULL; typedef int a[(18446744073709551615ULL <= (unsigned long long int) -1 ? 1 : -1)]; int i = 63;]], [[unsigned long long int ullmax = 18446744073709551615ull; return (ull << 63 | ull >> 63 | ull << i | ull >> i | ullmax / ull | ullmax % ull);]])], [ac_cv_type_unsigned_long_long_int=yes], [ac_cv_type_unsigned_long_long_int=no])]) if test $ac_cv_type_unsigned_long_long_int = yes; then AC_DEFINE([HAVE_UNSIGNED_LONG_LONG_INT], 1, [Define to 1 if the system has the type `unsigned long long int'.]) fi ]) # This macro is obsolescent and should go away soon. AC_DEFUN([gl_AC_TYPE_UNSIGNED_LONG_LONG], [ AC_REQUIRE([AC_TYPE_UNSIGNED_LONG_LONG_INT]) ac_cv_type_unsigned_long_long=$ac_cv_type_unsigned_long_long_int if test $ac_cv_type_unsigned_long_long = yes; then AC_DEFINE(HAVE_UNSIGNED_LONG_LONG, 1, [Define if you have the 'unsigned long long' type.]) fi ]) alpine-2.10+dfsg/m4/lcmessage.m40000600000175000017500000000240411512502114020060 0ustar paulproteuspaulproteus# lcmessage.m4 serial 4 (gettext-0.14.2) dnl Copyright (C) 1995-2002, 2004-2005 Free Software Foundation, Inc. dnl This file is free software; the Free Software Foundation dnl gives unlimited permission to copy and/or distribute it, dnl with or without modifications, as long as this notice is preserved. dnl dnl This file can can be used in projects which are not available under dnl the GNU General Public License or the GNU Library General Public dnl License but which still want to provide support for the GNU gettext dnl functionality. dnl Please note that the actual code of the GNU gettext library is covered dnl by the GNU Library General Public License, and the rest of the GNU dnl gettext package package is covered by the GNU General Public License. dnl They are *not* in the public domain. dnl Authors: dnl Ulrich Drepper , 1995. # Check whether LC_MESSAGES is available in . AC_DEFUN([gt_LC_MESSAGES], [ AC_CACHE_CHECK([for LC_MESSAGES], gt_cv_val_LC_MESSAGES, [AC_TRY_LINK([#include ], [return LC_MESSAGES], gt_cv_val_LC_MESSAGES=yes, gt_cv_val_LC_MESSAGES=no)]) if test $gt_cv_val_LC_MESSAGES = yes; then AC_DEFINE(HAVE_LC_MESSAGES, 1, [Define if your file defines LC_MESSAGES.]) fi ]) alpine-2.10+dfsg/m4/lib-prefix.m40000600000175000017500000001503612074052520020170 0ustar paulproteuspaulproteus# lib-prefix.m4 serial 5 (gettext-0.15) dnl Copyright (C) 2001-2005 Free Software Foundation, Inc. dnl This file is free software; the Free Software Foundation dnl gives unlimited permission to copy and/or distribute it, dnl with or without modifications, as long as this notice is preserved. dnl From Bruno Haible. dnl AC_LIB_ARG_WITH is synonymous to AC_ARG_WITH in autoconf-2.13, and dnl similar to AC_ARG_WITH in autoconf 2.52...2.57 except that is doesn't dnl require excessive bracketing. ifdef([AC_HELP_STRING], [AC_DEFUN([AC_LIB_ARG_WITH], [AC_ARG_WITH([$1],[[$2]],[$3],[$4])])], [AC_DEFUN([AC_][LIB_ARG_WITH], [AC_ARG_WITH([$1],[$2],[$3],[$4])])]) dnl AC_LIB_PREFIX adds to the CPPFLAGS and LDFLAGS the flags that are needed dnl to access previously installed libraries. The basic assumption is that dnl a user will want packages to use other packages he previously installed dnl with the same --prefix option. dnl This macro is not needed if only AC_LIB_LINKFLAGS is used to locate dnl libraries, but is otherwise very convenient. AC_DEFUN([AC_LIB_PREFIX], [ AC_BEFORE([$0], [AC_LIB_LINKFLAGS]) AC_REQUIRE([AC_PROG_CC]) AC_REQUIRE([AC_CANONICAL_HOST]) AC_REQUIRE([AC_LIB_PREPARE_MULTILIB]) AC_REQUIRE([AC_LIB_PREPARE_PREFIX]) dnl By default, look in $includedir and $libdir. use_additional=yes AC_LIB_WITH_FINAL_PREFIX([ eval additional_includedir=\"$includedir\" eval additional_libdir=\"$libdir\" ]) AC_LIB_ARG_WITH([lib-prefix], [ --with-lib-prefix[=DIR] search for libraries in DIR/include and DIR/lib --without-lib-prefix don't search for libraries in includedir and libdir], [ if test "X$withval" = "Xno"; then use_additional=no else if test "X$withval" = "X"; then AC_LIB_WITH_FINAL_PREFIX([ eval additional_includedir=\"$includedir\" eval additional_libdir=\"$libdir\" ]) else additional_includedir="$withval/include" additional_libdir="$withval/$acl_libdirstem" fi fi ]) if test $use_additional = yes; then dnl Potentially add $additional_includedir to $CPPFLAGS. dnl But don't add it dnl 1. if it's the standard /usr/include, dnl 2. if it's already present in $CPPFLAGS, dnl 3. if it's /usr/local/include and we are using GCC on Linux, dnl 4. if it doesn't exist as a directory. if test "X$additional_includedir" != "X/usr/include"; then haveit= for x in $CPPFLAGS; do AC_LIB_WITH_FINAL_PREFIX([eval x=\"$x\"]) if test "X$x" = "X-I$additional_includedir"; then haveit=yes break fi done if test -z "$haveit"; then if test "X$additional_includedir" = "X/usr/local/include"; then if test -n "$GCC"; then case $host_os in linux* | gnu* | k*bsd*-gnu) haveit=yes;; esac fi fi if test -z "$haveit"; then if test -d "$additional_includedir"; then dnl Really add $additional_includedir to $CPPFLAGS. CPPFLAGS="${CPPFLAGS}${CPPFLAGS:+ }-I$additional_includedir" fi fi fi fi dnl Potentially add $additional_libdir to $LDFLAGS. dnl But don't add it dnl 1. if it's the standard /usr/lib, dnl 2. if it's already present in $LDFLAGS, dnl 3. if it's /usr/local/lib and we are using GCC on Linux, dnl 4. if it doesn't exist as a directory. if test "X$additional_libdir" != "X/usr/$acl_libdirstem"; then haveit= for x in $LDFLAGS; do AC_LIB_WITH_FINAL_PREFIX([eval x=\"$x\"]) if test "X$x" = "X-L$additional_libdir"; then haveit=yes break fi done if test -z "$haveit"; then if test "X$additional_libdir" = "X/usr/local/$acl_libdirstem"; then if test -n "$GCC"; then case $host_os in linux*) haveit=yes;; esac fi fi if test -z "$haveit"; then if test -d "$additional_libdir"; then dnl Really add $additional_libdir to $LDFLAGS. LDFLAGS="${LDFLAGS}${LDFLAGS:+ }-L$additional_libdir" fi fi fi fi fi ]) dnl AC_LIB_PREPARE_PREFIX creates variables acl_final_prefix, dnl acl_final_exec_prefix, containing the values to which $prefix and dnl $exec_prefix will expand at the end of the configure script. AC_DEFUN([AC_LIB_PREPARE_PREFIX], [ dnl Unfortunately, prefix and exec_prefix get only finally determined dnl at the end of configure. if test "X$prefix" = "XNONE"; then acl_final_prefix="$ac_default_prefix" else acl_final_prefix="$prefix" fi if test "X$exec_prefix" = "XNONE"; then acl_final_exec_prefix='${prefix}' else acl_final_exec_prefix="$exec_prefix" fi acl_save_prefix="$prefix" prefix="$acl_final_prefix" eval acl_final_exec_prefix=\"$acl_final_exec_prefix\" prefix="$acl_save_prefix" ]) dnl AC_LIB_WITH_FINAL_PREFIX([statement]) evaluates statement, with the dnl variables prefix and exec_prefix bound to the values they will have dnl at the end of the configure script. AC_DEFUN([AC_LIB_WITH_FINAL_PREFIX], [ acl_save_prefix="$prefix" prefix="$acl_final_prefix" acl_save_exec_prefix="$exec_prefix" exec_prefix="$acl_final_exec_prefix" $1 exec_prefix="$acl_save_exec_prefix" prefix="$acl_save_prefix" ]) dnl AC_LIB_PREPARE_MULTILIB creates a variable acl_libdirstem, containing dnl the basename of the libdir, either "lib" or "lib64". AC_DEFUN([AC_LIB_PREPARE_MULTILIB], [ dnl There is no formal standard regarding lib and lib64. The current dnl practice is that on a system supporting 32-bit and 64-bit instruction dnl sets or ABIs, 64-bit libraries go under $prefix/lib64 and 32-bit dnl libraries go under $prefix/lib. We determine the compiler's default dnl mode by looking at the compiler's library search path. If at least dnl of its elements ends in /lib64 or points to a directory whose absolute dnl pathname ends in /lib64, we assume a 64-bit ABI. Otherwise we use the dnl default, namely "lib". acl_libdirstem=lib searchpath=`(LC_ALL=C $CC -print-search-dirs) 2>/dev/null | sed -n -e 's,^libraries: ,,p' | sed -e 's,^=,,'` if test -n "$searchpath"; then acl_save_IFS="${IFS= }"; IFS=":" for searchdir in $searchpath; do if test -d "$searchdir"; then case "$searchdir" in */lib64/ | */lib64 ) acl_libdirstem=lib64 ;; *) searchdir=`cd "$searchdir" && pwd` case "$searchdir" in */lib64 ) acl_libdirstem=lib64 ;; esac ;; esac fi done IFS="$acl_save_IFS" fi ]) alpine-2.10+dfsg/m4/nls.m40000600000175000017500000000226612074052520016724 0ustar paulproteuspaulproteus# nls.m4 serial 3 (gettext-0.15) dnl Copyright (C) 1995-2003, 2005-2006 Free Software Foundation, Inc. dnl This file is free software; the Free Software Foundation dnl gives unlimited permission to copy and/or distribute it, dnl with or without modifications, as long as this notice is preserved. dnl dnl This file can can be used in projects which are not available under dnl the GNU General Public License or the GNU Library General Public dnl License but which still want to provide support for the GNU gettext dnl functionality. dnl Please note that the actual code of the GNU gettext library is covered dnl by the GNU Library General Public License, and the rest of the GNU dnl gettext package package is covered by the GNU General Public License. dnl They are *not* in the public domain. dnl Authors: dnl Ulrich Drepper , 1995-2000. dnl Bruno Haible , 2000-2003. AC_PREREQ(2.50) AC_DEFUN([AM_NLS], [ AC_MSG_CHECKING([whether NLS is requested]) dnl Default is enabled NLS AC_ARG_ENABLE(nls, [ --disable-nls do not use Native Language Support], USE_NLS=$enableval, USE_NLS=yes) AC_MSG_RESULT($USE_NLS) AC_SUBST(USE_NLS) ]) alpine-2.10+dfsg/m4/iconv.m40000600000175000017500000000642611512502114017243 0ustar paulproteuspaulproteus# iconv.m4 serial AM4 (gettext-0.11.3) dnl Copyright (C) 2000-2002 Free Software Foundation, Inc. dnl This file is free software; the Free Software Foundation dnl gives unlimited permission to copy and/or distribute it, dnl with or without modifications, as long as this notice is preserved. dnl From Bruno Haible. AC_DEFUN([AM_ICONV_LINKFLAGS_BODY], [ dnl Prerequisites of AC_LIB_LINKFLAGS_BODY. AC_REQUIRE([AC_LIB_PREPARE_PREFIX]) AC_REQUIRE([AC_LIB_RPATH]) dnl Search for libiconv and define LIBICONV, LTLIBICONV and INCICONV dnl accordingly. AC_LIB_LINKFLAGS_BODY([iconv]) ]) AC_DEFUN([AM_ICONV_LINK], [ dnl Some systems have iconv in libc, some have it in libiconv (OSF/1 and dnl those with the standalone portable GNU libiconv installed). dnl Search for libiconv and define LIBICONV, LTLIBICONV and INCICONV dnl accordingly. AC_REQUIRE([AM_ICONV_LINKFLAGS_BODY]) dnl Add $INCICONV to CPPFLAGS before performing the following checks, dnl because if the user has installed libiconv and not disabled its use dnl via --without-libiconv-prefix, he wants to use it. The first dnl AC_TRY_LINK will then fail, the second AC_TRY_LINK will succeed. am_save_CPPFLAGS="$CPPFLAGS" AC_LIB_APPENDTOVAR([CPPFLAGS], [$INCICONV]) AC_CACHE_CHECK(for iconv, am_cv_func_iconv, [ am_cv_func_iconv="no, consider installing GNU libiconv" am_cv_lib_iconv=no AC_TRY_LINK([#include #include ], [iconv_t cd = iconv_open("",""); iconv(cd,NULL,NULL,NULL,NULL); iconv_close(cd);], am_cv_func_iconv=yes) if test "$am_cv_func_iconv" != yes; then am_save_LIBS="$LIBS" LIBS="$LIBS $LIBICONV" AC_TRY_LINK([#include #include ], [iconv_t cd = iconv_open("",""); iconv(cd,NULL,NULL,NULL,NULL); iconv_close(cd);], am_cv_lib_iconv=yes am_cv_func_iconv=yes) LIBS="$am_save_LIBS" fi ]) if test "$am_cv_func_iconv" = yes; then AC_DEFINE(HAVE_ICONV, 1, [Define if you have the iconv() function.]) fi if test "$am_cv_lib_iconv" = yes; then AC_MSG_CHECKING([how to link with libiconv]) AC_MSG_RESULT([$LIBICONV]) else dnl If $LIBICONV didn't lead to a usable library, we don't need $INCICONV dnl either. CPPFLAGS="$am_save_CPPFLAGS" LIBICONV= LTLIBICONV= fi AC_SUBST(LIBICONV) AC_SUBST(LTLIBICONV) ]) AC_DEFUN([AM_ICONV], [ AM_ICONV_LINK if test "$am_cv_func_iconv" = yes; then AC_MSG_CHECKING([for iconv declaration]) AC_CACHE_VAL(am_cv_proto_iconv, [ AC_TRY_COMPILE([ #include #include extern #ifdef __cplusplus "C" #endif #if defined(__STDC__) || defined(__cplusplus) size_t iconv (iconv_t cd, char * *inbuf, size_t *inbytesleft, char * *outbuf, size_t *outbytesleft); #else size_t iconv(); #endif ], [], am_cv_proto_iconv_arg1="", am_cv_proto_iconv_arg1="const") am_cv_proto_iconv="extern size_t iconv (iconv_t cd, $am_cv_proto_iconv_arg1 char * *inbuf, size_t *inbytesleft, char * *outbuf, size_t *outbytesleft);"]) am_cv_proto_iconv=`echo "[$]am_cv_proto_iconv" | tr -s ' ' | sed -e 's/( /(/'` AC_MSG_RESULT([$]{ac_t:- }[$]am_cv_proto_iconv) AC_DEFINE_UNQUOTED(ICONV_CONST, $am_cv_proto_iconv_arg1, [Define as const if the declaration of iconv() needs const.]) fi ]) alpine-2.10+dfsg/m4/longlong.m40000600000175000017500000000327412074052520017747 0ustar paulproteuspaulproteus# longlong.m4 serial 8 dnl Copyright (C) 1999-2006 Free Software Foundation, Inc. dnl This file is free software; the Free Software Foundation dnl gives unlimited permission to copy and/or distribute it, dnl with or without modifications, as long as this notice is preserved. dnl From Paul Eggert. # Define HAVE_LONG_LONG_INT if 'long long int' works. # This fixes a bug in Autoconf 2.60, but can be removed once we # assume 2.61 everywhere. # Note: If the type 'long long int' exists but is only 32 bits large # (as on some very old compilers), AC_TYPE_LONG_LONG_INT will not be # defined. In this case you can treat 'long long int' like 'long int'. AC_DEFUN([AC_TYPE_LONG_LONG_INT], [ AC_CACHE_CHECK([for long long int], [ac_cv_type_long_long_int], [AC_LINK_IFELSE( [AC_LANG_PROGRAM( [[long long int ll = 9223372036854775807ll; long long int nll = -9223372036854775807LL; typedef int a[((-9223372036854775807LL < 0 && 0 < 9223372036854775807ll) ? 1 : -1)]; int i = 63;]], [[long long int llmax = 9223372036854775807ll; return ((ll << 63) | (ll >> 63) | (ll < i) | (ll > i) | (llmax / ll) | (llmax % ll));]])], [ac_cv_type_long_long_int=yes], [ac_cv_type_long_long_int=no])]) if test $ac_cv_type_long_long_int = yes; then AC_DEFINE([HAVE_LONG_LONG_INT], 1, [Define to 1 if the system has the type `long long int'.]) fi ]) # This macro is obsolescent and should go away soon. AC_DEFUN([gl_AC_TYPE_LONG_LONG], [ AC_REQUIRE([AC_TYPE_LONG_LONG_INT]) ac_cv_type_long_long=$ac_cv_type_long_long_int if test $ac_cv_type_long_long = yes; then AC_DEFINE(HAVE_LONG_LONG, 1, [Define if you have the 'long long' type.]) fi ]) alpine-2.10+dfsg/m4/gettext.m40000600000175000017500000003773212074052520017622 0ustar paulproteuspaulproteus# gettext.m4 serial 59 (gettext-0.16.1) dnl Copyright (C) 1995-2006 Free Software Foundation, Inc. dnl This file is free software; the Free Software Foundation dnl gives unlimited permission to copy and/or distribute it, dnl with or without modifications, as long as this notice is preserved. dnl dnl This file can can be used in projects which are not available under dnl the GNU General Public License or the GNU Library General Public dnl License but which still want to provide support for the GNU gettext dnl functionality. dnl Please note that the actual code of the GNU gettext library is covered dnl by the GNU Library General Public License, and the rest of the GNU dnl gettext package package is covered by the GNU General Public License. dnl They are *not* in the public domain. dnl Authors: dnl Ulrich Drepper , 1995-2000. dnl Bruno Haible , 2000-2006. dnl Macro to add for using GNU gettext. dnl Usage: AM_GNU_GETTEXT([INTLSYMBOL], [NEEDSYMBOL], [INTLDIR]). dnl INTLSYMBOL can be one of 'external', 'no-libtool', 'use-libtool'. The dnl default (if it is not specified or empty) is 'no-libtool'. dnl INTLSYMBOL should be 'external' for packages with no intl directory, dnl and 'no-libtool' or 'use-libtool' for packages with an intl directory. dnl If INTLSYMBOL is 'use-libtool', then a libtool library dnl $(top_builddir)/intl/libintl.la will be created (shared and/or static, dnl depending on --{enable,disable}-{shared,static} and on the presence of dnl AM-DISABLE-SHARED). If INTLSYMBOL is 'no-libtool', a static library dnl $(top_builddir)/intl/libintl.a will be created. dnl If NEEDSYMBOL is specified and is 'need-ngettext', then GNU gettext dnl implementations (in libc or libintl) without the ngettext() function dnl will be ignored. If NEEDSYMBOL is specified and is dnl 'need-formatstring-macros', then GNU gettext implementations that don't dnl support the ISO C 99 formatstring macros will be ignored. dnl INTLDIR is used to find the intl libraries. If empty, dnl the value `$(top_builddir)/intl/' is used. dnl dnl The result of the configuration is one of three cases: dnl 1) GNU gettext, as included in the intl subdirectory, will be compiled dnl and used. dnl Catalog format: GNU --> install in $(datadir) dnl Catalog extension: .mo after installation, .gmo in source tree dnl 2) GNU gettext has been found in the system's C library. dnl Catalog format: GNU --> install in $(datadir) dnl Catalog extension: .mo after installation, .gmo in source tree dnl 3) No internationalization, always use English msgid. dnl Catalog format: none dnl Catalog extension: none dnl If INTLSYMBOL is 'external', only cases 2 and 3 can occur. dnl The use of .gmo is historical (it was needed to avoid overwriting the dnl GNU format catalogs when building on a platform with an X/Open gettext), dnl but we keep it in order not to force irrelevant filename changes on the dnl maintainers. dnl AC_DEFUN([AM_GNU_GETTEXT], [ dnl Argument checking. ifelse([$1], [], , [ifelse([$1], [external], , [ifelse([$1], [no-libtool], , [ifelse([$1], [use-libtool], , [errprint([ERROR: invalid first argument to AM_GNU_GETTEXT ])])])])]) ifelse([$2], [], , [ifelse([$2], [need-ngettext], , [ifelse([$2], [need-formatstring-macros], , [errprint([ERROR: invalid second argument to AM_GNU_GETTEXT ])])])]) define([gt_included_intl], ifelse([$1], [external], ifdef([AM_GNU_GETTEXT_][INTL_SUBDIR], [yes], [no]), [yes])) define([gt_libtool_suffix_prefix], ifelse([$1], [use-libtool], [l], [])) gt_NEEDS_INIT AM_GNU_GETTEXT_NEED([$2]) AC_REQUIRE([AM_PO_SUBDIRS])dnl ifelse(gt_included_intl, yes, [ AC_REQUIRE([AM_INTL_SUBDIR])dnl ]) dnl Prerequisites of AC_LIB_LINKFLAGS_BODY. AC_REQUIRE([AC_LIB_PREPARE_PREFIX]) AC_REQUIRE([AC_LIB_RPATH]) dnl Sometimes libintl requires libiconv, so first search for libiconv. dnl Ideally we would do this search only after the dnl if test "$USE_NLS" = "yes"; then dnl if { eval "gt_val=\$$gt_func_gnugettext_libc"; test "$gt_val" != "yes"; }; then dnl tests. But if configure.in invokes AM_ICONV after AM_GNU_GETTEXT dnl the configure script would need to contain the same shell code dnl again, outside any 'if'. There are two solutions: dnl - Invoke AM_ICONV_LINKFLAGS_BODY here, outside any 'if'. dnl - Control the expansions in more detail using AC_PROVIDE_IFELSE. dnl Since AC_PROVIDE_IFELSE is only in autoconf >= 2.52 and not dnl documented, we avoid it. ifelse(gt_included_intl, yes, , [ AC_REQUIRE([AM_ICONV_LINKFLAGS_BODY]) ]) dnl Sometimes, on MacOS X, libintl requires linking with CoreFoundation. gt_INTL_MACOSX dnl Set USE_NLS. AC_REQUIRE([AM_NLS]) ifelse(gt_included_intl, yes, [ BUILD_INCLUDED_LIBINTL=no USE_INCLUDED_LIBINTL=no ]) LIBINTL= LTLIBINTL= POSUB= dnl Add a version number to the cache macros. case " $gt_needs " in *" need-formatstring-macros "*) gt_api_version=3 ;; *" need-ngettext "*) gt_api_version=2 ;; *) gt_api_version=1 ;; esac gt_func_gnugettext_libc="gt_cv_func_gnugettext${gt_api_version}_libc" gt_func_gnugettext_libintl="gt_cv_func_gnugettext${gt_api_version}_libintl" dnl If we use NLS figure out what method if test "$USE_NLS" = "yes"; then gt_use_preinstalled_gnugettext=no ifelse(gt_included_intl, yes, [ AC_MSG_CHECKING([whether included gettext is requested]) AC_ARG_WITH(included-gettext, [ --with-included-gettext use the GNU gettext library included here], nls_cv_force_use_gnu_gettext=$withval, nls_cv_force_use_gnu_gettext=no) AC_MSG_RESULT($nls_cv_force_use_gnu_gettext) nls_cv_use_gnu_gettext="$nls_cv_force_use_gnu_gettext" if test "$nls_cv_force_use_gnu_gettext" != "yes"; then ]) dnl User does not insist on using GNU NLS library. Figure out what dnl to use. If GNU gettext is available we use this. Else we have dnl to fall back to GNU NLS library. if test $gt_api_version -ge 3; then gt_revision_test_code=' #ifndef __GNU_GETTEXT_SUPPORTED_REVISION #define __GNU_GETTEXT_SUPPORTED_REVISION(major) ((major) == 0 ? 0 : -1) #endif changequote(,)dnl typedef int array [2 * (__GNU_GETTEXT_SUPPORTED_REVISION(0) >= 1) - 1]; changequote([,])dnl ' else gt_revision_test_code= fi if test $gt_api_version -ge 2; then gt_expression_test_code=' + * ngettext ("", "", 0)' else gt_expression_test_code= fi AC_CACHE_CHECK([for GNU gettext in libc], [$gt_func_gnugettext_libc], [AC_TRY_LINK([#include $gt_revision_test_code extern int _nl_msg_cat_cntr; extern int *_nl_domain_bindings;], [bindtextdomain ("", ""); return * gettext ("")$gt_expression_test_code + _nl_msg_cat_cntr + *_nl_domain_bindings], [eval "$gt_func_gnugettext_libc=yes"], [eval "$gt_func_gnugettext_libc=no"])]) if { eval "gt_val=\$$gt_func_gnugettext_libc"; test "$gt_val" != "yes"; }; then dnl Sometimes libintl requires libiconv, so first search for libiconv. ifelse(gt_included_intl, yes, , [ AM_ICONV_LINK ]) dnl Search for libintl and define LIBINTL, LTLIBINTL and INCINTL dnl accordingly. Don't use AC_LIB_LINKFLAGS_BODY([intl],[iconv]) dnl because that would add "-liconv" to LIBINTL and LTLIBINTL dnl even if libiconv doesn't exist. AC_LIB_LINKFLAGS_BODY([intl]) AC_CACHE_CHECK([for GNU gettext in libintl], [$gt_func_gnugettext_libintl], [gt_save_CPPFLAGS="$CPPFLAGS" CPPFLAGS="$CPPFLAGS $INCINTL" gt_save_LIBS="$LIBS" LIBS="$LIBS $LIBINTL" dnl Now see whether libintl exists and does not depend on libiconv. AC_TRY_LINK([#include $gt_revision_test_code extern int _nl_msg_cat_cntr; extern #ifdef __cplusplus "C" #endif const char *_nl_expand_alias (const char *);], [bindtextdomain ("", ""); return * gettext ("")$gt_expression_test_code + _nl_msg_cat_cntr + *_nl_expand_alias ("")], [eval "$gt_func_gnugettext_libintl=yes"], [eval "$gt_func_gnugettext_libintl=no"]) dnl Now see whether libintl exists and depends on libiconv. if { eval "gt_val=\$$gt_func_gnugettext_libintl"; test "$gt_val" != yes; } && test -n "$LIBICONV"; then LIBS="$LIBS $LIBICONV" AC_TRY_LINK([#include $gt_revision_test_code extern int _nl_msg_cat_cntr; extern #ifdef __cplusplus "C" #endif const char *_nl_expand_alias (const char *);], [bindtextdomain ("", ""); return * gettext ("")$gt_expression_test_code + _nl_msg_cat_cntr + *_nl_expand_alias ("")], [LIBINTL="$LIBINTL $LIBICONV" LTLIBINTL="$LTLIBINTL $LTLIBICONV" eval "$gt_func_gnugettext_libintl=yes" ]) fi CPPFLAGS="$gt_save_CPPFLAGS" LIBS="$gt_save_LIBS"]) fi dnl If an already present or preinstalled GNU gettext() is found, dnl use it. But if this macro is used in GNU gettext, and GNU dnl gettext is already preinstalled in libintl, we update this dnl libintl. (Cf. the install rule in intl/Makefile.in.) if { eval "gt_val=\$$gt_func_gnugettext_libc"; test "$gt_val" = "yes"; } \ || { { eval "gt_val=\$$gt_func_gnugettext_libintl"; test "$gt_val" = "yes"; } \ && test "$PACKAGE" != gettext-runtime \ && test "$PACKAGE" != gettext-tools; }; then gt_use_preinstalled_gnugettext=yes else dnl Reset the values set by searching for libintl. LIBINTL= LTLIBINTL= INCINTL= fi ifelse(gt_included_intl, yes, [ if test "$gt_use_preinstalled_gnugettext" != "yes"; then dnl GNU gettext is not found in the C library. dnl Fall back on included GNU gettext library. nls_cv_use_gnu_gettext=yes fi fi if test "$nls_cv_use_gnu_gettext" = "yes"; then dnl Mark actions used to generate GNU NLS library. BUILD_INCLUDED_LIBINTL=yes USE_INCLUDED_LIBINTL=yes LIBINTL="ifelse([$3],[],\${top_builddir}/intl,[$3])/libintl.[]gt_libtool_suffix_prefix[]a $LIBICONV $LIBTHREAD" LTLIBINTL="ifelse([$3],[],\${top_builddir}/intl,[$3])/libintl.[]gt_libtool_suffix_prefix[]a $LTLIBICONV $LTLIBTHREAD" LIBS=`echo " $LIBS " | sed -e 's/ -lintl / /' -e 's/^ //' -e 's/ $//'` fi CATOBJEXT= if test "$gt_use_preinstalled_gnugettext" = "yes" \ || test "$nls_cv_use_gnu_gettext" = "yes"; then dnl Mark actions to use GNU gettext tools. CATOBJEXT=.gmo fi ]) if test -n "$INTL_MACOSX_LIBS"; then if test "$gt_use_preinstalled_gnugettext" = "yes" \ || test "$nls_cv_use_gnu_gettext" = "yes"; then dnl Some extra flags are needed during linking. LIBINTL="$LIBINTL $INTL_MACOSX_LIBS" LTLIBINTL="$LTLIBINTL $INTL_MACOSX_LIBS" fi fi if test "$gt_use_preinstalled_gnugettext" = "yes" \ || test "$nls_cv_use_gnu_gettext" = "yes"; then AC_DEFINE(ENABLE_NLS, 1, [Define to 1 if translation of program messages to the user's native language is requested.]) else USE_NLS=no fi fi AC_MSG_CHECKING([whether to use NLS]) AC_MSG_RESULT([$USE_NLS]) if test "$USE_NLS" = "yes"; then AC_MSG_CHECKING([where the gettext function comes from]) if test "$gt_use_preinstalled_gnugettext" = "yes"; then if { eval "gt_val=\$$gt_func_gnugettext_libintl"; test "$gt_val" = "yes"; }; then gt_source="external libintl" else gt_source="libc" fi else gt_source="included intl directory" fi AC_MSG_RESULT([$gt_source]) fi if test "$USE_NLS" = "yes"; then if test "$gt_use_preinstalled_gnugettext" = "yes"; then if { eval "gt_val=\$$gt_func_gnugettext_libintl"; test "$gt_val" = "yes"; }; then AC_MSG_CHECKING([how to link with libintl]) AC_MSG_RESULT([$LIBINTL]) AC_LIB_APPENDTOVAR([CPPFLAGS], [$INCINTL]) fi dnl For backward compatibility. Some packages may be using this. AC_DEFINE(HAVE_GETTEXT, 1, [Define if the GNU gettext() function is already present or preinstalled.]) AC_DEFINE(HAVE_DCGETTEXT, 1, [Define if the GNU dcgettext() function is already present or preinstalled.]) fi dnl We need to process the po/ directory. POSUB=po fi ifelse(gt_included_intl, yes, [ dnl If this is used in GNU gettext we have to set BUILD_INCLUDED_LIBINTL dnl to 'yes' because some of the testsuite requires it. if test "$PACKAGE" = gettext-runtime || test "$PACKAGE" = gettext-tools; then BUILD_INCLUDED_LIBINTL=yes fi dnl Make all variables we use known to autoconf. AC_SUBST(BUILD_INCLUDED_LIBINTL) AC_SUBST(USE_INCLUDED_LIBINTL) AC_SUBST(CATOBJEXT) dnl For backward compatibility. Some configure.ins may be using this. nls_cv_header_intl= nls_cv_header_libgt= dnl For backward compatibility. Some Makefiles may be using this. DATADIRNAME=share AC_SUBST(DATADIRNAME) dnl For backward compatibility. Some Makefiles may be using this. INSTOBJEXT=.mo AC_SUBST(INSTOBJEXT) dnl For backward compatibility. Some Makefiles may be using this. GENCAT=gencat AC_SUBST(GENCAT) dnl For backward compatibility. Some Makefiles may be using this. INTLOBJS= if test "$USE_INCLUDED_LIBINTL" = yes; then INTLOBJS="\$(GETTOBJS)" fi AC_SUBST(INTLOBJS) dnl Enable libtool support if the surrounding package wishes it. INTL_LIBTOOL_SUFFIX_PREFIX=gt_libtool_suffix_prefix AC_SUBST(INTL_LIBTOOL_SUFFIX_PREFIX) ]) dnl For backward compatibility. Some Makefiles may be using this. INTLLIBS="$LIBINTL" AC_SUBST(INTLLIBS) dnl Make all documented variables known to autoconf. AC_SUBST(LIBINTL) AC_SUBST(LTLIBINTL) AC_SUBST(POSUB) ]) dnl Checks for special options needed on MacOS X. dnl Defines INTL_MACOSX_LIBS. AC_DEFUN([gt_INTL_MACOSX], [ dnl Check for API introduced in MacOS X 10.2. AC_CACHE_CHECK([for CFPreferencesCopyAppValue], gt_cv_func_CFPreferencesCopyAppValue, [gt_save_LIBS="$LIBS" LIBS="$LIBS -Wl,-framework -Wl,CoreFoundation" AC_TRY_LINK([#include ], [CFPreferencesCopyAppValue(NULL, NULL)], [gt_cv_func_CFPreferencesCopyAppValue=yes], [gt_cv_func_CFPreferencesCopyAppValue=no]) LIBS="$gt_save_LIBS"]) if test $gt_cv_func_CFPreferencesCopyAppValue = yes; then AC_DEFINE([HAVE_CFPREFERENCESCOPYAPPVALUE], 1, [Define to 1 if you have the MacOS X function CFPreferencesCopyAppValue in the CoreFoundation framework.]) fi dnl Check for API introduced in MacOS X 10.3. AC_CACHE_CHECK([for CFLocaleCopyCurrent], gt_cv_func_CFLocaleCopyCurrent, [gt_save_LIBS="$LIBS" LIBS="$LIBS -Wl,-framework -Wl,CoreFoundation" AC_TRY_LINK([#include ], [CFLocaleCopyCurrent();], [gt_cv_func_CFLocaleCopyCurrent=yes], [gt_cv_func_CFLocaleCopyCurrent=no]) LIBS="$gt_save_LIBS"]) if test $gt_cv_func_CFLocaleCopyCurrent = yes; then AC_DEFINE([HAVE_CFLOCALECOPYCURRENT], 1, [Define to 1 if you have the MacOS X function CFLocaleCopyCurrent in the CoreFoundation framework.]) fi INTL_MACOSX_LIBS= if test $gt_cv_func_CFPreferencesCopyAppValue = yes || test $gt_cv_func_CFLocaleCopyCurrent = yes; then INTL_MACOSX_LIBS="-Wl,-framework -Wl,CoreFoundation" fi AC_SUBST([INTL_MACOSX_LIBS]) ]) dnl gt_NEEDS_INIT ensures that the gt_needs variable is initialized. m4_define([gt_NEEDS_INIT], [ m4_divert_text([DEFAULTS], [gt_needs=]) m4_define([gt_NEEDS_INIT], []) ]) dnl Usage: AM_GNU_GETTEXT_NEED([NEEDSYMBOL]) AC_DEFUN([AM_GNU_GETTEXT_NEED], [ m4_divert_text([INIT_PREPARE], [gt_needs="$gt_needs $1"]) ]) dnl Usage: AM_GNU_GETTEXT_VERSION([gettext-version]) AC_DEFUN([AM_GNU_GETTEXT_VERSION], []) alpine-2.10+dfsg/m4/intldir.m40000600000175000017500000000161612074052520017573 0ustar paulproteuspaulproteus# intldir.m4 serial 1 (gettext-0.16) dnl Copyright (C) 2006 Free Software Foundation, Inc. dnl This file is free software; the Free Software Foundation dnl gives unlimited permission to copy and/or distribute it, dnl with or without modifications, as long as this notice is preserved. dnl dnl This file can can be used in projects which are not available under dnl the GNU General Public License or the GNU Library General Public dnl License but which still want to provide support for the GNU gettext dnl functionality. dnl Please note that the actual code of the GNU gettext library is covered dnl by the GNU Library General Public License, and the rest of the GNU dnl gettext package package is covered by the GNU General Public License. dnl They are *not* in the public domain. AC_PREREQ(2.52) dnl Tells the AM_GNU_GETTEXT macro to consider an intl/ directory. AC_DEFUN([AM_GNU_GETTEXT_INTL_SUBDIR], []) alpine-2.10+dfsg/m4/intdiv0.m40000600000175000017500000000334011512502114017472 0ustar paulproteuspaulproteus# intdiv0.m4 serial 1 (gettext-0.11.3) dnl Copyright (C) 2002 Free Software Foundation, Inc. dnl This file is free software; the Free Software Foundation dnl gives unlimited permission to copy and/or distribute it, dnl with or without modifications, as long as this notice is preserved. dnl From Bruno Haible. AC_DEFUN([gt_INTDIV0], [ AC_REQUIRE([AC_PROG_CC])dnl AC_REQUIRE([AC_CANONICAL_HOST])dnl AC_CACHE_CHECK([whether integer division by zero raises SIGFPE], gt_cv_int_divbyzero_sigfpe, [ AC_TRY_RUN([ #include #include static void #ifdef __cplusplus sigfpe_handler (int sig) #else sigfpe_handler (sig) int sig; #endif { /* Exit with code 0 if SIGFPE, with code 1 if any other signal. */ exit (sig != SIGFPE); } int x = 1; int y = 0; int z; int nan; int main () { signal (SIGFPE, sigfpe_handler); /* IRIX and AIX (when "xlc -qcheck" is used) yield signal SIGTRAP. */ #if (defined (__sgi) || defined (_AIX)) && defined (SIGTRAP) signal (SIGTRAP, sigfpe_handler); #endif /* Linux/SPARC yields signal SIGILL. */ #if defined (__sparc__) && defined (__linux__) signal (SIGILL, sigfpe_handler); #endif z = x / y; nan = y / y; exit (1); } ], gt_cv_int_divbyzero_sigfpe=yes, gt_cv_int_divbyzero_sigfpe=no, [ # Guess based on the CPU. case "$host_cpu" in alpha* | i[34567]86 | m68k | s390*) gt_cv_int_divbyzero_sigfpe="guessing yes";; *) gt_cv_int_divbyzero_sigfpe="guessing no";; esac ]) ]) case "$gt_cv_int_divbyzero_sigfpe" in *yes) value=1;; *) value=0;; esac AC_DEFINE_UNQUOTED(INTDIV0_RAISES_SIGFPE, $value, [Define if integer division by zero raises signal SIGFPE.]) ]) alpine-2.10+dfsg/m4/longdouble.m40000600000175000017500000000227712074052520020264 0ustar paulproteuspaulproteus# longdouble.m4 serial 2 (gettext-0.15) dnl Copyright (C) 2002-2003, 2006 Free Software Foundation, Inc. dnl This file is free software; the Free Software Foundation dnl gives unlimited permission to copy and/or distribute it, dnl with or without modifications, as long as this notice is preserved. dnl From Bruno Haible. dnl Test whether the compiler supports the 'long double' type. dnl Prerequisite: AC_PROG_CC dnl This file is only needed in autoconf <= 2.59. Newer versions of autoconf dnl have a macro AC_TYPE_LONG_DOUBLE with identical semantics. AC_DEFUN([gt_TYPE_LONGDOUBLE], [ AC_CACHE_CHECK([for long double], gt_cv_c_long_double, [if test "$GCC" = yes; then gt_cv_c_long_double=yes else AC_TRY_COMPILE([ /* The Stardent Vistra knows sizeof(long double), but does not support it. */ long double foo = 0.0; /* On Ultrix 4.3 cc, long double is 4 and double is 8. */ int array [2*(sizeof(long double) >= sizeof(double)) - 1]; ], , gt_cv_c_long_double=yes, gt_cv_c_long_double=no) fi]) if test $gt_cv_c_long_double = yes; then AC_DEFINE(HAVE_LONG_DOUBLE, 1, [Define if you have the 'long double' type.]) fi ]) alpine-2.10+dfsg/m4/ltoptions.m40000600000175000017500000002724212074110240020156 0ustar paulproteuspaulproteus# Helper functions for option handling. -*- Autoconf -*- # # Copyright (C) 2004, 2005, 2007, 2008 Free Software Foundation, Inc. # Written by Gary V. Vaughan, 2004 # # This file is free software; the Free Software Foundation gives # unlimited permission to copy and/or distribute it, with or without # modifications, as long as this notice is preserved. # serial 6 ltoptions.m4 # This is to help aclocal find these macros, as it can't see m4_define. AC_DEFUN([LTOPTIONS_VERSION], [m4_if([1])]) # _LT_MANGLE_OPTION(MACRO-NAME, OPTION-NAME) # ------------------------------------------ m4_define([_LT_MANGLE_OPTION], [[_LT_OPTION_]m4_bpatsubst($1__$2, [[^a-zA-Z0-9_]], [_])]) # _LT_SET_OPTION(MACRO-NAME, OPTION-NAME) # --------------------------------------- # Set option OPTION-NAME for macro MACRO-NAME, and if there is a # matching handler defined, dispatch to it. Other OPTION-NAMEs are # saved as a flag. m4_define([_LT_SET_OPTION], [m4_define(_LT_MANGLE_OPTION([$1], [$2]))dnl m4_ifdef(_LT_MANGLE_DEFUN([$1], [$2]), _LT_MANGLE_DEFUN([$1], [$2]), [m4_warning([Unknown $1 option `$2'])])[]dnl ]) # _LT_IF_OPTION(MACRO-NAME, OPTION-NAME, IF-SET, [IF-NOT-SET]) # ------------------------------------------------------------ # Execute IF-SET if OPTION is set, IF-NOT-SET otherwise. m4_define([_LT_IF_OPTION], [m4_ifdef(_LT_MANGLE_OPTION([$1], [$2]), [$3], [$4])]) # _LT_UNLESS_OPTIONS(MACRO-NAME, OPTION-LIST, IF-NOT-SET) # ------------------------------------------------------- # Execute IF-NOT-SET unless all options in OPTION-LIST for MACRO-NAME # are set. m4_define([_LT_UNLESS_OPTIONS], [m4_foreach([_LT_Option], m4_split(m4_normalize([$2])), [m4_ifdef(_LT_MANGLE_OPTION([$1], _LT_Option), [m4_define([$0_found])])])[]dnl m4_ifdef([$0_found], [m4_undefine([$0_found])], [$3 ])[]dnl ]) # _LT_SET_OPTIONS(MACRO-NAME, OPTION-LIST) # ---------------------------------------- # OPTION-LIST is a space-separated list of Libtool options associated # with MACRO-NAME. If any OPTION has a matching handler declared with # LT_OPTION_DEFINE, dispatch to that macro; otherwise complain about # the unknown option and exit. m4_defun([_LT_SET_OPTIONS], [# Set options m4_foreach([_LT_Option], m4_split(m4_normalize([$2])), [_LT_SET_OPTION([$1], _LT_Option)]) m4_if([$1],[LT_INIT],[ dnl dnl Simply set some default values (i.e off) if boolean options were not dnl specified: _LT_UNLESS_OPTIONS([LT_INIT], [dlopen], [enable_dlopen=no ]) _LT_UNLESS_OPTIONS([LT_INIT], [win32-dll], [enable_win32_dll=no ]) dnl dnl If no reference was made to various pairs of opposing options, then dnl we run the default mode handler for the pair. For example, if neither dnl `shared' nor `disable-shared' was passed, we enable building of shared dnl archives by default: _LT_UNLESS_OPTIONS([LT_INIT], [shared disable-shared], [_LT_ENABLE_SHARED]) _LT_UNLESS_OPTIONS([LT_INIT], [static disable-static], [_LT_ENABLE_STATIC]) _LT_UNLESS_OPTIONS([LT_INIT], [pic-only no-pic], [_LT_WITH_PIC]) _LT_UNLESS_OPTIONS([LT_INIT], [fast-install disable-fast-install], [_LT_ENABLE_FAST_INSTALL]) ]) ])# _LT_SET_OPTIONS ## --------------------------------- ## ## Macros to handle LT_INIT options. ## ## --------------------------------- ## # _LT_MANGLE_DEFUN(MACRO-NAME, OPTION-NAME) # ----------------------------------------- m4_define([_LT_MANGLE_DEFUN], [[_LT_OPTION_DEFUN_]m4_bpatsubst(m4_toupper([$1__$2]), [[^A-Z0-9_]], [_])]) # LT_OPTION_DEFINE(MACRO-NAME, OPTION-NAME, CODE) # ----------------------------------------------- m4_define([LT_OPTION_DEFINE], [m4_define(_LT_MANGLE_DEFUN([$1], [$2]), [$3])[]dnl ])# LT_OPTION_DEFINE # dlopen # ------ LT_OPTION_DEFINE([LT_INIT], [dlopen], [enable_dlopen=yes ]) AU_DEFUN([AC_LIBTOOL_DLOPEN], [_LT_SET_OPTION([LT_INIT], [dlopen]) AC_DIAGNOSE([obsolete], [$0: Remove this warning and the call to _LT_SET_OPTION when you put the `dlopen' option into LT_INIT's first parameter.]) ]) dnl aclocal-1.4 backwards compatibility: dnl AC_DEFUN([AC_LIBTOOL_DLOPEN], []) # win32-dll # --------- # Declare package support for building win32 dll's. LT_OPTION_DEFINE([LT_INIT], [win32-dll], [enable_win32_dll=yes case $host in *-*-cygwin* | *-*-mingw* | *-*-pw32* | *-cegcc*) AC_CHECK_TOOL(AS, as, false) AC_CHECK_TOOL(DLLTOOL, dlltool, false) AC_CHECK_TOOL(OBJDUMP, objdump, false) ;; esac test -z "$AS" && AS=as _LT_DECL([], [AS], [0], [Assembler program])dnl test -z "$DLLTOOL" && DLLTOOL=dlltool _LT_DECL([], [DLLTOOL], [0], [DLL creation program])dnl test -z "$OBJDUMP" && OBJDUMP=objdump _LT_DECL([], [OBJDUMP], [0], [Object dumper program])dnl ])# win32-dll AU_DEFUN([AC_LIBTOOL_WIN32_DLL], [AC_REQUIRE([AC_CANONICAL_HOST])dnl _LT_SET_OPTION([LT_INIT], [win32-dll]) AC_DIAGNOSE([obsolete], [$0: Remove this warning and the call to _LT_SET_OPTION when you put the `win32-dll' option into LT_INIT's first parameter.]) ]) dnl aclocal-1.4 backwards compatibility: dnl AC_DEFUN([AC_LIBTOOL_WIN32_DLL], []) # _LT_ENABLE_SHARED([DEFAULT]) # ---------------------------- # implement the --enable-shared flag, and supports the `shared' and # `disable-shared' LT_INIT options. # DEFAULT is either `yes' or `no'. If omitted, it defaults to `yes'. m4_define([_LT_ENABLE_SHARED], [m4_define([_LT_ENABLE_SHARED_DEFAULT], [m4_if($1, no, no, yes)])dnl AC_ARG_ENABLE([shared], [AS_HELP_STRING([--enable-shared@<:@=PKGS@:>@], [build shared libraries @<:@default=]_LT_ENABLE_SHARED_DEFAULT[@:>@])], [p=${PACKAGE-default} case $enableval in yes) enable_shared=yes ;; no) enable_shared=no ;; *) enable_shared=no # Look at the argument we got. We use all the common list separators. lt_save_ifs="$IFS"; IFS="${IFS}$PATH_SEPARATOR," for pkg in $enableval; do IFS="$lt_save_ifs" if test "X$pkg" = "X$p"; then enable_shared=yes fi done IFS="$lt_save_ifs" ;; esac], [enable_shared=]_LT_ENABLE_SHARED_DEFAULT) _LT_DECL([build_libtool_libs], [enable_shared], [0], [Whether or not to build shared libraries]) ])# _LT_ENABLE_SHARED LT_OPTION_DEFINE([LT_INIT], [shared], [_LT_ENABLE_SHARED([yes])]) LT_OPTION_DEFINE([LT_INIT], [disable-shared], [_LT_ENABLE_SHARED([no])]) # Old names: AC_DEFUN([AC_ENABLE_SHARED], [_LT_SET_OPTION([LT_INIT], m4_if([$1], [no], [disable-])[shared]) ]) AC_DEFUN([AC_DISABLE_SHARED], [_LT_SET_OPTION([LT_INIT], [disable-shared]) ]) AU_DEFUN([AM_ENABLE_SHARED], [AC_ENABLE_SHARED($@)]) AU_DEFUN([AM_DISABLE_SHARED], [AC_DISABLE_SHARED($@)]) dnl aclocal-1.4 backwards compatibility: dnl AC_DEFUN([AM_ENABLE_SHARED], []) dnl AC_DEFUN([AM_DISABLE_SHARED], []) # _LT_ENABLE_STATIC([DEFAULT]) # ---------------------------- # implement the --enable-static flag, and support the `static' and # `disable-static' LT_INIT options. # DEFAULT is either `yes' or `no'. If omitted, it defaults to `yes'. m4_define([_LT_ENABLE_STATIC], [m4_define([_LT_ENABLE_STATIC_DEFAULT], [m4_if($1, no, no, yes)])dnl AC_ARG_ENABLE([static], [AS_HELP_STRING([--enable-static@<:@=PKGS@:>@], [build static libraries @<:@default=]_LT_ENABLE_STATIC_DEFAULT[@:>@])], [p=${PACKAGE-default} case $enableval in yes) enable_static=yes ;; no) enable_static=no ;; *) enable_static=no # Look at the argument we got. We use all the common list separators. lt_save_ifs="$IFS"; IFS="${IFS}$PATH_SEPARATOR," for pkg in $enableval; do IFS="$lt_save_ifs" if test "X$pkg" = "X$p"; then enable_static=yes fi done IFS="$lt_save_ifs" ;; esac], [enable_static=]_LT_ENABLE_STATIC_DEFAULT) _LT_DECL([build_old_libs], [enable_static], [0], [Whether or not to build static libraries]) ])# _LT_ENABLE_STATIC LT_OPTION_DEFINE([LT_INIT], [static], [_LT_ENABLE_STATIC([yes])]) LT_OPTION_DEFINE([LT_INIT], [disable-static], [_LT_ENABLE_STATIC([no])]) # Old names: AC_DEFUN([AC_ENABLE_STATIC], [_LT_SET_OPTION([LT_INIT], m4_if([$1], [no], [disable-])[static]) ]) AC_DEFUN([AC_DISABLE_STATIC], [_LT_SET_OPTION([LT_INIT], [disable-static]) ]) AU_DEFUN([AM_ENABLE_STATIC], [AC_ENABLE_STATIC($@)]) AU_DEFUN([AM_DISABLE_STATIC], [AC_DISABLE_STATIC($@)]) dnl aclocal-1.4 backwards compatibility: dnl AC_DEFUN([AM_ENABLE_STATIC], []) dnl AC_DEFUN([AM_DISABLE_STATIC], []) # _LT_ENABLE_FAST_INSTALL([DEFAULT]) # ---------------------------------- # implement the --enable-fast-install flag, and support the `fast-install' # and `disable-fast-install' LT_INIT options. # DEFAULT is either `yes' or `no'. If omitted, it defaults to `yes'. m4_define([_LT_ENABLE_FAST_INSTALL], [m4_define([_LT_ENABLE_FAST_INSTALL_DEFAULT], [m4_if($1, no, no, yes)])dnl AC_ARG_ENABLE([fast-install], [AS_HELP_STRING([--enable-fast-install@<:@=PKGS@:>@], [optimize for fast installation @<:@default=]_LT_ENABLE_FAST_INSTALL_DEFAULT[@:>@])], [p=${PACKAGE-default} case $enableval in yes) enable_fast_install=yes ;; no) enable_fast_install=no ;; *) enable_fast_install=no # Look at the argument we got. We use all the common list separators. lt_save_ifs="$IFS"; IFS="${IFS}$PATH_SEPARATOR," for pkg in $enableval; do IFS="$lt_save_ifs" if test "X$pkg" = "X$p"; then enable_fast_install=yes fi done IFS="$lt_save_ifs" ;; esac], [enable_fast_install=]_LT_ENABLE_FAST_INSTALL_DEFAULT) _LT_DECL([fast_install], [enable_fast_install], [0], [Whether or not to optimize for fast installation])dnl ])# _LT_ENABLE_FAST_INSTALL LT_OPTION_DEFINE([LT_INIT], [fast-install], [_LT_ENABLE_FAST_INSTALL([yes])]) LT_OPTION_DEFINE([LT_INIT], [disable-fast-install], [_LT_ENABLE_FAST_INSTALL([no])]) # Old names: AU_DEFUN([AC_ENABLE_FAST_INSTALL], [_LT_SET_OPTION([LT_INIT], m4_if([$1], [no], [disable-])[fast-install]) AC_DIAGNOSE([obsolete], [$0: Remove this warning and the call to _LT_SET_OPTION when you put the `fast-install' option into LT_INIT's first parameter.]) ]) AU_DEFUN([AC_DISABLE_FAST_INSTALL], [_LT_SET_OPTION([LT_INIT], [disable-fast-install]) AC_DIAGNOSE([obsolete], [$0: Remove this warning and the call to _LT_SET_OPTION when you put the `disable-fast-install' option into LT_INIT's first parameter.]) ]) dnl aclocal-1.4 backwards compatibility: dnl AC_DEFUN([AC_ENABLE_FAST_INSTALL], []) dnl AC_DEFUN([AM_DISABLE_FAST_INSTALL], []) # _LT_WITH_PIC([MODE]) # -------------------- # implement the --with-pic flag, and support the `pic-only' and `no-pic' # LT_INIT options. # MODE is either `yes' or `no'. If omitted, it defaults to `both'. m4_define([_LT_WITH_PIC], [AC_ARG_WITH([pic], [AS_HELP_STRING([--with-pic], [try to use only PIC/non-PIC objects @<:@default=use both@:>@])], [pic_mode="$withval"], [pic_mode=default]) test -z "$pic_mode" && pic_mode=m4_default([$1], [default]) _LT_DECL([], [pic_mode], [0], [What type of objects to build])dnl ])# _LT_WITH_PIC LT_OPTION_DEFINE([LT_INIT], [pic-only], [_LT_WITH_PIC([yes])]) LT_OPTION_DEFINE([LT_INIT], [no-pic], [_LT_WITH_PIC([no])]) # Old name: AU_DEFUN([AC_LIBTOOL_PICMODE], [_LT_SET_OPTION([LT_INIT], [pic-only]) AC_DIAGNOSE([obsolete], [$0: Remove this warning and the call to _LT_SET_OPTION when you put the `pic-only' option into LT_INIT's first parameter.]) ]) dnl aclocal-1.4 backwards compatibility: dnl AC_DEFUN([AC_LIBTOOL_PICMODE], []) ## ----------------- ## ## LTDL_INIT Options ## ## ----------------- ## m4_define([_LTDL_MODE], []) LT_OPTION_DEFINE([LTDL_INIT], [nonrecursive], [m4_define([_LTDL_MODE], [nonrecursive])]) LT_OPTION_DEFINE([LTDL_INIT], [recursive], [m4_define([_LTDL_MODE], [recursive])]) LT_OPTION_DEFINE([LTDL_INIT], [subproject], [m4_define([_LTDL_MODE], [subproject])]) m4_define([_LTDL_TYPE], []) LT_OPTION_DEFINE([LTDL_INIT], [installable], [m4_define([_LTDL_TYPE], [installable])]) LT_OPTION_DEFINE([LTDL_INIT], [convenience], [m4_define([_LTDL_TYPE], [convenience])]) alpine-2.10+dfsg/m4/inttypes.m40000600000175000017500000000147211512502114020000 0ustar paulproteuspaulproteus# inttypes.m4 serial 1 (gettext-0.11.4) dnl Copyright (C) 1997-2002 Free Software Foundation, Inc. dnl This file is free software; the Free Software Foundation dnl gives unlimited permission to copy and/or distribute it, dnl with or without modifications, as long as this notice is preserved. dnl From Paul Eggert. # Define HAVE_INTTYPES_H if exists and doesn't clash with # . AC_DEFUN([gt_HEADER_INTTYPES_H], [ AC_CACHE_CHECK([for inttypes.h], gt_cv_header_inttypes_h, [ AC_TRY_COMPILE( [#include #include ], [], gt_cv_header_inttypes_h=yes, gt_cv_header_inttypes_h=no) ]) if test $gt_cv_header_inttypes_h = yes; then AC_DEFINE_UNQUOTED(HAVE_INTTYPES_H, 1, [Define if exists and doesn't clash with .]) fi ]) alpine-2.10+dfsg/README0000600000175000017500000001273611512502127016230 0ustar paulproteuspaulproteus ----------------------------------------------------------------------- Alpine/Pico/Pilot/Web Alpine/Imapd Distribution ----------------------------------------------------------------------- /* ==================================================================== * Copyright 2006-2009 University of Washington * * Licensed under the Apache License, Version 2.0 (the "License"); * you may not use this file except in compliance with the License. * You may obtain a copy of the License at * * http://www.apache.org/licenses/LICENSE-2.0 * * ==================================================================== */ For the latest info about Alpine, see http://www.washington.edu/alpine ----------------------------------------------------------------------- DISTRIBUTION CONTENTS ----------------------------------------------------------------------- This Alpine distribution includes: alpine - The Alpine source directory configure - Script to set system-specific configuration, defaults contrib - Contributed ports and additions doc - Documentation directory. The main documentation is tech-notes.txt imap - Source tree containing C-Client IMAP implementation m4 - macros used in the configure process packages - Scripts for building packages for various Linux distributions pico - The Pico and Pilot source directory pith - Core functions common to Alpine/Web Alpine po - localization data web - Source and scripts for web-based version of Alpine Most of the documentation is in doc/tech-notes.txt. It is not user level documentation, but there are things in it some users might find useful. The directory doc/tech-notes contains source for doc/tech-notes.txt in HTML format which can be viewed via a Web pbrowser by opening doc/tech-notes/index.html. User level documentation for Alpine is contained in the programs themselves in the form of context-sensitive help. ----------------------------------------------------------------------- PRELIMINARIES ----------------------------------------------------------------------- If you are reading this, you have presumably succeeded in extracting the distribution from the compressed tar archive file, via the following command, or equivalent: tar zxf alpine.tar.z Some of the instructions that follow assume that your current workding directory is the alpine-X.XX directory created by the un-tar process above. ----------------------------------------------------------------------- BUILD PROCESS ----------------------------------------------------------------------- The Alpine build process is based on GNU autotools. On most Unix systems, generating a suitable Alpine binary from the source distribution should be as simple as typing the commands: ./configure make For a list of configuration options and default Alpine settings type: ./configure --help Note, the included UW IMAP Toolkit used for mailbox access does not make use of GNU autotools. However, in most cases Alpine's configure script should set the appropriate make target and options. The targetted OS can be set from Alpine's configure command line, but in rare cases more significant manual intervention may be required. If problems are encountered, see imap/README for more details. The PC-Alpine build is based on the Microsoft C compiler and libraries. The Alpine Team bases builds on Visual Studio 8 from the command line using the static build.bat batch and makefiles to generate suitable binaries. The Web Alpine application requires a few extra, manual steps to get all the components built and installed. See web/README for an explanation of the various components and web/INSTALL for a basic installation recipe. ----------------------------------------------------------------------- RESULTING EXECUTABLES ----------------------------------------------------------------------- The executables produced are: alpine The Alpine mailer. Once compiled this should work just fine on your system with no other files than this binary, and no modifications to your system. Optionally you may create two configuration files, /usr/local/lib/pine.conf and /usr/local/lib/pine.info. See the documentation for details. pico The standalone editor similar to the Alpine message composer. This is a very simple straight forward text editor. pilot The standalone file system navigator. alpined The Web Alpine serveret that is the primary component of Web Alpine imapd The IMAP daemon. If you want to run alpine in client/server mode, this is the daemon to run on the server. Installing this requires system privileges and modifications to /etc/services. See doc/tech-notes for more details. mtest The test IMAP client, an absolutely minimal mail client, useful for debugging. rpload Utility for uploading a local pinerc or address book to an IMAP server. rpdump Utility for downloading a pinerc or address book to the local machine. mailutil Utility for performing various operations on mailboxes, be they local or remote. In general "make install" should place alpine, pico and pilot, and their corresponding man pages, in the proper directory for your system. As the remaining binaries are intended for specific uses or are a component of a larger package, their installation is typically done by hand. -- alpine.tar.z README $Id: README 1204 2009-02-02 19:54:23Z hubert@u.washington.edu $ alpine-2.10+dfsg/aclocal.m40000600000175000017500000010763612074110246017215 0ustar paulproteuspaulproteus# generated automatically by aclocal 1.11.1 -*- Autoconf -*- # Copyright (C) 1996, 1997, 1998, 1999, 2000, 2001, 2002, 2003, 2004, # 2005, 2006, 2007, 2008, 2009 Free Software Foundation, Inc. # This file is free software; the Free Software Foundation # gives unlimited permission to copy and/or distribute it, # with or without modifications, as long as this notice is preserved. # This program is distributed in the hope that it will be useful, # but WITHOUT ANY WARRANTY, to the extent permitted by law; without # even the implied warranty of MERCHANTABILITY or FITNESS FOR A # PARTICULAR PURPOSE. m4_ifndef([AC_AUTOCONF_VERSION], [m4_copy([m4_PACKAGE_VERSION], [AC_AUTOCONF_VERSION])])dnl m4_if(m4_defn([AC_AUTOCONF_VERSION]), [2.68],, [m4_warning([this file was generated for autoconf 2.68. You have another version of autoconf. It may work, but is not guaranteed to. If you have problems, you may need to regenerate the build system entirely. To do so, use the procedure documented by the package, typically `autoreconf'.])]) # Copyright (C) 2002, 2003, 2005, 2006, 2007, 2008 Free Software Foundation, Inc. # # This file is free software; the Free Software Foundation # gives unlimited permission to copy and/or distribute it, # with or without modifications, as long as this notice is preserved. # AM_AUTOMAKE_VERSION(VERSION) # ---------------------------- # Automake X.Y traces this macro to ensure aclocal.m4 has been # generated from the m4 files accompanying Automake X.Y. # (This private macro should not be called outside this file.) AC_DEFUN([AM_AUTOMAKE_VERSION], [am__api_version='1.11' dnl Some users find AM_AUTOMAKE_VERSION and mistake it for a way to dnl require some minimum version. Point them to the right macro. m4_if([$1], [1.11.1], [], [AC_FATAL([Do not call $0, use AM_INIT_AUTOMAKE([$1]).])])dnl ]) # _AM_AUTOCONF_VERSION(VERSION) # ----------------------------- # aclocal traces this macro to find the Autoconf version. # This is a private macro too. Using m4_define simplifies # the logic in aclocal, which can simply ignore this definition. m4_define([_AM_AUTOCONF_VERSION], []) # AM_SET_CURRENT_AUTOMAKE_VERSION # ------------------------------- # Call AM_AUTOMAKE_VERSION and AM_AUTOMAKE_VERSION so they can be traced. # This function is AC_REQUIREd by AM_INIT_AUTOMAKE. AC_DEFUN([AM_SET_CURRENT_AUTOMAKE_VERSION], [AM_AUTOMAKE_VERSION([1.11.1])dnl m4_ifndef([AC_AUTOCONF_VERSION], [m4_copy([m4_PACKAGE_VERSION], [AC_AUTOCONF_VERSION])])dnl _AM_AUTOCONF_VERSION(m4_defn([AC_AUTOCONF_VERSION]))]) # AM_AUX_DIR_EXPAND -*- Autoconf -*- # Copyright (C) 2001, 2003, 2005 Free Software Foundation, Inc. # # This file is free software; the Free Software Foundation # gives unlimited permission to copy and/or distribute it, # with or without modifications, as long as this notice is preserved. # For projects using AC_CONFIG_AUX_DIR([foo]), Autoconf sets # $ac_aux_dir to `$srcdir/foo'. In other projects, it is set to # `$srcdir', `$srcdir/..', or `$srcdir/../..'. # # Of course, Automake must honor this variable whenever it calls a # tool from the auxiliary directory. The problem is that $srcdir (and # therefore $ac_aux_dir as well) can be either absolute or relative, # depending on how configure is run. This is pretty annoying, since # it makes $ac_aux_dir quite unusable in subdirectories: in the top # source directory, any form will work fine, but in subdirectories a # relative path needs to be adjusted first. # # $ac_aux_dir/missing # fails when called from a subdirectory if $ac_aux_dir is relative # $top_srcdir/$ac_aux_dir/missing # fails if $ac_aux_dir is absolute, # fails when called from a subdirectory in a VPATH build with # a relative $ac_aux_dir # # The reason of the latter failure is that $top_srcdir and $ac_aux_dir # are both prefixed by $srcdir. In an in-source build this is usually # harmless because $srcdir is `.', but things will broke when you # start a VPATH build or use an absolute $srcdir. # # So we could use something similar to $top_srcdir/$ac_aux_dir/missing, # iff we strip the leading $srcdir from $ac_aux_dir. That would be: # am_aux_dir='\$(top_srcdir)/'`expr "$ac_aux_dir" : "$srcdir//*\(.*\)"` # and then we would define $MISSING as # MISSING="\${SHELL} $am_aux_dir/missing" # This will work as long as MISSING is not called from configure, because # unfortunately $(top_srcdir) has no meaning in configure. # However there are other variables, like CC, which are often used in # configure, and could therefore not use this "fixed" $ac_aux_dir. # # Another solution, used here, is to always expand $ac_aux_dir to an # absolute PATH. The drawback is that using absolute paths prevent a # configured tree to be moved without reconfiguration. AC_DEFUN([AM_AUX_DIR_EXPAND], [dnl Rely on autoconf to set up CDPATH properly. AC_PREREQ([2.50])dnl # expand $ac_aux_dir to an absolute path am_aux_dir=`cd $ac_aux_dir && pwd` ]) # AM_CONDITIONAL -*- Autoconf -*- # Copyright (C) 1997, 2000, 2001, 2003, 2004, 2005, 2006, 2008 # Free Software Foundation, Inc. # # This file is free software; the Free Software Foundation # gives unlimited permission to copy and/or distribute it, # with or without modifications, as long as this notice is preserved. # serial 9 # AM_CONDITIONAL(NAME, SHELL-CONDITION) # ------------------------------------- # Define a conditional. AC_DEFUN([AM_CONDITIONAL], [AC_PREREQ(2.52)dnl ifelse([$1], [TRUE], [AC_FATAL([$0: invalid condition: $1])], [$1], [FALSE], [AC_FATAL([$0: invalid condition: $1])])dnl AC_SUBST([$1_TRUE])dnl AC_SUBST([$1_FALSE])dnl _AM_SUBST_NOTMAKE([$1_TRUE])dnl _AM_SUBST_NOTMAKE([$1_FALSE])dnl m4_define([_AM_COND_VALUE_$1], [$2])dnl if $2; then $1_TRUE= $1_FALSE='#' else $1_TRUE='#' $1_FALSE= fi AC_CONFIG_COMMANDS_PRE( [if test -z "${$1_TRUE}" && test -z "${$1_FALSE}"; then AC_MSG_ERROR([[conditional "$1" was never defined. Usually this means the macro was only invoked conditionally.]]) fi])]) # Copyright (C) 1999, 2000, 2001, 2002, 2003, 2004, 2005, 2006, 2009 # Free Software Foundation, Inc. # # This file is free software; the Free Software Foundation # gives unlimited permission to copy and/or distribute it, # with or without modifications, as long as this notice is preserved. # serial 10 # There are a few dirty hacks below to avoid letting `AC_PROG_CC' be # written in clear, in which case automake, when reading aclocal.m4, # will think it sees a *use*, and therefore will trigger all it's # C support machinery. Also note that it means that autoscan, seeing # CC etc. in the Makefile, will ask for an AC_PROG_CC use... # _AM_DEPENDENCIES(NAME) # ---------------------- # See how the compiler implements dependency checking. # NAME is "CC", "CXX", "GCJ", or "OBJC". # We try a few techniques and use that to set a single cache variable. # # We don't AC_REQUIRE the corresponding AC_PROG_CC since the latter was # modified to invoke _AM_DEPENDENCIES(CC); we would have a circular # dependency, and given that the user is not expected to run this macro, # just rely on AC_PROG_CC. AC_DEFUN([_AM_DEPENDENCIES], [AC_REQUIRE([AM_SET_DEPDIR])dnl AC_REQUIRE([AM_OUTPUT_DEPENDENCY_COMMANDS])dnl AC_REQUIRE([AM_MAKE_INCLUDE])dnl AC_REQUIRE([AM_DEP_TRACK])dnl ifelse([$1], CC, [depcc="$CC" am_compiler_list=], [$1], CXX, [depcc="$CXX" am_compiler_list=], [$1], OBJC, [depcc="$OBJC" am_compiler_list='gcc3 gcc'], [$1], UPC, [depcc="$UPC" am_compiler_list=], [$1], GCJ, [depcc="$GCJ" am_compiler_list='gcc3 gcc'], [depcc="$$1" am_compiler_list=]) AC_CACHE_CHECK([dependency style of $depcc], [am_cv_$1_dependencies_compiler_type], [if test -z "$AMDEP_TRUE" && test -f "$am_depcomp"; then # We make a subdir and do the tests there. Otherwise we can end up # making bogus files that we don't know about and never remove. For # instance it was reported that on HP-UX the gcc test will end up # making a dummy file named `D' -- because `-MD' means `put the output # in D'. mkdir conftest.dir # Copy depcomp to subdir because otherwise we won't find it if we're # using a relative directory. cp "$am_depcomp" conftest.dir cd conftest.dir # We will build objects and dependencies in a subdirectory because # it helps to detect inapplicable dependency modes. For instance # both Tru64's cc and ICC support -MD to output dependencies as a # side effect of compilation, but ICC will put the dependencies in # the current directory while Tru64 will put them in the object # directory. mkdir sub am_cv_$1_dependencies_compiler_type=none if test "$am_compiler_list" = ""; then am_compiler_list=`sed -n ['s/^#*\([a-zA-Z0-9]*\))$/\1/p'] < ./depcomp` fi am__universal=false m4_case([$1], [CC], [case " $depcc " in #( *\ -arch\ *\ -arch\ *) am__universal=true ;; esac], [CXX], [case " $depcc " in #( *\ -arch\ *\ -arch\ *) am__universal=true ;; esac]) for depmode in $am_compiler_list; do # Setup a source with many dependencies, because some compilers # like to wrap large dependency lists on column 80 (with \), and # we should not choose a depcomp mode which is confused by this. # # We need to recreate these files for each test, as the compiler may # overwrite some of them when testing with obscure command lines. # This happens at least with the AIX C compiler. : > sub/conftest.c for i in 1 2 3 4 5 6; do echo '#include "conftst'$i'.h"' >> sub/conftest.c # Using `: > sub/conftst$i.h' creates only sub/conftst1.h with # Solaris 8's {/usr,}/bin/sh. touch sub/conftst$i.h done echo "${am__include} ${am__quote}sub/conftest.Po${am__quote}" > confmf # We check with `-c' and `-o' for the sake of the "dashmstdout" # mode. It turns out that the SunPro C++ compiler does not properly # handle `-M -o', and we need to detect this. Also, some Intel # versions had trouble with output in subdirs am__obj=sub/conftest.${OBJEXT-o} am__minus_obj="-o $am__obj" case $depmode in gcc) # This depmode causes a compiler race in universal mode. test "$am__universal" = false || continue ;; nosideeffect) # after this tag, mechanisms are not by side-effect, so they'll # only be used when explicitly requested if test "x$enable_dependency_tracking" = xyes; then continue else break fi ;; msvisualcpp | msvcmsys) # This compiler won't grok `-c -o', but also, the minuso test has # not run yet. These depmodes are late enough in the game, and # so weak that their functioning should not be impacted. am__obj=conftest.${OBJEXT-o} am__minus_obj= ;; none) break ;; esac if depmode=$depmode \ source=sub/conftest.c object=$am__obj \ depfile=sub/conftest.Po tmpdepfile=sub/conftest.TPo \ $SHELL ./depcomp $depcc -c $am__minus_obj sub/conftest.c \ >/dev/null 2>conftest.err && grep sub/conftst1.h sub/conftest.Po > /dev/null 2>&1 && grep sub/conftst6.h sub/conftest.Po > /dev/null 2>&1 && grep $am__obj sub/conftest.Po > /dev/null 2>&1 && ${MAKE-make} -s -f confmf > /dev/null 2>&1; then # icc doesn't choke on unknown options, it will just issue warnings # or remarks (even with -Werror). So we grep stderr for any message # that says an option was ignored or not supported. # When given -MP, icc 7.0 and 7.1 complain thusly: # icc: Command line warning: ignoring option '-M'; no argument required # The diagnosis changed in icc 8.0: # icc: Command line remark: option '-MP' not supported if (grep 'ignoring option' conftest.err || grep 'not supported' conftest.err) >/dev/null 2>&1; then :; else am_cv_$1_dependencies_compiler_type=$depmode break fi fi done cd .. rm -rf conftest.dir else am_cv_$1_dependencies_compiler_type=none fi ]) AC_SUBST([$1DEPMODE], [depmode=$am_cv_$1_dependencies_compiler_type]) AM_CONDITIONAL([am__fastdep$1], [ test "x$enable_dependency_tracking" != xno \ && test "$am_cv_$1_dependencies_compiler_type" = gcc3]) ]) # AM_SET_DEPDIR # ------------- # Choose a directory name for dependency files. # This macro is AC_REQUIREd in _AM_DEPENDENCIES AC_DEFUN([AM_SET_DEPDIR], [AC_REQUIRE([AM_SET_LEADING_DOT])dnl AC_SUBST([DEPDIR], ["${am__leading_dot}deps"])dnl ]) # AM_DEP_TRACK # ------------ AC_DEFUN([AM_DEP_TRACK], [AC_ARG_ENABLE(dependency-tracking, [ --disable-dependency-tracking speeds up one-time build --enable-dependency-tracking do not reject slow dependency extractors]) if test "x$enable_dependency_tracking" != xno; then am_depcomp="$ac_aux_dir/depcomp" AMDEPBACKSLASH='\' fi AM_CONDITIONAL([AMDEP], [test "x$enable_dependency_tracking" != xno]) AC_SUBST([AMDEPBACKSLASH])dnl _AM_SUBST_NOTMAKE([AMDEPBACKSLASH])dnl ]) # Generate code to set up dependency tracking. -*- Autoconf -*- # Copyright (C) 1999, 2000, 2001, 2002, 2003, 2004, 2005, 2008 # Free Software Foundation, Inc. # # This file is free software; the Free Software Foundation # gives unlimited permission to copy and/or distribute it, # with or without modifications, as long as this notice is preserved. #serial 5 # _AM_OUTPUT_DEPENDENCY_COMMANDS # ------------------------------ AC_DEFUN([_AM_OUTPUT_DEPENDENCY_COMMANDS], [{ # Autoconf 2.62 quotes --file arguments for eval, but not when files # are listed without --file. Let's play safe and only enable the eval # if we detect the quoting. case $CONFIG_FILES in *\'*) eval set x "$CONFIG_FILES" ;; *) set x $CONFIG_FILES ;; esac shift for mf do # Strip MF so we end up with the name of the file. mf=`echo "$mf" | sed -e 's/:.*$//'` # Check whether this is an Automake generated Makefile or not. # We used to match only the files named `Makefile.in', but # some people rename them; so instead we look at the file content. # Grep'ing the first line is not enough: some people post-process # each Makefile.in and add a new line on top of each file to say so. # Grep'ing the whole file is not good either: AIX grep has a line # limit of 2048, but all sed's we know have understand at least 4000. if sed -n 's,^#.*generated by automake.*,X,p' "$mf" | grep X >/dev/null 2>&1; then dirpart=`AS_DIRNAME("$mf")` else continue fi # Extract the definition of DEPDIR, am__include, and am__quote # from the Makefile without running `make'. DEPDIR=`sed -n 's/^DEPDIR = //p' < "$mf"` test -z "$DEPDIR" && continue am__include=`sed -n 's/^am__include = //p' < "$mf"` test -z "am__include" && continue am__quote=`sed -n 's/^am__quote = //p' < "$mf"` # When using ansi2knr, U may be empty or an underscore; expand it U=`sed -n 's/^U = //p' < "$mf"` # Find all dependency output files, they are included files with # $(DEPDIR) in their names. We invoke sed twice because it is the # simplest approach to changing $(DEPDIR) to its actual value in the # expansion. for file in `sed -n " s/^$am__include $am__quote\(.*(DEPDIR).*\)$am__quote"'$/\1/p' <"$mf" | \ sed -e 's/\$(DEPDIR)/'"$DEPDIR"'/g' -e 's/\$U/'"$U"'/g'`; do # Make sure the directory exists. test -f "$dirpart/$file" && continue fdir=`AS_DIRNAME(["$file"])` AS_MKDIR_P([$dirpart/$fdir]) # echo "creating $dirpart/$file" echo '# dummy' > "$dirpart/$file" done done } ])# _AM_OUTPUT_DEPENDENCY_COMMANDS # AM_OUTPUT_DEPENDENCY_COMMANDS # ----------------------------- # This macro should only be invoked once -- use via AC_REQUIRE. # # This code is only required when automatic dependency tracking # is enabled. FIXME. This creates each `.P' file that we will # need in order to bootstrap the dependency handling code. AC_DEFUN([AM_OUTPUT_DEPENDENCY_COMMANDS], [AC_CONFIG_COMMANDS([depfiles], [test x"$AMDEP_TRUE" != x"" || _AM_OUTPUT_DEPENDENCY_COMMANDS], [AMDEP_TRUE="$AMDEP_TRUE" ac_aux_dir="$ac_aux_dir"]) ]) # Do all the work for Automake. -*- Autoconf -*- # Copyright (C) 1996, 1997, 1998, 1999, 2000, 2001, 2002, 2003, 2004, # 2005, 2006, 2008, 2009 Free Software Foundation, Inc. # # This file is free software; the Free Software Foundation # gives unlimited permission to copy and/or distribute it, # with or without modifications, as long as this notice is preserved. # serial 16 # This macro actually does too much. Some checks are only needed if # your package does certain things. But this isn't really a big deal. # AM_INIT_AUTOMAKE(PACKAGE, VERSION, [NO-DEFINE]) # AM_INIT_AUTOMAKE([OPTIONS]) # ----------------------------------------------- # The call with PACKAGE and VERSION arguments is the old style # call (pre autoconf-2.50), which is being phased out. PACKAGE # and VERSION should now be passed to AC_INIT and removed from # the call to AM_INIT_AUTOMAKE. # We support both call styles for the transition. After # the next Automake release, Autoconf can make the AC_INIT # arguments mandatory, and then we can depend on a new Autoconf # release and drop the old call support. AC_DEFUN([AM_INIT_AUTOMAKE], [AC_PREREQ([2.62])dnl dnl Autoconf wants to disallow AM_ names. We explicitly allow dnl the ones we care about. m4_pattern_allow([^AM_[A-Z]+FLAGS$])dnl AC_REQUIRE([AM_SET_CURRENT_AUTOMAKE_VERSION])dnl AC_REQUIRE([AC_PROG_INSTALL])dnl if test "`cd $srcdir && pwd`" != "`pwd`"; then # Use -I$(srcdir) only when $(srcdir) != ., so that make's output # is not polluted with repeated "-I." AC_SUBST([am__isrc], [' -I$(srcdir)'])_AM_SUBST_NOTMAKE([am__isrc])dnl # test to see if srcdir already configured if test -f $srcdir/config.status; then AC_MSG_ERROR([source directory already configured; run "make distclean" there first]) fi fi # test whether we have cygpath if test -z "$CYGPATH_W"; then if (cygpath --version) >/dev/null 2>/dev/null; then CYGPATH_W='cygpath -w' else CYGPATH_W=echo fi fi AC_SUBST([CYGPATH_W]) # Define the identity of the package. dnl Distinguish between old-style and new-style calls. m4_ifval([$2], [m4_ifval([$3], [_AM_SET_OPTION([no-define])])dnl AC_SUBST([PACKAGE], [$1])dnl AC_SUBST([VERSION], [$2])], [_AM_SET_OPTIONS([$1])dnl dnl Diagnose old-style AC_INIT with new-style AM_AUTOMAKE_INIT. m4_if(m4_ifdef([AC_PACKAGE_NAME], 1)m4_ifdef([AC_PACKAGE_VERSION], 1), 11,, [m4_fatal([AC_INIT should be called with package and version arguments])])dnl AC_SUBST([PACKAGE], ['AC_PACKAGE_TARNAME'])dnl AC_SUBST([VERSION], ['AC_PACKAGE_VERSION'])])dnl _AM_IF_OPTION([no-define],, [AC_DEFINE_UNQUOTED(PACKAGE, "$PACKAGE", [Name of package]) AC_DEFINE_UNQUOTED(VERSION, "$VERSION", [Version number of package])])dnl # Some tools Automake needs. AC_REQUIRE([AM_SANITY_CHECK])dnl AC_REQUIRE([AC_ARG_PROGRAM])dnl AM_MISSING_PROG(ACLOCAL, aclocal-${am__api_version}) AM_MISSING_PROG(AUTOCONF, autoconf) AM_MISSING_PROG(AUTOMAKE, automake-${am__api_version}) AM_MISSING_PROG(AUTOHEADER, autoheader) AM_MISSING_PROG(MAKEINFO, makeinfo) AC_REQUIRE([AM_PROG_INSTALL_SH])dnl AC_REQUIRE([AM_PROG_INSTALL_STRIP])dnl AC_REQUIRE([AM_PROG_MKDIR_P])dnl # We need awk for the "check" target. The system "awk" is bad on # some platforms. AC_REQUIRE([AC_PROG_AWK])dnl AC_REQUIRE([AC_PROG_MAKE_SET])dnl AC_REQUIRE([AM_SET_LEADING_DOT])dnl _AM_IF_OPTION([tar-ustar], [_AM_PROG_TAR([ustar])], [_AM_IF_OPTION([tar-pax], [_AM_PROG_TAR([pax])], [_AM_PROG_TAR([v7])])]) _AM_IF_OPTION([no-dependencies],, [AC_PROVIDE_IFELSE([AC_PROG_CC], [_AM_DEPENDENCIES(CC)], [define([AC_PROG_CC], defn([AC_PROG_CC])[_AM_DEPENDENCIES(CC)])])dnl AC_PROVIDE_IFELSE([AC_PROG_CXX], [_AM_DEPENDENCIES(CXX)], [define([AC_PROG_CXX], defn([AC_PROG_CXX])[_AM_DEPENDENCIES(CXX)])])dnl AC_PROVIDE_IFELSE([AC_PROG_OBJC], [_AM_DEPENDENCIES(OBJC)], [define([AC_PROG_OBJC], defn([AC_PROG_OBJC])[_AM_DEPENDENCIES(OBJC)])])dnl ]) _AM_IF_OPTION([silent-rules], [AC_REQUIRE([AM_SILENT_RULES])])dnl dnl The `parallel-tests' driver may need to know about EXEEXT, so add the dnl `am__EXEEXT' conditional if _AM_COMPILER_EXEEXT was seen. This macro dnl is hooked onto _AC_COMPILER_EXEEXT early, see below. AC_CONFIG_COMMANDS_PRE(dnl [m4_provide_if([_AM_COMPILER_EXEEXT], [AM_CONDITIONAL([am__EXEEXT], [test -n "$EXEEXT"])])])dnl ]) dnl Hook into `_AC_COMPILER_EXEEXT' early to learn its expansion. Do not dnl add the conditional right here, as _AC_COMPILER_EXEEXT may be further dnl mangled by Autoconf and run in a shell conditional statement. m4_define([_AC_COMPILER_EXEEXT], m4_defn([_AC_COMPILER_EXEEXT])[m4_provide([_AM_COMPILER_EXEEXT])]) # When config.status generates a header, we must update the stamp-h file. # This file resides in the same directory as the config header # that is generated. The stamp files are numbered to have different names. # Autoconf calls _AC_AM_CONFIG_HEADER_HOOK (when defined) in the # loop where config.status creates the headers, so we can generate # our stamp files there. AC_DEFUN([_AC_AM_CONFIG_HEADER_HOOK], [# Compute $1's index in $config_headers. _am_arg=$1 _am_stamp_count=1 for _am_header in $config_headers :; do case $_am_header in $_am_arg | $_am_arg:* ) break ;; * ) _am_stamp_count=`expr $_am_stamp_count + 1` ;; esac done echo "timestamp for $_am_arg" >`AS_DIRNAME(["$_am_arg"])`/stamp-h[]$_am_stamp_count]) # Copyright (C) 2001, 2003, 2005, 2008 Free Software Foundation, Inc. # # This file is free software; the Free Software Foundation # gives unlimited permission to copy and/or distribute it, # with or without modifications, as long as this notice is preserved. # AM_PROG_INSTALL_SH # ------------------ # Define $install_sh. AC_DEFUN([AM_PROG_INSTALL_SH], [AC_REQUIRE([AM_AUX_DIR_EXPAND])dnl if test x"${install_sh}" != xset; then case $am_aux_dir in *\ * | *\ *) install_sh="\${SHELL} '$am_aux_dir/install-sh'" ;; *) install_sh="\${SHELL} $am_aux_dir/install-sh" esac fi AC_SUBST(install_sh)]) # Copyright (C) 2003, 2005 Free Software Foundation, Inc. # # This file is free software; the Free Software Foundation # gives unlimited permission to copy and/or distribute it, # with or without modifications, as long as this notice is preserved. # serial 2 # Check whether the underlying file-system supports filenames # with a leading dot. For instance MS-DOS doesn't. AC_DEFUN([AM_SET_LEADING_DOT], [rm -rf .tst 2>/dev/null mkdir .tst 2>/dev/null if test -d .tst; then am__leading_dot=. else am__leading_dot=_ fi rmdir .tst 2>/dev/null AC_SUBST([am__leading_dot])]) # Add --enable-maintainer-mode option to configure. -*- Autoconf -*- # From Jim Meyering # Copyright (C) 1996, 1998, 2000, 2001, 2002, 2003, 2004, 2005, 2008 # Free Software Foundation, Inc. # # This file is free software; the Free Software Foundation # gives unlimited permission to copy and/or distribute it, # with or without modifications, as long as this notice is preserved. # serial 5 # AM_MAINTAINER_MODE([DEFAULT-MODE]) # ---------------------------------- # Control maintainer-specific portions of Makefiles. # Default is to disable them, unless `enable' is passed literally. # For symmetry, `disable' may be passed as well. Anyway, the user # can override the default with the --enable/--disable switch. AC_DEFUN([AM_MAINTAINER_MODE], [m4_case(m4_default([$1], [disable]), [enable], [m4_define([am_maintainer_other], [disable])], [disable], [m4_define([am_maintainer_other], [enable])], [m4_define([am_maintainer_other], [enable]) m4_warn([syntax], [unexpected argument to AM@&t@_MAINTAINER_MODE: $1])]) AC_MSG_CHECKING([whether to am_maintainer_other maintainer-specific portions of Makefiles]) dnl maintainer-mode's default is 'disable' unless 'enable' is passed AC_ARG_ENABLE([maintainer-mode], [ --][am_maintainer_other][-maintainer-mode am_maintainer_other make rules and dependencies not useful (and sometimes confusing) to the casual installer], [USE_MAINTAINER_MODE=$enableval], [USE_MAINTAINER_MODE=]m4_if(am_maintainer_other, [enable], [no], [yes])) AC_MSG_RESULT([$USE_MAINTAINER_MODE]) AM_CONDITIONAL([MAINTAINER_MODE], [test $USE_MAINTAINER_MODE = yes]) MAINT=$MAINTAINER_MODE_TRUE AC_SUBST([MAINT])dnl ] ) AU_DEFUN([jm_MAINTAINER_MODE], [AM_MAINTAINER_MODE]) # Check to see how 'make' treats includes. -*- Autoconf -*- # Copyright (C) 2001, 2002, 2003, 2005, 2009 Free Software Foundation, Inc. # # This file is free software; the Free Software Foundation # gives unlimited permission to copy and/or distribute it, # with or without modifications, as long as this notice is preserved. # serial 4 # AM_MAKE_INCLUDE() # ----------------- # Check to see how make treats includes. AC_DEFUN([AM_MAKE_INCLUDE], [am_make=${MAKE-make} cat > confinc << 'END' am__doit: @echo this is the am__doit target .PHONY: am__doit END # If we don't find an include directive, just comment out the code. AC_MSG_CHECKING([for style of include used by $am_make]) am__include="#" am__quote= _am_result=none # First try GNU make style include. echo "include confinc" > confmf # Ignore all kinds of additional output from `make'. case `$am_make -s -f confmf 2> /dev/null` in #( *the\ am__doit\ target*) am__include=include am__quote= _am_result=GNU ;; esac # Now try BSD make style include. if test "$am__include" = "#"; then echo '.include "confinc"' > confmf case `$am_make -s -f confmf 2> /dev/null` in #( *the\ am__doit\ target*) am__include=.include am__quote="\"" _am_result=BSD ;; esac fi AC_SUBST([am__include]) AC_SUBST([am__quote]) AC_MSG_RESULT([$_am_result]) rm -f confinc confmf ]) # Fake the existence of programs that GNU maintainers use. -*- Autoconf -*- # Copyright (C) 1997, 1999, 2000, 2001, 2003, 2004, 2005, 2008 # Free Software Foundation, Inc. # # This file is free software; the Free Software Foundation # gives unlimited permission to copy and/or distribute it, # with or without modifications, as long as this notice is preserved. # serial 6 # AM_MISSING_PROG(NAME, PROGRAM) # ------------------------------ AC_DEFUN([AM_MISSING_PROG], [AC_REQUIRE([AM_MISSING_HAS_RUN]) $1=${$1-"${am_missing_run}$2"} AC_SUBST($1)]) # AM_MISSING_HAS_RUN # ------------------ # Define MISSING if not defined so far and test if it supports --run. # If it does, set am_missing_run to use it, otherwise, to nothing. AC_DEFUN([AM_MISSING_HAS_RUN], [AC_REQUIRE([AM_AUX_DIR_EXPAND])dnl AC_REQUIRE_AUX_FILE([missing])dnl if test x"${MISSING+set}" != xset; then case $am_aux_dir in *\ * | *\ *) MISSING="\${SHELL} \"$am_aux_dir/missing\"" ;; *) MISSING="\${SHELL} $am_aux_dir/missing" ;; esac fi # Use eval to expand $SHELL if eval "$MISSING --run true"; then am_missing_run="$MISSING --run " else am_missing_run= AC_MSG_WARN([`missing' script is too old or missing]) fi ]) # Copyright (C) 2003, 2004, 2005, 2006 Free Software Foundation, Inc. # # This file is free software; the Free Software Foundation # gives unlimited permission to copy and/or distribute it, # with or without modifications, as long as this notice is preserved. # AM_PROG_MKDIR_P # --------------- # Check for `mkdir -p'. AC_DEFUN([AM_PROG_MKDIR_P], [AC_PREREQ([2.60])dnl AC_REQUIRE([AC_PROG_MKDIR_P])dnl dnl Automake 1.8 to 1.9.6 used to define mkdir_p. We now use MKDIR_P, dnl while keeping a definition of mkdir_p for backward compatibility. dnl @MKDIR_P@ is magic: AC_OUTPUT adjusts its value for each Makefile. dnl However we cannot define mkdir_p as $(MKDIR_P) for the sake of dnl Makefile.ins that do not define MKDIR_P, so we do our own dnl adjustment using top_builddir (which is defined more often than dnl MKDIR_P). AC_SUBST([mkdir_p], ["$MKDIR_P"])dnl case $mkdir_p in [[\\/$]]* | ?:[[\\/]]*) ;; */*) mkdir_p="\$(top_builddir)/$mkdir_p" ;; esac ]) # Helper functions for option handling. -*- Autoconf -*- # Copyright (C) 2001, 2002, 2003, 2005, 2008 Free Software Foundation, Inc. # # This file is free software; the Free Software Foundation # gives unlimited permission to copy and/or distribute it, # with or without modifications, as long as this notice is preserved. # serial 4 # _AM_MANGLE_OPTION(NAME) # ----------------------- AC_DEFUN([_AM_MANGLE_OPTION], [[_AM_OPTION_]m4_bpatsubst($1, [[^a-zA-Z0-9_]], [_])]) # _AM_SET_OPTION(NAME) # ------------------------------ # Set option NAME. Presently that only means defining a flag for this option. AC_DEFUN([_AM_SET_OPTION], [m4_define(_AM_MANGLE_OPTION([$1]), 1)]) # _AM_SET_OPTIONS(OPTIONS) # ---------------------------------- # OPTIONS is a space-separated list of Automake options. AC_DEFUN([_AM_SET_OPTIONS], [m4_foreach_w([_AM_Option], [$1], [_AM_SET_OPTION(_AM_Option)])]) # _AM_IF_OPTION(OPTION, IF-SET, [IF-NOT-SET]) # ------------------------------------------- # Execute IF-SET if OPTION is set, IF-NOT-SET otherwise. AC_DEFUN([_AM_IF_OPTION], [m4_ifset(_AM_MANGLE_OPTION([$1]), [$2], [$3])]) # Check to make sure that the build environment is sane. -*- Autoconf -*- # Copyright (C) 1996, 1997, 2000, 2001, 2003, 2005, 2008 # Free Software Foundation, Inc. # # This file is free software; the Free Software Foundation # gives unlimited permission to copy and/or distribute it, # with or without modifications, as long as this notice is preserved. # serial 5 # AM_SANITY_CHECK # --------------- AC_DEFUN([AM_SANITY_CHECK], [AC_MSG_CHECKING([whether build environment is sane]) # Just in case sleep 1 echo timestamp > conftest.file # Reject unsafe characters in $srcdir or the absolute working directory # name. Accept space and tab only in the latter. am_lf=' ' case `pwd` in *[[\\\"\#\$\&\'\`$am_lf]]*) AC_MSG_ERROR([unsafe absolute working directory name]);; esac case $srcdir in *[[\\\"\#\$\&\'\`$am_lf\ \ ]]*) AC_MSG_ERROR([unsafe srcdir value: `$srcdir']);; esac # Do `set' in a subshell so we don't clobber the current shell's # arguments. Must try -L first in case configure is actually a # symlink; some systems play weird games with the mod time of symlinks # (eg FreeBSD returns the mod time of the symlink's containing # directory). if ( set X `ls -Lt "$srcdir/configure" conftest.file 2> /dev/null` if test "$[*]" = "X"; then # -L didn't work. set X `ls -t "$srcdir/configure" conftest.file` fi rm -f conftest.file if test "$[*]" != "X $srcdir/configure conftest.file" \ && test "$[*]" != "X conftest.file $srcdir/configure"; then # If neither matched, then we have a broken ls. This can happen # if, for instance, CONFIG_SHELL is bash and it inherits a # broken ls alias from the environment. This has actually # happened. Such a system could not be considered "sane". AC_MSG_ERROR([ls -t appears to fail. Make sure there is not a broken alias in your environment]) fi test "$[2]" = conftest.file ) then # Ok. : else AC_MSG_ERROR([newly created file is older than distributed files! Check your system clock]) fi AC_MSG_RESULT(yes)]) # Copyright (C) 2001, 2003, 2005 Free Software Foundation, Inc. # # This file is free software; the Free Software Foundation # gives unlimited permission to copy and/or distribute it, # with or without modifications, as long as this notice is preserved. # AM_PROG_INSTALL_STRIP # --------------------- # One issue with vendor `install' (even GNU) is that you can't # specify the program used to strip binaries. This is especially # annoying in cross-compiling environments, where the build's strip # is unlikely to handle the host's binaries. # Fortunately install-sh will honor a STRIPPROG variable, so we # always use install-sh in `make install-strip', and initialize # STRIPPROG with the value of the STRIP variable (set by the user). AC_DEFUN([AM_PROG_INSTALL_STRIP], [AC_REQUIRE([AM_PROG_INSTALL_SH])dnl # Installed binaries are usually stripped using `strip' when the user # run `make install-strip'. However `strip' might not be the right # tool to use in cross-compilation environments, therefore Automake # will honor the `STRIP' environment variable to overrule this program. dnl Don't test for $cross_compiling = yes, because it might be `maybe'. if test "$cross_compiling" != no; then AC_CHECK_TOOL([STRIP], [strip], :) fi INSTALL_STRIP_PROGRAM="\$(install_sh) -c -s" AC_SUBST([INSTALL_STRIP_PROGRAM])]) # Copyright (C) 2006, 2008 Free Software Foundation, Inc. # # This file is free software; the Free Software Foundation # gives unlimited permission to copy and/or distribute it, # with or without modifications, as long as this notice is preserved. # serial 2 # _AM_SUBST_NOTMAKE(VARIABLE) # --------------------------- # Prevent Automake from outputting VARIABLE = @VARIABLE@ in Makefile.in. # This macro is traced by Automake. AC_DEFUN([_AM_SUBST_NOTMAKE]) # AM_SUBST_NOTMAKE(VARIABLE) # --------------------------- # Public sister of _AM_SUBST_NOTMAKE. AC_DEFUN([AM_SUBST_NOTMAKE], [_AM_SUBST_NOTMAKE($@)]) # Check how to create a tarball. -*- Autoconf -*- # Copyright (C) 2004, 2005 Free Software Foundation, Inc. # # This file is free software; the Free Software Foundation # gives unlimited permission to copy and/or distribute it, # with or without modifications, as long as this notice is preserved. # serial 2 # _AM_PROG_TAR(FORMAT) # -------------------- # Check how to create a tarball in format FORMAT. # FORMAT should be one of `v7', `ustar', or `pax'. # # Substitute a variable $(am__tar) that is a command # writing to stdout a FORMAT-tarball containing the directory # $tardir. # tardir=directory && $(am__tar) > result.tar # # Substitute a variable $(am__untar) that extract such # a tarball read from stdin. # $(am__untar) < result.tar AC_DEFUN([_AM_PROG_TAR], [# Always define AMTAR for backward compatibility. AM_MISSING_PROG([AMTAR], [tar]) m4_if([$1], [v7], [am__tar='${AMTAR} chof - "$$tardir"'; am__untar='${AMTAR} xf -'], [m4_case([$1], [ustar],, [pax],, [m4_fatal([Unknown tar format])]) AC_MSG_CHECKING([how to create a $1 tar archive]) # Loop over all known methods to create a tar archive until one works. _am_tools='gnutar m4_if([$1], [ustar], [plaintar]) pax cpio none' _am_tools=${am_cv_prog_tar_$1-$_am_tools} # Do not fold the above two line into one, because Tru64 sh and # Solaris sh will not grok spaces in the rhs of `-'. for _am_tool in $_am_tools do case $_am_tool in gnutar) for _am_tar in tar gnutar gtar; do AM_RUN_LOG([$_am_tar --version]) && break done am__tar="$_am_tar --format=m4_if([$1], [pax], [posix], [$1]) -chf - "'"$$tardir"' am__tar_="$_am_tar --format=m4_if([$1], [pax], [posix], [$1]) -chf - "'"$tardir"' am__untar="$_am_tar -xf -" ;; plaintar) # Must skip GNU tar: if it does not support --format= it doesn't create # ustar tarball either. (tar --version) >/dev/null 2>&1 && continue am__tar='tar chf - "$$tardir"' am__tar_='tar chf - "$tardir"' am__untar='tar xf -' ;; pax) am__tar='pax -L -x $1 -w "$$tardir"' am__tar_='pax -L -x $1 -w "$tardir"' am__untar='pax -r' ;; cpio) am__tar='find "$$tardir" -print | cpio -o -H $1 -L' am__tar_='find "$tardir" -print | cpio -o -H $1 -L' am__untar='cpio -i -H $1 -d' ;; none) am__tar=false am__tar_=false am__untar=false ;; esac # If the value was cached, stop now. We just wanted to have am__tar # and am__untar set. test -n "${am_cv_prog_tar_$1}" && break # tar/untar a dummy directory, and stop if the command works rm -rf conftest.dir mkdir conftest.dir echo GrepMe > conftest.dir/file AM_RUN_LOG([tardir=conftest.dir && eval $am__tar_ >conftest.tar]) rm -rf conftest.dir if test -s conftest.tar; then AM_RUN_LOG([$am__untar /dev/null 2>&1 && break fi done rm -rf conftest.dir AC_CACHE_VAL([am_cv_prog_tar_$1], [am_cv_prog_tar_$1=$_am_tool]) AC_MSG_RESULT([$am_cv_prog_tar_$1])]) AC_SUBST([am__tar]) AC_SUBST([am__untar]) ]) # _AM_PROG_TAR m4_include([m4/acx_pthread.m4]) m4_include([m4/gettext.m4]) m4_include([m4/iconv.m4]) m4_include([m4/lib-ld.m4]) m4_include([m4/lib-link.m4]) m4_include([m4/lib-prefix.m4]) m4_include([m4/libtool.m4]) m4_include([m4/ltoptions.m4]) m4_include([m4/ltsugar.m4]) m4_include([m4/ltversion.m4]) m4_include([m4/lt~obsolete.m4]) m4_include([m4/nls.m4]) m4_include([m4/po.m4]) m4_include([m4/progtest.m4]) alpine-2.10+dfsg/imap/0000700000175000017500000000000011512502152016261 5ustar paulproteuspaulproteusalpine-2.10+dfsg/imap/README0000600000175000017500000000604711512502125017152 0ustar paulproteuspaulproteus/* ======================================================================== * Copyright 1988-2007 University of Washington * * Licensed under the Apache License, Version 2.0 (the "License"); * you may not use this file except in compliance with the License. * You may obtain a copy of the License at * * http://www.apache.org/licenses/LICENSE-2.0 * * * ======================================================================== */ IMAP Toolkit Environment 4 April 2007 Mark Crispin UNIX QUICK BUILD NOTES These quick build notes assume that you have installed OpenSSL before attempting to build this software, and that you do not have any non-default configuration parameters. If you need additional information in building this software with OpenSSL, please refer to the docs/SSLBUILD file for more information. If you intend to build this software with a non-default configuration (including building a non-compliant server without SSL support), please refer to the docs/BUILD file for more information. 1) Look in the top-level Makefile and find your system type code. For example, modern versions of Linux will use either "slx", "lnp", or one of the lnp-variants (such as "lrh"). 2) Type "make" followed by the system type, e.g. "make slx". 3) Install the POP2 daemon (ipopd/ipop2d), the POP3 daemon (ipopd/ipop3d), and the IMAP daemon (imapd/imapd) on a system directory of your choosing. 4) Update /etc/services to register the pop2 service on TCP port 109, the pop3 service on TCP port 110, and the imap service on TCP port 143. Also update Yellow Pages/NIS/NetInfo/etc. if appropriate on your system. 5) Update /etc/inetd.conf (or install files on /etc/xinetd.d) to invoke the POP2, POP3, and IMAP daemons on their associated services. 6) If your system uses PAM authentication, be sure to set up /etc/pam.d/imap (*not* /etc/pam.d/imapd) and /etc/pam.d/pop (*not* /etc/pam.d/ipop3d or /etc/pam.d/pop3d or /etc/pam.d/popd or /etc/pam.d/pop3). 7) Unless you built your system without SSL support, you will need to set up SSL server certificates as described in docs/SSLBUILD. 6) That's all! Read the file docs/BUILD and docs/SSLBUILD if you need more detailed information and/or you don't understand these quick build instructions. MISCELLANEOUS NOTES mtest has been run under UNIX, DOS, Windows, NT, Macintosh, TOPS-20, and VMS. It is a very primitive interface, however, and is suited mainly as a model of how to write a main program for c-client. You should take a look at the source to figure out how to use it. Briefly, it first asks for a mailbox name (either a local file path or an IMAP mailbox in the form "{hostname}mailbox") and then puts you in a command mode where "?" will give you a list of commands. Pine is available separately on the FTP.CAC.Washington.EDU archives. The focus of development and support is for UNIX and Win32 (including Windows 95/98/Millenium, Windows NT, and Windows 2000). The other ports are not frequently used or tested, and may be incomplete. alpine-2.10+dfsg/imap/NOTICE0000600000175000017500000000136711512502125017176 0ustar paulproteuspaulproteusUW IMAP toolkit notices: This software was developed by the University of Washington (http://www.washington.edu/). The Univerity of Washington IMAP Toolkit (c-client API, dmail, imapd, ipop2d, ipop3d, mailutil, mlock, mtest, and tmail software; and its included text) is Copyright 1988-2007 by the University of Washington. The c-client library and mtest software are in part based upon code developed by Mark Crispin at Stanford University, and is * Copyright 1988 Stanford University and was developed in the * Symbolic Systems Resources Group of the Knowledge Systems Laboratory * at Stanford University in 1987-88, and was funded by the * Biomedical Research Technology Program of the National Institutes of * Health under grant number RR-00785. alpine-2.10+dfsg/imap/tools/0000700000175000017500000000000011512502152017421 5ustar paulproteuspaulproteusalpine-2.10+dfsg/imap/tools/uahelper.c0000600000175000017500000001667111512502122021404 0ustar paulproteuspaulproteus/* ======================================================================== * Copyright 1988-2006 University of Washington * * Licensed under the Apache License, Version 2.0 (the "License"); * you may not use this file except in compliance with the License. * You may obtain a copy of the License at * * http://www.apache.org/licenses/LICENSE-2.0 * * * ======================================================================== */ /* * Program: unANSIify * * Author: Mark Crispin * Networks and Distributed Computing * Computing & Communications * University of Washington * 4545 15th Ave NE * Seattle, WA 98105-4527 * Internet: MRC@CAC.Washington.EDU * * Date: 1 June 1995 * Last Edited: 30 August 2006 */ /* This program is designed to make traditional C sources out of my source * files which use ANSI syntax. This program depends heavily upon knowledge * of the way I write code, and is not a general purpose tool. I hope that * someday someone will provide a general purpose tool... */ #include #define LINELENGTH 1000 /* Find first non-whitespace * Accepts: string * Returns: 0 if no non-whitespace found, or pointer to non-whitespace */ char *fndnws (s) char *s; { while ((*s == ' ') || (*s == '\t')) if ((*s++ == '\n') || !*s) return (char *) 0; return s; } /* Find first whitespace * Accepts: string * Returns: 0 if no whitespace found, or pointer to whitespace */ char *fndws (s) char *s; { while ((*s != ' ') && (*s != '\t')) if ((*s++ == '\n') || !*s) return (char *) 0; return s; } /* Find end of commend * Accepts: string * Returns: -1 if end of comment found, else 0 */ int fndcmt (s) char *s; { while (*s && (*s != '\n')) if ((*s++ == '*') && (*s == '/')) return -1; return 0; } /* Output a line * Accepts: string */ void poot (s) char *s; { if (s) fputs (s,stdout); } /* Skip prefix * Accepts: string * Returns: updated string */ char *skipfx (s) char *s; { char c,*t = s,*tt; /* skip leading whitespace too */ while ((*s == ' ') || (*s == '\t')) *s++; if (s != t) { c = *s; /* save character */ *s = '\0'; /* tie off prefix */ poot (t); /* output prefix */ *s = c; /* restore character */ } /* a typedef? */ if (((s[0] == 't') && (s[1] == 'y') && (s[2] == 'p') && (s[3] == 'e') && (s[4] == 'd') && (s[5] == 'e') && (s[6] == 'f')) && (t = fndws (s)) && (t = fndnws (t))) { if ((t[0] == 'u') && (t[1] == 'n') && (t[2] == 's') && (t[3] == 'i') && (t[4] == 'g') && (t[5] == 'n') && (t[6] == 'e') && (t[7] == 'd') && (tt = fndws (t+7)) && (tt = fndnws (tt))) t = tt; c = *t; /* save character */ *t = '\0'; /* tie off prefix */ poot (s); /* output prefix */ *t = c; /* restore character */ s = t; /* new string pointer */ } /* static with known prefix */ else if (((s[0] == 's') && (s[1] == 't') && (s[2] == 'a') && (s[3] == 't') && (s[4] == 'i') && (s[5] == 'c') && (s[6] == ' ')) && (((s[7] == 'u') && (s[8] == 'n') && (s[9] == 's') && (s[10] == 'i') && (s[11] == 'g') && (s[12] == 'n') && (s[13] == 'e') && (s[14] == 'd')) || ((s[7] == 's') && (s[8] == 't') && (s[9] == 'r') && (s[10] == 'u') && (s[11] == 'c') && (s[12] == 't')) || ((s[7] == 'd') && (s[8] == 'o')) || ((s[9] == 'e') && (s[10] == 'l') && (s[11] == 's') && (s[12] == 'e'))) && (t = fndws (s)) && (t = fndnws (t)) && (t = fndws (t)) && (t = fndnws (t))) { c = *t; /* save character */ *t = '\0'; /* tie off prefix */ poot (s); /* output prefix */ *t = c; /* restore character */ s = t; /* new string pointer */ } /* one of the known prefixes? */ else if ((((s[0] == 'u') && (s[1] == 'n') && (s[2] == 's') && (s[3] == 'i') && (s[4] == 'g') && (s[5] == 'n') && (s[6] == 'e') && (s[7] == 'd')) || ((s[0] == 's') && (s[1] == 't') && (s[2] == 'r') && (s[3] == 'u') && (s[4] == 'c') && (s[5] == 't')) || ((s[0] == 's') && (s[1] == 't') && (s[2] == 'a') && (s[3] == 't') && (s[4] == 'i') && (s[5] == 'c')) || ((s[0] == 'd') && (s[1] == 'o')) || ((s[0] == 'e') && (s[1] == 'l') && (s[2] == 's') && (s[3] == 'e'))) && (t = fndws (s)) && (t = fndnws (t))) { c = *t; /* save character */ *t = '\0'; /* tie off prefix */ poot (s); /* output prefix */ *t = c; /* restore character */ s = t; /* new string pointer */ } /* may look like a proto, but isn't */ else if ((s[0] == 'r') && (s[1] == 'e') && (s[2] == 't') && (s[3] == 'u') && (s[4] == 'r') && (s[5] == 'n')) { poot (s); return 0; } return s; } /* UnANSI a line * Accepts: string */ void unansi (s) char *s; { char c,*t = s,*u,*v; while (t[1] && (t[1] != '\n')) t++; switch (*t) { case ',': /* continued on next line? */ /* slurp remainder of line */ fgets (t + 1,LINELENGTH - (t + 1 - s),stdin); unansi (s); /* try again */ break; case ';': /* function prototype? */ /* yes, tie it off */ *(fndws (fndnws (fndws (fndnws (s))))) = '\0'; printf ("%s ();\n",s); /* and output non-ANSI form */ break; case ')': *t = '\0'; /* tie off args */ if (*(t = fndnws (fndws (fndnws (fndws (fndnws (s)))))) == '(') { *t++ = '\0'; /* tie off */ while ((*t == ' ') || (*t == '\t')) t++; if ((t[0] == 'v') && (t[1] == 'o') && (t[2] == 'i') && (t[3] == 'd') && !t[4]) *t = '\0'; /* make void be same as null */ printf ("%s(",s); /* output start of function */ s = t; while (*s) { /* for each argument */ while ((*s == ' ') || (*s == '\t')) s++; for (u = v = s; (*u && (*u != ',') && (*u != '[')); u++) if ((*u == ' ') || (*u == '\t')) v = u; c = *u; /* remember delimiter */ *u = '\0'; /* tie off argument name */ while (*++v == '*'); /* remove leading pointer indication */ fputs (v,stdout); /* write variable name */ *(s = u) = c; /* restore delimiter */ while (*s && (*s != ',')) *s++; if (*s) fputc (*s++,stdout); } puts (")"); /* end of function */ while (*t) { /* for each argument */ fputs (" ",stdout); while ((*t == ' ') || (*t == '\t')) t++; while (*t && (*t != ',')) fputc (*t++,stdout); puts (";"); if (*t == ',') t++; } } else printf ("%s)",s); /* say what?? */ break; default: /* doesn't look like a function */ poot (s); } } main () { char *s,*t,line[LINELENGTH]; int c; while (s = fgets (line,LINELENGTH,stdin)) switch (line[0]) { case '/': /* comment */ if ((s[1] != '*') || fndcmt (s+2)) poot (line); else do poot (line); while (!fndcmt (line) && (s = fgets (line,LINELENGTH,stdin))); break; case '{': /* open function */ case '}': /* close function */ case '\f': /* formfeed */ case '\n': /* newline */ case '#': /* preprocessor command */ poot (line); break; case '\t': /* whitespace */ case ' ': /* look like function arg def in structure? */ if ((t = skipfx (line)) && (s = fndws (t)) && (s = fndnws (s)) && (((*s == '(') && (s[1] == '*')) || ((*s == '*') && (s[1] == '(') && (s[2] == '*'))) && (s = fndws (s)) && (s[-1] == ')') && (s = fndnws (s)) && (*s == '(')) unansi (t); else poot (t); break; default: /* begins with anything else */ /* look like function proto or def? */ if ((t = skipfx (line)) && (s = fndws (t)) && (s = fndnws (s)) && (s = fndws (s)) && (s = fndnws (s)) && (*s == '(')) unansi (t); else poot (t); break; } } alpine-2.10+dfsg/imap/tools/ua0000700000175000017500000000152311512502122017752 0ustar paulproteuspaulproteus#!/bin/sh # ======================================================================== # Copyright 1988-2006 University of Washington # # Licensed under the Apache License, Version 2.0 (the "License"); # you may not use this file except in compliance with the License. # You may obtain a copy of the License at # # http://www.apache.org/licenses/LICENSE-2.0 # # # ======================================================================== BASE=`pwd` if [ ! -f tools/uahelper ]; then (cd tools;make) fi if [ ! -d $3 ]; then mkdir $3 fi for i in $2/Makefile* ; do if [ -f $i ] ; then $1 "$BASE/$i" "$BASE/$3" fi done if [ -f $2/drivers ]; then $1 "$BASE/$2/drivers" "$BASE/$3" fi if [ -f $2/mkauths ]; then $1 "$BASE/$2/mkauths" "$BASE/$3" fi cd $2 for j in *.[ch]; do "$BASE/tools/uahelper" < $j > "$BASE/$3/$j" done exit 0 alpine-2.10+dfsg/imap/tools/an0000700000175000017500000000141411512502122017742 0ustar paulproteuspaulproteus#!/bin/sh # ======================================================================== # Copyright 1988-2007 University of Washington # # Licensed under the Apache License, Version 2.0 (the "License"); # you may not use this file except in compliance with the License. # You may obtain a copy of the License at # # http://www.apache.org/licenses/LICENSE-2.0 # # # ======================================================================== BASE=`pwd` if [ ! -d $3 ]; then mkdir $3 fi for i in $2/Makefile* ; do if [ -f $i ] ; then $1 "$BASE/$i" "$BASE/$3" fi done if [ -f $2/drivers ]; then $1 "$BASE/$2/drivers" "$BASE/$3" fi if [ -f $2/mkauths ]; then $1 "$BASE/$2/mkauths" "$BASE/$3" fi cd $2 for j in *.[ch]; do $1 "$BASE/$2/$j" "$BASE/$3" done exit 0 alpine-2.10+dfsg/imap/tools/Makefile0000600000175000017500000000153411512502122021063 0ustar paulproteuspaulproteus# ======================================================================== # Copyright 1988-2006 University of Washington # # Licensed under the Apache License, Version 2.0 (the "License"); # you may not use this file except in compliance with the License. # You may obtain a copy of the License at # # http://www.apache.org/licenses/LICENSE-2.0 # # # ======================================================================== # Program: Tools Makefile # # Author: Mark Crispin # Networks and Distributed Computing # Computing & Communications # University of Washington # Administration Building, AG-44 # Seattle, WA 98195 # Internet: MRC@CAC.Washington.EDU CC=cc RM=rm -f uahelper: $(CC) -o uahelper uahelper.c $(LDFLAGS) clean: sh -c '$(RM) *.o uahelper || true' # A monument to a hack of long ago and far away... love: @echo 'not war?' alpine-2.10+dfsg/imap/SUPPORT0000600000175000017500000000147511512502125017371 0ustar paulproteuspaulproteus/* ======================================================================== * Copyright 1988-2006 University of Washington * * Licensed under the Apache License, Version 2.0 (the "License"); * you may not use this file except in compliance with the License. * You may obtain a copy of the License at * * http://www.apache.org/licenses/LICENSE-2.0 * * * ======================================================================== */ BUG REPORTING ADDRESS Bug reports, comments, or questions regarding this software may be reported to the imap-uw@u.washington.edu mailing list (this replaces the old c-client@u.washington.edu mailing list). You can subscribe to this list by sending a message to: imap-uw-subscribe@mailman.u.washington.edu An alternative is to use the comp.mail.imap newsgroup. alpine-2.10+dfsg/imap/src/0000700000175000017500000000000011512502151017047 5ustar paulproteuspaulproteusalpine-2.10+dfsg/imap/src/tmail/0000700000175000017500000000000011512502151020155 5ustar paulproteuspaulproteusalpine-2.10+dfsg/imap/src/tmail/tquota.h0000600000175000017500000000161411512502122021645 0ustar paulproteuspaulproteus/* ======================================================================== * Copyright 1988-2007 University of Washington * * Licensed under the Apache License, Version 2.0 (the "License"); * you may not use this file except in compliance with the License. * You may obtain a copy of the License at * * http://www.apache.org/licenses/LICENSE-2.0 * * * ======================================================================== */ /* * Program: Mail Delivery Module Quota Hook * * Author: Mark Crispin * Networks and Distributed Computing * Computing & Communications * University of Washington * Administration Building, AG-44 * Seattle, WA 98195 * Internet: MRC@CAC.Washington.EDU * * Date: 10 September 2007 * Last Edited: 10 September 2007 */ /* Function prototypes */ long tmail_quota (STRING *msg,char *path,uid_t uid,char *tmp,char *sender, long precedence); alpine-2.10+dfsg/imap/src/tmail/Makefile0000600000175000017500000000230711512502122021617 0ustar paulproteuspaulproteus# ======================================================================== # Copyright 1988-2006 University of Washington # # Licensed under the Apache License, Version 2.0 (the "License"); # you may not use this file except in compliance with the License. # You may obtain a copy of the License at # # http://www.apache.org/licenses/LICENSE-2.0 # # # ======================================================================== # Program: tmail Makefile # # Author: Mark Crispin # Networks and Distributed Computing # Computing & Communications # University of Washington # Administration Building, AG-44 # Seattle, WA 98195 # Internet: MRC@CAC.Washington.EDU # # Date: 5 April 1993 # Last Edited: 10 September 2007 C = ../c-client CCLIENTLIB = $C/c-client.a SHELL = /bin/sh # Get local definitions from c-client directory CC = `cat $C/CCTYPE` CFLAGS = -I$C `cat $C/CFLAGS` LDFLAGS = $(CCLIENTLIB) `cat $C/LDFLAGS` tmail: $(CCLIENTLIB) tmail.o tquota.o $(CC) $(CFLAGS) -o tmail tmail.o tquota.o $(LDFLAGS) tmail.o: $C/mail.h $C/misc.h $C/osdep.h tquota.h tquota.o: tquota.h $(CCLIENTLIB): cd $C;make clean: rm -f *.o tmail # A monument to a hack of long ago and far away... love: @echo 'not war?' alpine-2.10+dfsg/imap/src/tmail/tmail.c0000600000175000017500000006172411512502122021441 0ustar paulproteuspaulproteus/* ======================================================================== * Copyright 1988-2007 University of Washington * * Licensed under the Apache License, Version 2.0 (the "License"); * you may not use this file except in compliance with the License. * You may obtain a copy of the License at * * http://www.apache.org/licenses/LICENSE-2.0 * * * ======================================================================== */ /* * Program: Mail Delivery Module * * Author: Mark Crispin * Networks and Distributed Computing * Computing & Communications * University of Washington * Administration Building, AG-44 * Seattle, WA 98195 * Internet: MRC@CAC.Washington.EDU * * Date: 5 April 1993 * Last Edited: 30 October 2008 */ #include #include #include extern int errno; /* just in case */ #include #include #include #include "c-client.h" #include "tquota.h" /* Globals */ char *version = "22"; /* tmail edit version */ int debug = NIL; /* debugging (don't fork) */ int trycreate = NIL; /* flag saying gotta create before appending */ int critical = NIL; /* flag saying in critical code */ char *sender = NIL; /* message origin */ char *inbox = NIL; /* inbox file */ long precedence = 0; /* delivery precedence - used by quota hook */ DRIVER *format = NIL; /* desired format */ /* Function prototypes */ void file_string_init (STRING *s,void *data,unsigned long size); char file_string_next (STRING *s); void file_string_setpos (STRING *s,unsigned long i); int main (int argc,char *argv[]); int deliver (FILE *f,unsigned long msglen,char *user); long ibxpath (MAILSTREAM *ds,char **mailbox,char *path); int deliver_safely (MAILSTREAM *prt,STRING *st,char *mailbox,char *path, uid_t uid,char *tmp); int delivery_unsafe (char *path,uid_t uid,struct stat *sbuf,char *tmp); int fail (char *string,int code); char *getusername (char *s,char **t); /* File string driver for file stringstructs */ STRINGDRIVER file_string = { file_string_init, /* initialize string structure */ file_string_next, /* get next byte in string structure */ file_string_setpos /* set position in string structure */ }; /* Cache buffer for file stringstructs */ #define CHUNKLEN 16384 char chunk[CHUNKLEN]; /* Initialize file string structure for file stringstruct * Accepts: string structure * pointer to string * size of string */ void file_string_init (STRING *s,void *data,unsigned long size) { s->data = data; /* note fd */ s->size = size; /* note size */ s->chunk = chunk; s->chunksize = (unsigned long) CHUNKLEN; SETPOS (s,0); /* set initial position */ } /* Get next character from file stringstruct * Accepts: string structure * Returns: character, string structure chunk refreshed */ char file_string_next (STRING *s) { char c = *s->curpos++; /* get next byte */ SETPOS (s,GETPOS (s)); /* move to next chunk */ return c; /* return the byte */ } /* Set string pointer position for file stringstruct * Accepts: string structure * new position */ void file_string_setpos (STRING *s,unsigned long i) { if (i > s->size) i = s->size; /* don't permit setting beyond EOF */ s->offset = i; /* set new offset */ s->curpos = s->chunk; /* reset position */ /* set size of data */ if (s->cursize = min (s->chunksize,SIZE (s))) { /* move to that position in the file */ fseek ((FILE *) s->data,s->offset,SEEK_SET); fread (s->curpos,sizeof (char),(unsigned int) s->cursize,(FILE *) s->data); } } /* Main program */ int main (int argc,char *argv[]) { FILE *f = NIL; int pid,c,ret = 0; unsigned long msglen,status = 0; char *s,tmp[MAILTMPLEN]; uid_t ruid = getuid (); struct passwd *pwd; openlog ("tmail",LOG_PID,LOG_MAIL); #include "linkage.c" /* make sure have some arguments */ if (--argc < 1) _exit (fail ("usage: tmail [-D] user[+folder]",EX_USAGE)); /* process all flags */ while (argc && (*(s = *++argv)) == '-') { argc--; /* gobble this argument */ switch (s[1]) { /* what is this flag? */ case 'D': /* debug */ debug = T; /* don't fork */ break; case 'I': /* inbox specifier */ if (inbox || format) _exit (fail ("duplicate -b or -I",EX_USAGE)); if (argc--) inbox = cpystr (*++argv); else _exit (fail ("missing argument to -I",EX_USAGE)); break; case 'f': /* new name for this flag */ case 'r': /* flag giving return path */ if (sender) _exit (fail ("duplicate -f or -r",EX_USAGE)); if (argc--) sender = cpystr (*++argv); else _exit (fail ("missing argument to -f or -r",EX_USAGE)); break; case 'b': /* create INBOX in this format */ if (inbox || format) _exit (fail ("duplicate -b or -I",EX_USAGE)); if (!argc--) _exit (fail ("missing argument to -b",EX_USAGE)); if (!(format = mail_parameters (NIL,GET_DRIVER,*++argv))) _exit (fail ("unknown format to -b",EX_USAGE)); else if (!(format->flags & DR_LOCAL) || !compare_cstring (format->name,"dummy")) _exit (fail ("invalid format to -b",EX_USAGE)); break; /* following flags are undocumented */ case 'p': /* precedence for quota */ if (s[2] && ((s[2] == '-') || isdigit (s[2]))) precedence = atol (s + 2); else if (argc-- && ((*(s = *++argv) == '-') || isdigit (*s))) precedence = atol (s); else _exit (fail ("missing argument to -p",EX_USAGE)); break; case 'd': /* obsolete flag meaning multiple users */ break; /* ignore silently */ /* -s has been deprecated and replaced by the -s and -k flags in dmail. * dmail's -k flag does what -s once did in tmail; dmail's -s flag * takes no argument and just sets \Seen. Flag setting is more properly * done in dmail which runs as the user and is clearly at the user's * behest. Since tmail runs privileged, -s would have to be disabled * unless the caller is also privileged. */ case 's': /* obsolete flag meaning delivery flags */ if (!argc--) /* takes an argument */ _exit (fail ("missing argument to deprecated flag",EX_USAGE)); syslog (LOG_INFO,"tmail called with deprecated flag: -s %.200s",*++argv); break; default: /* anything else */ _exit (fail ("unknown switch",EX_USAGE)); } } if (!argc) ret = fail ("no recipients",EX_USAGE); else if (!(f = tmpfile ())) ret = fail ("can't make temp file",EX_TEMPFAIL); else { /* build delivery headers */ if (sender) fprintf (f,"Return-Path: <%s>\015\012",sender); /* start Received line: */ fprintf (f,"Received: via tmail-%s.%s",CCLIENTVERSION,version); /* not root or daemon? */ if (ruid && !((pwd = getpwnam ("daemon")) && (ruid == pwd->pw_uid))) { pwd = getpwuid (ruid); /* get unprivileged user's information */ if (inbox || format) { if (pwd) sprintf (tmp,"user %.80s",pwd->pw_name); else sprintf (tmp,"UID %ld",(long) ruid); strcat (tmp," is not privileged to use -b or -I"); _exit (fail (tmp,EX_USAGE)); } fputs (" (invoked by ",f); if (pwd) fprintf (f,"user %s",pwd->pw_name); else fprintf (f,"UID %ld",(long) ruid); fputs (")",f); } /* write "for" if single recipient */ if (argc == 1) fprintf (f," for %s",*argv); fputs ("; ",f); rfc822_date (tmp); fputs (tmp,f); fputs ("\015\012",f); /* copy text from standard input */ if (!fgets (tmp,MAILTMPLEN-1,stdin) || !(s = strchr (tmp,'\n')) || (s == tmp) || s[1]) _exit (fail ("bad first message line",EX_USAGE)); if (s[-1] == '\015') { /* nuke leading "From " line */ if ((tmp[0] != 'F') || (tmp[1] != 'r') || (tmp[2] != 'o') || (tmp[3] != 'm') || (tmp[4] != ' ')) fputs (tmp,f); while ((c = getchar ()) != EOF) putc (c,f); } else { mm_log ("tmail called with LF-only newlines",WARN); if ((tmp[0] != 'F') || (tmp[1] != 'r') || (tmp[2] != 'o') || (tmp[3] != 'm') || (tmp[4] != ' ')) { *s++ = '\015'; /* overwrite NL with CRLF */ *s++ = '\012'; *s = '\0'; /* tie off string */ fputs (tmp,f); /* write line */ } /* copy text from standard input */ while ((c = getchar ()) != EOF) { /* add CR if needed */ if (c == '\012') putc ('\015',f); putc (c,f); } } msglen = ftell (f); /* size of message */ fflush (f); /* make sure all changes written out */ if (ferror (f)) ret = fail ("error writing temp file",EX_TEMPFAIL); else if (!msglen) ret = fail ("empty message",EX_TEMPFAIL); /* single delivery */ else if (argc == 1) ret = deliver (f,msglen,*argv); else do { /* multiple delivery uses daughter forks */ if ((pid = fork ()) < 0) ret = fail (strerror (errno),EX_OSERR); else if (pid) { /* mother process */ grim_pid_reap_status (pid,NIL,(void *) status); /* normal termination? */ if (!ret) ret = (status & 0xff) ? EX_SOFTWARE : (status & 0xff00) >> 8; } /* daughter process */ else _exit (deliver (f,msglen,*argv)); } while (--argc && *argv++); mm_dlog (ret ? "error in delivery" : "all recipients delivered"); } if (f) fclose (f); /* all done with temporary file */ _exit (ret); /* normal exit */ return 0; /* stupid gcc */ } /* Deliver message to recipient list * Accepts: file description of message temporary file * size of message temporary file in bytes * recipient name * Returns: NIL if success, else error code */ int deliver (FILE *f,unsigned long msglen,char *user) { MAILSTREAM *ds = NIL; char *s,*t,*mailbox,tmp[MAILTMPLEN],path[MAILTMPLEN]; struct passwd *pwd; STRING st; struct stat sbuf; uid_t duid; uid_t euid = geteuid (); /* get user record */ if (!(pwd = getpwnam (getusername (user,&mailbox)))) { sprintf (tmp,"no such user as %.80s",user); return fail (tmp,EX_NOUSER); } /* absurd is absurd */ if (mailbox && (strlen (mailbox) > 256)) return fail ("absurd folder name",EX_NOUSER); /* big security hole if this is allowed */ if (!(duid = pwd->pw_uid)) return fail ("mail to root prohibited",EX_NOUSER); /* log in as user if different than euid */ if ((duid != euid) && !loginpw (pwd,1,&user)) { sprintf (tmp,"unable to log in UID %ld from UID %ld", (long) duid,(long) euid); return fail (tmp,EX_NOUSER); } /* can't use pwd after this point */ env_init (pwd->pw_name,pwd->pw_dir); sprintf (tmp,"delivering to %.80s+%.80s",user,mailbox ? mailbox : "INBOX"); mm_dlog (tmp); /* prepare stringstruct */ INIT (&st,file_string,(void *) f,msglen); if (mailbox) { /* non-INBOX name */ switch (mailbox[0]) { /* make sure a valid name */ default: /* other names, try to deliver if not INBOX */ if (!strstr (mailbox,"..") && !strstr (mailbox,"//") && !strstr (mailbox,"/~") && mailboxfile (path,mailbox) && path[0] && !deliver_safely (NIL,&st,mailbox,path,duid,tmp)) return NIL; case '%': case '*': /* wildcards not valid */ case '#': /* namespace name not valid */ case '/': /* absolute path names not valid */ case '~': /* user names not valid */ sprintf (tmp,"invalid mailbox name %.80s+%.80s",user,mailbox); mm_log (tmp,WARN); break; } mm_dlog ("retrying delivery to INBOX"); SETPOS (&st,0); /* rewind stringstruct just in case */ } /* -I specified and not "-I INBOX"? */ if (inbox && !(((inbox[0] == 'I') || (inbox[0] == 'i')) && ((inbox[1] == 'N') || (inbox[1] == 'n')) && ((inbox[2] == 'B') || (inbox[2] == 'b')) && ((inbox[3] == 'O') || (inbox[3] == 'o')) && ((inbox[4] == 'X') || (inbox[4] == 'x')) && !inbox[5])) { DRIVER *dv = NIL; /* "-I #driver.xxx/name"? */ if ((*inbox == '#') && ((inbox[1] == 'd') || (inbox[1] == 'D')) && ((inbox[2] == 'r') || (inbox[2] == 'R')) && ((inbox[3] == 'i') || (inbox[3] == 'I')) && ((inbox[4] == 'v') || (inbox[4] == 'V')) && ((inbox[5] == 'e') || (inbox[5] == 'E')) && ((inbox[6] == 'r') || (inbox[6] == 'R')) && (inbox[7] == '.') && (s = strchr (inbox+8,'/'))) { *s = '\0'; /* temporarily tie off driver name */ if (!((dv = mail_parameters (NIL,GET_DRIVER,(void *) (inbox+8))) && (mailboxfile (path,s[1] ? s + 1 : "&&&&&") == path) && (s[1] || ((t = strstr (path,"&&&&&")) && strcpy (t,"INBOX"))))) { path[0] = '\0'; /* bad -I argument, no path resolved */ sprintf (tmp,"Unable to resolve driver in %.80s, -I ignored",inbox); mm_log (tmp,WARN); } *s = '/'; /* restore delimiter */ } /* resolve "-I other" specification */ else if (mailboxfile (path,inbox) && path[0]) { /* resolution succeeded, impute driver */ if (!strcmp (inbox,"mail.txt")) dv = mail_parameters (NIL,GET_DRIVER,(void *) "tenex"); else if (!strcmp (inbox,"INBOX.MTX")) dv = mail_parameters (NIL,GET_DRIVER,(void *) "mtx"); else if (!strcmp (inbox,"mbox")) dv = mail_parameters (NIL,GET_DRIVER,(void *) "unix"); } else { /* bad -I argument */ path[0] = '\0'; /* no path resolved */ sprintf (tmp,"Unable to resolve %.80s, -I ignored",inbox); mm_log (tmp,WARN); } if (*path) { /* -I successfully resolved a path? */ MAILSTREAM dpr; dpr.dtb = dv; if (dv) ds = &dpr; /* supplicate to the Evil One if necessary */ if (lstat (path,&sbuf) && !path_create (ds,path)) { /* the Evil One rejected the plea */ sprintf (tmp,"Unable to create %.80s, -I ignored",path); mm_log (tmp,WARN); } /* now attempt delivery */ else return deliver_safely (ds,&st,inbox,path,duid,tmp); } } /* no -I, resolve "INBOX" into path */ if (mailboxfile (path,mailbox = "INBOX") && !path[0]) { /* clear box, get generic INBOX prototype */ if (!(ds = mail_open (NIL,"INBOX",OP_PROTOTYPE))) fatal ("no INBOX prototype"); /* standard system driver? */ if (!strcmp (ds->dtb->name,"unix") || !strcmp (ds->dtb->name,"mmdf")) { strcpy (path,sysinbox ());/* use system INBOX */ if (!lstat (path,&sbuf)) /* deliver to existing system INBOX */ return deliver_safely (ds,&st,mailbox,path,duid,tmp); } else { /* other driver, try ~/INBOX */ if ((mailboxfile (path,"&&&&&") == path) && (s = strstr (path,"&&&&&")) && strcpy (s,"INBOX") && !lstat (path,&sbuf)){ /* deliver to existing ~/INBOX */ sprintf (tmp,"#driver.%s/INBOX",ds->dtb->name); return deliver_safely (ds,&st,cpystr (tmp),path,duid,tmp); } } /* not dummy, deliver to driver imputed path */ if (strcmp (ds->dtb->name,"dummy")) return (ibxpath (ds,&mailbox,path) && !lstat (path,&sbuf)) ? deliver_safely (ds,&st,mailbox,path,duid,tmp) : fail ("unable to resolve INBOX path",EX_CANTCREAT); /* dummy, empty imputed append path exist? */ if (ibxpath (ds = default_proto (T),&mailbox,path) && !lstat (path,&sbuf) && !sbuf.st_size) return deliver_safely (ds,&st,mailbox,path,duid,tmp); /* impute path that we will create */ if (!ibxpath (ds = format ? (format->open) (NIL) : default_proto (NIL), &mailbox,path)) return fail ("unable to resolve INBOX",EX_CANTCREAT); } /* black box, must create, get create proto */ else if (lstat (path,&sbuf)) ds = default_proto (NIL); else { /* black box, existing file */ /* empty file, get append prototype */ if (!sbuf.st_size) ds = default_proto (T); /* non-empty, get prototype from its data */ else if (!(ds = mail_open (NIL,"INBOX",OP_PROTOTYPE))) fatal ("no INBOX prototype"); /* error if unknown format */ if (!strcmp (ds->dtb->name,"phile")) return fail ("unknown format INBOX",EX_UNAVAILABLE); /* otherwise can deliver to it */ return deliver_safely (ds,&st,mailbox,path,duid,tmp); } sprintf (tmp,"attempting to create mailbox %.80s path %.80s",mailbox,path); mm_dlog (tmp); /* supplicate to the Evil One */ if (!path_create (ds,path)) return fail ("can't create INBOX",EX_CANTCREAT); sprintf (tmp,"created %.80s",path); mm_dlog (tmp); /* deliver the message */ return deliver_safely (ds,&st,mailbox,path,duid,tmp); } /* Resolve INBOX from driver prototype into mailbox name and filesystem path * Accepts: driver prototype * pointer to mailbox name string pointer * buffer to return mailbox path * Returns: T if success, NIL if error */ long ibxpath (MAILSTREAM *ds,char **mailbox,char *path) { char *s,tmp[MAILTMPLEN]; long ret = T; if (!ds) ret = NIL; else if (!strcmp (ds->dtb->name,"unix") || !strcmp (ds->dtb->name,"mmdf")) strcpy (path,sysinbox ()); /* use system INBOX for unix and MMDF */ else if (!strcmp (ds->dtb->name,"tenex")) ret = (mailboxfile (path,"mail.txt") == path) ? T : NIL; else if (!strcmp (ds->dtb->name,"mtx")) ret = (mailboxfile (path,"INBOX.MTX") == path) ? T : NIL; else if (!strcmp (ds->dtb->name,"mbox")) ret = (mailboxfile (path,"mbox") == path) ? T : NIL; /* better not be a namespace driver */ else if (ds->dtb->flags & DR_NAMESPACE) return NIL; /* INBOX in home directory */ else ret = ((mailboxfile (path,"&&&&&") == path) && (s = strstr (path,"&&&&&")) && strcpy (s,"INBOX")) ? T : NIL; if (ret) { /* don't bother if lossage */ sprintf (tmp,"#driver.%s/INBOX",ds->dtb->name); *mailbox = cpystr (tmp); /* name of INBOX in this namespace */ } return ret; } /* Deliver safely * Accepts: prototype stream to force mailbox format * stringstruct of message temporary file * mailbox name * filesystem path name * user id * scratch buffer for messages * Returns: NIL if success, else error code */ int deliver_safely (MAILSTREAM *prt,STRING *st,char *mailbox,char *path, uid_t uid,char *tmp) { struct stat sbuf; int i = delivery_unsafe (path,uid,&sbuf,tmp); if (i) return i; /* give up now if delivery unsafe */ /* directory, not file */ if ((sbuf.st_mode & S_IFMT) == S_IFDIR) { if (sbuf.st_mode & 0001) { /* listable directories may be worrisome */ sprintf (tmp,"WARNING: directory %.80s is listable",path); mm_log (tmp,WARN); } } else { /* file, not directory */ if (sbuf.st_nlink != 1) { /* multiple links may be worrisome */ sprintf (tmp,"WARNING: multiple links to file %.80s",path); mm_log (tmp,WARN); } if (sbuf.st_mode & 0111) { /* executable files may be worrisome */ sprintf (tmp,"WARNING: file %.80s is executable",path); mm_log (tmp,WARN); } } if (sbuf.st_mode & 0002) { /* public-write files may be worrisome */ sprintf (tmp,"WARNING: file %.80s is publicly-writable",path); mm_log (tmp,WARN); } if (sbuf.st_mode & 0004) { /* public-write files may be worrisome */ sprintf (tmp,"WARNING: file %.80s is publicly-readable",path); mm_log (tmp,WARN); } /* check site-written quota procedure */ if (!tmail_quota (st,path,uid,tmp,sender,precedence)) return fail (tmp,-1); /* so far, so good */ sprintf (tmp,"%s appending to %.80s (%s %.80s)", prt ? prt->dtb->name : "default",mailbox, ((sbuf.st_mode & S_IFMT) == S_IFDIR) ? "directory" : "file",path); mm_dlog (tmp); /* do the append now! */ if (!mail_append (prt,mailbox,st)) { sprintf (tmp,"message delivery failed to %.80s",path); return fail (tmp,EX_CANTCREAT); } /* note success */ sprintf (tmp,"delivered to %.80s",path); mm_log (tmp,NIL); /* make sure nothing evil this way comes */ return delivery_unsafe (path,uid,&sbuf,tmp); } /* Verify that delivery is safe * Accepts: path name * user id * stat buffer * scratch buffer for messages * Returns: NIL if delivery is safe, error code if unsafe */ int delivery_unsafe (char *path,uid_t uid,struct stat *sbuf,char *tmp) { u_short type; sprintf (tmp,"Verifying safe delivery to %.80s by UID %ld",path,(long) uid); mm_dlog (tmp); /* prepare message just in case */ sprintf (tmp,"delivery to %.80s unsafe: ",path); /* unsafe if can't get its status */ if (lstat (path,sbuf)) strcat (tmp,strerror (errno)); else if (sbuf->st_uid != uid) /* unsafe if UID does not match */ sprintf (tmp + strlen (tmp),"uid mismatch (%ld != %ld)", (long) sbuf->st_uid,(long) uid); /* check file type */ else switch (sbuf->st_mode & S_IFMT) { case S_IFDIR: /* directory is always OK */ return NIL; case S_IFREG: /* file is unsafe if setuid */ if (sbuf->st_mode & S_ISUID) strcat (tmp,"setuid file"); /* or setgid */ else if (sbuf->st_mode & S_ISGID) strcat (tmp,"setgid file"); else return NIL; /* otherwise safe */ break; case S_IFCHR: strcat (tmp,"character special"); break; case S_IFBLK: strcat (tmp,"block special"); break; case S_IFLNK: strcat (tmp,"symbolic link"); break; case S_IFSOCK: strcat (tmp,"socket"); break; default: sprintf (tmp + strlen (tmp),"file type %07o",(unsigned int) type); } return fail (tmp,EX_CANTCREAT); } /* Report an error * Accepts: string to output */ int fail (char *string,int code) { mm_log (string,ERROR); /* pass up the string */ switch (code) { #if T case EX_USAGE: case EX_OSERR: case EX_SOFTWARE: case EX_NOUSER: case EX_CANTCREAT: case EX_UNAVAILABLE: code = EX_TEMPFAIL; /* coerce these to TEMPFAIL */ #endif break; case -1: /* quota failure... */ code = EX_CANTCREAT; /* ...really returns this code */ break; default: break; } return code; /* error code to return */ } /* Get user name from username+mailbox specifier * Accepts: username/mailbox specifier * pointer to return location for mailbox specifier * Returns: user name, mailbox specifier value NIL if INBOX, patches out + */ char *getusername (char *s,char **t) { if (*t = strchr (s,'+')) { /* have a mailbox specifier? */ *(*t)++ = '\0'; /* yes, tie off user name */ /* user+ and user+INBOX same as user */ if (!**t || !compare_cstring ((unsigned char *) *t,"INBOX")) *t = NIL; } return s; /* return user name */ } /* Co-routines from MAIL library */ /* Message matches a search * Accepts: MAIL stream * message number */ void mm_searched (MAILSTREAM *stream,unsigned long msgno) { fatal ("mm_searched() call"); } /* Message exists (i.e. there are that many messages in the mailbox) * Accepts: MAIL stream * message number */ void mm_exists (MAILSTREAM *stream,unsigned long number) { fatal ("mm_exists() call"); } /* Message expunged * Accepts: MAIL stream * message number */ void mm_expunged (MAILSTREAM *stream,unsigned long number) { fatal ("mm_expunged() call"); } /* Message flags update seen * Accepts: MAIL stream * message number */ void mm_flags (MAILSTREAM *stream,unsigned long number) { } /* Mailbox found * Accepts: MAIL stream * delimiter * mailbox name * mailbox attributes */ void mm_list (MAILSTREAM *stream,int delimiter,char *name,long attributes) { fatal ("mm_list() call"); } /* Subscribed mailbox found * Accepts: MAIL stream * delimiter * mailbox name * mailbox attributes */ void mm_lsub (MAILSTREAM *stream,int delimiter,char *name,long attributes) { fatal ("mm_lsub() call"); } /* Mailbox status * Accepts: MAIL stream * mailbox name * mailbox status */ void mm_status (MAILSTREAM *stream,char *mailbox,MAILSTATUS *status) { fatal ("mm_status() call"); } /* Notification event * Accepts: MAIL stream * string to log * error flag */ void mm_notify (MAILSTREAM *stream,char *string,long errflg) { char tmp[MAILTMPLEN]; tmp[11] = '\0'; /* see if TRYCREATE */ if (!strcmp (ucase (strncpy (tmp,string,11)),"[TRYCREATE]")) trycreate = T; mm_log (string,errflg); /* just do mm_log action */ } /* Log an event for the user to see * Accepts: string to log * error flag */ void mm_log (char *string,long errflg) { if (trycreate)mm_dlog(string);/* debug logging only if trycreate in effect */ else { /* ordinary logging */ fprintf (stderr,"%s\n",string); switch (errflg) { case NIL: /* no error */ syslog (LOG_INFO,"%s",string); break; case PARSE: /* parsing problem */ case WARN: /* warning */ syslog (LOG_WARNING,"%s",string); break; case ERROR: /* error */ default: syslog (LOG_ERR,"%s",string); break; } } } /* Log an event to debugging telemetry * Accepts: string to log */ void mm_dlog (char *string) { if (debug) fprintf (stderr,"%s\n",string); syslog (LOG_DEBUG,"%s",string); } /* Get user name and password for this host * Accepts: parse of network mailbox name * where to return user name * where to return password * trial count */ void mm_login (NETMBX *mb,char *username,char *password,long trial) { fatal ("mm_login() call"); } /* About to enter critical code * Accepts: stream */ void mm_critical (MAILSTREAM *stream) { critical = T; /* note in critical code */ } /* About to exit critical code * Accepts: stream */ void mm_nocritical (MAILSTREAM *stream) { critical = NIL; /* note not in critical code */ } /* Disk error found * Accepts: stream * system error code * flag indicating that mailbox may be clobbered * Returns: T if user wants to abort */ long mm_diskerror (MAILSTREAM *stream,long errcode,long serious) { return T; } /* Log a fatal error event * Accepts: string to log */ void mm_fatal (char *string) { printf ("?%s\n",string); /* shouldn't happen normally */ } alpine-2.10+dfsg/imap/src/tmail/tmail.10000600000175000017500000001454411512502122021355 0ustar paulproteuspaulproteus.ig * ======================================================================== * Copyright 1988-2007 University of Washington * * Licensed under the Apache License, Version 2.0 (the "License"); * you may not use this file except in compliance with the License. * You may obtain a copy of the License at * * http://www.apache.org/licenses/LICENSE-2.0 * * * ======================================================================== .. .TH TMAIL 1 "September 27, 2007" .SH NAME tmail \- Mail Delivery Module .nh .SH SYNOPSIS .B tmail .I [-b format] [\-D] [-f from_name] [\-I inbox_specifier] user[+folder] ... .SH DESCRIPTION .I tmail delivers mail to a user's INBOX or a designated folder. .I tmail may be configured as a drop-in replacement for .IR binmail (1), .IR mail.local (1) or any program intended for use for mail delivery by a mail delivery program such as .IR sendmail (8). .PP .I tmail is intended to be used for direct delivery by the mailer daemon; .IR dmail (1) is the preferred tool for user applications, e.g. a mail delivery filter such as .IR procmail (1) . If .I tmail is used for a user application, then the calling program must be aware of the restrictions noted below. .PP When .I tmail exits, it returns exit status values to enable the mail delivery program to determine whether a message was delivered successfully or had a temporary (requeue for later delivery) or permanent (return to sender) failure. .PP If the .I +folder extension is included in the user argument, .I tmail will attempt to deliver to the designated folder. If the folder does not exist or the extension is not included, the message is delivered to the user's INBOX. If delivery is to INBOX and no INBOX currently exists, .I tmail will create a new INBOX, using the \fB-I\fR or \fB-b\fR flag if specified. .I tmail recognizes the format of an existing INBOX or folder, and appends the new message in that format. .PP The \fB-b\fR flag specifies a format to create INBOX if INBOX does not already exist. This flag requires privileges, and can not be used with \fB-I\fR. The argument is a format name such as mix, mbx, etc. .PP The \fB-D\fR flag specifies debugging; this enables additional message telemetry. .PP The \fB-f\fR or \fB-r\fR flag is used by the mail delivery program to specify a Return-Path. The header .br Return-Path: <\fIfrom_name\fR> .br is prepended to the message before delivery. .PP The \fB-I\fR flag is used by the mail delivery program to specify an alternative INBOX name. This flag requires privileges, and can not be used with \fB-b\fR. This affects the location and format of INBOX. If specified, it should be in one of three forms: .sp The first form of argument to \fB-I\fR is the string "INBOX", which means to write to the system default inbox using the system default mailbox format. These system defaults are defined when the c-client library is built. .sp The second form of argument to \fB-I\fR is a delivery specification, consisting of "#driver.", a c-client mailbox format driver name, "/", and a file name. This will write to the specified file in the specified format. For example, #driver.mbx/INBOX will write to file "INBOX" in the home directory in mbx format; and #driver.unix/mail/incoming will write to file "incoming" in the user's "mail" subdirectory in unix (default UNIX) format. .sp The third form of argument to \fB-I\fR is any other name. Normally, this will write to the specified file on the user's home directory in the specified format. However, certain names are special. These are: .PP .nf value equivalant to ----- ------------- INBOX.MTX #driver.mtx/INBOX.MTX mbox #driver.unix/mbox mail.txt #driver.tenex/mail.txt .fi .PP If \fB-I\fR is not specified, the default action is \fB-I INBOX\fR. .PP If multiple recipients are specified on the command line, .I tmail spawns one child process per recipient to perform actual delivery. This way of calling .I tmail is not recommended; see below under .IR RESTRICTIONS . .SH INSTALLATION If .I tmail is to be used for mail delivery from the mail delivery program, it .I must be installed setuid root. .sp If sendmail is the mail delivery program, .I tmail is invoked from sendmail.cf. Look for the "Mlocal" line, and substitute the path name for the .I tmail binary in place of /bin/mail, /usr/lib/mail.local, etc. You should also add the flag to invoke .I tmail with CRLF style newlines; this is usually done with E=\\r\\n in the Mlocal line. .sp Here is an example of an Mlocal line in sendmail version 8: .sp .nf Mlocal, P=/usr/local/etc/tmail, F=lsDFMAw5:/|@qPrn+, S=10/30, R=20/40, E=\\r\\n, T=DNS/RFC822/X-Unix, A=tmail $u .fi .PP If .I tmail is to be called with the \fB-I\fR flag, it must be invoked with both real and effective UID root. Many sendmail configurations invoke the local mailer as the sending user when that user is local, which will prevent \fB-b\fR or \fB-I\fR from working. .SH SECURITY CONSIDERATIONS If .I tmail is invoked by an ordinary user, the Received: header line will indicate the name or UID of the user that invoked it. .PP Ordinary users are not permitted to use the \fB-b\fR or \fB-I\fR flag since otherwise a user could create any file on another user's directory. .PP .I tmail can deliver mail to home directories. In addition, .I tmail can be used to deliver mail to other mail folders in a home directory or an inferior directory of a home directory. .SH RESTRICTIONS The calling program should invoke .I tmail with CRLF newlines, otherwise .I tmail will complain in syslog. .PP Absolute pathnames and .I ~user specifications are not permitted in .I +folder extensions. .PP Ordinary users are not permitted to use the \fB-I\fR flag. .PP IMAP4 namespace names are not yet supported in .I +folder extensions. .PP It is not possible to use .I tmail to deliver to .IR mh (1) format mailboxes. .PP If delivery to multiple users is specified and delivery to any single user fails, the entire delivery will be reported as having failed, even though delivery to other users may have succeeded. If .I tmail is used for mail delivery from .IR sendmail (8), a separate tmail invocation should be done for each user. Otherwise a delivery failure for a single user in a message going to multiple users will cause multiple deliveries to all the other users every time .IR sendmail (8), retries. .SH AUTHOR Mark Crispin, MRC@CAC.Washington.EDU .SH "SEE ALSO" binmail(1) .br sendmail(8) alpine-2.10+dfsg/imap/src/tmail/tquota.c0000600000175000017500000000237011512502122021640 0ustar paulproteuspaulproteus/* ======================================================================== * Copyright 1988-2007 University of Washington * * Licensed under the Apache License, Version 2.0 (the "License"); * you may not use this file except in compliance with the License. * You may obtain a copy of the License at * * http://www.apache.org/licenses/LICENSE-2.0 * * * ======================================================================== */ /* * Program: Mail Delivery Module Quota Hook * * Author: Mark Crispin * Networks and Distributed Computing * Computing & Communications * University of Washington * Administration Building, AG-44 * Seattle, WA 98195 * Internet: MRC@CAC.Washington.EDU * * Date: 10 September 2007 * Last Edited: 10 September 2007 */ #include "c-client.h" /* Site-written routine to validate delivery per quota and policy * Accepts: stringstruct of message temporary file * filesystem path * recipient user id * return path * buffer to write error message * precedence setting * Returns: T if can deliver, or NIL if quota issue and must bounce */ long tmail_quota (STRING *msg,char *path,uid_t uid,char *tmp,char *sender, long precedence) { return LONGT; /* dummy success return */ } alpine-2.10+dfsg/imap/src/mailutil/0000700000175000017500000000000011512502152020670 5ustar paulproteuspaulproteusalpine-2.10+dfsg/imap/src/mailutil/makefile.ntk0000600000175000017500000000264311512502122023167 0ustar paulproteuspaulproteus# ======================================================================== # Copyright 1988-2006 University of Washington # # Licensed under the Apache License, Version 2.0 (the "License"); # you may not use this file except in compliance with the License. # You may obtain a copy of the License at # # http://www.apache.org/licenses/LICENSE-2.0 # # # ======================================================================== # Program: MAILUTIL Makefile for Windows 9x and Windows NT + Kerberos # # Author: Mark Crispin # Networks and Distributed Computing # Computing & Communications # University of Washington # Administration Building, AG-44 # Seattle, WA 98195 # Internet: MRC@CAC.Washington.EDU # # Date: 25 February 1996 # Last Edited: 30 August 2006 C = ..\c-client CCLIENTLIB = $C\cclient.lib K5 = \k5\lib K5LIB = $(K5)\comerr32.lib $(K5)\gssapi32.lib $(K5)\krb5_32.lib LIBS = $(CCLIENTLIB) $(K5LIB) ws2_32.lib winmm.lib advapi32.lib OSCOMPAT = /DWIN32 /D_WIN32_WINNT=0x0400 VSCOMPAT = /D_CRT_SECURE_NO_DEPRECATE /D_CRT_NONSTDC_NO_DEPRECATE CFLAGS= -I$C /MT /W3 $(OSCOMPAT) $(VSCOMPAT) -nologo $(EXTRACFLAGS) mailutil: $(CCLIENTLIB) mailutil.obj LINK /NOLOGO mailutil.obj $(LIBS) mailutil.obj: $C\mail.h $C\smtp.h $C\misc.h $C\osdep.h mailutil.c $(CCLIENTLIB): @echo Make c-client first false clean: del *.obj *.exe *.lib *.exp || rem # A monument to a hack of long ago and far away... love: @echo not war? alpine-2.10+dfsg/imap/src/mailutil/Makefile0000600000175000017500000000225511512502122022333 0ustar paulproteuspaulproteus# ======================================================================== # Copyright 1988-2006 University of Washington # # Licensed under the Apache License, Version 2.0 (the "License"); # you may not use this file except in compliance with the License. # You may obtain a copy of the License at # # http://www.apache.org/licenses/LICENSE-2.0 # # # ======================================================================== # Program: mailutil Makefile # # Author: Mark Crispin # Networks and Distributed Computing # Computing & Communications # University of Washington # Administration Building, AG-44 # Seattle, WA 98195 # Internet: MRC@CAC.Washington.EDU # # Date: 2 February 1993 # Last Edited: 30 August 2006 C = ../c-client CCLIENTLIB = $C/c-client.a SHELL = /bin/sh # Get local definitions from c-client directory CC = `cat $C/CCTYPE` CFLAGS = -I$C `cat $C/CFLAGS` LDFLAGS = $(CCLIENTLIB) `cat $C/LDFLAGS` mailutil: $(CCLIENTLIB) mailutil.o $(CC) $(CFLAGS) -o mailutil mailutil.o $(LDFLAGS) mailutil.o: $C/mail.h $C/misc.h $C/osdep.h $(CCLIENTLIB): cd $C;make clean: rm -f *.o mailutil # A monument to a hack of long ago and far away... love: @echo 'not war?' alpine-2.10+dfsg/imap/src/mailutil/mailutil.c0000600000175000017500000007105711512502122022665 0ustar paulproteuspaulproteus/* ======================================================================== * Copyright 1988-2008 University of Washington * * Licensed under the Apache License, Version 2.0 (the "License"); * you may not use this file except in compliance with the License. * You may obtain a copy of the License at * * http://www.apache.org/licenses/LICENSE-2.0 * * * ======================================================================== */ /* * Program: Mail utility * * Author: Mark Crispin * UW Technology * University of Washington * Seattle, WA 98195 * Internet: MRC@Washington.EDU * * Date: 2 February 1994 * Last Edited: 19 February 2008 */ #include #include extern int errno; /* just in case */ #include "c-client.h" #ifdef SYSCONFIG /* defined in env_unix.h */ #include #endif /* Globals */ char *version = "13"; /* edit number */ int debugp = NIL; /* flag saying debug */ int verbosep = NIL; /* flag saying verbose */ int rwcopyp = NIL; /* flag saying readwrite copy (for POP) */ int kwcopyp = NIL; /* flag saying keyword copy */ int ignorep = NIL; /* flag saying ignore keywords */ int critical = NIL; /* flag saying in critical code */ int trycreate = NIL; /* [TRYCREATE] seen */ char *suffix = NIL; /* suffer merge mode suffix text */ int ddelim = -1; /* destination delimiter */ FILE *f = NIL; /* Usage strings */ char *usage2 = "usage: %s %s\n\n%s\n"; char *usage3 = "usage: %s %s %s\n\n%s\n"; char *usgchk = "check [MAILBOX]"; char *usgcre = "create MAILBOX"; char *usgdel = "delete MAILBOX"; char *usgren = "rename SOURCE DESTINATION"; char *usgcpymov = "[-rw[copy]] [-kw[copy]] [-ig[nore]] SOURCE DESTINATION"; char *usgappdel = "[-rw[copy]] [-kw[copy]] [-ig[nore]] SOURCE DESTINATION"; char *usgprn = "prune mailbox SEARCH_CRITERIA"; char *usgxfr = "transfer [-rw[copy]] [-kw[copy]] [-ig[nore]] [-m[erge] m] SOURCE DEST"; #ifdef SYSCONFIG char *stdsw = "Standard switches valid with any command:\n\t[-d[ebug]] [-v[erbose]] [-u[ser] userid] [--]"; #else char *stdsw = "Standard switches valid with any command:\n\t[-d[ebug]] [-v[erbose]]"; #endif /* Merge modes */ #define mPROMPT 1 #define mAPPEND 2 #define mSUFFIX 3 /* Function prototypes */ void ms_init (STRING *s,void *data,unsigned long size); char ms_next (STRING *s); void ms_setpos (STRING *s,unsigned long i); int main (int argc,char *argv[]); SEARCHPGM *prune_criteria (char *criteria); int prune_criteria_number (unsigned long *number,char **r); int mbxcopy (MAILSTREAM *source,MAILSTREAM *dest,char *dst,int create,int del, int mode); long mm_append (MAILSTREAM *stream,void *data,char **flags,char **date, STRING **message); /* Append package */ typedef struct append_package { MAILSTREAM *stream; /* source stream */ unsigned long msgno; /* current message number */ unsigned long msgmax; /* maximum message number */ char *flags; /* current flags */ char *date; /* message internal date */ STRING *message; /* stringstruct of message */ } APPENDPACKAGE; /* Message string driver for message stringstructs */ STRINGDRIVER mstring = { ms_init, /* initialize string structure */ ms_next, /* get next byte in string structure */ ms_setpos /* set position in string structure */ }; /* Initialize file string structure for file stringstruct * Accepts: string structure * pointer to message data structure * size of string */ void ms_init (STRING *s,void *data,unsigned long size) { APPENDPACKAGE *md = (APPENDPACKAGE *) data; s->data = data; /* note stream/msgno and header length */ mail_fetch_header (md->stream,md->msgno,NIL,NIL,&s->data1, FT_PREFETCHTEXT|FT_PEEK); #if 0 s->size = size; /* message size */ #else /* This kludge is necessary because of broken IMAP servers (sigh!) */ mail_fetch_text (md->stream,md->msgno,NIL,&s->size,FT_PEEK); s->size += s->data1; /* header + body size */ #endif SETPOS (s,0); } /* Get next character from file stringstruct * Accepts: string structure * Returns: character, string structure chunk refreshed */ char ms_next (STRING *s) { char c = *s->curpos++; /* get next byte */ SETPOS (s,GETPOS (s)); /* move to next chunk */ return c; /* return the byte */ } /* Set string pointer position for file stringstruct * Accepts: string structure * new position */ void ms_setpos (STRING *s,unsigned long i) { APPENDPACKAGE *md = (APPENDPACKAGE *) s->data; if (i < s->data1) { /* want header? */ s->chunk = mail_fetch_header (md->stream,md->msgno,NIL,NIL,NIL,FT_PEEK); s->chunksize = s->data1; /* header length */ s->offset = 0; /* offset is start of message */ } else if (i < s->size) { /* want body */ s->chunk = mail_fetch_text (md->stream,md->msgno,NIL,NIL,FT_PEEK); s->chunksize = s->size - s->data1; s->offset = s->data1; /* offset is end of header */ } else { /* off end of message */ s->chunk = NIL; /* make sure that we crack on this then */ s->chunksize = 1; /* make sure SNX cracks the right way... */ s->offset = i; } /* initial position and size */ s->curpos = s->chunk + (i -= s->offset); s->cursize = s->chunksize - i; } /* Main program */ int main (int argc,char *argv[]) { MAILSTREAM *source = NIL; MAILSTREAM *dest = NIL; SEARCHPGM *criteria; char c,*s,*dp,*t,*t1,tmp[MAILTMPLEN],mbx[MAILTMPLEN]; unsigned long m,len,curlen,start,last; int i; int merge = NIL; int retcode = 1; int moreswitchp = T; char *cmd = NIL; char *src = NIL; char *dst = NIL; char *pgm = argc ? argv[0] : "mailutil"; #include "linkage.c" for (i = 1; i < argc; i++) { s = argv[i]; /* pick up argument */ /* parse switches */ if (moreswitchp && (*s == '-')) { if (!strcmp (s,"-debug") || !strcmp (s,"-d")) debugp = T; else if (!strcmp (s,"-verbose") || !strcmp (s,"-v")) verbosep = T; else if (!strcmp (s,"-rwcopy") || !strcmp (s,"-rw")) rwcopyp = T; else if (!strcmp (s,"-kwcopy") || !strcmp (s,"-kw")) kwcopyp = T; else if (!strcmp (s,"-ignore") || !strcmp (s,"-ig")) ignorep = T; else if ((!strcmp (s,"-merge") || !strcmp (s,"-m")) && (++i < argc)) { if (!strcmp (s = argv[i],"prompt")) merge = mPROMPT; else if (!strcmp (s,"append")) merge = mAPPEND; else if (!strncmp (s,"suffix=",7) && s[7]) { merge = mSUFFIX; suffix = cpystr (s+7); } else { printf ("unknown merge option: %s\n",s); exit (retcode); } } #ifdef SYSCONFIG else if ((!strcmp (s,"-user") || !strcmp (s,"-u")) && (++i < argc)) { struct passwd *pw = getpwnam (s = argv[i]); if (!pw) { printf ("unknown user id: %s\n",argv[i]); exit (retcode); } else if (setuid (pw->pw_uid)) { perror ("unable to change user id"); exit (retcode); } } #endif /* -- means no more switches, so mailbox name can start with "-" */ else if ((s[1] == '-') && !s[2]) moreswitchp = NIL; else { printf ("unknown switch: %s\n",s); exit (retcode); } } else if (!cmd) cmd = s; /* first non-switch is command */ else if (!src) src = s; /* second non-switch is source */ else if (!dst) dst = s; /* third non-switch is destination */ else { printf ("unknown argument: %s\n",s); exit (retcode); } } if (kwcopyp && ignorep) { puts ("-kwcopy and -ignore are mutually exclusive"); exit (retcode); } if (!cmd) cmd = ""; /* prevent SEGV */ if (!strcmp (cmd,"check")) { /* check for new messages */ if (!src) src = "INBOX"; if (dst || merge || rwcopyp || kwcopyp || ignorep) printf (usage2,pgm,usgchk,stdsw); else if (mail_status (source = (*src == '{') ? mail_open (NIL,src,OP_HALFOPEN | (debugp ? OP_DEBUG : NIL)) : NIL, src,SA_MESSAGES | SA_RECENT | SA_UNSEEN)) retcode = 0; } else if (!strcmp (cmd,"create")) { if (!src || dst || merge || rwcopyp || kwcopyp || ignorep) printf (usage2,pgm,usgcre,stdsw); else if (mail_create (source = (*src == '{') ? mail_open (NIL,src,OP_HALFOPEN | (debugp ? OP_DEBUG : NIL)) : NIL,src)) retcode = 0; } else if (!strcmp (cmd,"delete")) { if (!src || dst || merge || rwcopyp || kwcopyp || ignorep) printf (usage2,pgm,usgdel,stdsw); else if (mail_delete (source = (*src == '{') ? mail_open (NIL,src,OP_HALFOPEN | (debugp ? OP_DEBUG : NIL)) : NIL,src)) retcode = 0; } else if (!strcmp (cmd,"rename")) { if (!src || !dst || merge || rwcopyp || kwcopyp || ignorep) printf (usage2,pgm,usgren,stdsw); else if (mail_rename (source = (*src == '{') ? mail_open (NIL,src,OP_HALFOPEN | (debugp ? OP_DEBUG : NIL)) : NIL,src,dst)) retcode = 0; } else if ((i = !strcmp (cmd,"move")) || !strcmp (cmd,"copy")) { if (!src || !dst || merge) printf (usage3,pgm,cmd,usgcpymov,stdsw); else if (source = mail_open (NIL,src,((i || rwcopyp) ? NIL : OP_READONLY) | (debugp ? OP_DEBUG : NIL))) { dest = NIL; /* open destination stream if network */ if ((*dst != '{') || (dest = mail_open (NIL,dst,OP_HALFOPEN | (debugp ? OP_DEBUG : NIL)))) { if (mbxcopy (source,dest,dst,T,i,merge)) retcode = 0; } } } else if ((i = !strcmp (cmd,"appenddelete")) || !strcmp (cmd,"append")) { if (!src || !dst || merge) printf (usage3,pgm,cmd,usgappdel,stdsw); else if (source = mail_open (NIL,src,((i || rwcopyp) ? NIL : OP_READONLY) | (debugp ? OP_DEBUG : NIL))) { dest = NIL; /* open destination stream if network */ if ((*dst != '{') || (dest = mail_open (NIL,dst,OP_HALFOPEN | (debugp ? OP_DEBUG : NIL)))) { if (mbxcopy (source,dest,dst,NIL,i,merge)) retcode = 0; } } } else if (!strcmp (cmd,"prune")) { if (!src || !dst || merge || rwcopyp || kwcopyp || ignorep || !(criteria = prune_criteria (dst))) printf (usage2,pgm,usgprn,stdsw); else if ((source = mail_open (NIL,src,(debugp ? OP_DEBUG : NIL))) && mail_search_full (source,NIL,criteria,SE_FREE)) { for (m = 1, s = t = NIL, len = start = last = 0; m <= source->nmsgs; m++) if (mail_elt (source,m)->searched) { if (s) { /* continuing a range? */ if (m == last + 1) last = m; else { /* no, end of previous range? */ if (last != start) sprintf (t,":%lu,%lu",last,m); /* no, just this message */ else sprintf (t,",%lu",m); start = last = m; /* either way, start new range */ /* running out of space? */ if ((len - (curlen = (t += strlen (t)) - s)) < 20) { fs_resize ((void **) &s,len += MAILTMPLEN); t = s + curlen; /* relocate current pointer */ } } } else { /* first time, start new buffer */ s = (char *) fs_get (len = MAILTMPLEN); sprintf (s,"%lu",start = last = m); t = s + strlen (s); /* end of buffer */ } } /* finish last range if necessary */ if (last != start) sprintf (t,":%lu",last); if (s) { /* delete/expunge any matching messages */ mail_flag (source,s,"\\Deleted",ST_SET); m = source->nmsgs; /* get number of messages before purge */ mail_expunge (source); printf ("%lu message(s) purged\n",m - source->nmsgs); fs_give ((void **) &s); /* flush buffer */ } else puts ("No matching messages, so nothing purged"); source = mail_close (source); } } else if (!strcmp (cmd,"transfer")) { if (!src || !dst) printf (usage2,pgm,usgxfr,stdsw); else if ((*src == '{') && /* open source mailbox */ !(source = mail_open (NIL,src,OP_HALFOPEN | (debugp ? OP_DEBUG : NIL)))); else if ((*dst == '{') && /* open destination server */ !(dest = mail_open (NIL,dst,OP_HALFOPEN | (debugp ? OP_DEBUG : NIL)))); else if (!(f = tmpfile ())) puts ("can't open temporary file"); else { if (verbosep) puts ("Listing mailboxes..."); if (dest) strcpy (strchr (strcpy (tmp,dest->mailbox),'}') + 1, dp = strchr (dst,'}') + 1); else { dp = dst; tmp[0] = '\0'; } mail_list (dest,tmp,""); rewind (f); /* list all mailboxes matching prefix */ if (ddelim < 0) { /* if server failed to give delimiter */ puts ("warning: unable to get destination hierarchy delimiter!"); ddelim = 0; /* default to none */ } if (source) strcpy (strchr (strcpy (tmp,source->mailbox),'}') + 1, strchr (src,'}') + 1); else strcpy (tmp,src); mail_list (source,tmp,"*"); rewind (f); /* read back mailbox names */ for (retcode = 0; !retcode && (fgets (tmp,MAILTMPLEN-1,f)); ) { if (t = strchr (tmp+1,'\n')) *t = '\0'; for (t = mbx,t1 = dest ? dest->mailbox : "",c = NIL; (c != '}') && *t1; *t++ = c= *t1++); for (t1 = dp; *t1; *t++ = *t1++); /* point to name without delim or netspec */ t1 = source ? (strchr (tmp+1,'}') + 1) : tmp + 1; /* src and mbx have different delimiters? */ if (ddelim && (ddelim != tmp[0])) while (c = *t1++) { /* swap delimiters then */ if (c == ddelim) c = tmp[0] ? tmp[0] : 'x'; else if (c == tmp[0]) c = ddelim; *t++ = c; } /* easy case */ else while (*t1) *t++ = *t1++; *t++ = '\0'; if (verbosep) { printf ("Copying %s\n => %s\n",tmp+1,mbx); fflush (stdout); } if (source = mail_open (source,tmp+1,(debugp ? OP_DEBUG : NIL) | (rwcopyp ? NIL : OP_READONLY))) { if (!mbxcopy (source,dest,mbx,T,NIL,merge)) retcode = 1; if (source->dtb->flags & DR_LOCAL) source = mail_close (source); } else printf ("can't open source mailbox %s\n",tmp+1); } } } else { printf ("%s version %s.%s\n\n",pgm,CCLIENTVERSION,version); printf (usage2,pgm,"command [switches] arguments",stdsw); printf ("\nCommands:\n %s\n",usgchk); puts (" ;; report number of messages and new messages"); printf (" %s\n",usgcre); puts (" ;; create new mailbox"); printf (" %s\n",usgdel); puts (" ;; delete existing mailbox"); printf (" %s\n",usgren); puts (" ;; rename mailbox to a new name"); printf (" copy %s\n",usgcpymov); printf (" move %s\n",usgcpymov); puts (" ;; create new mailbox and copy/move messages"); printf (" append %s\n",usgappdel); printf (" appenddelete %s\n",usgappdel); puts (" ;; copy/move messages to existing mailbox"); printf (" %s\n",usgprn); puts (" ;; prune mailbox of messages matching criteria"); printf (" %s\n",usgxfr); puts (" ;; copy source hierarchy to destination"); puts (" ;; -merge modes are prompt, append, or suffix=xxxx"); } /* close streams */ if (source) mail_close (source); if (dest) mail_close (dest); exit (retcode); return retcode; /* stupid compilers */ } /* Pruning criteria, somewhat extended from mail_criteria() * Accepts: criteria * Returns: search program if parse successful, else NIL */ SEARCHPGM *prune_criteria (char *criteria) { SEARCHPGM *pgm = NIL; char *criterion,*r,tmp[MAILTMPLEN]; int f; if (criteria) { /* only if criteria defined */ /* make writeable copy of criteria */ criteria = cpystr (criteria); /* for each criterion */ for (pgm = mail_newsearchpgm (), criterion = strtok_r (criteria," ",&r); criterion; (criterion = strtok_r (NIL," ",&r))) { f = NIL; /* init then scan the criterion */ switch (*ucase (criterion)) { case 'A': /* possible ALL, ANSWERED */ if (!strcmp (criterion+1,"LL")) f = T; else if (!strcmp (criterion+1,"NSWERED")) f = pgm->answered = T; break; case 'B': /* possible BCC, BEFORE, BODY */ if (!strcmp (criterion+1,"CC")) f = mail_criteria_string (&pgm->bcc,&r); else if (!strcmp (criterion+1,"EFORE")) f = mail_criteria_date (&pgm->before,&r); else if (!strcmp (criterion+1,"ODY")) f = mail_criteria_string (&pgm->body,&r); break; case 'C': /* possible CC */ if (!strcmp (criterion+1,"C")) f = mail_criteria_string (&pgm->cc,&r); break; case 'D': /* possible DELETED, DRAFT */ if (!strcmp (criterion+1,"ELETED")) f = pgm->deleted = T; else if (!strcmp (criterion+1,"RAFT")) f = pgm->draft = T; break; case 'F': /* possible FLAGGED, FROM */ if (!strcmp (criterion+1,"LAGGED")) f = pgm->flagged = T; else if (!strcmp (criterion+1,"ROM")) f = mail_criteria_string (&pgm->from,&r); break; case 'K': /* possible KEYWORD */ if (!strcmp (criterion+1,"EYWORD")) f = mail_criteria_string (&pgm->keyword,&r); break; case 'L': /* possible LARGER */ if (!strcmp (criterion+1,"ARGER")) f = prune_criteria_number (&pgm->larger,&r); case 'N': /* possible NEW */ if (!strcmp (criterion+1,"EW")) f = pgm->recent = pgm->unseen = T; break; case 'O': /* possible OLD, ON */ if (!strcmp (criterion+1,"LD")) f = pgm->old = T; else if (!strcmp (criterion+1,"N")) f = mail_criteria_date (&pgm->on,&r); break; case 'R': /* possible RECENT */ if (!strcmp (criterion+1,"ECENT")) f = pgm->recent = T; break; case 'S': /* possible SEEN, SENT*, SINCE, SMALLER, SUBJECT */ if (!strcmp (criterion+1,"EEN")) f = pgm->seen = T; else if (!strncmp (criterion+1,"ENT",3)) { if (!strcmp (criterion+4,"BEFORE")) f = mail_criteria_date (&pgm->sentbefore,&r); else if (!strcmp (criterion+4,"ON")) f = mail_criteria_date (&pgm->senton,&r); else if (!strcmp (criterion+4,"SINCE")) f = mail_criteria_date (&pgm->sentsince,&r); } else if (!strcmp (criterion+1,"INCE")) f = mail_criteria_date (&pgm->since,&r); else if (!strcmp (criterion+1,"MALLER")) f = prune_criteria_number (&pgm->smaller,&r); else if (!strcmp (criterion+1,"UBJECT")) f = mail_criteria_string (&pgm->subject,&r); break; case 'T': /* possible TEXT, TO */ if (!strcmp (criterion+1,"EXT")) f = mail_criteria_string (&pgm->text,&r); else if (!strcmp (criterion+1,"O")) f = mail_criteria_string (&pgm->to,&r); break; case 'U': /* possible UN* */ if (criterion[1] == 'N') { if (!strcmp (criterion+2,"ANSWERED")) f = pgm->unanswered = T; else if (!strcmp (criterion+2,"DELETED")) f = pgm->undeleted = T; else if (!strcmp (criterion+2,"DRAFT")) f = pgm->undraft = T; else if (!strcmp (criterion+2,"FLAGGED")) f = pgm->unflagged = T; else if (!strcmp (criterion+2,"KEYWORD")) f = mail_criteria_string (&pgm->unkeyword,&r); else if (!strcmp (criterion+2,"SEEN")) f = pgm->unseen = T; } break; default: /* we will barf below */ break; } if (!f) { /* if can't identify criterion */ sprintf (tmp,"Unknown search criterion: %.30s",criterion); MM_LOG (tmp,ERROR); mail_free_searchpgm (&pgm); break; } } /* no longer need copy of criteria */ fs_give ((void **) &criteria); } return pgm; } /* Parse a number * Accepts: pointer to integer to return * pointer to strtok state * Returns: T if successful, else NIL */ int prune_criteria_number (unsigned long *number,char **r) { char *t; STRINGLIST *s = NIL; /* parse the date and return fn if OK */ int ret = (mail_criteria_string (&s,r) && (*number = strtoul ((char *) s->text.data,&t,10)) && !*t) ? T : NIL; if (s) mail_free_stringlist (&s); return ret; } /* Copy mailbox * Accepts: stream open on source * halfopen stream for destination or NIL * destination mailbox name * non-zero to create destination mailbox * non-zero to delete messages from source after copying * merge mode * Returns: T if success, NIL if error */ int mbxcopy (MAILSTREAM *source,MAILSTREAM *dest,char *dst,int create,int del, int mode) { char *s,tmp[MAILTMPLEN]; APPENDPACKAGE ap; STRING st; char *ndst = NIL; int ret = NIL; trycreate = NIL; /* no TRYCREATE yet */ if (create) while (!mail_create (dest,dst) && (mode != mAPPEND)) { switch (mode) { case mPROMPT: /* prompt user for new name */ tmp[0] = '\0'; while (!tmp[0]) { /* read name */ fputs ("alternative name: ",stdout); fflush (stdout); fgets (tmp,MAILTMPLEN-1,stdin); if (s = strchr (tmp,'\n')) *s = '\0'; } if (ndst) fs_give ((void **) &ndst); ndst = cpystr (tmp); break; case mSUFFIX: /* try again with new suffix */ if (ndst) fs_give ((void **) &ndst); sprintf (ndst = (char *) fs_get (strlen (dst) + strlen (suffix) + 1), "%s%s",dst,suffix); printf ("retry to create %s\n",ndst); mode = mPROMPT; /* switch to prompt mode if name fails */ break; case NIL: /* not merging */ return NIL; } if (ndst) dst = ndst; /* if alternative name given, use it */ } if (kwcopyp) { int i; size_t len; char *dummymsg = "Date: Thu, 18 May 2006 00:00 -0700\r\nFrom: dummy@example.com\r\nSubject: dummy\r\n\r\ndummy\r\n"; for (i = 0,len = 0; i < NUSERFLAGS; ++i) if (source->user_flags[i]) len += strlen (source->user_flags[i]) + 1; if (len) { /* easy if no user flags to copy... */ char *t; char *tail = "\\Deleted)"; char *flags = (char *) fs_get (1 + len + strlen (tail) + 1); s = flags; *s++ = '('; for (i = 0; i < NUSERFLAGS; ++i) if (t = source->user_flags[i]) { while (*t) *s++ = *t++; *s++ = ' '; } strcpy (s,tail); /* terminate flags list */ if ((dst[0] == '#') && ((dst[1] == 'D') || (dst[1] == 'd')) && ((dst[2] == 'R') || (dst[2] == 'r')) && ((dst[3] == 'I') || (dst[3] == 'i')) && ((dst[4] == 'V') || (dst[4] == 'v')) && ((dst[5] == 'E') || (dst[5] == 'e')) && ((dst[6] == 'R') || (dst[6] == 'r')) && (dst[7] == '.') && (t = strchr (dst+8,'/'))) ++t; else t = dst; INIT (&st,mail_string,dummymsg,strlen (dummymsg)); if (!(mail_append (dest,dst,&st) && (dest = mail_open (dest,t,debugp ? OP_DEBUG : NIL)))) { fs_give ((void **) &flags); return NIL; } mail_setflag (dest,"*",flags); mail_expunge (dest); fs_give ((void **) &flags); } } if (source->nmsgs) { /* non-empty source */ if (verbosep) printf ("%s [%lu message(s)] => %s\n", source->mailbox,source->nmsgs,dst); ap.stream = source; /* prepare append package */ ap.msgno = 0; ap.msgmax = source->nmsgs; ap.flags = ap.date = NIL; ap.message = &st; /* make sure we have all messages */ sprintf (tmp,"1:%lu",ap.msgmax); mail_fetchfast (source,tmp); if (mail_append_multiple (dest,dst,mm_append,(void *) &ap)) { --ap.msgno; /* make sure user knows it won */ if (verbosep) printf ("[Ok %lu messages(s)]\n",ap.msgno); if (del && ap.msgno) { /* delete source messages */ sprintf (tmp,"1:%lu",ap.msgno); mail_flag (source,tmp,"\\Deleted",ST_SET); /* flush moved messages */ mail_expunge (source); } ret = T; } else if ((mode == mAPPEND) && trycreate) ret = mbxcopy (source,dest,dst,create,del,mPROMPT); else if (verbosep) puts ("[Failed]"); } else { /* empty source */ if (verbosep) printf ("%s [empty] => %s\n",source->mailbox,dst); ret = T; } if (ndst) fs_give ((void **) &ndst); return ret; } /* Append callback * Accepts: mail stream * append package * pointer to return flags * pointer to return date * pointer to return message stringstruct * Returns: T on success */ long mm_append (MAILSTREAM *stream,void *data,char **flags,char **date, STRING **message) { char *t,*t1,tmp[MAILTMPLEN]; unsigned long u; MESSAGECACHE *elt; APPENDPACKAGE *ap = (APPENDPACKAGE *) data; *flags = *date = NIL; /* assume no flags or date */ if (ap->flags) fs_give ((void **) &ap->flags); if (ap->date) fs_give ((void **) &ap->date); mail_gc (ap->stream,GC_TEXTS); if (++ap->msgno <= ap->msgmax) { /* initialize flag string */ memset (t = tmp,0,MAILTMPLEN); /* output system flags */ if ((elt = mail_elt (ap->stream,ap->msgno))->seen) strcat (t," \\Seen"); if (elt->deleted) strcat (t," \\Deleted"); if (elt->flagged) strcat (t," \\Flagged"); if (elt->answered) strcat (t," \\Answered"); if (elt->draft) strcat (t," \\Draft"); /* any user flags? */ if (!ignorep && (u = elt->user_flags)) do if ((t1 = ap->stream->user_flags[find_rightmost_bit (&u)]) && (MAILTMPLEN - ((t += strlen (t)) - tmp)) > (long) (2 + strlen (t1))){ *t++ = ' '; /* space delimiter */ strcpy (t,t1); /* copy the user flag */ } while (u); /* until no more user flags */ *flags = ap->flags = cpystr (tmp + 1); *date = ap->date = cpystr (mail_date (tmp,elt)); *message = ap->message; /* message stringstruct */ INIT (ap->message,mstring,(void *) ap,elt->rfc822_size); } else *message = NIL; /* all done */ return LONGT; } /* Co-routines from MAIL library */ /* Message matches a search * Accepts: MAIL stream * message number */ void mm_searched (MAILSTREAM *stream,unsigned long msgno) { /* dummy routine */ } /* Message exists (i.e. there are that many messages in the mailbox) * Accepts: MAIL stream * message number */ void mm_exists (MAILSTREAM *stream,unsigned long number) { /* dummy routine */ } /* Message expunged * Accepts: MAIL stream * message number */ void mm_expunged (MAILSTREAM *stream,unsigned long number) { /* dummy routine */ } /* Message flags update seen * Accepts: MAIL stream * message number */ void mm_flags (MAILSTREAM *stream,unsigned long number) { /* dummy routine */ } /* Mailbox found * Accepts: MAIL stream * hierarchy delimiter * mailbox name * mailbox attributes */ void mm_list (MAILSTREAM *stream,int delimiter,char *name,long attributes) { /* note destination delimiter */ if (ddelim < 0) ddelim = delimiter; /* if got a selectable name */ else if (!(attributes & LATT_NOSELECT) && *name) fprintf (f,"%c%s\n",delimiter,name); } /* Subscribe mailbox found * Accepts: MAIL stream * hierarchy delimiter * mailbox name * mailbox attributes */ void mm_lsub (MAILSTREAM *stream,int delimiter,char *name,long attributes) { /* dummy routine */ } /* Mailbox status * Accepts: MAIL stream * mailbox name * mailbox status */ void mm_status (MAILSTREAM *stream,char *mailbox,MAILSTATUS *status) { if (status->recent || status->unseen) printf ("%lu new message(s) (%lu unseen),",status->recent,status->unseen); else fputs ("No new messages,",stdout); printf (" %lu total in %s\n",status->messages,mailbox); } /* Notification event * Accepts: MAIL stream * string to log * error flag */ void mm_notify (MAILSTREAM *stream,char *string,long errflg) { if (!errflg && (string[0] == '[') && ((string[1] == 'T') || (string[1] == 't')) && ((string[2] == 'R') || (string[2] == 'r')) && ((string[3] == 'Y') || (string[3] == 'y')) && ((string[4] == 'C') || (string[4] == 'c')) && ((string[5] == 'R') || (string[5] == 'r')) && ((string[6] == 'E') || (string[6] == 'e')) && ((string[7] == 'A') || (string[7] == 'a')) && ((string[8] == 'T') || (string[8] == 't')) && ((string[9] == 'E') || (string[9] == 'e')) && (string[10] == ']')) trycreate = T; mm_log (string,errflg); /* just do mm_log action */ } /* Log an event for the user to see * Accepts: string to log * error flag */ void mm_log (char *string,long errflg) { switch (errflg) { case BYE: case NIL: /* no error */ if (verbosep) fprintf (stderr,"[%s]\n",string); break; case PARSE: /* parsing problem */ case WARN: /* warning */ fprintf (stderr,"warning: %s\n",string); break; case ERROR: /* error */ default: fprintf (stderr,"%s\n",string); break; } } /* Log an event to debugging telemetry * Accepts: string to log */ void mm_dlog (char *string) { fprintf (stderr,"%s\n",string); } /* Get user name and password for this host * Accepts: parse of network mailbox name * where to return user name * where to return password * trial count */ void mm_login (NETMBX *mb,char *username,char *password,long trial) { char *s,tmp[MAILTMPLEN]; sprintf (s = tmp,"{%s/%s",mb->host,mb->service); if (*mb->user) sprintf (tmp+strlen (tmp),"/user=%s", strcpy (username,mb->user)); if (*mb->authuser) sprintf (tmp+strlen (tmp),"/authuser=%s",mb->authuser); if (*mb->user) strcat (s = tmp,"} password:"); else { printf ("%s} username: ",tmp); fgets (username,NETMAXUSER-1,stdin); username[NETMAXUSER-1] = '\0'; if (s = strchr (username,'\n')) *s = '\0'; s = "password: "; } strcpy (password,getpass (s)); } /* About to enter critical code * Accepts: stream */ void mm_critical (MAILSTREAM *stream) { critical = T; /* note in critical code */ } /* About to exit critical code * Accepts: stream */ void mm_nocritical (MAILSTREAM *stream) { critical = NIL; /* note not in critical code */ } /* Disk error found * Accepts: stream * system error code * flag indicating that mailbox may be clobbered * Returns: T if user wants to abort */ long mm_diskerror (MAILSTREAM *stream,long errcode,long serious) { return T; } /* Log a fatal error event * Accepts: string to log */ void mm_fatal (char *string) { fprintf (stderr,"FATAL: %s\n",string); } alpine-2.10+dfsg/imap/src/mailutil/makefile.w2k0000600000175000017500000000247211512502122023076 0ustar paulproteuspaulproteus# ======================================================================== # Copyright 1988-2006 University of Washington # # Licensed under the Apache License, Version 2.0 (the "License"); # you may not use this file except in compliance with the License. # You may obtain a copy of the License at # # http://www.apache.org/licenses/LICENSE-2.0 # # # ======================================================================== # Program: MAILUTIL Makefile for Windows 2000/XP # # Author: Mark Crispin # Networks and Distributed Computing # Computing & Communications # University of Washington # Administration Building, AG-44 # Seattle, WA 98195 # Internet: MRC@CAC.Washington.EDU # # Date: 25 February 1996 # Last Edited: 30 August 2006 C = ..\c-client CCLIENTLIB = $C\cclient.lib LIBS = $(CCLIENTLIB) ws2_32.lib winmm.lib advapi32.lib secur32.lib crypt32.lib OSCOMPAT = /DWIN32 VSCOMPAT = /D_CRT_SECURE_NO_DEPRECATE /D_CRT_NONSTDC_NO_DEPRECATE CFLAGS= -I$C /MT /W3 $(OSCOMPAT) $(VSCOMPAT) -nologo $(EXTRACFLAGS) mailutil: $(CCLIENTLIB) mailutil.obj LINK /NOLOGO mailutil.obj $(LIBS) mailutil.obj: $C\mail.h $C\smtp.h $C\misc.h $C\osdep.h mailutil.c $(CCLIENTLIB): @echo Make c-client first false clean: del *.obj *.exe *.lib *.exp || rem # A monument to a hack of long ago and far away... love: @echo not war? alpine-2.10+dfsg/imap/src/mailutil/mailutil.10000600000175000017500000001770211512502122022600 0ustar paulproteuspaulproteus.ig * ======================================================================== * Copyright 1988-2008 University of Washington * * Licensed under the Apache License, Version 2.0 (the "License"); * you may not use this file except in compliance with the License. * You may obtain a copy of the License at * * http://www.apache.org/licenses/LICENSE-2.0 * * * ======================================================================== .. .TH mailutil 1 "March 3, 2008" .SH NAME mailutil - mail utility program .nh .SH SYNTAX .B mailutil command [switches] [arguments] .PP All commands accept the -d, -v, and -u switches in addition to any command-specific switches. .PP .B mailutil check [MAILBOX] .PP .B mailutil create MAILBOX .PP .B mailutil delete MAILBOX .PP .B mailutil rename SOURCE DESTINATION .PP .B mailutil copy [-rw] [-kw] [-ig] SOURCE DESTINATION .PP .B mailutil move [-rw] [-kw] [-ig] SOURCE DESTINATION .PP .B mailutil append [-rw] [-kw] [-ig] SOURCE DESTINATION .PP .B mailutil appenddelete [-rw] [-kw] [-ig] SOURCE DESTINATION .PP .B mailutil prune MAILBOX CRITERIA .PP .B mailutil transfer [-m mode] [-rw] [-kw] [-ig] SOURCE DESTINATION .SH DESCRIPTION .B mailutil replaces the old chkmail, imapcopy, imapmove, imapxfer, mbxcopy, mbxcreat, and mbxcvt programs. .PP .B mailutil check determines whether new mail exists in the given mailbox (the default is INBOX). The number of new messages is defined as the number of messages that have "Recent" status set. If the mailbox contains no new messages, .B mailutil check will indicate that no new mail is present; otherwise, it will report the number of new messages. In either case, it will also indicate the canonical form of the name of the mailbox. .PP .B mailutil create creates a new .I mailbox with the given name. The mailbox name must not already exist. A mailbox can be created in a particular format by prefixing the name with .I #driver. followed by the format name and a .I / character. For example, the command .br mailutil create #driver.mbx/junkmail .br will create a new mailbox named "junkmail" in mbx format. .PP .B mailutil delete deletes an existing .I mailbox with the given name. .PP .B mailutil rename renames an existing mailbox to a new name (which must not already exist). This only works if the old and new names are in the same mail store. A more general means to rename a mailbox is to do a .B mailutil copy of the old name to the new name, followed by a .B mailutil delete of the old name. .PP .B mailutil copy creates a new mailbox and copies messages from the old mailbox to the new mailbox. As in .B mailutil create a mailbox format can be specified with the new mailbox. For example, the command .br mailutil copy INBOX #driver.mbx/INBOX .br will copy messages from your existing INBOX to an mbx-format INBOX. .PP .B mailutil move is similar to .B mailutil copy but in addition will also remove (delete and expunge) the messages from the old mailbox after copying them to the new mailbox. .PP .B mailutil append and .B mailutil appenddelete are similar to .B mailutil copy and .B mailutil move respectively except that they do not create the destination mailbox. .PP .B mailutil prune prunes the mailbox of messages which match certain criteria, which are in the form of IMAP2 (RFC 1176) SEARCH arguments. For example, the command. .br mailutil prune INBOX "before 1-jan-2004" .br will delete and expunge all messages written before January 1, 2004. .PP Note that mailutil implements pruning by deleting the matching messages, and then expunging the mailbox. Consequently, mailutil will also expunge any messages which were deleted at the time of the pruning. .PP .B mailutil transfer copies an entire hierarchy of mailboxes from the named source to the named destination. Mailboxes are created on the destination as needed. Any error in copying messages will cause the transfer to stop. .PP Normally, any error in creation will cause the transfer to stop. However, if .B -m MODE or .B -merge MODE is specified, a merging transfer is performed. The .B MODE argument indicats the type of merge: .PP .B -m[erge] prompt indicates that the user should be asked for an alternative name to create. If creating the new name fails, the user will be asked again. .PP .B -m[erge] append indicates that it's alright to copy the messages into an existing mailbox with that name. If the mailbox does not exist, the user will be prompted for an alternative name. .PP .B -m[erge] suffix=XXXX where XXXX is any string, indicates that an alternative name should be built by appending the given suffix to the name. It that alternative name can't be created, then the user will be prompted for an alternative name. .PP The source hierarchy consists of all mailboxes which start with the given source name. With the exception of a remote system specification (within "{}" braces), the source name is used as the name of the destination. The destination hierarchy is a prefix applied to any new names being created. For example, .br mailutil transfer foo bar .br will copy all mailboxes with names beginning with "foo" to names beginning with "bar" (hence "foobar" will be copied to "barfoobar"). Similarly, .br mailutil transfer "{imap.foo.com}" "{imap.bar.com}old/" .br will copy all mailboxes from the imap.foo.com IMAP server to equivalent names starting with "old/" on the imap.bar.com IMAP server. .SH FLAGS The .B -d or .B -debug flag prints full debugging telemetry including protocol operations. .PP The .B -v or .B -verbose flag prints verbose (non-error) telemetry. .PP The .B -u USERID or .B -user USERID switch attempts to become the indicated user. This is for the benefit of system administrators who want to do mailutil operations on a userid that does not normally have shell access. .PP The .B -rw or .B -rwcopy flag causes the source mailbox to be open in readwrite mode rather than readonly mode. Normally, mailutil tries to use readonly mode to avoid altering any flags in the source mailbox, but some mailbox types, e.g. POP3, can't be open in readonly mode. .PP The .B -kw or .B -kwcopy flag causes the keywords of the source mailbox to be created in the destination mailbox. Normally, mailutil does not create keywords in the destination mailbox so only those keywords that are already defined in the destination mailbox will be preserved. Note that some IMAP servers may automatically create keywords, so this flag may not be necessary. .PP The .B -ig or .B -ignore flag causes the keywords of the source mailbox to be ignored completely and no attempt is made to copy them to the destination mailbox. .PP The .B -ig[nore] and .B -kw[copy] flags are mutually exclusive. .SH ARGUMENTS The arguments are standard c-client mailbox names. A variety of mailbox name formats and types of mailboxes are supported by c-client; examples of the most common forms of names are: .PP .I .IP Name 15 .I Meaning .IP INBOX primary incoming mail folder on the local system .IP archive/tx-project mail folder named "tx-project" in "archive" subdirectory of local filesystem home directory .IP {imapserver.foo.com}INBOX primary incoming mail folder on IMAP server system "imapserver.foo.com" .IP {imapserver.foo.com}archive/tx-project mail folder named "tx-project" in "archive" subdirectory on IMAP server system "imapserver.foo.com" .IP #news.comp.mail.misc newsgroup "comp.mail.misc" on local filesystem .IP {newserver.foo.com/nntp}comp.mail.misc newsgroup "comp.mail.misc" on NNTP server system "newserver.foo.com" .IP {popserver.foo.com/pop3} mail folder on POP3 server system "popserver.foo.com" .LP See your system manager for more information about the types of mailboxes which are available on your system. .SH RESTRICTIONS You must surround a .I {host}mailbox argument with quotation marks if you run .B mailutil from .IR csh (1) or another shell for which braces have special meaning. .PP You must surround a .I #driver.format/mailbox argument with quotation marks if you run .B mailutil from a shell in which "#" is the comment character. .SH AUTHOR Mark Crispin, MRC@Washington.EDU alpine-2.10+dfsg/imap/src/mailutil/makefile.nt0000600000175000017500000000261411512502122023012 0ustar paulproteuspaulproteus# ======================================================================== # Copyright 1988-2006 University of Washington # # Licensed under the Apache License, Version 2.0 (the "License"); # you may not use this file except in compliance with the License. # You may obtain a copy of the License at # # http://www.apache.org/licenses/LICENSE-2.0 # # # ======================================================================== # Program: MAILUTIL Makefile for Windows 9x and Windows NT # # Author: Mark Crispin # Networks and Distributed Computing # Computing & Communications # University of Washington # Administration Building, AG-44 # Seattle, WA 98195 # Internet: MRC@CAC.Washington.EDU # # Date: 25 February 1996 # Last Edited: 30 August 2006 C = ..\c-client CCLIENTLIB = $C\cclient.lib LIBS = $(CCLIENTLIB) ws2_32.lib winmm.lib advapi32.lib CFLAGS= -I$C /MT /W3 /DWIN32 /D_WIN32_WINNT=0x0400 -nologo $(EXTRACFLAGS) OSCOMPAT = /DWIN32 /D_WIN32_WINNT=0x0400 VSCOMPAT = /D_CRT_SECURE_NO_DEPRECATE /D_CRT_NONSTDC_NO_DEPRECATE CFLAGS= -I$C /MT /W3 $(OSCOMPAT) $(VSCOMPAT) -nologo $(EXTRACFLAGS) mailutil: $(CCLIENTLIB) mailutil.obj LINK /NOLOGO mailutil.obj $(LIBS) mailutil.obj: $C\mail.h $C\smtp.h $C\misc.h $C\osdep.h mailutil.c $(CCLIENTLIB): @echo Make c-client first false clean: del *.obj *.exe *.lib *.exp || rem # A monument to a hack of long ago and far away... love: @echo not war? alpine-2.10+dfsg/imap/src/osdep/0000700000175000017500000000000011512502152020162 5ustar paulproteuspaulproteusalpine-2.10+dfsg/imap/src/osdep/vms/0000700000175000017500000000000011512502151020766 5ustar paulproteuspaulproteusalpine-2.10+dfsg/imap/src/osdep/vms/fs_vms.c0000600000175000017500000000260011512502124022427 0ustar paulproteuspaulproteus/* ======================================================================== * Copyright 1988-2006 University of Washington * * Licensed under the Apache License, Version 2.0 (the "License"); * you may not use this file except in compliance with the License. * You may obtain a copy of the License at * * http://www.apache.org/licenses/LICENSE-2.0 * * * ======================================================================== */ /* * Program: Free storage management routines * * Author: Mark Crispin * Networks and Distributed Computing * Computing & Communications * University of Washington * Administration Building, AG-44 * Seattle, WA 98195 * Internet: MRC@CAC.Washington.EDU * * Date: 1 August 1988 * Last Edited: 30 August 2006 */ /* Get a block of free storage * Accepts: size of desired block * Returns: free storage block */ void *fs_get (size_t size) { void *block = malloc (size ? size : (size_t) 1); if (!block) fatal ("Out of memory"); return (block); } /* Resize a block of free storage * Accepts: ** pointer to current block * new size */ void fs_resize (void **block,size_t size) { if (!(*block = realloc (*block,size ? size : (size_t) 1))) fatal ("Can't resize memory"); } /* Return a block of free storage * Accepts: ** pointer to free storage block */ void fs_give (void **block) { free (*block); *block = NIL; } alpine-2.10+dfsg/imap/src/osdep/vms/os_vms.h0000600000175000017500000000230111512502124022443 0ustar paulproteuspaulproteus/* ======================================================================== * Copyright 1988-2007 University of Washington * * Licensed under the Apache License, Version 2.0 (the "License"); * you may not use this file except in compliance with the License. * You may obtain a copy of the License at * * http://www.apache.org/licenses/LICENSE-2.0 * * * ======================================================================== */ /* * Program: Operating-system dependent routines -- VMS version * * Author: Mark Crispin * Networks and Distributed Computing * Computing & Communications * University of Washington * Administration Building, AG-44 * Seattle, WA 98195 * Internet: MRC@CAC.Washington.EDU * * Date: 2 August 1994 * Last Edited: 30 January 2007 */ #include #include #include #include #include #include #define L_SET SEEK_SET #define L_INCR SEEK_CUR #define L_XTND SEEK_END #include "env_vms.h" #include "fs.h" #include "ftl.h" #include "nl.h" #include "tcp.h" #define gethostid clock #define random rand #define unlink delete char *getpass (const char *prompt); #define strtok_r(a,b,c) strtok(a,b) alpine-2.10+dfsg/imap/src/osdep/vms/dummy.h0000600000175000017500000000276411512502124022305 0ustar paulproteuspaulproteus/* ======================================================================== * Copyright 1988-2006 University of Washington * * Licensed under the Apache License, Version 2.0 (the "License"); * you may not use this file except in compliance with the License. * You may obtain a copy of the License at * * http://www.apache.org/licenses/LICENSE-2.0 * * * ======================================================================== */ /* * Program: Dummy routines * * Author: Mark Crispin * Networks and Distributed Computing * Computing & Communications * University of Washington * Administration Building, AG-44 * Seattle, WA 98195 * Internet: MRC@CAC.Washington.EDU * * Date: 9 May 1991 * Last Edited: 30 August 2006 */ /* Exported function prototypes */ void dummy_scan (MAILSTREAM *stream,char *ref,char *pat,char *contents); void dummy_list (MAILSTREAM *stream,char *ref,char *pat); void dummy_lsub (MAILSTREAM *stream,char *ref,char *pat); long scan_contents (DRIVER *dtb,char *name,char *contents, unsigned long csiz,unsigned long fsiz); long dummy_scan_contents (char *name,char *contents,unsigned long csiz, unsigned long fsiz); long dummy_create (MAILSTREAM *stream,char *mailbox); long dummy_create_path (MAILSTREAM *stream,char *path,long dirmode); long dummy_delete (MAILSTREAM *stream,char *mailbox); long dummy_rename (MAILSTREAM *stream,char *old,char *newname); char *dummy_file (char *dst,char *name); long dummy_canonicalize (char *tmp,char *ref,char *pat); alpine-2.10+dfsg/imap/src/osdep/vms/link.opt0000600000175000017500000000003011512502124022442 0ustar paulproteuspaulproteusSYS$SHARE:VAXCRTL/SHARE alpine-2.10+dfsg/imap/src/osdep/vms/nl_vms.c0000600000175000017500000000507711512502124022443 0ustar paulproteuspaulproteus/* ======================================================================== * Copyright 1988-2006 University of Washington * * Licensed under the Apache License, Version 2.0 (the "License"); * you may not use this file except in compliance with the License. * You may obtain a copy of the License at * * http://www.apache.org/licenses/LICENSE-2.0 * * * ======================================================================== */ /* * Program: UNIX/VMS newline routines * * Author: Mark Crispin * Networks and Distributed Computing * Computing & Communications * University of Washington * Administration Building, AG-44 * Seattle, WA 98195 * Internet: MRC@CAC.Washington.EDU * * Date: 1 August 1988 * Last Edited: 30 August 2006 */ /* Copy string with CRLF newlines * Accepts: destination string * pointer to size of destination string buffer * source string * length of source string * Returns: length of copied string */ unsigned long strcrlfcpy (unsigned char **dst,unsigned long *dstl, unsigned char *src,unsigned long srcl) { long i = srcl * 2,j; unsigned char c,*d = src; if (*dst) { /* candidate destination provided? */ /* count NLs if doesn't fit worst-case */ if (i > *dstl) for (i = j = srcl; j; --j) if (*d++ == '\012') i++; /* still too small, must reset destination */ if (i > *dstl) fs_give ((void **) dst); } /* make a new buffer if needed */ if (!*dst) *dst = (char *) fs_get ((*dstl = i) + 1); d = *dst; /* destination string */ if (srcl) do { /* main copy loop */ if ((c = *src++) < '\016') { /* prepend CR to LF */ if (c == '\012') *d++ = '\015'; /* unlikely CR */ else if ((c == '\015') && (srcl > 1) && (*src == '\012')) { *d++ = c; /* copy the CR */ c = *src++; /* grab the LF */ --srcl; /* adjust the count */ } } *d++ = c; /* copy character */ } while (--srcl); *d = '\0'; /* tie off destination */ return d - *dst; /* return length */ } /* Length of string after strcrlfcpy applied * Accepts: source string * Returns: length of string */ unsigned long strcrlflen (STRING *s) { unsigned long pos = GETPOS (s); unsigned long i = SIZE (s); unsigned long j = i; while (j--) switch (SNX (s)) {/* search for newlines */ case '\015': /* unlikely carriage return */ if (j && (CHR (s) == '\012')) { SNX (s); /* eat the line feed */ j--; } break; case '\012': /* line feed? */ i++; default: /* ordinary chararacter */ break; } SETPOS (s,pos); /* restore old position */ return i; } alpine-2.10+dfsg/imap/src/osdep/vms/dummyvms.c0000600000175000017500000001575611512502124023033 0ustar paulproteuspaulproteus/* ======================================================================== * Copyright 1988-2006 University of Washington * * Licensed under the Apache License, Version 2.0 (the "License"); * you may not use this file except in compliance with the License. * You may obtain a copy of the License at * * http://www.apache.org/licenses/LICENSE-2.0 * * * ======================================================================== */ /* * Program: Dummy routines for VMS * * Author: Mark Crispin * Networks and Distributed Computing * Computing & Communications * University of Washington * Administration Building, AG-44 * Seattle, WA 98195 * Internet: MRC@CAC.Washington.EDU * * Date: 24 May 1993 * Last Edited: 30 August 2006 */ #include #include #include "mail.h" #include "osdep.h" #include "dummy.h" #include "misc.h" /* Function prototypes */ DRIVER *dummy_valid (char *name); void *dummy_parameters (long function,void *value); MAILSTREAM *dummy_open (MAILSTREAM *stream); void dummy_close (MAILSTREAM *stream,long options); long dummy_ping (MAILSTREAM *stream); void dummy_check (MAILSTREAM *stream); long dummy_expunge (MAILSTREAM *stream,char *sequence,long options); long dummy_copy (MAILSTREAM *stream,char *sequence,char *mailbox,long options); long dummy_append (MAILSTREAM *stream,char *mailbox,append_t af,void *data); /* Dummy routines */ /* Driver dispatch used by MAIL */ DRIVER dummydriver = { "dummy", /* driver name */ DR_LOCAL|DR_MAIL, /* driver flags */ (DRIVER *) NIL, /* next driver */ dummy_valid, /* mailbox is valid for us */ dummy_parameters, /* manipulate parameters */ dummy_scan, /* scan mailboxes */ dummy_list, /* list mailboxes */ dummy_lsub, /* list subscribed mailboxes */ NIL, /* subscribe to mailbox */ NIL, /* unsubscribe from mailbox */ dummy_create, /* create mailbox */ dummy_delete, /* delete mailbox */ dummy_rename, /* rename mailbox */ mail_status_default, /* status of mailbox */ dummy_open, /* open mailbox */ dummy_close, /* close mailbox */ NIL, /* fetch message "fast" attributes */ NIL, /* fetch message flags */ NIL, /* fetch overview */ NIL, /* fetch message structure */ NIL, /* fetch header */ NIL, /* fetch text */ NIL, /* fetch message data */ NIL, /* unique identifier */ NIL, /* message number from UID */ NIL, /* modify flags */ NIL, /* per-message modify flags */ NIL, /* search for message based on criteria */ NIL, /* sort messages */ NIL, /* thread messages */ dummy_ping, /* ping mailbox to see if still alive */ dummy_check, /* check for new messages */ dummy_expunge, /* expunge deleted messages */ dummy_copy, /* copy messages to another mailbox */ dummy_append, /* append string message to mailbox */ NIL /* garbage collect stream */ }; /* prototype stream */ MAILSTREAM dummyproto = {&dummydriver}; /* Dummy validate mailbox * Accepts: mailbox name * Returns: our driver if name is valid, NIL otherwise */ DRIVER *dummy_valid (char *name) { char tmp[MAILTMPLEN]; /* must be valid local mailbox */ return (name && *name && (*name != '{') && !compare_cstring (name,"INBOX")) ? &dummydriver : NIL; } /* Dummy manipulate driver parameters * Accepts: function code * function-dependent value * Returns: function-dependent return value */ void *dummy_parameters (long function,void *value) { return NIL; } /* Dummy scan mailboxes * Accepts: mail stream * reference * pattern to search * string to scan */ void dummy_scan (MAILSTREAM *stream,char *ref,char *pat,char *contents) { /* return silently */ } /* Dummy list mailboxes * Accepts: mail stream * reference * pattern to search */ void dummy_list (MAILSTREAM *stream,char *ref,char *pat) { /* return silently */ } /* Dummy list subscribed mailboxes * Accepts: mail stream * reference * pattern to search */ void dummy_lsub (MAILSTREAM *stream,char *ref,char *pat) { /* return silently */ } /* Dummy create mailbox * Accepts: mail stream * mailbox name to create * driver type to use * Returns: T on success, NIL on failure */ long dummy_create (MAILSTREAM *stream,char *mailbox) { return NIL; /* always fails */ } /* Dummy delete mailbox * Accepts: mail stream * mailbox name to delete * Returns: T on success, NIL on failure */ long dummy_delete (MAILSTREAM *stream,char *mailbox) { return NIL; /* always fails */ } /* Mail rename mailbox * Accepts: mail stream * old mailbox name * new mailbox name * Returns: T on success, NIL on failure */ long dummy_rename (MAILSTREAM *stream,char *old,char *newname) { return NIL; /* always fails */ } /* Dummy open * Accepts: stream to open * Returns: stream on success, NIL on failure */ MAILSTREAM *dummy_open (MAILSTREAM *stream) { char tmp[MAILTMPLEN]; /* OP_PROTOTYPE call or silence */ if (!stream || stream->silent) return NIL; if (compare_cstring (stream->mailbox,"INBOX")) { sprintf (tmp,"Not a mailbox: %s",stream->mailbox); mm_log (tmp,ERROR); return NIL; /* always fails */ } if (!stream->silent) { /* only if silence not requested */ mail_exists (stream,0); /* say there are 0 messages */ mail_recent (stream,0); stream->uid_validity = time (0); } stream->inbox = T; /* note that it's an INBOX */ return stream; /* return success */ } /* Dummy close * Accepts: MAIL stream * options */ void dummy_close (MAILSTREAM *stream,long options) { /* return silently */ } /* Dummy ping mailbox * Accepts: MAIL stream * Returns: T if stream alive, else NIL * No-op for readonly files, since read/writer can expunge it from under us! */ long dummy_ping (MAILSTREAM *stream) { return T; } /* Dummy check mailbox * Accepts: MAIL stream * No-op for readonly files, since read/writer can expunge it from under us! */ void dummy_check (MAILSTREAM *stream) { dummy_ping (stream); /* invoke ping */ } /* Dummy expunge mailbox * Accepts: MAIL stream * sequence to expunge if non-NIL * expunge options * Returns: T, always */ long dummy_expunge (MAILSTREAM *stream,char *sequence,long options) { return LONGT; } /* Dummy copy message(s) * Accepts: MAIL stream * sequence * destination mailbox * options * Returns: T if copy successful, else NIL */ long dummy_copy (MAILSTREAM *stream,char *sequence,char *mailbox,long options) { if ((options & CP_UID) ? mail_uid_sequence (stream,sequence) : mail_sequence (stream,sequence)) fatal ("Impossible dummy_copy"); return NIL; } /* Dummy append message string * Accepts: mail stream * destination mailbox * append callback function * data for callback * Returns: T on success, NIL on failure */ long dummy_append (MAILSTREAM *stream,char *mailbox,append_t af,void *data) { char tmp[MAILTMPLEN]; sprintf (tmp,"Can't append to %s",mailbox); mm_log (tmp,ERROR); /* pass up error */ return NIL; /* always fails */ } alpine-2.10+dfsg/imap/src/osdep/vms/link_mnt.opt0000600000175000017500000000004711512502124023330 0ustar paulproteuspaulproteusMULTINET:MULTINET_SOCKET_LIBRARY/SHARE alpine-2.10+dfsg/imap/src/osdep/vms/os_vms.c0000600000175000017500000000344611512502124022451 0ustar paulproteuspaulproteus/* ======================================================================== * Copyright 1988-2006 University of Washington * * Licensed under the Apache License, Version 2.0 (the "License"); * you may not use this file except in compliance with the License. * You may obtain a copy of the License at * * http://www.apache.org/licenses/LICENSE-2.0 * * * ======================================================================== */ /* * Program: Operating-system dependent routines -- VMS version * * Author: Mark Crispin * Networks and Distributed Computing * Computing & Communications * University of Washington * Administration Building, AG-44 * Seattle, WA 98195 * Internet: MRC@CAC.Washington.EDU * * Date: 2 August 1994 * Last Edited: 30 August 2006 */ #include "tcp_vms.h" /* must be before osdep includes tcp.h */ #include "mail.h" #include "osdep.h" #include #include #include #include #include #include #include #include #include extern int errno; /* just in case */ #include "misc.h" #include "fs_vms.c" #include "ftl_vms.c" #include "nl_vms.c" #include "env_vms.c" #include "tcp_vms.c" #define server_login(user,pass,authuser,argc,argv) NIL #define authserver_login(user,authuser,argc,argv) NIL #define myusername() "" /* dummy definition to prevent build errors */ #define MD5ENABLE "" #include "auth_md5.c" #include "auth_pla.c" #include "auth_log.c" /* Emulator for UNIX getpass() call * Accepts: prompt * Returns: password */ #define PWDLEN 128 /* used by Linux */ char *getpass (const char *prompt) { char *s; static char pwd[PWDLEN]; fputs (prompt,stdout); fgets (pwd,PWDLEN-1,stdin); if (s = strchr (pwd,'\n')) *s = '\0'; return pwd; } alpine-2.10+dfsg/imap/src/osdep/vms/build.com0000600000175000017500000000560311512502124022573 0ustar paulproteuspaulproteus$! ======================================================================== $! Copyright 1988-2006 University of Washington $! $! Licensed under the Apache License, Version 2.0 (the "License"); $! you may not use this file except in compliance with the License. $! You may obtain a copy of the License at $! $! http://www.apache.org/licenses/LICENSE-2.0 $! $! $! ======================================================================== $! $! Program: Portable c-client build for VMS $! $! Author: Mark Crispin $! Networks and Distributed Computing $! Computing & Communications $! University of Washington $! Administration Building, AG-44 $! Seattle, WA 98195 $! Internet: MRC@CAC.Washington.EDU $! $! Date: 2 August 1994 $! Last Edited: 30 August 2006 $! $! Change this to your local timezone. This value is the number of minutes $! east of UTC (formerly known as GMT). Sample values: -300 (US east coast), $! -480 (US west coast), 540 (Japan), 60 (western Europe). $! VAX C's HELP information says that you should be able to use gmtime(), but $! it returns 0 for the struct. ftime(), you ask? It, too, returns 0 for a $! timezone. Nothing sucks like a VAX! $! $ CC_TIMEZONE=-480 $! $! CC options $! $ CC_PREF = "/OPTIMIZE/INCLUDE=[]" $ CC_PREF = CC_PREF + "/DEFINE=net_getbuffer=NET_GETBUF" $ CC_PREF = CC_PREF + "/DEFINE=LOCALTIMEZONE='CC_TIMEZONE'" $! $! Determine TCP type $! $ TCP_TYPE = "VMSN" ! default to none $ IF F$LOCATE("MULTINET", P1) .LT. F$LENGTH(P1) $ THEN $ DEFINE SYS MULTINET_ROOT:[MULTINET.INCLUDE.SYS],sys$library $ DEFINE NETINET MULTINET_ROOT:[MULTINET.INCLUDE.NETINET] $ DEFINE ARPA MULTINET_ROOT:[MULTINET.INCLUDE.ARPA] $ TCP_TYPE = "VMSM" ! Multinet $ LINK_OPT = ",LINK_MNT/OPTION" $ ENDIF $ IF F$LOCATE("NETLIB", P1) .LT. F$LENGTH(P1) $ THEN $ DEFINE SYS SYS$LIBRARY: ! normal .H location $ DEFINE NETINET SYS$LIBRARY: $ DEFINE ARPA SYS$LIBRARY: $ LINK_OPT = ",LINK_NLB/OPTION" $ TCP_TYPE = "VMSL" ! NETLIB $ ENDIF $ IF TCP_TYPE .EQS. "VMSN" $ THEN $ DEFINE SYS SYS$LIBRARY: ! normal .H location $ DEFINE NETINET SYS$LIBRARY: $ DEFINE ARPA SYS$LIBRARY: $ LINK_OPT = "" $ ENDIF $! $ COPY TCP_'TCP_TYPE'.C TCP_VMS.C; $! $ COPY OS_VMS.H OSDEP.H; $ SET VERIFY $ CC'CC_PREF' MAIL $ CC'CC_PREF' IMAP4R1 $ CC'CC_PREF' SMTP $ CC'CC_PREF' NNTP $ CC'CC_PREF' POP3 $ CC'CC_PREF' DUMMYVMS $ CC'CC_PREF' RFC822 $ CC'CC_PREF' MISC $ CC'CC_PREF' OS_VMS $ CC'CC_PREF' SMANAGER $ CC'CC_PREF' FLSTRING $ CC'CC_PREF' NEWSRC $ CC'CC_PREF' NETMSG $ CC'CC_PREF' UTF8 $ CC'CC_PREF' UTF8AUX $ CC'CC_PREF' MTEST $ CC'CC_PREF' MAILUTIL $! $ LINK MTEST,OS_VMS,MAIL,IMAP4R1,SMTP,NNTP,POP3,DUMMYVMS,RFC822,MISC,UTF8,- UTF8AUX,SMANAGER,FLSTRING,NEWSRC,NETMSG,- SYS$INPUT:/OPTION'LINK_OPT',LINK/OPTION PSECT=_CTYPE_,NOWRT $ LINK MAILUTIL,OS_VMS,MAIL,IMAP4R1,SMTP,NNTP,POP3,DUMMYVMS,RFC822,MISC,UTF8,- UTF8AUX,SMANAGER,FLSTRING,NEWSRC,NETMSG,- SYS$INPUT:/OPTION'LINK_OPT',LINK/OPTION PSECT=_CTYPE_,NOWRT $ SET NOVERIFY $ EXIT alpine-2.10+dfsg/imap/src/osdep/vms/tcp_vmsl.c0000600000175000017500000002345511512502124022774 0ustar paulproteuspaulproteus/* ======================================================================== * Copyright 1988-2008 University of Washington * * Licensed under the Apache License, Version 2.0 (the "License"); * you may not use this file except in compliance with the License. * You may obtain a copy of the License at * * http://www.apache.org/licenses/LICENSE-2.0 * * * ======================================================================== */ /* * Program: VMS TCP/IP routines for Netlib. * * Author: Mark Crispin * Networks and Distributed Computing * Computing & Communications * University of Washington * Administration Building, AG-44 * Seattle, WA 98195 * Internet: MRC@CAC.Washington.EDU * * Date: 2 August 1994 * Last Edited: 13 January 2008 */ /* Thanks to Yehavi Bourvine at The Hebrew University of Jerusalem who contributed the original VMS code */ #include static char *tcp_getline_work (TCPSTREAM *stream,unsigned long *size, long *contd); /* TCP/IP manipulate parameters * Accepts: function code * function-dependent value * Returns: function-dependent return value */ void *tcp_parameters (long function,void *value) { return NIL; } /* TCP/IP open * Accepts: host name * contact service name * contact port number * Returns: TCP/IP stream if success else NIL */ TCPSTREAM *tcp_open (char *host,char *service,unsigned long port) { TCPSTREAM *stream = NIL; unsigned long sock; int status; char tmp[MAILTMPLEN]; /* hostname to connect to */ struct dsc$descriptor HostDesc = { 0, DSC$K_DTYPE_T, DSC$K_CLASS_S, NULL }; port &= 0xffff; /* erase flags */ /* assign a local socket */ if (!((status = net_assign (&sock)) & 0x1)) { sprintf (tmp,"Unable to assign to net, status=%d",status); mm_log (tmp,ERROR); return NIL; } if (!((status = net_bind (&sock,1)) & 0x1)) { sprintf (tmp,"Unable to create local socket, status=%d",status); mm_log (tmp,ERROR); return NIL; } /* open connection */ HostDesc.dsc$w_length = strlen (host); HostDesc.dsc$a_pointer = host; if (!((status = tcp_connect (&sock,&HostDesc,port)) & 0x1)) { sprintf (tmp,"Can't connect to %.80s,%lu: %s",host,port,strerror (errno)); mm_log (tmp,ERROR); return NIL; } /* create TCP/IP stream */ stream = (TCPSTREAM *) fs_get (sizeof (TCPSTREAM)); stream->host = cpystr (host); /* copy official host name */ /* copy local host name */ stream->localhost = cpystr (mylocalhost ()); stream->port = port; /* copy port number */ /* init sockets */ stream->tcpsi = stream->tcpso = sock; stream->ictr = 0; /* init input counter */ return stream; /* return success */ } /* TCP/IP authenticated open * Accepts: NETMBX specifier * service name * returned user name buffer * Returns: TCP/IP stream if success else NIL */ TCPSTREAM *tcp_aopen (NETMBX *mb,char *service,char *usrbuf) { return NIL; } /* TCP receive line * Accepts: TCP stream * Returns: text line string or NIL if failure */ char *tcp_getline (TCPSTREAM *stream) { unsigned long n,contd; char *ret = tcp_getline_work (stream,&n,&contd); if (ret && contd) { /* got a line needing continuation? */ STRINGLIST *stl = mail_newstringlist (); STRINGLIST *stc = stl; do { /* collect additional lines */ stc->text.data = (unsigned char *) ret; stc->text.size = n; stc = stc->next = mail_newstringlist (); ret = tcp_getline_work (stream,&n,&contd); } while (ret && contd); if (ret) { /* stash final part of line on list */ stc->text.data = (unsigned char *) ret; stc->text.size = n; /* determine how large a buffer we need */ for (n = 0, stc = stl; stc; stc = stc->next) n += stc->text.size; ret = fs_get (n + 1); /* copy parts into buffer */ for (n = 0, stc = stl; stc; n += stc->text.size, stc = stc->next) memcpy (ret + n,stc->text.data,stc->text.size); ret[n] = '\0'; } mail_free_stringlist (&stl);/* either way, done with list */ } return ret; } /* TCP receive line or partial line * Accepts: TCP stream * pointer to return size * pointer to return continuation flag * Returns: text line string, size and continuation flag, or NIL if failure */ static char *tcp_getline_work (TCPSTREAM *stream,unsigned long *size, long *contd) { unsigned long n; char *s,*ret,c,d; *contd = NIL; /* assume no continuation */ /* make sure have data */ if (!tcp_getdata (stream)) return NIL; for (s = stream->iptr, n = 0, c = '\0'; stream->ictr--; n++, c = d) { d = *stream->iptr++; /* slurp another character */ if ((c == '\015') && (d == '\012')) { ret = (char *) fs_get (n--); memcpy (ret,s,*size = n); /* copy into a free storage string */ ret[n] = '\0'; /* tie off string with null */ return ret; } } /* copy partial string from buffer */ memcpy ((ret = (char *) fs_get (n)),s,*size = n); /* get more data from the net */ if (!tcp_getdata (stream)) fs_give ((void **) &ret); /* special case of newline broken by buffer */ else if ((c == '\015') && (*stream->iptr == '\012')) { stream->iptr++; /* eat the line feed */ stream->ictr--; ret[*size = --n] = '\0'; /* tie off string with null */ } else *contd = LONGT; /* continuation needed */ return ret; } /* TCP/IP receive buffer * Accepts: TCP/IP stream * size in bytes * buffer to read into * Returns: T if success, NIL otherwise */ long tcp_getbuffer (TCPSTREAM *stream,unsigned long size,char *buffer) { unsigned long n; char *bufptr = buffer; while (size > 0) { /* until request satisfied */ if (!tcp_getdata (stream)) return NIL; n = min (size,stream->ictr);/* number of bytes to transfer */ /* do the copy */ memcpy (bufptr,stream->iptr,n); bufptr += n; /* update pointer */ stream->iptr +=n; size -= n; /* update # of bytes to do */ stream->ictr -=n; } bufptr[0] = '\0'; /* tie off string */ return T; } /* TCP/IP receive data * Accepts: TCP/IP stream * Returns: T if success, NIL otherwise */ long tcp_getdata (TCPSTREAM *stream) { char tmp[MAILTMPLEN]; int i,status; /* Note: the doc says we need here dynamic descriptor, but we need static * one... */ struct dsc$descriptor BufDesc = {BUFLEN,DSC$K_DTYPE_T,DSC$K_CLASS_S, stream->ibuf}; static short iosb[4]; if (stream->tcpsi < 0) return NIL; while (stream->ictr < 1) { /* if nothing in the buffer */ if (!((status = tcp_receive(&(stream->tcpsi), &BufDesc, iosb)) & 0x1)) { sprintf (tmp,"Error reading from TcpIp/NETLIB, status=%d",status); mm_log (tmp,ERROR); return tcp_abort (stream); } if (iosb[1] > BUFLEN) i = BUFLEN; else i = iosb[1]; if (i < 1) return tcp_abort (stream); stream->ictr = i; /* set new byte count */ stream->iptr = stream->ibuf;/* point at TCP buffer */ } return T; } /* TCP/IP send string as record * Accepts: TCP/IP stream * string pointer * Returns: T if success else NIL */ long tcp_soutr (TCPSTREAM *stream,char *string) { return tcp_sout (stream,string,(unsigned long) strlen (string)); } /* TCP/IP send string * Accepts: TCP/IP stream * string pointer * byte count * Returns: T if success else NIL */ long tcp_sout (TCPSTREAM *stream,char *string,unsigned long size) { int status; struct dsc$descriptor_s BufDesc = {strlen(string),DSC$K_DTYPE_T, DSC$K_CLASS_S,string }; /* 2 = Do not add \r\n */ return ((status = tcp_send (&(stream->tcpso),&BufDesc,2)) & 0x1) ? T : tcp_abort (stream); } /* TCP/IP close * Accepts: TCP/IP stream */ void tcp_close (TCPSTREAM *stream) { tcp_abort (stream); /* nuke the stream */ /* flush host names */ fs_give ((void **) &stream->host); fs_give ((void **) &stream->localhost); fs_give ((void **) &stream); /* flush the stream */ } /* TCP/IP abort stream * Accepts: TCP/IP stream * Returns: NIL always */ long tcp_abort (TCPSTREAM *stream) { if (stream->tcpsi >= 0) { /* no-op if no socket */ /* nuke the socket */ tcp_disconnect (&(stream->tcpsi)); stream->tcpsi = stream->tcpso = -1; } return NIL; } /* TCP/IP get host name * Accepts: TCP/IP stream * Returns: host name for this stream */ char *tcp_host (TCPSTREAM *stream) { return stream->host; /* return host name */ } /* TCP/IP get remote host name * Accepts: TCP/IP stream * Returns: host name for this stream */ char *tcp_remotehost (TCPSTREAM *stream) { return stream->host; /* return host name */ } /* TCP/IP return port for this stream * Accepts: TCP/IP stream * Returns: port number for this stream */ unsigned long tcp_port (TCPSTREAM *stream) { return stream->port; /* return port number */ } /* TCP/IP get local host name * Accepts: TCP/IP stream * Returns: local host name */ char *tcp_localhost (TCPSTREAM *stream) { return stream->localhost; /* return local host name */ } /* Return my local host name * Returns: my local host name */ char *mylocalhost () { int status; char tmp[MAILTMPLEN]; if (!myLocalHost) { /* have local host yet? */ /* receives local host name */ struct dsc$descriptor LocalhostDesc = {0,DSC$K_DTYPE_T,DSC$K_CLASS_D,NULL}; if (!((status = net_get_hostname (&LocalhostDesc)) & 0x1)) { sprintf (tmp,"Can't get local hostname, status=%d",status); mm_log (tmp,ERROR); return "UNKNOWN"; } strncpy (tmp,LocalhostDesc.dsc$a_pointer,LocalhostDesc.dsc$w_length); tmp[LocalhostDesc.dsc$w_length] = '\0'; str$free1_dx (&LocalhostDesc); myLocalHost = cpystr (tmp); } return myLocalHost; } /* TCP/IP return canonical form of host name * Accepts: host name * Returns: canonical form of host name */ char *tcp_canonical (char *name) { return name; } /* TCP/IP get client host name (server calls only) * Returns: client host name */ char *tcp_clienthost () { return "UNKNOWN"; } alpine-2.10+dfsg/imap/src/osdep/vms/env_vms.h0000600000175000017500000000367311512502124022627 0ustar paulproteuspaulproteus/* ======================================================================== * Copyright 1988-2006 University of Washington * * Licensed under the Apache License, Version 2.0 (the "License"); * you may not use this file except in compliance with the License. * You may obtain a copy of the License at * * http://www.apache.org/licenses/LICENSE-2.0 * * * ======================================================================== */ /* * Program: VMS environment routines * * Author: Mark Crispin * Networks and Distributed Computing * Computing & Communications * University of Washington * Administration Building, AG-44 * Seattle, WA 98195 * Internet: MRC@CAC.Washington.EDU * * Date: 2 August 1994 * Last Edited: 30 August 2006 */ #define SUBSCRIPTIONFILE(t) sprintf (t,"%s\\SUBSCRIPTIONS.TXT",myhomedir ()) #define SUBSCRIPTIONTEMP(t) sprintf (t,"%s\\SUBSCRIPTIONS.TMP",myhomedir ()) /* Function prototypes */ #include "env.h" char *myusername (); /* syslog() emulation */ #define LOG_MAIL (2<<3) /* mail system */ #define LOG_DAEMON (3<<3) /* system daemons */ #define LOG_AUTH (4<<3) /* security/authorization messages */ #define LOG_EMERG 0 /* system is unusable */ #define LOG_ALERT 1 /* action must be taken immediately */ #define LOG_CRIT 2 /* critical conditions */ #define LOG_ERR 3 /* error conditions */ #define LOG_WARNING 4 /* warning conditions */ #define LOG_NOTICE 5 /* normal but signification condition */ #define LOG_INFO 6 /* informational */ #define LOG_DEBUG 7 /* debug-level messages */ #define LOG_PID 0x01 /* log the pid with each message */ #define LOG_CONS 0x02 /* log on the console if errors in sending */ #define LOG_ODELAY 0x04 /* delay open until syslog() is called */ #define LOG_NDELAY 0x08 /* don't delay open */ #define LOG_NOWAIT 0x10 /* if forking to log on console, don't wait() */ void openlog (const char *ident,int logopt,int facility); void syslog (int priority,const char *message,...); alpine-2.10+dfsg/imap/src/osdep/vms/tcp_vms.h0000600000175000017500000000234211512502124022615 0ustar paulproteuspaulproteus/* ======================================================================== * Copyright 1988-2006 University of Washington * * Licensed under the Apache License, Version 2.0 (the "License"); * you may not use this file except in compliance with the License. * You may obtain a copy of the License at * * http://www.apache.org/licenses/LICENSE-2.0 * * * ======================================================================== */ /* * Program: VMS TCP/IP routines * * Author: Mark Crispin * Networks and Distributed Computing * Computing & Communications * University of Washington * Administration Building, AG-44 * Seattle, WA 98195 * Internet: MRC@CAC.Washington.EDU * * Date: 1 August 1988 * Last Edited: 30 August 2006 */ /* TCP input buffer */ #define BUFLEN 8192 /* TCP I/O stream */ #define TCPSTREAM struct tcp_stream TCPSTREAM { char *host; /* host name */ unsigned long port; /* port number */ char *localhost; /* local host name */ int tcpsi; /* input socket */ int tcpso; /* output socket */ int ictr; /* input counter */ char *iptr; /* input pointer */ char ibuf[BUFLEN]; /* input buffer */ }; /* Local function prototypes */ long tcp_abort (TCPSTREAM *stream); alpine-2.10+dfsg/imap/src/osdep/vms/clean.com0000600000175000017500000000150411512502124022552 0ustar paulproteuspaulproteus$! ======================================================================== $! Copyright 1988-2006 University of Washington $! $! Licensed under the Apache License, Version 2.0 (the "License"); $! you may not use this file except in compliance with the License. $! You may obtain a copy of the License at $! $! http://www.apache.org/licenses/LICENSE-2.0 $! $! $! ======================================================================== $! $! Program: Portable c-client cleanup for VMS $! $! Author: Mark Crispin $! Networks and Distributed Computing $! Computing & Communications $! University of Washington $! Administration Building, AG-44 $! Seattle, WA 98195 $! Internet: MRC@CAC.Washington.EDU $! $! Date: 14 June 1995 $! Last Edited: 30 August 2006 $! $ DELETE *.OBJ;*,OSDEP.*;*,TCP_VMS.C;*,MTEST.EXE;*,MAILUTIL.EXE;* alpine-2.10+dfsg/imap/src/osdep/vms/linkage.c0000600000175000017500000000243411512502124022551 0ustar paulproteuspaulproteus/* ======================================================================== * Copyright 1988-2007 University of Washington * * Licensed under the Apache License, Version 2.0 (the "License"); * you may not use this file except in compliance with the License. * You may obtain a copy of the License at * * http://www.apache.org/licenses/LICENSE-2.0 * * * ======================================================================== */ /* * Program: Default driver linkage * * Author: Mark Crispin * Networks and Distributed Computing * Computing & Communications * University of Washington * Administration Building, AG-44 * Seattle, WA 98195 * Internet: MRC@CAC.Washington.EDU * * Date: 13 June 1995 * Last Edited: 23 May 2007 */ mail_link (&imapdriver); /* link in the imap driver */ mail_link (&nntpdriver); /* link in the nntp driver */ mail_link (&pop3driver); /* link in the pop3 driver */ mail_link (&dummydriver); /* link in the dummy driver */ auth_link (&auth_ext); /* link in the ext authenticator */ auth_link (&auth_md5); /* link in the md5 authenticator */ auth_link (&auth_pla); /* link in the plain authenticator */ auth_link (&auth_log); /* link in the log authenticator */ mail_versioncheck (CCLIENTVERSION); /* validate version */ alpine-2.10+dfsg/imap/src/osdep/vms/env_vms.c0000600000175000017500000000762211512502124022620 0ustar paulproteuspaulproteus/* ======================================================================== * Copyright 1988-2006 University of Washington * * Licensed under the Apache License, Version 2.0 (the "License"); * you may not use this file except in compliance with the License. * You may obtain a copy of the License at * * http://www.apache.org/licenses/LICENSE-2.0 * * * ======================================================================== */ /* * Program: VMS environment routines * * Author: Mark Crispin * Networks and Distributed Computing * Computing & Communications * University of Washington * Administration Building, AG-44 * Seattle, WA 98195 * Internet: MRC@CAC.Washington.EDU * * Date: 2 August 1994 * Last Edited: 30 August 2006 */ static char *myUserName = NIL; /* user name */ static char *myLocalHost = NIL; /* local host name */ static char *myHomeDir = NIL; /* home directory name */ static char *myNewsrc = NIL; /* newsrc file name */ #include "pmatch.c" /* include wildcard pattern matcher */ /* Environment manipulate parameters * Accepts: function code * function-dependent value * Returns: function-dependent return value */ void *env_parameters (long function,void *value) { void *ret = NIL; switch ((int) function) { case SET_USERNAME: myUserName = cpystr ((char *) value); case GET_USERNAME: ret = (void *) myUserName; break; case SET_HOMEDIR: myHomeDir = cpystr ((char *) value); case GET_HOMEDIR: ret = (void *) myHomeDir; break; case SET_LOCALHOST: myLocalHost = cpystr ((char *) value); case GET_LOCALHOST: ret = (void *) myLocalHost; break; case SET_NEWSRC: if (myNewsrc) fs_give ((void **) &myNewsrc); myNewsrc = cpystr ((char *) value); case GET_NEWSRC: if (!myNewsrc) { /* set news file name if not defined */ char tmp[MAILTMPLEN]; sprintf (tmp,"%s:.newsrc",myhomedir ()); myNewsrc = cpystr (tmp); } ret = (void *) myNewsrc; break; } return ret; } /* Write current time * Accepts: destination string * optional format of day-of-week prefix * format of date and time */ static void do_date (char *date,char *prefix,char *fmt) { time_t tn = time (0); struct tm *t = localtime (&tn); int zone = LOCALTIMEZONE + (t->tm_isdst ? 60 : 0); if (prefix) { /* want day of week? */ sprintf (date,prefix,days[t->tm_wday]); date += strlen (date); /* make next sprintf append */ } /* output the date */ sprintf (date,fmt,t->tm_mday,months[t->tm_mon],t->tm_year+1900, t->tm_hour,t->tm_min,t->tm_sec,zone/60,abs (zone) % 60); } /* Write current time in RFC 822 format * Accepts: destination string */ void rfc822_date (char *date) { do_date (date,"%s, ","%d %s %d %02d:%02d:%02d %+03d%02d"); } /* Write current time in internal format * Accepts: destination string */ void internal_date (char *date) { do_date (date,NIL,"%02d-%s-%d %02d:%02d:%02d %+03d%02d"); } /* Return my user name * Returns: my user name */ char *myusername () { struct stat sbuf; char tmp[MAILTMPLEN]; if (!myUserName) { /* get user name if don't have it yet */ myUserName = cpystr (cuserid (NIL)); myHomeDir = cpystr ("SYS$LOGIN"); } return myUserName; } /* Return my home directory name * Returns: my home directory name */ char *myhomedir () { if (!myHomeDir) myusername ();/* initialize if first time */ return myHomeDir; } /* Determine default prototype stream to user * Accepts: type (NIL for create, T for append) * Returns: default prototype stream */ MAILSTREAM *default_proto (long type) { return NIL; /* no default prototype */ } /* Emulator for BSD syslog() routine * Accepts: priority * message * parameters */ void syslog (int priority,const char *message,...) { } /* Emulator for BSD openlog() routine * Accepts: identity * options * facility */ void openlog (const char *ident,int logopt,int facility) { } alpine-2.10+dfsg/imap/src/osdep/vms/link_nlb.opt0000600000175000017500000000002111512502124023275 0ustar paulproteuspaulproteusNETLIB_SHR/SHARE alpine-2.10+dfsg/imap/src/osdep/vms/linkage.h0000600000175000017500000000174311512502124022560 0ustar paulproteuspaulproteus/* ======================================================================== * Copyright 1988-2006 University of Washington * * Licensed under the Apache License, Version 2.0 (the "License"); * you may not use this file except in compliance with the License. * You may obtain a copy of the License at * * http://www.apache.org/licenses/LICENSE-2.0 * * * ======================================================================== */ /* * Program: Default driver linkage * * Author: Mark Crispin * Networks and Distributed Computing * Computing & Communications * University of Washington * Administration Building, AG-44 * Seattle, WA 98195 * Internet: MRC@CAC.Washington.EDU * * Date: 13 June 1995 * Last Edited: 30 August 2006 */ extern DRIVER imapdriver; extern DRIVER nntpdriver; extern DRIVER pop3driver; extern DRIVER dummydriver; extern AUTHENTICATOR auth_ext; extern AUTHENTICATOR auth_log; extern AUTHENTICATOR auth_md5; extern AUTHENTICATOR auth_pla; alpine-2.10+dfsg/imap/src/osdep/vms/pmatch.c0000600000175000017500000000545411512502124022420 0ustar paulproteuspaulproteus/* ======================================================================== * Copyright 1988-2006 University of Washington * * Licensed under the Apache License, Version 2.0 (the "License"); * you may not use this file except in compliance with the License. * You may obtain a copy of the License at * * http://www.apache.org/licenses/LICENSE-2.0 * * * ======================================================================== */ /* * Program: IMAP Wildcard Matching Routines (case-independent) * * Author: Mark Crispin * Networks and Distributed Computing * Computing & Communications * University of Washington * Administration Building, AG-44 * Seattle, WA 98195 * Internet: MRC@CAC.Washington.EDU * * Date: 15 June 2000 * Last Edited: 30 August 2006 */ /* Wildcard pattern match * Accepts: base string * pattern string * delimiter character * Returns: T if pattern matches base, else NIL */ long pmatch_full (unsigned char *s,unsigned char *pat,unsigned char delim) { switch (*pat) { case '%': /* non-recursive */ /* % at end, OK if no inferiors */ if (!pat[1]) return (delim && strchr (s,delim)) ? NIL : T; /* scan remainder of string until delimiter */ do if (pmatch_full (s,pat+1,delim)) return T; while ((*s != delim) && *s++); break; case '*': /* match 0 or more characters */ if (!pat[1]) return T; /* * at end, unconditional match */ /* scan remainder of string */ do if (pmatch_full (s,pat+1,delim)) return T; while (*s++); break; case '\0': /* end of pattern */ return *s ? NIL : T; /* success if also end of base */ default: /* match this character */ return compare_uchar (*pat,*s) ? NIL : pmatch_full (s+1,pat+1,delim); } return NIL; } /* Directory pattern match * Accepts: base string * pattern string * delimiter character * Returns: T if base is a matching directory of pattern, else NIL */ long dmatch (unsigned char *s,unsigned char *pat,unsigned char delim) { switch (*pat) { case '%': /* non-recursive */ if (!*s) return T; /* end of base means have a subset match */ if (!*++pat) return NIL; /* % at end, no inferiors permitted */ /* scan remainder of string until delimiter */ do if (dmatch (s,pat,delim)) return T; while ((*s != delim) && *s++); if (*s && !s[1]) return T; /* ends with delimiter, must be subset */ return dmatch (s,pat,delim);/* do new scan */ case '*': /* match 0 or more characters */ return T; /* unconditional match */ case '\0': /* end of pattern */ break; default: /* match this character */ if (*s) return compare_uchar (*pat,*s) ? NIL : dmatch (s+1,pat+1,delim); /* end of base, return if at delimiter */ else if (*pat == delim) return T; break; } return NIL; } alpine-2.10+dfsg/imap/src/osdep/vms/tcp_vmsm.c0000600000175000017500000003225311512502124022771 0ustar paulproteuspaulproteus/* ======================================================================== * Copyright 1988-2008 University of Washington * * Licensed under the Apache License, Version 2.0 (the "License"); * you may not use this file except in compliance with the License. * You may obtain a copy of the License at * * http://www.apache.org/licenses/LICENSE-2.0 * * * ======================================================================== */ /* * Program: VMS TCP/IP routines for Multinet * * Author: Mark Crispin * Networks and Distributed Computing * Computing & Communications * University of Washington * Administration Building, AG-44 * Seattle, WA 98195 * Internet: MRC@CAC.Washington.EDU * * Date: 2 August 1994 * Last Edited: 13 January 2008 */ static tcptimeout_t tmoh = NIL; /* TCP timeout handler routine */ static long ttmo_read = 0; /* TCP timeouts, in seconds */ static long ttmo_write = 0; static char *tcp_getline_work (TCPSTREAM *stream,unsigned long *size, long *contd); /* TCP/IP manipulate parameters * Accepts: function code * function-dependent value * Returns: function-dependent return value */ void *tcp_parameters (long function,void *value) { void *ret = NIL; switch ((int) function) { case SET_TIMEOUT: tmoh = (tcptimeout_t) value; case GET_TIMEOUT: ret = (void *) tmoh; break; case SET_READTIMEOUT: ttmo_read = (long) value; case GET_READTIMEOUT: ret = (void *) ttmo_read; break; case SET_WRITETIMEOUT: ttmo_write = (long) value; case GET_WRITETIMEOUT: ret = (void *) ttmo_write; break; } return ret; } /* TCP/IP open * Accepts: host name * contact service name * contact port number * Returns: TCP/IP stream if success else NIL */ TCPSTREAM *tcp_open (char *host,char *service,unsigned long port) { TCPSTREAM *stream = NIL; int sock; char *s; struct sockaddr_in sin; struct hostent *host_name; char hostname[MAILTMPLEN]; char tmp[MAILTMPLEN]; struct protoent *pt = getprotobyname ("tcp"); struct servent *sv = NIL; port &= 0xffff; /* erase flags */ if (service) { /* service specified? */ if (*service == '*') { /* yes, special alt driver kludge? */ sv = getservbyname (service + 1,"tcp"); } else sv = getservbyname (service,"tcp"); } /* user service name port */ if (sv) port = ntohs (sin.sin_port = sv->s_port); /* copy port number in network format */ else sin.sin_port = htons (port); /* The domain literal form is used (rather than simply the dotted decimal as with other Unix programs) because it has to be a valid "host name" in mailsystem terminology. */ /* look like domain literal? */ if (host[0] == '[' && host[(strlen (host))-1] == ']') { strcpy (hostname,host+1); /* yes, copy number part */ hostname[(strlen (hostname))-1] = '\0'; if ((sin.sin_addr.s_addr = inet_addr (hostname)) != -1) { sin.sin_family = AF_INET; /* family is always Internet */ strcpy (hostname,host); /* hostname is user's argument */ } else { sprintf (tmp,"Bad format domain-literal: %.80s",host); mm_log (tmp,ERROR); return NIL; } } else { /* lookup host name, note that brain-dead Unix requires lowercase! */ strcpy (hostname,host); /* in case host is in write-protected memory */ if ((host_name = gethostbyname (lcase (hostname)))) { /* copy address type */ sin.sin_family = host_name->h_addrtype; /* copy host name */ strcpy (hostname,host_name->h_name); /* copy host addresses */ memcpy (&sin.sin_addr,host_name->h_addr,host_name->h_length); } else { sprintf (tmp,"No such host as %.80s",host); mm_log (tmp,ERROR); return NIL; } } /* get a TCP stream */ if ((sock = socket (sin.sin_family,SOCK_STREAM,pt ? pt->p_proto : 0)) < 0) { sprintf (tmp,"Unable to create TCP socket: %s",strerror (errno)); mm_log (tmp,ERROR); return NIL; } #if 0 /* Maybe this test is necessary. It depends upon how VMS implements * fd_set. UNIX-style fd_set needs it; Windows-style does not. */ else if (sock >= FD_SETSIZE) {/* unselectable sockets are useless */ sprintf (tmp,"Unable to create selectable TCP socket (%d >= %d)", sock,FD_SETSIZE); close (sock); return NIL; } #endif /* open connection */ if (connect (sock,(struct sockaddr *)&sin,sizeof (sin)) < 0) { sprintf (tmp,"Can't connect to %.80s,%d: %s",hostname,port, strerror (errno)); mm_log (tmp,ERROR); return NIL; } /* create TCP/IP stream */ stream = (TCPSTREAM *) fs_get (sizeof (TCPSTREAM)); /* copy official host name */ stream->host = cpystr (hostname); /* get local name */ gethostname (tmp,MAILTMPLEN-1); stream->localhost = cpystr ((host_name = gethostbyname (tmp)) ? host_name->h_name : tmp); /* init sockets */ stream->port = port; /* port number */ stream->tcpsi = stream->tcpso = sock; stream->ictr = 0; /* init input counter */ return stream; /* return success */ } /* TCP/IP authenticated open * Accepts: NETMBX specifier * service name * returned user name buffer * Returns: TCP/IP stream if success else NIL */ TCPSTREAM *tcp_aopen (NETMBX *mb,char *service,char *usrbuf) { return NIL; } /* TCP receive line * Accepts: TCP stream * Returns: text line string or NIL if failure */ char *tcp_getline (TCPSTREAM *stream) { unsigned long n,contd; char *ret = tcp_getline_work (stream,&n,&contd); if (ret && contd) { /* got a line needing continuation? */ STRINGLIST *stl = mail_newstringlist (); STRINGLIST *stc = stl; do { /* collect additional lines */ stc->text.data = (unsigned char *) ret; stc->text.size = n; stc = stc->next = mail_newstringlist (); ret = tcp_getline_work (stream,&n,&contd); } while (ret && contd); if (ret) { /* stash final part of line on list */ stc->text.data = (unsigned char *) ret; stc->text.size = n; /* determine how large a buffer we need */ for (n = 0, stc = stl; stc; stc = stc->next) n += stc->text.size; ret = fs_get (n + 1); /* copy parts into buffer */ for (n = 0, stc = stl; stc; n += stc->text.size, stc = stc->next) memcpy (ret + n,stc->text.data,stc->text.size); ret[n] = '\0'; } mail_free_stringlist (&stl);/* either way, done with list */ } return ret; } /* TCP receive line or partial line * Accepts: TCP stream * pointer to return size * pointer to return continuation flag * Returns: text line string, size and continuation flag, or NIL if failure */ static char *tcp_getline_work (TCPSTREAM *stream,unsigned long *size, long *contd) { unsigned long n; char *s,*ret,c,d; *contd = NIL; /* assume no continuation */ /* make sure have data */ if (!tcp_getdata (stream)) return NIL; for (s = stream->iptr, n = 0, c = '\0'; stream->ictr--; n++, c = d) { d = *stream->iptr++; /* slurp another character */ if ((c == '\015') && (d == '\012')) { ret = (char *) fs_get (n--); memcpy (ret,s,*size = n); /* copy into a free storage string */ ret[n] = '\0'; /* tie off string with null */ return ret; } } /* copy partial string from buffer */ memcpy ((ret = (char *) fs_get (n)),s,*size = n); /* get more data from the net */ if (!tcp_getdata (stream)) fs_give ((void **) &ret); /* special case of newline broken by buffer */ else if ((c == '\015') && (*stream->iptr == '\012')) { stream->iptr++; /* eat the line feed */ stream->ictr--; ret[*size = --n] = '\0'; /* tie off string with null */ } else *contd = LONGT; /* continuation needed */ return ret; } /* TCP/IP receive buffer * Accepts: TCP/IP stream * size in bytes * buffer to read into * Returns: T if success, NIL otherwise */ long tcp_getbuffer (TCPSTREAM *stream,unsigned long size,char *buffer) { unsigned long n; char *bufptr = buffer; while (size > 0) { /* until request satisfied */ if (!tcp_getdata (stream)) return NIL; n = min (size,stream->ictr);/* number of bytes to transfer */ /* do the copy */ memcpy (bufptr,stream->iptr,n); bufptr += n; /* update pointer */ stream->iptr +=n; size -= n; /* update # of bytes to do */ stream->ictr -=n; } bufptr[0] = '\0'; /* tie off string */ return T; } /* TCP/IP receive data * Accepts: TCP/IP stream * Returns: T if success, NIL otherwise */ long tcp_getdata (TCPSTREAM *stream) { int i; fd_set fds,efds; struct timeval tmo; time_t t = time (0); if (stream->tcpsi < 0) return NIL; while (stream->ictr < 1) { /* if nothing in the buffer */ time_t tl = time (0); /* start of request */ tmo.tv_sec = ttmo_read; /* read timeout */ tmo.tv_usec = 0; FD_ZERO (&fds); /* initialize selection vector */ FD_ZERO (&efds); /* handle errors too */ FD_SET (stream->tcpsi,&fds);/* set bit in selection vector */ FD_SET(stream->tcpsi,&efds);/* set bit in error selection vector */ errno = NIL; /* block and read */ while (((i = select (getdtablesize (),&fds,0,&efds,ttmo_read ? &tmo:0))<0) && (errno == EINTR)); if (!i) { /* timeout? */ time_t tc = time (0); if (tmoh && ((*tmoh) (tc - t,tc - tl))) continue; else return tcp_abort (stream); } else if (i < 0) return tcp_abort (stream); while (((i = socket_read (stream->tcpsi,stream->ibuf,BUFLEN)) < 0) && (errno == EINTR)); if (i < 1) return tcp_abort (stream); stream->iptr = stream->ibuf;/* point at TCP buffer */ stream->ictr = i; /* set new byte count */ } return T; } /* TCP/IP send string as record * Accepts: TCP/IP stream * string pointer * Returns: T if success else NIL */ long tcp_soutr (TCPSTREAM *stream,char *string) { return tcp_sout (stream,string,(unsigned long) strlen (string)); } /* TCP/IP send string * Accepts: TCP/IP stream * string pointer * byte count * Returns: T if success else NIL */ long tcp_sout (TCPSTREAM *stream,char *string,unsigned long size) { int i; fd_set fds; struct timeval tmo; time_t t = time (0); if (stream->tcpso < 0) return NIL; while (size > 0) { /* until request satisfied */ time_t tl = time (0); /* start of request */ tmo.tv_sec = ttmo_write; /* write timeout */ tmo.tv_usec = 0; FD_ZERO (&fds); /* initialize selection vector */ FD_SET (stream->tcpso,&fds);/* set bit in selection vector */ errno = NIL; /* block and write */ while (((i = select (getdtablesize (),0,&fds,0,ttmo_write ? &tmo : 0)) < 0) && (errno == EINTR)); if (!i) { /* timeout? */ time_t tc = time (0); if (tmoh && ((*tmoh) (tc - t,tc - tl))) continue; else return tcp_abort (stream); } else if (i < 0) return tcp_abort (stream); while (((i = socket_write (stream->tcpso,string,size)) < 0) && (errno == EINTR)); if (i < 0) return tcp_abort (stream); size -= i; /* how much we sent */ string += i; } return T; /* all done */ } /* TCP/IP close * Accepts: TCP/IP stream */ void tcp_close (TCPSTREAM *stream) { tcp_abort (stream); /* nuke the stream */ /* flush host names */ fs_give ((void **) &stream->host); fs_give ((void **) &stream->localhost); fs_give ((void **) &stream); /* flush the stream */ } /* TCP/IP abort stream * Accepts: TCP/IP stream * Returns: NIL always */ long tcp_abort (TCPSTREAM *stream) { int i; if (stream->tcpsi >= 0) { /* no-op if no socket */ /* nuke the socket */ socket_close (stream->tcpsi); if (stream->tcpsi != stream->tcpso) socket_close (stream->tcpso); stream->tcpsi = stream->tcpso = -1; } return NIL; } /* TCP/IP get host name * Accepts: TCP/IP stream * Returns: host name for this stream */ char *tcp_host (TCPSTREAM *stream) { return stream->host; /* return host name */ } /* TCP/IP get remote host name * Accepts: TCP/IP stream * Returns: host name for this stream */ char *tcp_remotehost (TCPSTREAM *stream) { return stream->host; /* return host name */ } /* TCP/IP return port for this stream * Accepts: TCP/IP stream * Returns: port number for this stream */ unsigned long tcp_port (TCPSTREAM *stream) { return stream->port; /* return port number */ } /* TCP/IP get local host name * Accepts: TCP/IP stream * Returns: local host name */ char *tcp_localhost (TCPSTREAM *stream) { return stream->localhost; /* return local host name */ } /* Return my local host name * Returns: my local host name */ char *mylocalhost () { char tmp[MAILTMPLEN]; struct hostent *hn; if (!myLocalHost) { /* have local host yet? */ gethostname(tmp,MAILTMPLEN);/* get local host name */ myLocalHost = cpystr ((hn = gethostbyname (tmp)) ? hn->h_name : tmp); } return myLocalHost; } /* TCP/IP return canonical form of host name * Accepts: host name * Returns: canonical form of host name */ char *tcp_canonical (char *name) { char host[MAILTMPLEN]; struct hostent *he; /* look like domain literal? */ if (name[0] == '[' && name[strlen (name) - 1] == ']') return name; /* note that Unix requires lowercase! */ else return (he = gethostbyname (lcase (strcpy (host,name)))) ? he->h_name : name; } /* TCP/IP get client host name (server calls only) * Returns: client host name */ char *tcp_clienthost () { return "UNKNOWN"; } alpine-2.10+dfsg/imap/src/osdep/vms/tcp_vmsn.c0000600000175000017500000000770611512502124022777 0ustar paulproteuspaulproteus/* ======================================================================== * Copyright 1988-2006 University of Washington * * Licensed under the Apache License, Version 2.0 (the "License"); * you may not use this file except in compliance with the License. * You may obtain a copy of the License at * * http://www.apache.org/licenses/LICENSE-2.0 * * * ======================================================================== */ /* * Program: Dummy VMS TCP/IP routines for non-TCP/IP systems * * Author: Mark Crispin * Networks and Distributed Computing * Computing & Communications * University of Washington * Administration Building, AG-44 * Seattle, WA 98195 * Internet: MRC@CAC.Washington.EDU * * Date: 2 August 1994 * Last Edited: 30 August 2006 */ /* TCP/IP manipulate parameters * Accepts: function code * function-dependent value * Returns: function-dependent return value */ void *tcp_parameters (long function,void *value) { return NIL; } /* TCP/IP open * Accepts: host name * contact service name * contact port number * Returns: TCP/IP stream if success else NIL */ TCPSTREAM *tcp_open (char *host,char *service,unsigned long port) { char tmp[MAILTMPLEN]; port &= 0xffff; /* erase flags */ if (port) sprintf (tmp,"Can't connect to %.80s,%d: no TCP",host,port); else sprintf (tmp,"Can't connect to %.80s,%s: no TCP",host,service); mm_log (tmp,ERROR); return NIL; } /* TCP/IP authenticated open * Accepts: NETMBX specifier * service name * returned user name buffer * Returns: TCP/IP stream if success else NIL */ TCPSTREAM *tcp_aopen (NETMBX *mb,char *service,char *usrbuf) { return NIL; } /* TCP/IP receive line * Accepts: TCP/IP stream * Returns: text line string or NIL if failure */ char *tcp_getline (TCPSTREAM *stream) { return NIL; } /* TCP/IP receive buffer * Accepts: TCP/IP stream * size in bytes * buffer to read into * Returns: T if success, NIL otherwise */ long tcp_getbuffer (TCPSTREAM *stream,unsigned long size,char *buffer) { return NIL; } /* TCP/IP receive data * Accepts: TCP/IP stream * Returns: T if success, NIL otherwise */ long tcp_getdata (TCPSTREAM *stream) { return NIL; } /* TCP/IP send string as record * Accepts: TCP/IP stream * string pointer * Returns: T if success else NIL */ long tcp_soutr (TCPSTREAM *stream,char *string) { return NIL; } /* TCP/IP send string * Accepts: TCP/IP stream * string pointer * byte count * Returns: T if success else NIL */ long tcp_sout (TCPSTREAM *stream,char *string,unsigned long size) { return NIL; } /* TCP/IP close * Accepts: TCP/IP stream */ void tcp_close (TCPSTREAM *stream) { } /* TCP/IP abort stream * Accepts: TCP/IP stream * Returns: NIL always */ long tcp_abort (TCPSTREAM *stream) { return NIL; } /* TCP/IP get host name * Accepts: TCP/IP stream * Returns: host name for this stream */ char *tcp_host (TCPSTREAM *stream) { return NIL; } /* TCP/IP get remote host name * Accepts: TCP/IP stream * Returns: host name for this stream */ char *tcp_remotehost (TCPSTREAM *stream) { return NIL; } /* TCP/IP get local host name * Accepts: TCP/IP stream * Returns: local host name */ char *tcp_localhost (TCPSTREAM *stream) { return NIL; } /* TCP/IP return port for this stream * Accepts: TCP/IP stream * Returns: port number for this stream */ unsigned long tcp_port (TCPSTREAM *stream) { return 0xffffffff; /* return port number */ } /* Return my local host name * Returns: my local host name */ char *mylocalhost () { /* have local host yet? */ if (!myLocalHost) myLocalHost = cpystr (getenv ("SYS$NODE")); return myLocalHost; } /* TCP/IP return canonical form of host name * Accepts: host name * Returns: canonical form of host name */ char *tcp_canonical (char *name) { return name; } /* TCP/IP get client host name (server calls only) * Returns: client host name */ char *tcp_clienthost () { return "UNKNOWN"; } alpine-2.10+dfsg/imap/src/osdep/vms/ftl_vms.c0000600000175000017500000000167311512502124022615 0ustar paulproteuspaulproteus/* ======================================================================== * Copyright 1988-2006 University of Washington * * Licensed under the Apache License, Version 2.0 (the "License"); * you may not use this file except in compliance with the License. * You may obtain a copy of the License at * * http://www.apache.org/licenses/LICENSE-2.0 * * * ======================================================================== */ /* * Program: DOS/VMS/TOPS-20 crash management routines * * Author: Mark Crispin * Networks and Distributed Computing * Computing & Communications * University of Washington * Administration Building, AG-44 * Seattle, WA 98195 * Internet: MRC@CAC.Washington.EDU * * Date: 1 August 1988 * Last Edited: 30 August 2006 */ /* Report a fatal error * Accepts: string to output */ void fatal (char *string) { mm_fatal (string); /* pass up the string */ abort (); /* die horribly */ } alpine-2.10+dfsg/imap/src/osdep/mac/0000700000175000017500000000000012074110156020725 5ustar paulproteuspaulproteusalpine-2.10+dfsg/imap/src/osdep/mac/os_mac.h0000600000175000017500000000325211512502123022336 0ustar paulproteuspaulproteus/* ======================================================================== * Copyright 1988-2006 University of Washington * * Licensed under the Apache License, Version 2.0 (the "License"); * you may not use this file except in compliance with the License. * You may obtain a copy of the License at * * http://www.apache.org/licenses/LICENSE-2.0 * * * ======================================================================== */ /* * Program: Operating-system dependent routines -- Macintosh version * * Author: Mark Crispin * Networks and Distributed Computing * Computing & Communications * University of Washington * Administration Building, AG-44 * Seattle, WA 98195 * Internet: MRC@CAC.Washington.EDU * * Date: 26 January 1992 * Last Edited: 30 August 2006 */ /* This is a totally new operating-system dependent module for the Macintosh, * written using THINK C on my Mac PowerBook-100 in my free time. * Unlike earlier efforts, this version requires no external TCP library. It * also takes advantage of the Map panel in System 7 for the timezone. */ #include #include #include #include #ifndef noErr #include #include #include #include #include #include #include #include #include #endif #define L_SET SEEK_SET #define L_INCR SEEK_CUR #define L_XTND SEEK_END extern short resolveropen; /* make this global so caller can sniff */ #include "env_mac.h" #include "fs.h" #include "ftl.h" #include "nl.h" #include "tcp.h" #define TCPDRIVER "\p.IPP" #define gethostid clock long wait (void); long random (void); alpine-2.10+dfsg/imap/src/osdep/mac/dummy.h0000600000175000017500000000276411512502123022237 0ustar paulproteuspaulproteus/* ======================================================================== * Copyright 1988-2006 University of Washington * * Licensed under the Apache License, Version 2.0 (the "License"); * you may not use this file except in compliance with the License. * You may obtain a copy of the License at * * http://www.apache.org/licenses/LICENSE-2.0 * * * ======================================================================== */ /* * Program: Dummy routines * * Author: Mark Crispin * Networks and Distributed Computing * Computing & Communications * University of Washington * Administration Building, AG-44 * Seattle, WA 98195 * Internet: MRC@CAC.Washington.EDU * * Date: 9 May 1991 * Last Edited: 30 August 2006 */ /* Exported function prototypes */ void dummy_scan (MAILSTREAM *stream,char *ref,char *pat,char *contents); void dummy_list (MAILSTREAM *stream,char *ref,char *pat); void dummy_lsub (MAILSTREAM *stream,char *ref,char *pat); long scan_contents (DRIVER *dtb,char *name,char *contents, unsigned long csiz,unsigned long fsiz); long dummy_scan_contents (char *name,char *contents,unsigned long csiz, unsigned long fsiz); long dummy_create (MAILSTREAM *stream,char *mailbox); long dummy_create_path (MAILSTREAM *stream,char *path,long dirmode); long dummy_delete (MAILSTREAM *stream,char *mailbox); long dummy_rename (MAILSTREAM *stream,char *old,char *newname); char *dummy_file (char *dst,char *name); long dummy_canonicalize (char *tmp,char *ref,char *pat); alpine-2.10+dfsg/imap/src/osdep/mac/osdep.h0000600000175000017500000000146411512502123022212 0ustar paulproteuspaulproteus/* ======================================================================== * Copyright 1988-2006 University of Washington * * Licensed under the Apache License, Version 2.0 (the "License"); * you may not use this file except in compliance with the License. * You may obtain a copy of the License at * * http://www.apache.org/licenses/LICENSE-2.0 * * * ======================================================================== */ /* * Program: Operating-system dependent routines -- Macintosh version * * Author: Mark Crispin * Networks and Distributed Computing * Computing & Communications * University of Washington * Administration Building, AG-44 * Seattle, WA 98195 * Internet: MRC@CAC.Washington.EDU * * Date: 13 June 1995 * Last Edited: 30 August 2006 */ #include "os_mac.h" alpine-2.10+dfsg/imap/src/osdep/mac/env_mac.h0000600000175000017500000000364211512502123022510 0ustar paulproteuspaulproteus/* ======================================================================== * Copyright 1988-2006 University of Washington * * Licensed under the Apache License, Version 2.0 (the "License"); * you may not use this file except in compliance with the License. * You may obtain a copy of the License at * * http://www.apache.org/licenses/LICENSE-2.0 * * * ======================================================================== */ /* * Program: Macintosh environment routines * * Author: Mark Crispin * Networks and Distributed Computing * Computing & Communications * University of Washington * Administration Building, AG-44 * Seattle, WA 98195 * Internet: MRC@CAC.Washington.EDU * * Date: 25 May 1995 * Last Edited: 30 August 2006 */ #define SUBSCRIPTIONFILE(t) sprintf (t,"%s:Mailbox List",myhomedir ()) #define SUBSCRIPTIONTEMP(t) sprintf (t,"%s:Mailbox List Temp",myhomedir ()) /* Function prototypes */ #include "env.h" /* syslog() emulation */ #define LOG_MAIL (2<<3) /* mail system */ #define LOG_DAEMON (3<<3) /* system daemons */ #define LOG_AUTH (4<<3) /* security/authorization messages */ #define LOG_EMERG 0 /* system is unusable */ #define LOG_ALERT 1 /* action must be taken immediately */ #define LOG_CRIT 2 /* critical conditions */ #define LOG_ERR 3 /* error conditions */ #define LOG_WARNING 4 /* warning conditions */ #define LOG_NOTICE 5 /* normal but signification condition */ #define LOG_INFO 6 /* informational */ #define LOG_DEBUG 7 /* debug-level messages */ #define LOG_PID 0x01 /* log the pid with each message */ #define LOG_CONS 0x02 /* log on the console if errors in sending */ #define LOG_ODELAY 0x04 /* delay open until syslog() is called */ #define LOG_NDELAY 0x08 /* don't delay open */ #define LOG_NOWAIT 0x10 /* if forking to log on console, don't wait() */ void openlog (const char *ident,int logopt,int facility); void syslog (int priority,const char *message,...); alpine-2.10+dfsg/imap/src/osdep/mac/fs_mac.c0000600000175000017500000000260011512502123022314 0ustar paulproteuspaulproteus/* ======================================================================== * Copyright 1988-2006 University of Washington * * Licensed under the Apache License, Version 2.0 (the "License"); * you may not use this file except in compliance with the License. * You may obtain a copy of the License at * * http://www.apache.org/licenses/LICENSE-2.0 * * * ======================================================================== */ /* * Program: Free storage management routines * * Author: Mark Crispin * Networks and Distributed Computing * Computing & Communications * University of Washington * Administration Building, AG-44 * Seattle, WA 98195 * Internet: MRC@CAC.Washington.EDU * * Date: 1 August 1988 * Last Edited: 30 August 2006 */ /* Get a block of free storage * Accepts: size of desired block * Returns: free storage block */ void *fs_get (size_t size) { void *block = malloc (size ? size : (size_t) 1); if (!block) fatal ("Out of memory"); return (block); } /* Resize a block of free storage * Accepts: ** pointer to current block * new size */ void fs_resize (void **block,size_t size) { if (!(*block = realloc (*block,size ? size : (size_t) 1))) fatal ("Can't resize memory"); } /* Return a block of free storage * Accepts: ** pointer to free storage block */ void fs_give (void **block) { free (*block); *block = NIL; } alpine-2.10+dfsg/imap/src/osdep/mac/nl_mac.c0000600000175000017500000000420211512502123022315 0ustar paulproteuspaulproteus/* ======================================================================== * Copyright 1988-2006 University of Washington * * Licensed under the Apache License, Version 2.0 (the "License"); * you may not use this file except in compliance with the License. * You may obtain a copy of the License at * * http://www.apache.org/licenses/LICENSE-2.0 * * * ======================================================================== */ /* * Program: Mac newline routines * * Author: Mark Crispin * Networks and Distributed Computing * Computing & Communications * University of Washington * Administration Building, AG-44 * Seattle, WA 98195 * Internet: MRC@CAC.Washington.EDU * * Date: 26 January 1992 * Last Edited: 30 August 2006 */ /* Copy string with CRLF newlines * Accepts: destination string * pointer to size of destination string buffer * source string * length of source string * Returns: length of copied string */ unsigned long strcrlfcpy (unsigned char **dst,unsigned long *dstl, unsigned char *src,unsigned long srcl) { long i,j; unsigned char c,*d = src; if (*dst) { /* destination provided? */ if ((i = srcl * 2) > *dstl) /* calculate worst-case situation */ for (i = j = srcl; j; --j) if (*d++ == '\015') i++; /* flush destination buffer if too small */ if (i > *dstl) fs_give ((void **) dst); } /* make a new buffer if needed */ if (!*dst) *dst = (char *) fs_get ((*dstl = i) + 1); d = *dst; /* destination string */ if (srcl) do { /* copy string */ c = *d++ = *src++; /* copy character */ /* append line feed to bare CR */ if ((c == '\015') && (*src != '\012')) *d++ = '\012'; } while (--srcl); *d = '\0'; /* tie off destination */ return d - *dst; /* return length */ } /* Length of string after strcrlfcpy applied * Accepts: source string * Returns: length of string */ unsigned long strcrlflen (STRING *s) { unsigned long pos = GETPOS (s); unsigned long i = SIZE (s); unsigned long j = i; while (j--) if ((SNX (s) == '\015') && ((CHR (s) != '\012') || !j)) i++; SETPOS (s,pos); /* restore old position */ return i; } alpine-2.10+dfsg/imap/src/osdep/mac/mtest.sit.hqx0000600000175000017500000002551611512502123023407 0ustar paulproteuspaulproteus(This file must be converted with BinHex 4.0) :#@edCA0d,R0TG!"6594%8dP8)3#3""l`!!!"4[4p8dP8)3!#!!!Hm(*-BA8#bJ# 3!aB"#Jd!$'edCA0d,VNZFR0bB`#3%j@,!*!8"h-!N!6rN!4bFh*M8P0&4!%!TFk UMDPEIVJ!!"f3!!#3"JEY!*!%`hJ!N!KIY3c!q+l(4rK4`['9YjP(D"GY*FH1(-X cXLBR0(,Fbb2([#i[,dqCK"rKGS3@iEFb3JQeji4&VeZ[1Tp``PGTPS4GCi46F[` )*dr*J*-T2h+-c2N46VMfC-$*Vi46-Z(N'*P4`L5F(#G2#5GiGT&MK"*'9LD!erG CjLAcHUq9(@&*RN@fj0Ne))``F[c)XC9`B,`kD)!("P!!B+%+X!"Ij9MdF'6TDbk eDS@rkBHYZjA")jZhqKjc,5mCd(FTrHqIGj@qeG-@lI&rjBp%)kdK&fVILa2,2T2 )Nrd4Q1G"rm8Y@pe%8-SkIQSGk2H@qIe3dIJcJrAH1R9c&i2J#HpTbZ[82H$e3hN Gr+r1$kAiHS*IpmchqmF6`GH$qi)l!%)YfjZ9XS-II05ZY0Hd[$N205VQN@SCP1m )Y64Y8k#VBqraRH@Q)09I"'0XA!G`I`Z`"YrDNrJL[SBi1UackpVJ'9h60qKDB,' ZI9HZ+l((G5@JIUk!US1Z-MDXaLiE+K4V$)T"`eF&6AH$4eI`"F3!(Y2Kj)ABCH6 #b6&ffHN-mSr[[a($&e6dMmla&Iiep%rHVrQhHi#(0JaJe+#i-PJ&%!J"P1Cl!ep YQ2T$jSEJi2Z0c+hDh!RbcmB"'fT`%@-'kLB+!r6'c4USMFh0fb68Y(llUk)VPLr Ed,hR3+5c[D2(piA[kG@V9rTHlZTmZbd5lH`ji1X1qelC&HhSl'V[kHkL2X*kMAQ aAlcJMXYmY&+R(%SV"d9HaYKaMM2'05VCQ-Q6Z-8I6HNNK$jrP@'C#fhdRG$`*Iq %&@Cib6p[RSd[23pm09LaTDQaQHE,TKFhEZ)8(AZN&j&$@cB%&dm`1'D23KiA`i4 k2MCcJkB$!`hclN6Fi$P,$&'1lZ1NTbALF5'11FV9NaR+!fJ,m`$QQX5KhSi!*8i 0H"P%&KpL"M!d&Sm2'A1eSI*J(ND+Nh2H4CbM[(`bCJHJ,N8-+K58K!`YM1)PBC( MF0C+`KM%5qDK'9kBG#fF$!KI)Lr"'SQFp+A[c%U3!1a*+dC(4bhbb%J@6`TE[35 MM(Nm(X4XR"M-a)90**KqZ"l(V4#iN!!lHpDXM)NM`EB,Cr%6K!Nq4h*KmA)pB*I )`FD3!b4&J$+3!2'`Cjcj!bJL9'E`T&l56UjPreMAX3FQ,GJZd#hK9K%451'Ll4J [Q!K6EaUrTfIlcI)Grdj,Q,L8F($6rf6,&2hjQq2Ql%alc$FQUj8Y-F8G'4R*miZ 6r#N"Nhme6(qhkM0Gm4bIGkdBkR++CrL5,4D&DElPi!UIMbP,)&-ICUi63Q#+l`6 Mr0435I-cJc8P-0hc+6l8CL,C!fPlFU@j0YHYP5HlVH6iFMqck@,jbDiKPVai*iE U$Ik%rBbr0$p6)-ka&c4LTeHf'r90kr2kc1PIL8)!1m$[-EHZbBe6E*MC$6#jJ*S D5ADDE#fUXfa6S4$,$R1GEqqVFra(qSj!BB$kcE6AAIeme%lY-+NSX$"!#a3%h`& Q*k"SP1XGG*8[q[)kriiqr[N`q606mMGrMr6Ym@A(IIpC!`re#`28larr"3,URqc [!JVpml$rlr*6*KrShqr[f3f'4hk$ZAhbP(CPb2rrCL3-m3pHa&&p!ZrP1,mSX(" (RI3Qr550fhJiM2F2G!"KiYhmHX("5F#`F3Cii$"NqG''q!Q&BH'NM`)*!fm-NMJ G#iK#50`+6KKLT8)))B%,06GHI$PV%q'LL"-iAR[``!-0+5$5!(j#))h,X24N"1M Z3b$mh!-#ETlA5jqQAj-I-'p$,*iGIjfpb3C00LpePpdq'U&fJp!9LaP)F'!L&(# B-5QFhja-i,Ii3Z#f[f4jF[adr42@M*(aS%(r(cJ$V%XHH6)M*j%XNB0M090iPKm LA!c@+El%Er(aKNG'k+Uq'6Iie,4jIhRpArhcH[pGRlRkjh#kDmVcVp8l0@+3!*- C-3dda3h982@pIFIkIZcpjA`I1q0HjqjcpETeZPLFAMG*`Fd9K!Ihi0Vp`bA5LG* hUZq8VJ`VcUpGcBK0cMcR"h&$E,bKHRr0IYFEPf+ABZGi0Kklp*kV`G9iZ[%FBMH rb60J'$JdYQJ98C5$i*'hHLqX$cj("j*GmUV[S,cU1p,C'LAqPjfYZeGLrMhLP&p !I"@iP2Q)8riXB-@A8,d'p(lS*8`T3Z`S(+*+ZVBKKRHdK,Ph`N#[r#[[UN(HZi, RmL$f+@NM9SlBFD(YENEXX0#SAS2B+U&4(82X+D&4I3Da#U&48BGBJp#BAipB3'K 82B2B3PQ$$a&l6QJ8DBJY%4T&Rb$Q&4UHaBLY&4UP5a&E)65mYBK9#BhL5X4@#Sf 5"BMjK)Dk#,(5*lDrdp8@m8ADSYhl)UeYr`%0!!GYG'9cG#kj3)#D#J&2H#J!&c6 +!*!$J!#3"!&EEhJT,!#3%4B!N!MrN!438Np+5d&)6!%!UKPEcE$CcD)!!(*+!*! '&`d!N!3HUJ#3#1[c$J#9qCRFXlGVCEICCSIR+lY0&eVRAMZqXX[00PXS2r@Df1A KkHA*"VNBTjER*iZH[pFm&Z8ZE"qcfblm[',l@,%Y@BlrBZI+'dRENNhB`TG6`U+ %rm+qcS9IXHh##19fLpl##EGFH-DfXHfjAGJq`Xl0#&Z"UN(Pee&qXHelQ@6(IQ( lb#E,Nrd4YNmb@CI$RfG![9r(Q-!B#jFc&X+DS8F3ArE,60Kl5)j0,',#3EXF'lA Ff"lcGF6XpqJ3VDZ[VCVRG&G6"[,RPeil*ApGbRl6q$rjPKb*9Y(1D'@k1jk56ib Eb(5E,A,-M0L$VA*XbY0-Yr-@1CBlLqRfhkE85@)CT[d855D6KeK',QTi*XDBC34 L5e$cI81&5RrqMB2Q!HmIb'5XY(jK24d42+cfld3SK%*fYiD6QclP6#EAG(r)aeP A9eeCik`c3H*Pl-%"%f1(rd'SBd9bYr%[Ke#EaC*,Y$c-`"ZCB(aPl&BS5Mh,BLD N0[#0c'FQ[EfTSphSF9G+mm35REeC$@ABQb1@KQ[EQd)a(q9fL4i("NpNfN2KQ-m SrQ-S(2)pT,1(,a$YBE%N(&VZLmCm8CdpQL8R8qpEN@Q2GN5E4pEl1X,aD,-2+*' J,iSDk,LB&@mhVGUh%i%T`9"c@lc&*aE90$@hqTTDI0'15bkj3XE)'FC`$f"%"*l 1P"DI2aMbLE&Sh#I+hk8AU)Im6@dGbUP#l9$8Yd)"kNG#BZUa&")[D50+5NM)&9b (+Q,e$K1L)[VIr25C($[MAIaX"HGhq)+1&j!!e[2jJj+Bi9hm,'b0jr&KUjKP@[a prP3lUX&jI')FUX(jqP([8`qIabF--RE1iir'PSMXGrLk$$B+fa(Rm6-0[2G([SX r"YZFmrJ'bKlZfl[ie([83qIV4le(06c22e6lh(IaUAI([SY2[8XIeB'afAb9Ir$ Df*FU$RcS#1"L*RJ,Ea'm-fRG)RJrZ&A`AVj,m,SFJVIm#X%lcb9ikpb#ep-PH+p #E1P2"'r!,RL[ALpi`bm+hXK8V%Z`hSce%F(lBEhJM4F*hQXl"Hp(eQ,G*(MAbRj Q$[XD'T2@ZpNUa&HaZ`@Ri-$UI+HX[rmZrkFkaRE&f&5@+e`QI%6A4AYGekUNX", a$f$r%H%$&&q992!JbRG&K)XDRZXL%808*$F5I@jPT8B8j'B8aRlIb[FAeAq55dH 1L1MQrZMBlqI#N6heG3RbIm0h"PIj6mS9SQrVVEIZf)'ii2IIHL[fZKNcr(lX)9e Qc0LaJqPIj*p+"@Tqh$jQE2+q8I`V51f,88$DMjNaBmC[idIcNIFrX['[3-eISDr ,(liA2GB#PGG%M!Y$j0I99(,S4!lH0"+9j69jk$RX1"[J-k&q&K)M!KJPmk2bp!& 6A(i)A$f%aJ9#mk**M)h2!k&-a+NY%$!d(f"'9ic!cqF$K"F86-V-6b31L6b5G`0 1M&'($4C$r*(IEi'!bf%jZAp2)MJRAj%!m+V!I53X6@!NNPIi-M$VJ*EN'9#9N!" a&YKjY(!C*kkY+8YVm&1V[[Q*Em&G4"8%*T5f,[#88kD'H-`rfpl-l%cSlTfdA9f "JHN(J%eSm*4@)PpM4k`P',DM)A3i[eTGJ6&"`DPF8NCpe"&Fi@Z-%4"P0#'KVZJ [*D-5cj9JHF(B(,XfiL-JBI-6ph@T+dUX9+M'@9P0&@T[#VEaI(3iraee4Fp0i$M ,UZ%S8Bqf"80A0`@dM*j99r5IR0'bfSC5UT%ah0(LLr"D$Z!BeBaU'aTVU*EKMXE fTQDHHdChlq40kSUZ9+[Z+8@0""1kSbfiP#2TZlpQQDfZk&!&D9'*Qh46eMA0V8e 4Z8%STi[9&If[j942(BHFSX&33-Rq5%lCFLGG'%BMSCk#N4UTJi!'FlG!4h'FNPU T&$KMB#kf"'2"F+LT$GjI0$b-H3($G!YKeP3ZTYbbDi+G[TDDF![[Um`"V"&D(HU G[+-pdDB)cfQ`AL29cPmJ9B,h"%-m&1`FlT@F&1Fi2G6j(E%QQ8Nbd5%AUL[i8-( a90C32aYL`ACH(TD"2Rj'AF'05MqA53XEUIGmSH9U3qZ"%&GA'!MMC-i"%Nd8C3+ *ea'RPkXVE!)&TEc"6VT5lqI&(N)CUk&iURNZrKLR,d,jQ,S#3d'4UZ9F3M,(%FV (eC9GU+*i5ZTi,V&QcP[%Ek[9&GfJ-QCP3`PRc'!(&4QFM[2Ve*@09rUKYEkmK,M I&28hchBiC+i'`RTe"FjV+U%9HSK`lP&ApKk`"H%%+aYUUF2-`Bj`iqcCPhd3LN, 1kAje"C+FIA"HE5A2rZT`F(CM&%M03dM[I4dTVL&p3ehC*"A*8pR!1c`@l'LFj5M NkEqTJp$a'"p6ZV5kJEM'l'p6q*CA,Zf!&T,VPY)iT)9HdcLY3aT(IdlMC*l91)C c'SI8d"Q0SkQK8aT(8d1R0)ljV-E*rSh'XIa+iea`9Z-S@ZL8aY'dd%Q0SfQKNaT Re$Q0-rUdaY'8d!Q0Ne*#ac@1TS41D"a0#Ch31"HHd$LTbPMIi(A9bcQQ#EB&8Yl )!#XVHU$IbG$d`+Y1aS"Zd*h9$4RRG-22[C'MZL&GXcGbh(&BhDmZMP6LeqTL3!Z 3!,Vi$jq8e-8C,D#ULhHdJ+BZ6QN"FK[He!*(0&$+EAM94dkhicBF8D$pEJ-T8*C 5S1Q2e-9E@Z!"ZL1#F*R4@q-TDk#qP#q[J"K)kc#&J8b@U#Yh(T@-+R"h"VJc'!$ *DASST808jr%G6d*c(NrT%10C(8*+i)`1k9F#*cd*c@NiT5kbckN,bePeFF&[e-@ )AkN,43fF8KHD'MMT5@KUi+4U'(e@0B`jTaSd2A"#0D6d`((9S1Q"%kT"d`-R9)2 e,GA`5krK4R90H3d004jd,$UX28B*bA-BIkkZQ-03F#4*aJQ&9*b"MU8C$*NYbQT ULE0UI1hKk,9DjLPPmpjMbNE12-AUkJ6'+kcqpJ6'YQ$+$aQS@ATZYc@P3c3rC%L (r,IEQY)KQJ*kABHNU[JH051TE"%j+UD3!1mDA*QLCE4'AE8j0#"j1,H'I,(f$TR G"QG*hRYLPQ63&Cjdc"@QUC)hAH(GfKcDXY)&0930FdZm[4fha2bA-j`f@JNpVDk D%P*jhFKjr98(HI`aII2fr1Uc#2q-&rQ-E(I[HlDS+e!8$X09@*c$fS,Y`4Ke#8I Ulf&00mJp,+Jp$*ErT@iB8#+N'hkQ4)5[k"mS9eIS"Xk+eVdecK+`M$!'9)Mf+JQ hYiG$(T9*G32-C$M0T,SlD`pZ89GYbZ3(5TiQ18m!03haSqNSRfY91+SPIXR0U5Q 6YlNj@mf*lLqMR*b45*[2dp4fp@Yk3R(dDKX@8%@cX)m&fhK@`PHZkhT%AD%LE(+ 218Y,FEHFN!$ME'Q*qMSk&VFe8G2)+KhG1%eGY5Q6[@J4Z9lBZf5pqEU[A&V@!08 R'%Tp(Ea83afESpCerS*+F*f3!$dr(QbqZLADG-fV26#+L30B)c8XMkq6#j!!`6i BVH*95KlUQC'9S9LEHPrD-(Z3!0I-mFS@P[(jKV,P[K"RaHK3GA09T0+bKF4K@D@ qjF(AFaUVpN&jC6ARM2*JQi`c@0YaDNB0C498Uk`'Ak!kh06bDNBADVPA1MP5DE# T,4`BcXQU)LfUj'bBY5JBDJPI-maBip8Z"'m5BjM"Ql&SQ&1'EiLab(e4r'*T!9@ daKH+$fG2p`$)c&DfQ1G%69S'0ZBj(I1JbqVVZ3GG&Sf'Sj688EHD2'LjRq4+'FY 4+CRC"R$)JjElU84@k3h0d@#%FMqDd@5Y6V@eR&NpiA#EaTH$[5F1e65EDRS-kb+ e!Z@9Lk('K+cbB'G08ka9eA[2U5Xi@0&Yi&,jaS,QL+Tr"cfA+FFm&rZ3!1FbpCc RmVkcRN[H1FrPMmjj,[RR2*GTjcbALpr`A!Ca,MRVG8ar`qXBp$$HIml$X*rf-!T 1HaL&Tcf-5dpl')l6dfdc6Xc1lPCA0[2Rr8$cE!1GFjQ+9+i`Lepe,BiLcG+3!$c 92#G8qdK1+IllJ)SN9FXjK63JM[4[kSUEPBjaVj*6bVhjS-U8cJ8HkL*M8cc@fN% ia*3TR$QUHk[JQ!QR%3VYpI'A)`l1pDRjPlVDZKR8AC&`C)CfadP+"j!!krZD$QJ HdJ%d!hK'"kLhMlbM!l6E4dlT!2*pcmcjTLD#hjRce5D#6bQ'IZIhT',)1Z[5QRr MdQUZc5qFS04%i0Y1N!!b$haUcPHE"cijjjY@jrD4JFN,ZRhNcCRmkp8e0Imb`1R UY%JkJ[QAe&4,rrc,bDQ@LHG[5,P[VHBk(kfEiMUREjK9'H!ZcA0qaF91KcHhR&j P9L@P4XJl2U0'IMkYm[EG*cHQ[)k"1HDd$kSK6Hq%@qTZ!XhV',UE)$h"V1raQ`6 )D98bT,FH8-F&fjXL-k1A+[HTT'R3&cbMY,bZa!Te6EN54eRpIqj6qBA#+(a$B@b kmKXdUc'1pqCiTp4!rVUHliGR2&681hq`KVK@4[e"U962kp`5LYV[HFYMj6a!DSC ij9rP'9A'Ce5*@SlRqcTbPSVXk,m8rjAkMQrm6UUq-NFa2A%8CQ+2ZcSI5qQZS6X AdR2l1[pjBfBUCdee$GqiFP`hV$QL'`CQ9G)6h,apG+SfrI$0fkN*0-f[16@"4MF 3r1m%fMVY[L5icNlFfm$-(AK4$hLChK'3!+EJh[idd'qB`$I%#2,M6%akN!"U#)p ,qVqSJrqI(QlqArf8"brKC8[r3[T,rV)Hf6b-Jjj%IZ`a#hm3'K2Um0BX["Z+ap$ 2Zr*CM(8*&HaQi4RX+i@2#jm4RXC,X&B,EKjG,r`9R4"fim`DS3+ReJZI%'l$UGh #-cLcFIM-TiHaEdlPTV`c5hk9dfmr[*XU$F&(6`f,+$&b4N3QcX9E+,[hCEiSl`d kC6p1f6Z8IDZbAk[X0bRlEmVlV&*j6hbLj(GfRl83'pkeaclq0#PATlRUVaq4HPJ VeXlT4ELUF,(8Bj3UqT)2jUh(lZYjeq&NPp56FEI8Bc)JpM,@ql(QZ3,ZcQ65(@C kpb*h*a0XFj+ET*l-Uk5[@CRBcYUNQlVhimaY!401ZHQ8&*pr`(a9K%NpqJF$KUU E!VT%T43ACjXlr51Q&bfTPFUN(N1[D2%DmSV&5jL)r0ejA9*mHP'Tdq2%fE[&DPY RPNR8*qbSdM+F,mblERS4&(8$6Yq#q-5mp8#V,kY'I+eB,HS$&UP(pe8pNCl&[er U-mk8&LDIG"l)bV(94X5%25,X(,9N91p@CamE(FP-f"GX3%9ehAmTA5A&q4[r@%@ Im5Gj@m`Va8jcjprbPfi'6$McI0iGE&c"E(1AAlGiJa4I[-(p[H5"+`VBE+Uaehc PKJ*6paI&bBRL3L1kjr&!@dAIiH[ceSSjJHGXa9@ImYX6da+9diY+H+dbR`j8%lC D-IDN9V%H`aT8F+@iiV!l%F56bSaqID)P-3eRRVH&fF`rA9G3b@C9ljkFp'bSQLf m2k$V6NVab-MZKaG[%0'EPMVTS(p%SBJDe!If*#i'ETIpXe)FrB-B'd&p`k-6dBP cM$Pi)*G$l04p+@,CHG2Q,ET0IK[U[MIa2V(1jVCC[@ER(QD+#GGCGfkIrh"brde VGklckk5iM5AXK#-+LDQfZYUANP[&@YFGE25P3I$4Z-4BejIG3@B4DlYIGPK4J4H R,RjXfdbVc4Uk)Q#VG`C'BmeEk-69h&p&K$&8a*'I41eeKakYef)lqQ1pMfj+(UD kk6BkTM&,94!c+k,(Y5bRhZA[M$4h2icp!F)$`Xfph@b%%VZ6BKCAmP"JDAXV-24 dVZ6(9Yhpmrdl,%ecLr`2iT6"[)aGQ$cXZ'LadlELd-lH6ffXkXqpYIF6F[C+I+B D4bbImP2MkPl*Ear2l`ANPT%mj,MS3j4EV2G6[F$B@(@C-hPijVh5Kj%91N4iTZc (9[EBYfGD!`jdbG6!L(UR2eI19pMMY5U4(Zm)*E,G#fi@RNA''p'0P-(M9$&aa8m 2Lh0qHVMU$V"@[L1Ij3GX8r1Cp8TAb3pCcU0lQ2ka+af(jKDjaSrH`bjh(1VH0pr ThiXH,qEm8qarN!$Rd)-FHU,*'10j6,JrRehZcjf&E0`2"#bl2REA(8c[dp[biF+ QN!"h!IF[a,T)cXDZjpF9ER[q4ZEUBSAEN8pGP$QXK9CGmDVNppDK0m5CSlbMEG1 BIZ0DacDUKQ-lVm4$bEhH@@*1BS&BI"64%T31-Ph!1K1Sk)&4lNJ1)e6TS'dhF2H *FjKC,2EVQJ`5[E#4&4BPl[YmZFe8@(6(ClpFIYIDJ!&m2pdV`R[3#`8qLYUmSa( 9+9'V9irGT*+qj(EE@LQHZ%q+lcq!$Pr"G+DY,%2k-`E@!mFAPG5@PXePh3QaX3k m,jUNH2k+[SffkNr[qZlU*lBpZS[(9f`ra)TY-ke@a0EdhXc2q*8cTSdpIF[i#Bp b)UHhTmr$6lL8%hS$[9BQKaJQq6Q0lp$ab5eH2AD2%qZJXaSGeTR@cBXA2CcXUh) &$N[la%2+Q9[kcr3TCe`Kmdh1GX21BZFqTL[-SE13!+i&6&rJC(TE!6-90%,EIDm )0Q1Hi(CprB&mGV(J,R[S'lY+h5kADqZfR@ZUGl-Lff4NrJVUT9"jl$-i[rkYmbY &i56#p*2R,DN-UVU@6DaD[Fa5fP@k'LG&l1+P8+jX($m4aeNc2fR!UEJG,mj-*Zr UDMEB)0fPq1BEPPUkYVQ,(Fa9l#k@iRIGX(5#RFISP,[L#ZDZq15f3U1l`Q'8iY3 4ckjpGKe3$R4YfhU$)f2l9RZ'Zq+4VHk+hKYmTSeVPZSTjiCLlh-ICD3)`4@'Z8E `a'451AR&L'GhIc&[XTLGRe&Im9*&IF8FShIF!-VDqJV$GAMQhq%&'`TBpjF+*d2 pCIUI)Tljjl,E+[`6aBa%-E,iR$J'D%X3fCMI)-j,6)X)k"IplC0%%mkjmYdDaLa aRTMKY3jNDDZ[%)Y&G-1U``8QU,cU*lBQl0fIRrqYj*1hIMf[QZFbVkS-UR-+H"" pjLMUhPI5Gc!(RE3CXCF4ZaHa,b$f)m4Z41`@a2iGX5rdDqBF-Cq0#jLaQaM)PIT B$$J4i1`(6Jca&X5p5Mb+Z!I9#+2A-4H!Phl1BFZK6)X'P1Pd)2UT'YLl+([Xje" &X(G3"E#rQ$,#hLBf5[&#iIEbUHk)jIC*K8+LS[#3!(52q$"f"m9[bQGYVFb8Q&` SL*@*#SPH*-BrdXA*r3'p@1bk+AAU$prJ+hU&X5pX[UJ04bEU2XP'ZCd0j"eZ*#m %qlqCaqq1CTX@9GH5ZhFh`M30XVe"RY0mK03(jKUH*(m%QFdK*`6lFR*!X+p[Z,+ 'iPH95189,&0B*NpR#(H9ZJKIZ,r848kam%eb)A$qm9,A!Z$S*TAMdQVBIhjH,+V Cf"I`*%GkTjmP&c&i6"6,f)mBhYe(XFaka1!98Xc`AF4!9K6,rL&HEiKhr9'XaBT c5)ZK9LdVF@iPjNB`#p&b(@+GF!U3!(2,HX3LQ2j!R9YZ4Lb'qBkPL(d'X6E8'Vh 5mJA%FKKHG*M,@Zj%E)HFAmL!'0L'amb)i9Q$2$B#X30+E$4Lqr*I3PE--!@a2EB rTZG''UC4RA1R`,YMKKUFHkCM*Hi9CKB"XDFQ2B@EFTRK`iKpQePi[Dp(,5Nb&l& 1a(*B&krhpi'a5ijPASAB6UEMHBp$V"$+Rf)6%)0DjV&*r!@-Q6aQ3mc%$$b@KaM F(Kkl'$',NSGG',YRVj+(!qHQ+RR-3LaAb@-1BK192+j!6&6bF!(lN!"F'`YHeEK RIfEle8fYEB2[A-fZ#erMLpD9d*0B"pl(UMkP0I8+9U()@"I&&&Md@Mh0K'A94F1 aF$0Z,XqLDlNaF1$Vb#S4Ui0,Si#Ji5H4$`Vm2`!5FJ!!!3#3!`%8!*!$&!#3!c) U9*!(+LVX!!!U+P53#Z`!!#T8N!-*EA4PFh3ZFfPd!J#3!e0*9%46593K!3!!T!) -!*!$!3!!8dP84&0*9#%"!!#N!J`!N"+`fEpN!!!Hm!!!!8C892q3"953!q`!N!4 8N!Er9*!&l!!!+P53"Iq3!e53!q`!N!-U9*!+l1`!N!-Ul&53"qcX!*!&l!$X9*! $l*!$!*!+l*!$!*!,!3#3!rq3#J#3#"!!+!!@!48#!3#3"J-!N!-"!*!$!43!N!- 8!*!$-J&20H`KbJ#3!a`!-J!!8f9dC`#3!`S!!2rr!*!%!8pi(2'-: alpine-2.10+dfsg/imap/src/osdep/mac/ftl_mac.c0000600000175000017500000000176311512502123022502 0ustar paulproteuspaulproteus/* ======================================================================== * Copyright 1988-2006 University of Washington * * Licensed under the Apache License, Version 2.0 (the "License"); * you may not use this file except in compliance with the License. * You may obtain a copy of the License at * * http://www.apache.org/licenses/LICENSE-2.0 * * * ======================================================================== */ /* * Program: Mac crash management routines * * Author: Mark Crispin * Networks and Distributed Computing * Computing & Communications * University of Washington * Administration Building, AG-44 * Seattle, WA 98195 * Internet: MRC@CAC.Washington.EDU * * Date: 26 January 1992 * Last Edited: 30 August 2006 */ /* Report a fatal error * Accepts: string to output */ void fatal (char *string) { mm_fatal (string); /* pass up the string */ /* nuke the resolver */ if (resolveropen) CloseResolver (); abort (); /* die horribly */ } alpine-2.10+dfsg/imap/src/osdep/mac/env_mac.c0000600000175000017500000001354011512502123022501 0ustar paulproteuspaulproteus/* ======================================================================== * Copyright 1988-2006 University of Washington * * Licensed under the Apache License, Version 2.0 (the "License"); * you may not use this file except in compliance with the License. * You may obtain a copy of the License at * * http://www.apache.org/licenses/LICENSE-2.0 * * * ======================================================================== */ /* * Program: Mac environment routines * * Author: Mark Crispin * Networks and Distributed Computing * Computing & Communications * University of Washington * Administration Building, AG-44 * Seattle, WA 98195 * Internet: MRC@CAC.Washington.EDU * * Date: 26 January 1992 * Last Edited: 30 August 2006 */ static char *myHomeDir = NIL; /* home directory name */ static char *myLocalHost = NIL; /* local host name */ static char *myNewsrc = NIL; /* newsrc file name */ #include "pmatch.c" /* include wildcard pattern matcher */ /* Environment manipulate parameters * Accepts: function code * function-dependent value * Returns: function-dependent return value */ void *env_parameters (long function,void *value) { void *ret = NIL; char tmp[MAILTMPLEN]; switch ((int) function) { case SET_HOMEDIR: if (myHomeDir) fs_give ((void **) &myHomeDir); myHomeDir = cpystr ((char *) value); case GET_HOMEDIR: /* set home directory if not defined */ if (!myHomeDir) myHomeDir = cpystr (""); ret = (void *) myHomeDir; break; case SET_LOCALHOST: myLocalHost = cpystr ((char *) value); case GET_LOCALHOST: ret = (void *) myLocalHost ? myLocalHost : "random-mac"; break; case SET_NEWSRC: if (myNewsrc) fs_give ((void **) &myNewsrc); myNewsrc = cpystr ((char *) value); case GET_NEWSRC: if (!myNewsrc) { /* set news file name if not defined */ sprintf (tmp,"%s:News State",myhomedir ()); myNewsrc = cpystr (tmp); } ret = (void *) myNewsrc; break; } return ret; } /* Write current time * Accepts: destination string * format of date and time * * This depends upon the ReadLocation() call in System 7 and the * user properly setting his location/timezone in the Map control * panel. * Nothing is done about the gmtFlags.dlsDelta byte yet, since I * don't know how it's supposed to work. */ static void do_date (char *date,char *fmt) { long tz,tzm; time_t ti = time (0); struct tm *t = localtime (&ti); MachineLocation loc; ReadLocation (&loc); /* get location/timezone poop */ /* get sign-extended time zone */ tz = (loc.gmtFlags.gmtDelta & 0x00ffffff) | ((loc.gmtFlags.gmtDelta & 0x00800000) ? 0xff000000 : 0); tz /= 60; /* get timezone in minutes */ tzm = tz % 60; /* get minutes from the hour */ /* output time */ strftime (date,MAILTMPLEN,fmt,t); /* now output time zone */ sprintf (date += strlen (date),"%+03ld%02ld",tz/60,tzm >= 0 ? tzm : -tzm); } /* Write current time in RFC 822 format * Accepts: destination string */ void rfc822_date (char *date) { do_date (date,"%a, %d %b %Y %H:%M:%S "); } /* Write current time in internal format * Accepts: destination string */ void internal_date (char *date) { do_date (date,"%2d-%b-%Y %H:%M:%S "); } /* Return my local host name * Returns: my local host name */ char *mylocalhost (void) { return (char *) mail_parameters (NIL,GET_LOCALHOST,NIL); } /* Return my home directory name * Returns: my home directory name */ char *myhomedir () { return (char *) mail_parameters (NIL,GET_HOMEDIR,NIL); } /* Determine default prototype stream to user * Accepts: type (NIL for create, T for append) * Returns: default prototype stream */ MAILSTREAM *default_proto (long type) { extern MAILSTREAM dummyproto; return &dummyproto; /* return default driver's prototype */ } /* Block until event satisfied * Called as: while (wait_condition && wait ()); * Returns T if OK, NIL if user wants to abort * * Allows user to run a desk accessory, select a different window, or go * to another application while waiting for the event to finish. COMMAND/. * will abort the wait. * Assumes the Apple menu has the apple character as its first character, * and that the main program has disabled all other menus. */ long wait () { EventRecord event; WindowPtr window; MenuInfo **m; long r; Str255 tmp; /* wait for an event */ WaitNextEvent (everyEvent,&event,(long) 6,NIL); switch (event.what) { /* got one -- what is it? */ case mouseDown: /* mouse clicked */ switch (FindWindow (event.where,&window)) { case inMenuBar: /* menu bar item? */ /* yes, interesting event? */ if (r = MenuSelect (event.where)) { /* round-about test for Apple menu */ if ((*(m = GetMHandle (HiWord (r))))->menuData[1] == appleMark) { /* get desk accessory name */ GetItem (m,LoWord (r),tmp); OpenDeskAcc (tmp); /* fire it up */ SetPort (window); /* put us back at our window */ } else SysBeep (60); /* the fool forgot to disable it! */ } HiliteMenu (0); /* unhighlight it */ break; case inContent: /* some window was selected */ if (window != FrontWindow ()) SelectWindow (window); break; default: /* ignore all others */ break; } break; case keyDown: /* key hit - if COMMAND/. then punt */ if ((event.modifiers & cmdKey) && (event.message & charCodeMask) == '.') return NIL; break; default: /* ignore all others */ break; } return T; /* try wait test again */ } /* Return random number */ long random () { return (long) rand () << 16 + rand (); } /* Emulator for BSD syslog() routine * Accepts: priority * message * parameters */ void syslog (int priority,const char *message,...) { } /* Emulator for BSD openlog() routine * Accepts: identity * options * facility */ void openlog (const char *ident,int logopt,int facility) { } alpine-2.10+dfsg/imap/src/osdep/mac/dummymac.c0000600000175000017500000001575611512502123022720 0ustar paulproteuspaulproteus/* ======================================================================== * Copyright 1988-2006 University of Washington * * Licensed under the Apache License, Version 2.0 (the "License"); * you may not use this file except in compliance with the License. * You may obtain a copy of the License at * * http://www.apache.org/licenses/LICENSE-2.0 * * * ======================================================================== */ /* * Program: Dummy routines for Mac * * Author: Mark Crispin * Networks and Distributed Computing * Computing & Communications * University of Washington * Administration Building, AG-44 * Seattle, WA 98195 * Internet: MRC@CAC.Washington.EDU * * Date: 24 May 1993 * Last Edited: 30 August 2006 */ #include #include #include "mail.h" #include "osdep.h" #include "dummy.h" #include "misc.h" /* Function prototypes */ DRIVER *dummy_valid (char *name); void *dummy_parameters (long function,void *value); MAILSTREAM *dummy_open (MAILSTREAM *stream); void dummy_close (MAILSTREAM *stream,long options); long dummy_ping (MAILSTREAM *stream); void dummy_check (MAILSTREAM *stream); long dummy_expunge (MAILSTREAM *stream,char *sequence,long options); long dummy_copy (MAILSTREAM *stream,char *sequence,char *mailbox,long options); long dummy_append (MAILSTREAM *stream,char *mailbox,append_t af,void *data); /* Dummy routines */ /* Driver dispatch used by MAIL */ DRIVER dummydriver = { "dummy", /* driver name */ DR_LOCAL|DR_MAIL, /* driver flags */ (DRIVER *) NIL, /* next driver */ dummy_valid, /* mailbox is valid for us */ dummy_parameters, /* manipulate parameters */ dummy_scan, /* scan mailboxes */ dummy_list, /* list mailboxes */ dummy_lsub, /* list subscribed mailboxes */ NIL, /* subscribe to mailbox */ NIL, /* unsubscribe from mailbox */ dummy_create, /* create mailbox */ dummy_delete, /* delete mailbox */ dummy_rename, /* rename mailbox */ mail_status_default, /* status of mailbox */ dummy_open, /* open mailbox */ dummy_close, /* close mailbox */ NIL, /* fetch message "fast" attributes */ NIL, /* fetch message flags */ NIL, /* fetch overview */ NIL, /* fetch message structure */ NIL, /* fetch header */ NIL, /* fetch text */ NIL, /* fetch message data */ NIL, /* unique identifier */ NIL, /* message number from UID */ NIL, /* modify flags */ NIL, /* per-message modify flags */ NIL, /* search for message based on criteria */ NIL, /* sort messages */ NIL, /* thread messages */ dummy_ping, /* ping mailbox to see if still alive */ dummy_check, /* check for new messages */ dummy_expunge, /* expunge deleted messages */ dummy_copy, /* copy messages to another mailbox */ dummy_append, /* append string message to mailbox */ NIL /* garbage collect stream */ }; /* prototype stream */ MAILSTREAM dummyproto = {&dummydriver}; /* Dummy validate mailbox * Accepts: mailbox name * Returns: our driver if name is valid, NIL otherwise */ DRIVER *dummy_valid (char *name) { char tmp[MAILTMPLEN]; /* must be valid local mailbox */ return (name && *name && (*name != '{') && !compare_cstring (name,"INBOX")) ? &dummydriver : NIL; } /* Dummy manipulate driver parameters * Accepts: function code * function-dependent value * Returns: function-dependent return value */ void *dummy_parameters (long function,void *value) { return NIL; } /* Dummy scan mailboxes * Accepts: mail stream * reference * pattern to search * string to scan */ void dummy_scan (MAILSTREAM *stream,char *ref,char *pat,char *contents) { /* return silently */ } /* Dummy list mailboxes * Accepts: mail stream * reference * pattern to search */ void dummy_list (MAILSTREAM *stream,char *ref,char *pat) { /* return silently */ } /* Dummy list subscribed mailboxes * Accepts: mail stream * reference * pattern to search */ void dummy_lsub (MAILSTREAM *stream,char *ref,char *pat) { /* return silently */ } /* Dummy create mailbox * Accepts: mail stream * mailbox name to create * driver type to use * Returns: T on success, NIL on failure */ long dummy_create (MAILSTREAM *stream,char *mailbox) { return NIL; /* always fails */ } /* Dummy delete mailbox * Accepts: mail stream * mailbox name to delete * Returns: T on success, NIL on failure */ long dummy_delete (MAILSTREAM *stream,char *mailbox) { return NIL; /* always fails */ } /* Mail rename mailbox * Accepts: mail stream * old mailbox name * new mailbox name * Returns: T on success, NIL on failure */ long dummy_rename (MAILSTREAM *stream,char *old,char *newname) { return NIL; /* always fails */ } /* Dummy open * Accepts: stream to open * Returns: stream on success, NIL on failure */ MAILSTREAM *dummy_open (MAILSTREAM *stream) { char tmp[MAILTMPLEN]; /* OP_PROTOTYPE call or silence */ if (!stream || stream->silent) return NIL; if (compare_cstring (stream->mailbox,"INBOX")) { sprintf (tmp,"Not a mailbox: %s",stream->mailbox); mm_log (tmp,ERROR); return NIL; /* always fails */ } if (!stream->silent) { /* only if silence not requested */ mail_exists (stream,0); /* say there are 0 messages */ mail_recent (stream,0); stream->uid_validity = time (0); } stream->inbox = T; /* note that it's an INBOX */ return stream; /* return success */ } /* Dummy close * Accepts: MAIL stream * options */ void dummy_close (MAILSTREAM *stream,long options) { /* return silently */ } /* Dummy ping mailbox * Accepts: MAIL stream * Returns: T if stream alive, else NIL * No-op for readonly files, since read/writer can expunge it from under us! */ long dummy_ping (MAILSTREAM *stream) { return T; } /* Dummy check mailbox * Accepts: MAIL stream * No-op for readonly files, since read/writer can expunge it from under us! */ void dummy_check (MAILSTREAM *stream) { dummy_ping (stream); /* invoke ping */ } /* Dummy expunge mailbox * Accepts: MAIL stream * sequence to expunge if non-NIL * expunge options * Returns: T, always */ long dummy_expunge (MAILSTREAM *stream,char *sequence,long options) { return LONGT; } /* Dummy copy message(s) * Accepts: MAIL stream * sequence * destination mailbox * options * Returns: T if copy successful, else NIL */ long dummy_copy (MAILSTREAM *stream,char *sequence,char *mailbox,long options) { if ((options & CP_UID) ? mail_uid_sequence (stream,sequence) : mail_sequence (stream,sequence)) fatal ("Impossible dummy_copy"); return NIL; } /* Dummy append message string * Accepts: mail stream * destination mailbox * append callback function * data for callback * Returns: T on success, NIL on failure */ long dummy_append (MAILSTREAM *stream,char *mailbox,append_t af,void *data) { char tmp[MAILTMPLEN]; sprintf (tmp,"Can't append to %s",mailbox); mm_log (tmp,ERROR); /* pass up error */ return NIL; /* always fails */ } alpine-2.10+dfsg/imap/src/osdep/mac/tcp_mac.h0000600000175000017500000000243611512502123022506 0ustar paulproteuspaulproteus/* ======================================================================== * Copyright 1988-2006 University of Washington * * Licensed under the Apache License, Version 2.0 (the "License"); * you may not use this file except in compliance with the License. * You may obtain a copy of the License at * * http://www.apache.org/licenses/LICENSE-2.0 * * * ======================================================================== */ /* * Program: Macintosh TCP/IP routines * * Author: Mark Crispin * Networks and Distributed Computing * Computing & Communications * University of Washington * Administration Building, AG-44 * Seattle, WA 98195 * Internet: MRC@CAC.Washington.EDU * * Date: 26 January 1992 * Last Edited: 30 August 2006 */ /* TCP input buffer */ #define BUFLEN (size_t) 8192 /* TCP input buffer */ /* TCP I/O stream */ #define TCPSTREAM struct tcp_stream TCPSTREAM { char *host; /* host name */ unsigned long port; /* port number */ char *localhost; /* local host name */ struct TCPiopb pb; /* MacTCP parameter block */ long ictr; /* input counter */ char *iptr; /* input pointer */ char ibuf[BUFLEN]; /* input buffer */ }; extern ResultUPP tcp_dns_upp; pascal void tcp_dns_result (struct hostInfo *hostInfoPtr,char *userDataPtr); alpine-2.10+dfsg/imap/src/osdep/mac/tcp_mac.c0000600000175000017500000004031312074110156022502 0ustar paulproteuspaulproteus/* ======================================================================== * Copyright 1988-2008 University of Washington * * Licensed under the Apache License, Version 2.0 (the "License"); * you may not use this file except in compliance with the License. * You may obtain a copy of the License at * * http://www.apache.org/licenses/LICENSE-2.0 * * * ======================================================================== */ /* * Program: Macintosh TCP/IP routines * * Author: Mark Crispin * Networks and Distributed Computing * Computing & Communications * University of Washington * Administration Building, AG-44 * Seattle, WA 98195 * Internet: MRC@CAC.Washington.EDU * * Date: 26 January 1992 * Last Edited: 13 January 2008 */ /* This is a totally new operating-system dependent module for the Macintosh, * written using THINK C on my Mac PowerBook-100 in my free time. * Unlike earlier efforts, this version requires no external TCP library. It * also takes advantage of the Map panel in System 7 for the timezone. */ static tcptimeout_t tmoh = NIL; /* TCP timeout handler routine */ static long ttmo_open = 75; /* TCP timeouts, in seconds */ static long ttmo_read = 0; static long ttmo_write = 0; static long ttmo_close = 0; static char *tcp_getline_work (TCPSTREAM *stream,unsigned long *size, long *contd); /* TCP/IP manipulate parameters * Accepts: function code * function-dependent value * Returns: function-dependent return value */ void *tcp_parameters (long function,void *value) { void *ret = NIL; switch ((int) function) { case SET_TIMEOUT: tmoh = (tcptimeout_t) value; case GET_TIMEOUT: ret = (void *) tmoh; break; case SET_OPENTIMEOUT: ttmo_open = (long) value; case GET_OPENTIMEOUT: ret = (void *) ttmo_open; break; case SET_READTIMEOUT: ttmo_read = (long) value; case GET_READTIMEOUT: ret = (void *) ttmo_read; break; case SET_WRITETIMEOUT: ttmo_write = (long) value; case GET_WRITETIMEOUT: ret = (void *) ttmo_write; break; case SET_CLOSETIMEOUT: ttmo_close = (long) value; case GET_CLOSETIMEOUT: ret = (void *) ttmo_close; break; } return ret; } /* TCP/IP open * Accepts: host name * contact service name * contact port number * Returns: TCP stream if success else NIL */ TCPSTREAM *tcp_open (char *host,char *service,unsigned long port) { TCPSTREAM *stream; struct hostInfo hst; struct TCPCreatePB *createpb; struct TCPOpenPB *openpb; char *s; unsigned long i,j,k,l; char tmp[MAILTMPLEN]; port &= 0xffff; /* erase flags */ /* init MacTCP */ if (!TCPdriver && OpenDriver (TCPDRIVER,&TCPdriver)) { mm_log ("Can't init MacTCP",ERROR); return NIL; } if (!resolveropen && OpenResolver (NIL)) { mm_log ("Can't init domain resolver",ERROR); return NIL; } resolveropen = T; /* note resolver open now */ /* domain literal? */ if (host[0] == '[' && host[strlen (host)-1] == ']') { if (((i = strtoul (s = host+1,&s,10)) <= 255) && *s++ == '.' && ((j = strtoul (s,&s,10)) <= 255) && *s++ == '.' && ((k = strtoul (s,&s,10)) <= 255) && *s++ == '.' && ((l = strtoul (s,&s,10)) <= 255) && *s++ == ']' && !*s) { hst.addr[0] = (i << 24) + (j << 16) + (k << 8) + l; hst.addr[1] = 0; /* only one address to try! */ sprintf (hst.cname,"[%ld.%ld.%ld.%ld]",i,j,k,l); } else { sprintf (tmp,"Bad format domain-literal: %.80s",host); mm_log (tmp,ERROR); return NIL; } } else { /* look up host name */ if (!tcp_dns_upp) tcp_dns_upp = NewResultProc (tcp_dns_result); if (StrToAddr (host,&hst,tcp_dns_upp,NIL)) { while (hst.rtnCode == cacheFault && wait ()); /* kludge around MacTCP bug */ if (hst.rtnCode == outOfMemory) { mm_log ("Re-initializing domain resolver",WARN); CloseResolver (); /* bop it on the head and try again */ OpenResolver (NIL); /* note this will leak 12K */ StrToAddr (host,&hst,tcp_dns_upp,NIL); while (hst.rtnCode == cacheFault && wait ()); } if (hst.rtnCode) { /* still have error status? */ switch (hst.rtnCode) { /* analyze return */ case nameSyntaxErr: s = "Syntax error in name"; break; case noResultProc: s = "No result procedure"; break; case noNameServer: s = "No name server found"; break; case authNameErr: s = "Host does not exist"; break; case noAnsErr: s = "No name servers responding"; break; case dnrErr: s = "Name server returned an error"; break; case outOfMemory: s = "Not enough memory to resolve name"; break; case notOpenErr: s = "Driver not open"; break; default: s = NIL; break; } if (s) sprintf (tmp,"%s: %.80s",s,host); else sprintf (tmp,"Unknown resolver error (%ld): %.80s", hst.rtnCode,host); mm_log (tmp,ERROR); return NIL; } } } /* create local TCP/IP stream */ stream = (TCPSTREAM *) fs_get (sizeof (TCPSTREAM)); stream->ictr = 0; /* initialize input */ stream->pb.ioCRefNum = TCPdriver; createpb = &stream->pb.csParam.create; openpb = &stream->pb.csParam.open; stream->pb.csCode = TCPCreate;/* create a TCP stream */ /* set up buffer for TCP */ createpb->rcvBuffLen = 4*BUFLEN; createpb->rcvBuff = fs_get (createpb->rcvBuffLen); createpb->notifyProc = NIL; /* no special notify procedure */ createpb->userDataPtr = NIL; if (PBControlSync ((ParmBlkPtr) &stream->pb)) fatal ("Can't create TCP stream"); /* open TCP connection */ stream->pb.csCode = TCPActiveOpen; openpb->ulpTimeoutValue = (int) ttmo_open; openpb->ulpTimeoutAction = T; openpb->validityFlags = timeoutValue|timeoutAction; /* remote host (should try all) */ openpb->remoteHost = hst.addr[0]; openpb->remotePort = port; /* caller specified remote port */ openpb->localPort = 0; /* generate a local port */ openpb->tosFlags = 0; /* no special TOS */ openpb->precedence = 0; /* no special precedence */ openpb->dontFrag = 0; /* allow fragmentation */ openpb->timeToLive = 255; /* standards say 60, UNIX uses 255 */ openpb->security = 0; /* no special security */ openpb->optionCnt = 0; /* no IP options */ openpb->options[0] = 0; openpb->userDataPtr = NIL; /* no special data pointer */ PBControlAsync ((ParmBlkPtr) &stream->pb); while (stream->pb.ioResult == inProgress && wait ()); if (stream->pb.ioResult) { /* got back error status? */ sprintf (tmp,"Can't connect to %.80s,%ld",hst.cname,port); mm_log (tmp,ERROR); /* nuke the buffer */ stream->pb.csCode = TCPRelease; createpb->userDataPtr = NIL; if (PBControlSync ((ParmBlkPtr) &stream->pb)) fatal ("TCPRelease lossage"); /* free its buffer */ fs_give ((void **) &createpb->rcvBuff); fs_give ((void **) &stream);/* and the local stream */ return NIL; } /* copy host names for later use */ stream->host = cpystr (hst.cname); /* tie off trailing dot */ stream->host[strlen (stream->host) - 1] = '\0'; /* the open gave us our address */ i = (openpb->localHost >> 24) & 0xff; j = (openpb->localHost >> 16) & 0xff; k = (openpb->localHost >> 8) & 0xff; l = openpb->localHost & 0xff; sprintf (tmp,"[%ld.%ld.%ld.%ld]",i,j,k,l); stream->localhost = cpystr (tmp); if (!myLocalHost) myLocalHost = cpystr (tmp); stream->port = port; /* copy port number */ return stream; } /* Called when have return from DNS * Accepts: host info pointer * user data pointer */ ResultUPP tcp_dns_upp = NIL; pascal void tcp_dns_result (struct hostInfo *hostInfoPtr,char *userDataPtr) { /* dummy routine */ } /* TCP/IP authenticated open * Accepts: NETMBX specifier * service name * returned user name buffer * Returns: TCP/IP stream if success else NIL */ TCPSTREAM *tcp_aopen (NETMBX *mb,char *service,char *usrbuf) { return NIL; /* no authenticated opens on Mac */ } /* TCP receive line * Accepts: TCP stream * Returns: text line string or NIL if failure */ char *tcp_getline (TCPSTREAM *stream) { unsigned long n,contd; char *ret = tcp_getline_work (stream,&n,&contd); if (ret && contd) { /* got a line needing continuation? */ STRINGLIST *stl = mail_newstringlist (); STRINGLIST *stc = stl; do { /* collect additional lines */ stc->text.data = (unsigned char *) ret; stc->text.size = n; stc = stc->next = mail_newstringlist (); ret = tcp_getline_work (stream,&n,&contd); } while (ret && contd); if (ret) { /* stash final part of line on list */ stc->text.data = (unsigned char *) ret; stc->text.size = n; /* determine how large a buffer we need */ for (n = 0, stc = stl; stc; stc = stc->next) n += stc->text.size; ret = fs_get (n + 1); /* copy parts into buffer */ for (n = 0, stc = stl; stc; n += stc->text.size, stc = stc->next) memcpy (ret + n,stc->text.data,stc->text.size); ret[n] = '\0'; } mail_free_stringlist (&stl);/* either way, done with list */ } return ret; } /* TCP receive line or partial line * Accepts: TCP stream * pointer to return size * pointer to return continuation flag * Returns: text line string, size and continuation flag, or NIL if failure */ static char *tcp_getline_work (TCPSTREAM *stream,unsigned long *size, long *contd) { unsigned long n; char *s,*ret,c,d; *contd = NIL; /* assume no continuation */ /* make sure have data */ if (!tcp_getdata (stream)) return NIL; for (s = stream->iptr, n = 0, c = '\0'; stream->ictr--; n++, c = d) { d = *stream->iptr++; /* slurp another character */ if ((c == '\015') && (d == '\012')) { ret = (char *) fs_get (n--); memcpy (ret,s,*size = n); /* copy into a free storage string */ ret[n] = '\0'; /* tie off string with null */ return ret; } } /* copy partial string from buffer */ memcpy ((ret = (char *) fs_get (n)),s,*size = n); /* get more data from the net */ if (!tcp_getdata (stream)) fs_give ((void **) &ret); /* special case of newline broken by buffer */ else if ((c == '\015') && (*stream->iptr == '\012')) { stream->iptr++; /* eat the line feed */ stream->ictr--; ret[*size = --n] = '\0'; /* tie off string with null */ } else *contd = LONGT; /* continuation needed */ return ret; } /* TCP/IP receive buffer * Accepts: TCP/IP stream * size in bytes * buffer to read into * Returns: T if success, NIL otherwise */ long tcp_getbuffer (TCPSTREAM *stream,unsigned long size,char *buffer) { unsigned long n; char *bufptr = buffer; while (size > 0) { /* until request satisfied */ if (!tcp_getdata (stream)) return NIL; n = min (size,stream->ictr);/* number of bytes to transfer */ /* do the copy */ memcpy (bufptr,stream->iptr,n); bufptr += n; /* update pointer */ stream->iptr +=n; size -= n; /* update # of bytes to do */ stream->ictr -=n; } bufptr[0] = '\0'; /* tie off string */ return T; } /* TCP/IP receive data * Accepts: TCP/IP stream * Returns: T if success, NIL otherwise */ long tcp_getdata (TCPSTREAM *stream) { time_t t = time (0); struct TCPReceivePB *receivepb = &stream->pb.csParam.receive; struct TCPAbortPB *abortpb = &stream->pb.csParam.abort; while (stream->ictr < 1) { /* if nothing in the buffer */ time_t tl = time (0); stream->pb.csCode = TCPRcv; /* receive TCP data */ receivepb->commandTimeoutValue = (int) ttmo_read; receivepb->rcvBuff = stream->ibuf; receivepb->rcvBuffLen = BUFLEN; receivepb->secondTimeStamp = 0; receivepb->userDataPtr = NIL; PBControlAsync ((ParmBlkPtr) &stream->pb); while (stream->pb.ioResult == inProgress && wait ()); if (stream->pb.ioResult) { /* punt if got an error */ time_t tc = time (0); if ((stream->pb.ioResult == commandTimeout) && tmoh && ((*tmoh) (tc - t,tc - tl, stream->host))) continue; /* nuke connection */ stream->pb.csCode = TCPAbort; abortpb->userDataPtr = NIL; PBControlSync ((ParmBlkPtr) &stream->pb); return NIL; } stream->iptr = stream->ibuf;/* point at TCP buffer */ stream->ictr = receivepb->rcvBuffLen; } return T; } /* TCP/IP send string as record * Accepts: TCP/IP stream * string pointer * Returns: T if success else NIL */ long tcp_soutr (TCPSTREAM *stream,char *string) { return tcp_sout (stream,string,(unsigned long) strlen (string)); } /* TCP/IP send string * Accepts: TCP/IP stream * string pointer * byte count * Returns: T if success else NIL */ long tcp_sout (TCPSTREAM *stream,char *string,unsigned long size) { struct TCPSendPB *sendpb = &stream->pb.csParam.send; struct TCPAbortPB *abortpb = &stream->pb.csParam.abort; struct { unsigned short length; Ptr buffer; unsigned short trailer; } wds; while (wds.length = (size > (unsigned long) 32768) ? 32768 : size) { wds.buffer = string; /* buffer */ wds.trailer = 0; /* tie off buffer */ size -= wds.length; /* this many words will be output */ string += wds.length; stream->pb.csCode = TCPSend;/* send TCP data */ sendpb->ulpTimeoutValue = (int) ttmo_write; sendpb->ulpTimeoutAction = 0; sendpb->validityFlags = timeoutValue|timeoutAction; sendpb->pushFlag = T; /* send the data now */ sendpb->urgentFlag = NIL; /* non-urgent data */ sendpb->wdsPtr = (Ptr) &wds; sendpb->userDataPtr = NIL; PBControlAsync ((ParmBlkPtr) &stream->pb); while (stream->pb.ioResult == inProgress && wait ()); if (stream->pb.ioResult) { /* punt if got an error */ /* nuke connection */ stream->pb.csCode =TCPAbort; abortpb->userDataPtr = NIL; PBControlSync ((ParmBlkPtr) &stream->pb); return NIL; } } return T; /* success */ } /* TCP/IP close * Accepts: TCP/IP stream */ void tcp_close (TCPSTREAM *stream) { struct TCPClosePB *closepb = &stream->pb.csParam.close; struct TCPCreatePB *createpb = &stream->pb.csParam.create; stream->pb.csCode = TCPClose; /* close TCP stream */ closepb->ulpTimeoutValue = (int) ttmo_close; closepb->ulpTimeoutAction = 0; closepb->validityFlags = timeoutValue|timeoutAction; closepb->userDataPtr = NIL; PBControlAsync ((ParmBlkPtr) &stream->pb); while (stream->pb.ioResult == inProgress && wait ()); stream->pb.csCode =TCPRelease;/* flush the buffers */ createpb->userDataPtr = NIL; if (PBControlSync ((ParmBlkPtr) &stream->pb)) fatal ("TCPRelease lossage"); /* free its buffer */ fs_give ((void **) &createpb->rcvBuff); /* flush host names */ fs_give ((void **) &stream->host); fs_give ((void **) &stream->localhost); fs_give ((void **) &stream); /* flush the stream */ } /* TCP/IP return host for this stream * Accepts: TCP/IP stream * Returns: host name for this stream */ char *tcp_host (TCPSTREAM *stream) { return stream->host; /* return host name */ } /* TCP/IP return remote host for this stream * Accepts: TCP/IP stream * Returns: host name for this stream */ char *tcp_remotehost (TCPSTREAM *stream) { return stream->host; /* return host name */ } /* TCP/IP return port for this stream * Accepts: TCP/IP stream * Returns: port number for this stream */ unsigned long tcp_port (TCPSTREAM *stream) { return stream->port; /* return port number */ } /* TCP/IP return local host for this stream * Accepts: TCP/IP stream * Returns: local host name for this stream */ char *tcp_localhost (TCPSTREAM *stream) { return stream->localhost; /* return local host name */ } /* TCP/IP return canonical form of host name * Accepts: host name * Returns: canonical form of host name */ char *tcp_canonical (char *name) { int i; struct hostInfo hst; /* look like domain literal? */ if (name[0] == '[' && name[i = (strlen (name))-1] == ']') return name; if (StrToAddr (name,&hst,tcp_dns_upp,NIL)) { while (hst.rtnCode == cacheFault && wait ()); /* kludge around MacTCP bug */ if (hst.rtnCode == outOfMemory) { mm_log ("Re-initializing domain resolver",WARN); CloseResolver (); /* bop it on the head and try again */ OpenResolver (NIL); /* note this will leak 12K */ StrToAddr (name,&hst,tcp_dns_upp,NIL); while (hst.rtnCode == cacheFault && wait ()); } /* still have error status? */ if (hst.rtnCode) return name; } return hst.cname; /* success */ } /* TCP/IP get client host name (server calls only) * Returns: client host name */ char *tcp_clienthost () { return "UNKNOWN"; } alpine-2.10+dfsg/imap/src/osdep/mac/linkage.c0000600000175000017500000000243411512502123022503 0ustar paulproteuspaulproteus/* ======================================================================== * Copyright 1988-2007 University of Washington * * Licensed under the Apache License, Version 2.0 (the "License"); * you may not use this file except in compliance with the License. * You may obtain a copy of the License at * * http://www.apache.org/licenses/LICENSE-2.0 * * * ======================================================================== */ /* * Program: Default driver linkage * * Author: Mark Crispin * Networks and Distributed Computing * Computing & Communications * University of Washington * Administration Building, AG-44 * Seattle, WA 98195 * Internet: MRC@CAC.Washington.EDU * * Date: 13 June 1995 * Last Edited: 23 May 2007 */ mail_link (&imapdriver); /* link in the imap driver */ mail_link (&nntpdriver); /* link in the nntp driver */ mail_link (&pop3driver); /* link in the pop3 driver */ mail_link (&dummydriver); /* link in the dummy driver */ auth_link (&auth_ext); /* link in the ext authenticator */ auth_link (&auth_md5); /* link in the md5 authenticator */ auth_link (&auth_pla); /* link in the plain authenticator */ auth_link (&auth_log); /* link in the log authenticator */ mail_versioncheck (CCLIENTVERSION); /* validate version */ alpine-2.10+dfsg/imap/src/osdep/mac/linkage.h0000600000175000017500000000174311512502123022512 0ustar paulproteuspaulproteus/* ======================================================================== * Copyright 1988-2006 University of Washington * * Licensed under the Apache License, Version 2.0 (the "License"); * you may not use this file except in compliance with the License. * You may obtain a copy of the License at * * http://www.apache.org/licenses/LICENSE-2.0 * * * ======================================================================== */ /* * Program: Default driver linkage * * Author: Mark Crispin * Networks and Distributed Computing * Computing & Communications * University of Washington * Administration Building, AG-44 * Seattle, WA 98195 * Internet: MRC@CAC.Washington.EDU * * Date: 13 June 1995 * Last Edited: 30 August 2006 */ extern DRIVER imapdriver; extern DRIVER nntpdriver; extern DRIVER pop3driver; extern DRIVER dummydriver; extern AUTHENTICATOR auth_ext; extern AUTHENTICATOR auth_log; extern AUTHENTICATOR auth_md5; extern AUTHENTICATOR auth_pla; alpine-2.10+dfsg/imap/src/osdep/mac/pmatch.c0000600000175000017500000000545411512502123022352 0ustar paulproteuspaulproteus/* ======================================================================== * Copyright 1988-2006 University of Washington * * Licensed under the Apache License, Version 2.0 (the "License"); * you may not use this file except in compliance with the License. * You may obtain a copy of the License at * * http://www.apache.org/licenses/LICENSE-2.0 * * * ======================================================================== */ /* * Program: IMAP Wildcard Matching Routines (case-independent) * * Author: Mark Crispin * Networks and Distributed Computing * Computing & Communications * University of Washington * Administration Building, AG-44 * Seattle, WA 98195 * Internet: MRC@CAC.Washington.EDU * * Date: 15 June 2000 * Last Edited: 30 August 2006 */ /* Wildcard pattern match * Accepts: base string * pattern string * delimiter character * Returns: T if pattern matches base, else NIL */ long pmatch_full (unsigned char *s,unsigned char *pat,unsigned char delim) { switch (*pat) { case '%': /* non-recursive */ /* % at end, OK if no inferiors */ if (!pat[1]) return (delim && strchr (s,delim)) ? NIL : T; /* scan remainder of string until delimiter */ do if (pmatch_full (s,pat+1,delim)) return T; while ((*s != delim) && *s++); break; case '*': /* match 0 or more characters */ if (!pat[1]) return T; /* * at end, unconditional match */ /* scan remainder of string */ do if (pmatch_full (s,pat+1,delim)) return T; while (*s++); break; case '\0': /* end of pattern */ return *s ? NIL : T; /* success if also end of base */ default: /* match this character */ return compare_uchar (*pat,*s) ? NIL : pmatch_full (s+1,pat+1,delim); } return NIL; } /* Directory pattern match * Accepts: base string * pattern string * delimiter character * Returns: T if base is a matching directory of pattern, else NIL */ long dmatch (unsigned char *s,unsigned char *pat,unsigned char delim) { switch (*pat) { case '%': /* non-recursive */ if (!*s) return T; /* end of base means have a subset match */ if (!*++pat) return NIL; /* % at end, no inferiors permitted */ /* scan remainder of string until delimiter */ do if (dmatch (s,pat,delim)) return T; while ((*s != delim) && *s++); if (*s && !s[1]) return T; /* ends with delimiter, must be subset */ return dmatch (s,pat,delim);/* do new scan */ case '*': /* match 0 or more characters */ return T; /* unconditional match */ case '\0': /* end of pattern */ break; default: /* match this character */ if (*s) return compare_uchar (*pat,*s) ? NIL : dmatch (s+1,pat+1,delim); /* end of base, return if at delimiter */ else if (*pat == delim) return T; break; } return NIL; } alpine-2.10+dfsg/imap/src/osdep/mac/os_mac.c0000600000175000017500000000420411512502123022327 0ustar paulproteuspaulproteus/* ======================================================================== * Copyright 1988-2006 University of Washington * * Licensed under the Apache License, Version 2.0 (the "License"); * you may not use this file except in compliance with the License. * You may obtain a copy of the License at * * http://www.apache.org/licenses/LICENSE-2.0 * * * ======================================================================== */ /* * Program: Operating-system dependent routines -- Macintosh version * * Author: Mark Crispin * Networks and Distributed Computing * Computing & Communications * University of Washington * Administration Building, AG-44 * Seattle, WA 98195 * Internet: MRC@CAC.Washington.EDU * * Date: 26 January 1992 * Last Edited: 30 August 2006 */ /* This is a totally new operating-system dependent module for the Macintosh, * written using THINK C on my Mac PowerBook-100 in my free time. * Unlike earlier efforts, this version requires no external TCP library. It * also takes advantage of the Map panel in System 7 for the timezone. */ /* PPC cretins broke the MachineLocation struct */ #define gmtFlags u #include #include #include #include #define tcp_port MacTCP_port #include #include #include #include #include #include #include #include #include #include #include #include #undef tcp_port #include "tcp_mac.h" /* must be before osdep.h */ #include "mail.h" #include "osdep.h" #include "misc.h" static short TCPdriver = 0; /* MacTCP's reference number */ short resolveropen = 0; /* TCP's resolver open */ #include "env_mac.c" #include "fs_mac.c" #include "ftl_mac.c" #include "nl_mac.c" #include "tcp_mac.c" #define open(a,b,c) open (a,b) #define server_login(user,pass,authuser,argc,argv) NIL #define authserver_login(user,authuser,argc,argv) NIL #define myusername() "" /* dummy definition to prevent build errors */ #define MD5ENABLE "" #include "auth_md5.c" #include "auth_pla.c" #include "auth_log.c" alpine-2.10+dfsg/imap/src/osdep/wce/0000700000175000017500000000000011512502151020737 5ustar paulproteuspaulproteusalpine-2.10+dfsg/imap/src/osdep/wce/dummywce.c0000600000175000017500000001621211512502124022741 0ustar paulproteuspaulproteus/* ======================================================================== * Copyright 1988-2006 University of Washington * * Licensed under the Apache License, Version 2.0 (the "License"); * you may not use this file except in compliance with the License. * You may obtain a copy of the License at * * http://www.apache.org/licenses/LICENSE-2.0 * * * ======================================================================== */ /* * Program: Dummy routines for WCE * * Author: Mark Crispin * Networks and Distributed Computing * Computing & Communications * University of Washington * Administration Building, AG-44 * Seattle, WA 98195 * Internet: MRC@CAC.Washington.EDU * * Date: 24 May 1993 * Last Edited: 30 August 2006 */ #include #include #include #include #include #include "mail.h" #include "osdep.h" #include #include #include "dummy.h" #include "misc.h" /* Function prototypes */ DRIVER *dummy_valid (char *name); void *dummy_parameters (long function,void *value); MAILSTREAM *dummy_open (MAILSTREAM *stream); void dummy_close (MAILSTREAM *stream,long options); long dummy_ping (MAILSTREAM *stream); void dummy_check (MAILSTREAM *stream); long dummy_expunge (MAILSTREAM *stream,char *sequence,long options); long dummy_copy (MAILSTREAM *stream,char *sequence,char *mailbox,long options); long dummy_append (MAILSTREAM *stream,char *mailbox,append_t af,void *data); /* Dummy routines */ /* Driver dispatch used by MAIL */ DRIVER dummydriver = { "dummy", /* driver name */ DR_LOCAL|DR_MAIL, /* driver flags */ (DRIVER *) NIL, /* next driver */ dummy_valid, /* mailbox is valid for us */ dummy_parameters, /* manipulate parameters */ dummy_scan, /* scan mailboxes */ dummy_list, /* list mailboxes */ dummy_lsub, /* list subscribed mailboxes */ NIL, /* subscribe to mailbox */ NIL, /* unsubscribe from mailbox */ dummy_create, /* create mailbox */ dummy_delete, /* delete mailbox */ dummy_rename, /* rename mailbox */ mail_status_default, /* status of mailbox */ dummy_open, /* open mailbox */ dummy_close, /* close mailbox */ NIL, /* fetch message "fast" attributes */ NIL, /* fetch message flags */ NIL, /* fetch overview */ NIL, /* fetch message structure */ NIL, /* fetch header */ NIL, /* fetch text */ NIL, /* fetch message data */ NIL, /* unique identifier */ NIL, /* message number from UID */ NIL, /* modify flags */ NIL, /* per-message modify flags */ NIL, /* search for message based on criteria */ NIL, /* sort messages */ NIL, /* thread messages */ dummy_ping, /* ping mailbox to see if still alive */ dummy_check, /* check for new messages */ dummy_expunge, /* expunge deleted messages */ dummy_copy, /* copy messages to another mailbox */ dummy_append, /* append string message to mailbox */ NIL /* garbage collect stream */ }; /* prototype stream */ MAILSTREAM dummyproto = {&dummydriver}; /* driver parameters */ static char *file_extension = NIL; /* Dummy validate mailbox * Accepts: mailbox name * Returns: our driver if name is valid, NIL otherwise */ DRIVER *dummy_valid (char *name) { char *s,tmp[MAILTMPLEN]; struct stat sbuf; /* must be valid local mailbox */ return (name && *name && (*name != '{') && (s = mailboxfile (tmp,name)) && (!*s || !stat (s,&sbuf))) ? &dummydriver : NIL; } /* Dummy manipulate driver parameters * Accepts: function code * function-dependent value * Returns: function-dependent return value */ void *dummy_parameters (long function,void *value) { return value; } /* Dummy scan mailboxes * Accepts: mail stream * reference * pattern to search * string to scan */ void dummy_scan (MAILSTREAM *stream,char *ref,char *pat,char *contents) { /* return silently */ } /* Dummy list mailboxes * Accepts: mail stream * reference * pattern to search */ void dummy_list (MAILSTREAM *stream,char *ref,char *pat) { /* return silently */ } /* Dummy list subscribed mailboxes * Accepts: mail stream * pattern to search */ void dummy_lsub (MAILSTREAM *stream,char *ref,char *pat) { /* return silently */ } /* Dummy create mailbox * Accepts: mail stream * mailbox name to create * Returns: T on success, NIL on failure */ long dummy_create (MAILSTREAM *stream,char *mailbox) { return NIL; /* always fails */ } /* Dummy delete mailbox * Accepts: mail stream * mailbox name to delete * Returns: T on success, NIL on failure */ long dummy_delete (MAILSTREAM *stream,char *mailbox) { return NIL; /* always fails */ } /* Mail rename mailbox * Accepts: mail stream * old mailbox name * new mailbox name * Returns: T on success, NIL on failure */ long dummy_rename (MAILSTREAM *stream,char *old,char *newname) { return NIL; /* always fails */ } /* Dummy open * Accepts: stream to open * Returns: stream on success, NIL on failure */ MAILSTREAM *dummy_open (MAILSTREAM *stream) { char tmp[MAILTMPLEN]; /* OP_PROTOTYPE call or silence */ if (!stream || stream->silent) return NIL; if (compare_cstring (stream->mailbox,"INBOX")) { sprintf (tmp,"Not a mailbox: %s",stream->mailbox); mm_log (tmp,ERROR); return NIL; /* always fails */ } if (!stream->silent) { /* only if silence not requested */ mail_exists (stream,0); /* say there are 0 messages */ mail_recent (stream,0); stream->uid_validity = time (0); } stream->inbox = T; /* note that it's an INBOX */ return stream; /* return success */ } /* Dummy close * Accepts: MAIL stream * options */ void dummy_close (MAILSTREAM *stream,long options) { /* return silently */ } /* Dummy ping mailbox * Accepts: MAIL stream * Returns: T if stream alive, else NIL * No-op for readonly files, since read/writer can expunge it from under us! */ long dummy_ping (MAILSTREAM *stream) { return T; } /* Dummy check mailbox * Accepts: MAIL stream * No-op for readonly files, since read/writer can expunge it from under us! */ void dummy_check (MAILSTREAM *stream) { dummy_ping (stream); /* invoke ping */ } /* Dummy expunge mailbox * Accepts: MAIL stream * sequence to expunge if non-NIL * expunge options * Returns: T, always */ long dummy_expunge (MAILSTREAM *stream,char *sequence,long options) { return LONGT; } /* Dummy copy message(s) * Accepts: MAIL stream * sequence * destination mailbox * options * Returns: T if copy successful, else NIL */ long dummy_copy (MAILSTREAM *stream,char *sequence,char *mailbox,long options) { if ((options & CP_UID) ? mail_uid_sequence (stream,sequence) : mail_sequence (stream,sequence)) fatal ("Impossible dummy_copy"); return NIL; } /* Dummy append message string * Accepts: mail stream * destination mailbox * stringstruct of message to append * Returns: T on success, NIL on failure */ long dummy_append (MAILSTREAM *stream,char *mailbox,append_t af,void *data) { char tmp[MAILTMPLEN]; sprintf (tmp,"Can't append to %s",mailbox); mm_log (tmp,ERROR); /* pass up error */ return NIL; /* always fails */ } alpine-2.10+dfsg/imap/src/osdep/wce/mkautaux.bat0000600000175000017500000000222611512502124023272 0ustar paulproteuspaulproteus@ECHO OFF REM ======================================================================== REM Copyright 1988-2006 University of Washington REM REM Licensed under the Apache License, Version 2.0 (the "License"); REM you may not use this file except in compliance with the License. REM You may obtain a copy of the License at REM REM http://www.apache.org/licenses/LICENSE-2.0 REM REM REM ======================================================================== REM Program: Authenticator Linkage Generator auxillary for NT/Win9x REM REM Author: Mark Crispin REM Networks and Distributed Computing REM Computing & Communications REM University of Washington REM Administration Building, AG-44 REM Seattle, WA 98195 REM Internet: MRC@CAC.Washington.EDU REM REM Date: 6 December 1995 REM Last Edited:30 August 2006 ECHO extern AUTHENTICATOR auth_%1; >> LINKAGE.H REM Note the introduction of the caret to quote the ampersand in NT if "%OS%" == "Windows_NT" ECHO auth_link (^&auth_%1); /* link in the %1 authenticator */ >> LINKAGE.C if "%OS%" == "" ECHO auth_link (&auth_%1); /* link in the %1 authenticator */ >> LINKAGE.C ECHO #include "auth_%1.c" >> AUTHS.C alpine-2.10+dfsg/imap/src/osdep/wce/env_wce.h0000600000175000017500000000433211512502124022542 0ustar paulproteuspaulproteus/* ======================================================================== * Copyright 1988-2006 University of Washington * * Licensed under the Apache License, Version 2.0 (the "License"); * you may not use this file except in compliance with the License. * You may obtain a copy of the License at * * http://www.apache.org/licenses/LICENSE-2.0 * * * ======================================================================== */ /* * Program: WCE environment routines * * Author: Mark Crispin * Networks and Distributed Computing * Computing & Communications * University of Washington * Administration Building, AG-44 * Seattle, WA 98195 * Internet: MRC@CAC.Washington.EDU * * Date: 1 August 1988 * Last Edited: 30 August 2006 */ #define SUBSCRIPTIONFILE(t) sprintf (t,"%s\\MAILBOX.LST",myhomedir ()) #define SUBSCRIPTIONTEMP(t) sprintf (t,"%s\\MAILBOX.TMP",myhomedir ()) #define L_SET SEEK_SET /* Function prototypes */ #include "env.h" static char *defaultDrive (void); static char *homeDrive (void); static char *homePath (char *path); char *sysinbox (); long random (); unsigned long unix_crlfcpy (char **dst,unsigned long *dstl,char *src, unsigned long srcl); unsigned long unix_crlflen (STRING *s); #define getpid random /* syslog() emulation */ #define LOG_MAIL (2<<3) /* mail system */ #define LOG_DAEMON (3<<3) /* system daemons */ #define LOG_AUTH (4<<3) /* security/authorization messages */ #define LOG_EMERG 0 /* system is unusable */ #define LOG_ALERT 1 /* action must be taken immediately */ #define LOG_CRIT 2 /* critical conditions */ #define LOG_ERR 3 /* error conditions */ #define LOG_WARNING 4 /* warning conditions */ #define LOG_NOTICE 5 /* normal but signification condition */ #define LOG_INFO 6 /* informational */ #define LOG_DEBUG 7 /* debug-level messages */ #define LOG_PID 0x01 /* log the pid with each message */ #define LOG_CONS 0x02 /* log on the console if errors in sending */ #define LOG_ODELAY 0x04 /* delay open until syslog() is called */ #define LOG_NDELAY 0x08 /* don't delay open */ #define LOG_NOWAIT 0x10 /* if forking to log on console, don't wait() */ void openlog (const char *ident,int logopt,int facility); void syslog (int priority,const char *message,...); alpine-2.10+dfsg/imap/src/osdep/wce/dummy.h0000600000175000017500000000276411512502124022256 0ustar paulproteuspaulproteus/* ======================================================================== * Copyright 1988-2006 University of Washington * * Licensed under the Apache License, Version 2.0 (the "License"); * you may not use this file except in compliance with the License. * You may obtain a copy of the License at * * http://www.apache.org/licenses/LICENSE-2.0 * * * ======================================================================== */ /* * Program: Dummy routines * * Author: Mark Crispin * Networks and Distributed Computing * Computing & Communications * University of Washington * Administration Building, AG-44 * Seattle, WA 98195 * Internet: MRC@CAC.Washington.EDU * * Date: 9 May 1991 * Last Edited: 30 August 2006 */ /* Exported function prototypes */ void dummy_scan (MAILSTREAM *stream,char *ref,char *pat,char *contents); void dummy_list (MAILSTREAM *stream,char *ref,char *pat); void dummy_lsub (MAILSTREAM *stream,char *ref,char *pat); long scan_contents (DRIVER *dtb,char *name,char *contents, unsigned long csiz,unsigned long fsiz); long dummy_scan_contents (char *name,char *contents,unsigned long csiz, unsigned long fsiz); long dummy_create (MAILSTREAM *stream,char *mailbox); long dummy_create_path (MAILSTREAM *stream,char *path,long dirmode); long dummy_delete (MAILSTREAM *stream,char *mailbox); long dummy_rename (MAILSTREAM *stream,char *old,char *newname); char *dummy_file (char *dst,char *name); long dummy_canonicalize (char *tmp,char *ref,char *pat); alpine-2.10+dfsg/imap/src/osdep/wce/ftl_wce.c0000600000175000017500000000167311512502124022537 0ustar paulproteuspaulproteus/* ======================================================================== * Copyright 1988-2006 University of Washington * * Licensed under the Apache License, Version 2.0 (the "License"); * you may not use this file except in compliance with the License. * You may obtain a copy of the License at * * http://www.apache.org/licenses/LICENSE-2.0 * * * ======================================================================== */ /* * Program: DOS/VMS/TOPS-20 crash management routines * * Author: Mark Crispin * Networks and Distributed Computing * Computing & Communications * University of Washington * Administration Building, AG-44 * Seattle, WA 98195 * Internet: MRC@CAC.Washington.EDU * * Date: 1 August 1988 * Last Edited: 30 August 2006 */ /* Report a fatal error * Accepts: string to output */ void fatal (char *string) { mm_fatal (string); /* pass up the string */ abort (); /* die horribly */ } alpine-2.10+dfsg/imap/src/osdep/wce/drivraux.bat0000600000175000017500000000212611512502124023276 0ustar paulproteuspaulproteus@ECHO OFF REM ======================================================================== REM Copyright 1988-2006 University of Washington REM REM Licensed under the Apache License, Version 2.0 (the "License"); REM you may not use this file except in compliance with the License. REM You may obtain a copy of the License at REM REM http://www.apache.org/licenses/LICENSE-2.0 REM REM REM ======================================================================== REM Program: Driver Linkage Generator auxillary for NT/Win9x REM REM Author: Mark Crispin REM Networks and Distributed Computing REM Computing & Communications REM University of Washington REM Administration Building, AG-44 REM Seattle, WA 98195 REM Internet: MRC@CAC.Washington.EDU REM REM Date: 11 October 1989 REM Last Edited:30 August 2006 ECHO extern DRIVER %1driver; >> LINKAGE.H REM Note the introduction of the caret to quote the ampersand in NT if "%OS%" == "Windows_NT" ECHO mail_link (^&%1driver); /* link in the %1 driver */ >> LINKAGE.C if "%OS%" == "" ECHO mail_link (&%1driver); /* link in the %1 driver */ >> LINKAGE.C alpine-2.10+dfsg/imap/src/osdep/wce/tcp_wce.c0000600000175000017500000005656511512502124022552 0ustar paulproteuspaulproteus/* ======================================================================== * Copyright 1988-2008 University of Washington * * Licensed under the Apache License, Version 2.0 (the "License"); * you may not use this file except in compliance with the License. * You may obtain a copy of the License at * * http://www.apache.org/licenses/LICENSE-2.0 * * * ======================================================================== */ /* * Program: Winsock TCP/IP routines * * Author: Mark Crispin from Mike Seibel's Winsock code * Networks and Distributed Computing * Computing & Communications * University of Washington * Administration Building, AG-44 * Seattle, WA 98195 * Internet: MRC@CAC.Washington.EDU * * Date: 11 April 1989 * Last Edited: 13 January 2008 */ #define TCPMAXSEND 32768 /* Private functions */ int tcp_socket_open (struct sockaddr_in *sin,char *tmp,char *hst, unsigned long port); static char *tcp_getline_work (TCPSTREAM *stream,unsigned long *size, long *contd); long tcp_abort (TCPSTREAM *stream); long tcp_close_socket (SOCKET *sock); char *tcp_name (struct sockaddr_in *sin,long flag); char *tcp_name_valid (char *s); /* Private data */ int wsa_initted = 0; /* init ? */ static int wsa_sock_open = 0; /* keep track of open sockets */ static tcptimeout_t tmoh = NIL; /* TCP timeout handler routine */ static long ttmo_read = 0; /* TCP timeouts, in seconds */ static long ttmo_write = 0; static long allowreversedns = T;/* allow reverse DNS lookup */ static long tcpdebug = NIL; /* extra TCP debugging telemetry */ /* TCP/IP manipulate parameters * Accepts: function code * function-dependent value * Returns: function-dependent return value */ void *tcp_parameters (long function,void *value) { void *ret = NIL; switch ((int) function) { case SET_TIMEOUT: tmoh = (tcptimeout_t) value; case GET_TIMEOUT: ret = (void *) tmoh; break; case SET_READTIMEOUT: ttmo_read = (long) value; case GET_READTIMEOUT: ret = (void *) ttmo_read; break; case SET_WRITETIMEOUT: ttmo_write = (long) value; case GET_WRITETIMEOUT: ret = (void *) ttmo_write; break; case SET_ALLOWREVERSEDNS: allowreversedns = (long) value; case GET_ALLOWREVERSEDNS: ret = (void *) allowreversedns; break; case SET_TCPDEBUG: tcpdebug = (long) value; case GET_TCPDEBUG: ret = (void *) tcpdebug; break; } return ret; } /* TCP/IP open * Accepts: host name * contact service name * contact port number and optional silent flag * Returns: TCP/IP stream if success else NIL */ TCPSTREAM *tcp_open (char *host,char *service,unsigned long port) { TCPSTREAM *stream = NIL; int i; SOCKET sock = INVALID_SOCKET; int silent = (port & NET_SILENT) ? T : NIL; char *s; struct sockaddr_in sin; struct hostent *he; char hostname[MAILTMPLEN]; char tmp[MAILTMPLEN]; struct servent *sv = NIL; blocknotify_t bn = (blocknotify_t) mail_parameters (NIL,GET_BLOCKNOTIFY,NIL); if (!wsa_initted++) { /* init Windows Sockets */ WSADATA wsock; if (i = (int) WSAStartup (WSA_VERSION,&wsock)) { wsa_initted = 0; /* in case we try again */ sprintf (tmp,"Unable to start Windows Sockets (%d)",i); mm_log (tmp,ERROR); return NIL; } } port &= 0xffff; /* erase flags */ /* lookup service */ if (service && (sv = getservbyname (service,"tcp"))) port = ntohs (sin.sin_port = sv->s_port); /* copy port number in network format */ else sin.sin_port = htons ((u_short) port); /* The domain literal form is used (rather than simply the dotted decimal as with other Windows programs) because it has to be a valid "host name" in mailsystem terminology. */ sin.sin_family = AF_INET; /* family is always Internet */ /* look like domain literal? */ if (host[0] == '[' && host[(strlen (host))-1] == ']') { strcpy (tmp,host+1); /* yes, copy number part */ tmp[strlen (tmp)-1] = '\0'; if ((sin.sin_addr.s_addr = inet_addr (tmp)) == INADDR_NONE) { sprintf (tmp,"Bad format domain-literal: %.80s",host); mm_log (tmp,ERROR); return NIL; } else { sin.sin_family = AF_INET; /* family is always Internet */ strcpy (hostname,host); (*bn) (BLOCK_TCPOPEN,NIL); sock = tcp_socket_open (&sin,tmp,hostname,port); (*bn) (BLOCK_NONE,NIL); } } else { /* lookup host name */ if (tcpdebug) { sprintf (tmp,"DNS resolution %.80s",host); mm_log (tmp,TCPDEBUG); } (*bn) (BLOCK_DNSLOOKUP,NIL);/* look up name */ if (!(he = gethostbyname (lcase (strcpy (tmp,host))))) sprintf (tmp,"Host not found (#%d): %s",WSAGetLastError(),host); (*bn) (BLOCK_NONE,NIL); if (he) { /* DNS resolution won? */ if (tcpdebug) mm_log ("DNS resolution done",TCPDEBUG); /* copy address type */ sin.sin_family = he->h_addrtype; /* copy host name */ strcpy (hostname,he->h_name); wsa_sock_open++; /* prevent tcp_close_socket() from freeing in loop */ for (i = 0; (sock == INVALID_SOCKET) && (s = he->h_addr_list[i]); i++) { if (i && !silent) mm_log (tmp,WARN); memcpy (&sin.sin_addr,s,he->h_length); (*bn) (BLOCK_TCPOPEN,NIL); sock = tcp_socket_open (&sin,tmp,hostname,port); (*bn) (BLOCK_NONE,NIL); } wsa_sock_open--; /* undo protection */ } } if (sock == INVALID_SOCKET) { /* error? */ if (!silent) mm_log (tmp,ERROR); tcp_close_socket (&sock); /* do possible cleanup action */ } else { /* got a socket, create TCP/IP stream */ stream = (TCPSTREAM *) memset (fs_get (sizeof (TCPSTREAM)),0, sizeof (TCPSTREAM)); stream->port = port; /* port number */ /* init socket */ stream->tcpsi = stream->tcpso = sock; stream->ictr = 0; /* init input counter */ /* copy official host name */ stream->host = cpystr (hostname); if (tcpdebug) mm_log ("Stream open and ready for read",TCPDEBUG); } return stream; /* return success */ } /* Open a TCP socket * Accepts: Internet socket address block * scratch buffer * host name for error message * port number for error message * Returns: socket if success, else -1 with error string in scratch buffer */ int tcp_socket_open (struct sockaddr_in *sin,char *tmp,char *hst, unsigned long port) { int sock; char *s; sprintf (tmp,"Trying IP address [%s]",inet_ntoa (sin->sin_addr)); mm_log (tmp,NIL); /* get a TCP stream */ if ((sock = socket (sin->sin_family,SOCK_STREAM,0)) == INVALID_SOCKET) { sprintf (tmp,"Unable to create TCP socket (%d)",WSAGetLastError()); return -1; } wsa_sock_open++; /* count this socket as open */ /* open connection */ if (connect (sock,(struct sockaddr *) sin,sizeof (struct sockaddr_in)) == SOCKET_ERROR) { switch (WSAGetLastError ()){/* analyze error */ case WSAECONNREFUSED: s = "Refused"; break; case WSAENOBUFS: s = "Insufficient system resources"; break; case WSAETIMEDOUT: s = "Timed out"; break; case WSAEHOSTUNREACH: s = "Host unreachable"; break; default: s = "Unknown error"; break; } sprintf (tmp,"Can't connect to %.80s,%ld: %s (%d)",hst,port,s, WSAGetLastError ()); tcp_close_socket (&sock); /* flush socket */ sock = INVALID_SOCKET; } return sock; /* return the socket */ } /* TCP/IP authenticated open * Accepts: NETMBX specifier * service name * returned user name buffer * Returns: TCP/IP stream if success else NIL */ TCPSTREAM *tcp_aopen (NETMBX *mb,char *service,char *usrbuf) { return NIL; /* always NIL on Windows */ } /* TCP receive line * Accepts: TCP stream * Returns: text line string or NIL if failure */ char *tcp_getline (TCPSTREAM *stream) { unsigned long n,contd; char *ret = tcp_getline_work (stream,&n,&contd); if (ret && contd) { /* got a line needing continuation? */ STRINGLIST *stl = mail_newstringlist (); STRINGLIST *stc = stl; do { /* collect additional lines */ stc->text.data = (unsigned char *) ret; stc->text.size = n; stc = stc->next = mail_newstringlist (); ret = tcp_getline_work (stream,&n,&contd); } while (ret && contd); if (ret) { /* stash final part of line on list */ stc->text.data = (unsigned char *) ret; stc->text.size = n; /* determine how large a buffer we need */ for (n = 0, stc = stl; stc; stc = stc->next) n += stc->text.size; ret = fs_get (n + 1); /* copy parts into buffer */ for (n = 0, stc = stl; stc; n += stc->text.size, stc = stc->next) memcpy (ret + n,stc->text.data,stc->text.size); ret[n] = '\0'; } mail_free_stringlist (&stl);/* either way, done with list */ } return ret; } /* TCP receive line or partial line * Accepts: TCP stream * pointer to return size * pointer to return continuation flag * Returns: text line string, size and continuation flag, or NIL if failure */ static char *tcp_getline_work (TCPSTREAM *stream,unsigned long *size, long *contd) { unsigned long n; char *s,*ret,c,d; *contd = NIL; /* assume no continuation */ /* make sure have data */ if (!tcp_getdata (stream)) return NIL; for (s = stream->iptr, n = 0, c = '\0'; stream->ictr--; n++, c = d) { d = *stream->iptr++; /* slurp another character */ if ((c == '\015') && (d == '\012')) { ret = (char *) fs_get (n--); memcpy (ret,s,*size = n); /* copy into a free storage string */ ret[n] = '\0'; /* tie off string with null */ return ret; } } /* copy partial string from buffer */ memcpy ((ret = (char *) fs_get (n)),s,*size = n); /* get more data from the net */ if (!tcp_getdata (stream)) fs_give ((void **) &ret); /* special case of newline broken by buffer */ else if ((c == '\015') && (*stream->iptr == '\012')) { stream->iptr++; /* eat the line feed */ stream->ictr--; ret[*size = --n] = '\0'; /* tie off string with null */ } else *contd = LONGT; /* continuation needed */ return ret; } /* TCP/IP receive buffer * Accepts: TCP/IP stream * size in bytes * buffer to read into * Returns: T if success, NIL otherwise */ long tcp_getbuffer (TCPSTREAM *stream,unsigned long size,char *s) { unsigned long n; /* make sure socket still alive */ if (stream->tcpsi == INVALID_SOCKET) return NIL; /* can transfer bytes from buffer? */ if (n = min (size,stream->ictr)) { memcpy (s,stream->iptr,n); /* yes, slurp as much as we can from it */ s += n; /* update pointer */ stream->iptr +=n; size -= n; /* update # of bytes to do */ stream->ictr -=n; } if (size) { int i; fd_set fds; struct timeval tmo; time_t tc,t = time (0); blocknotify_t bn=(blocknotify_t) mail_parameters (NIL,GET_BLOCKNOTIFY,NIL); (*bn) (BLOCK_TCPREAD,NIL); while (size > 0) { /* until request satisfied */ time_t tl = time (0); if (tcpdebug) mm_log ("Reading TCP buffer",TCPDEBUG); FD_ZERO (&fds); /* initialize selection vector */ FD_SET (stream->tcpsi,&fds);/* set bit in selection vector */ tmo.tv_sec = ttmo_read; tmo.tv_usec = 0; /* block and read */ switch ((stream->tcpsi == stream->tcpso) ? select (stream->tcpsi+1,&fds,0,0, ttmo_read ? &tmo : (struct timeval *) 0) : 1) { case SOCKET_ERROR: /* error */ if (WSAGetLastError () != WSAEINTR) return tcp_abort (stream); break; case 0: /* timeout */ tc = time (0); if (tmoh && ((*tmoh) (tc - t,tc - tl))) break; return tcp_abort (stream); default: if (stream->tcpsi == stream->tcpso) while (((i = recv (stream->tcpsi,s,(int) min (maxposint,size),0)) == SOCKET_ERROR) && (WSAGetLastError () == WSAEINTR)); else while (((i = read (stream->tcpsi,s,(int) min (maxposint,size))) < 0) && (errno == EINTR)); switch (i) { case SOCKET_ERROR: /* error */ case 0: /* no data read */ return tcp_abort (stream); default: s += i; /* point at new place to write */ size -= i; /* reduce byte count */ if (tcpdebug) mm_log ("Successfully read TCP buffer",TCPDEBUG); } } } (*bn) (BLOCK_NONE,NIL); } *s = '\0'; /* tie off string */ return T; } /* TCP/IP receive data * Accepts: TCP/IP stream * Returns: T if success, NIL otherwise */ long tcp_getdata (TCPSTREAM *stream) { struct timeval tmo; int i; fd_set fds; time_t tc,t = time (0); blocknotify_t bn = (blocknotify_t) mail_parameters (NIL,GET_BLOCKNOTIFY,NIL); FD_ZERO (&fds); /* initialize selection vector */ if (stream->tcpsi == INVALID_SOCKET) return NIL; (*bn) (BLOCK_TCPREAD,NIL); tmo.tv_sec = ttmo_read; tmo.tv_usec = 0; while (stream->ictr < 1) { /* if nothing in the buffer */ time_t tl = time (0); if (tcpdebug) mm_log ("Reading TCP data",TCPDEBUG); FD_SET (stream->tcpsi,&fds);/* set bit in selection vector */ /* block and read */ switch ((stream->tcpsi == stream->tcpso) ? select (stream->tcpsi+1,&fds,0,0, ttmo_read ? &tmo : (struct timeval *) 0) : 1) { case SOCKET_ERROR: /* error */ if (WSAGetLastError () != WSAEINTR) return tcp_abort (stream); break; case 0: /* timeout */ tc = time (0); if (tmoh && ((*tmoh) (tc - t,tc - tl))) break; return tcp_abort (stream); default: if (stream->tcpsi == stream->tcpso) while (((i = recv (stream->tcpsi,stream->ibuf,BUFLEN,0)) == SOCKET_ERROR) && (WSAGetLastError () == WSAEINTR)); else while (((i = read (stream->tcpsi,stream->ibuf,BUFLEN)) < 0) && (errno == EINTR)); switch (i) { case SOCKET_ERROR: /* error */ case 0: /* no data read */ return tcp_abort (stream); default: stream->ictr = i; /* set new byte count */ /* point at TCP buffer */ stream->iptr = stream->ibuf; if (tcpdebug) mm_log ("Successfully read TCP data",TCPDEBUG); } } } (*bn) (BLOCK_NONE,NIL); return T; } /* TCP/IP send string as record * Accepts: TCP/IP stream * string pointer * Returns: T if success else NIL */ long tcp_soutr (TCPSTREAM *stream,char *string) { return tcp_sout (stream,string,(unsigned long) strlen (string)); } /* TCP/IP send string * Accepts: TCP/IP stream * string pointer * byte count * Returns: T if success else NIL */ long tcp_sout (TCPSTREAM *stream,char *string,unsigned long size) { int i; struct timeval tmo; fd_set fds; time_t tc,t = time (0); blocknotify_t bn = (blocknotify_t) mail_parameters (NIL,GET_BLOCKNOTIFY,NIL); tmo.tv_sec = ttmo_write; tmo.tv_usec = 0; FD_ZERO (&fds); /* initialize selection vector */ if (stream->tcpso == INVALID_SOCKET) return NIL; (*bn) (BLOCK_TCPWRITE,NIL); while (size > 0) { /* until request satisfied */ time_t tl = time (0); if (tcpdebug) mm_log ("Writing to TCP",TCPDEBUG); FD_SET (stream->tcpso,&fds);/* set bit in selection vector */ /* block and write */ switch ((stream->tcpsi == stream->tcpso) ? select (stream->tcpso+1,NULL,&fds,NULL, tmo.tv_sec ? &tmo : (struct timeval *) 0) : 1) { case SOCKET_ERROR: /* error */ if (WSAGetLastError () != WSAEINTR) return tcp_abort (stream); break; case 0: /* timeout */ tc = time (0); if (tmoh && ((*tmoh) (tc - t,tc - tl))) break; return tcp_abort (stream); default: if (stream->tcpsi == stream->tcpso) while (((i = send (stream->tcpso,string, (int) min (size,TCPMAXSEND),0)) == SOCKET_ERROR) && (WSAGetLastError () == WSAEINTR)); else while (((i = write (stream->tcpso,string, min (size,TCPMAXSEND))) < 0) && (errno == EINTR)); if (i == SOCKET_ERROR) return tcp_abort (stream); size -= i; /* count this size */ if (tcpdebug) mm_log ("successfully wrote to TCP",TCPDEBUG); string += i; } } (*bn) (BLOCK_NONE,NIL); return T; /* all done */ } /* TCP/IP close * Accepts: TCP/IP stream */ void tcp_close (TCPSTREAM *stream) { tcp_abort (stream); /* nuke the sockets */ /* flush host names */ if (stream->host) fs_give ((void **) &stream->host); if (stream->remotehost) fs_give ((void **) &stream->remotehost); if (stream->localhost) fs_give ((void **) &stream->localhost); fs_give ((void **) &stream); /* flush the stream */ } /* TCP/IP abort sockets * Accepts: TCP/IP stream * Returns: NIL, always */ long tcp_abort (TCPSTREAM *stream) { if (stream->tcpsi != stream->tcpso) tcp_close_socket (&stream->tcpso); else stream->tcpso = INVALID_SOCKET; return tcp_close_socket (&stream->tcpsi); } /* TCP/IP abort stream * Accepts: WinSock socket * Returns: NIL, always */ long tcp_close_socket (SOCKET *sock) { blocknotify_t bn = (blocknotify_t) mail_parameters (NIL,GET_BLOCKNOTIFY,NIL); /* something to close? */ if (sock && (*sock != INVALID_SOCKET)) { (*bn) (BLOCK_TCPCLOSE,NIL); closesocket (*sock); /* WinSock socket close */ *sock = INVALID_SOCKET; (*bn) (BLOCK_NONE,NIL); wsa_sock_open--; /* drop this socket */ } /* no more open streams? */ if (wsa_initted && !wsa_sock_open) { mm_log ("Winsock cleanup",NIL); wsa_initted = 0; /* no more sockets, so... */ WSACleanup (); /* free up resources until needed */ } return NIL; } /* TCP/IP get host name * Accepts: TCP/IP stream * Returns: host name for this stream */ char *tcp_host (TCPSTREAM *stream) { return stream->host; /* use tcp_remotehost() if want guarantees */ } /* TCP/IP get remote host name * Accepts: TCP/IP stream * Returns: host name for this stream */ char *tcp_remotehost (TCPSTREAM *stream) { if (!stream->remotehost) { struct sockaddr_in sin; int sinlen = sizeof (struct sockaddr_in); stream->remotehost = /* get socket's peer name */ ((getpeername (stream->tcpsi,(struct sockaddr *) &sin,&sinlen) == SOCKET_ERROR) || (sinlen <= 0)) ? cpystr (stream->host) : tcp_name (&sin,NIL); } return stream->remotehost; } /* TCP/IP return port for this stream * Accepts: TCP/IP stream * Returns: port number for this stream */ unsigned long tcp_port (TCPSTREAM *stream) { return stream->port; /* return port number */ } /* TCP/IP get local host name * Accepts: TCP/IP stream * Returns: local host name */ char *tcp_localhost (TCPSTREAM *stream) { if (!stream->localhost) { struct sockaddr_in sin; int sinlen = sizeof (struct sockaddr_in); stream->localhost = /* get socket's name */ ((stream->port & 0xffff000) || ((getsockname (stream->tcpsi,(struct sockaddr *) &sin,&sinlen) == SOCKET_ERROR) || (sinlen <= 0))) ? cpystr (mylocalhost ()) : tcp_name (&sin,NIL); } return stream->localhost; /* return local host name */ } /* TCP/IP get client host address (server calls only) * Returns: client host address */ char *tcp_clientaddr () { if (!myClientAddr) { struct sockaddr_in sin; int sinlen = sizeof (struct sockaddr_in); myClientAddr = /* get stdin's peer name */ ((getpeername (0,(struct sockaddr *) &sin,&sinlen) == SOCKET_ERROR) || (sinlen <= 0)) ? cpystr ("UNKNOWN") : cpystr (inet_ntoa (sin.sin_addr)); } return myClientAddr; } /* TCP/IP get client host name (server calls only) * Returns: client host name */ char *tcp_clienthost () { if (!myClientHost) { struct sockaddr_in sin; int sinlen = sizeof (struct sockaddr_in); myClientHost = /* get stdin's peer name */ ((getpeername (0,(struct sockaddr *) &sin,&sinlen) == SOCKET_ERROR) || (sinlen <= 0)) ? cpystr ("UNKNOWN") : tcp_name (&sin,T); } return myClientHost; } /* TCP/IP get server host address (server calls only) * Returns: server host address */ char *tcp_serveraddr () { if (!myServerAddr) { struct sockaddr_in sin; int sinlen = sizeof (struct sockaddr_in); myServerAddr = /* get stdin's peer name */ ((getsockname (0,(struct sockaddr *) &sin,&sinlen) == SOCKET_ERROR) || (sinlen <= 0)) ? cpystr ("UNKNOWN") : cpystr (inet_ntoa (sin.sin_addr)); } return myServerAddr; } /* TCP/IP get server host name (server calls only) * Returns: server host name */ static long myServerPort = -1; char *tcp_serverhost () { if (!myServerHost) { struct sockaddr_in sin; int sinlen = sizeof (struct sockaddr_in); if (!wsa_initted++) { /* init Windows Sockets */ WSADATA wsock; if (WSAStartup (WSA_VERSION,&wsock)) { wsa_initted = 0; return "random-pc"; /* try again later? */ } } /* get stdin's name */ if ((getsockname (0,(struct sockaddr *) &sin,&sinlen) == SOCKET_ERROR) || (sinlen <= 0)) myServerHost = cpystr (mylocalhost ()); else { myServerHost = tcp_name (&sin,NIL); myServerPort = ntohs (sin.sin_port); } } return myServerHost; } /* TCP/IP get server port number (server calls only) * Returns: server port number */ long tcp_serverport () { if (!myServerHost) tcp_serverhost (); return myServerPort; } /* TCP/IP return canonical form of host name * Accepts: host name * Returns: canonical form of host name */ char *tcp_canonical (char *name) { char *ret,host[MAILTMPLEN]; struct hostent *he; blocknotify_t bn = (blocknotify_t) mail_parameters (NIL,GET_BLOCKNOTIFY,NIL); /* look like domain literal? */ if (name[0] == '[' && name[strlen (name) - 1] == ']') return name; (*bn) (BLOCK_DNSLOOKUP,NIL); if (tcpdebug) { sprintf (host,"DNS canonicalization %.80s",name); mm_log (host,TCPDEBUG); } /* note that NT requires lowercase! */ ret = (he = gethostbyname (lcase (strcpy (host,name)))) ? he->h_name : name; (*bn) (BLOCK_NONE,NIL); if (tcpdebug) mm_log ("DNS canonicalization done",TCPDEBUG); return ret; } /* TCP/IP return name from socket * Accepts: socket * verbose flag * Returns: cpystr name */ char *tcp_name (struct sockaddr_in *sin,long flag) { char *ret,*t,adr[MAILTMPLEN],tmp[MAILTMPLEN]; sprintf (ret = adr,"[%.80s]",inet_ntoa (sin->sin_addr)); if (allowreversedns) { struct hostent *he; blocknotify_t bn = (blocknotify_t)mail_parameters(NIL,GET_BLOCKNOTIFY,NIL); void *data; if (tcpdebug) { sprintf (tmp,"Reverse DNS resolution %s",adr); mm_log (tmp,TCPDEBUG); } (*bn) (BLOCK_DNSLOOKUP,NIL);/* quell alarms */ data = (*bn) (BLOCK_SENSITIVE,NIL); /* translate address to name */ if (t = tcp_name_valid ((he = gethostbyaddr ((char *) &sin->sin_addr, sizeof (struct in_addr), sin->sin_family)) ? (char *) he->h_name : NIL)) { /* produce verbose form if needed */ if (flag) sprintf (ret = tmp,"%s %s",t,adr); else ret = t; } (*bn) (BLOCK_NONSENSITIVE,data); (*bn) (BLOCK_NONE,NIL); /* alarms OK now */ if (tcpdebug) mm_log ("Reverse DNS resolution done",TCPDEBUG); } return cpystr (ret); } /* Return my local host name * Returns: my local host name */ char *mylocalhost (void) { if (!myLocalHost) { char tmp[MAILTMPLEN]; if (!wsa_initted++) { /* init Windows Sockets */ WSADATA wsock; if (WSAStartup (WSA_VERSION,&wsock)) { wsa_initted = 0; return "random-pc"; /* try again later? */ } } myLocalHost = cpystr ((gethostname (tmp,MAILTMPLEN-1) == SOCKET_ERROR) ? "random-pc" : tcp_canonical (tmp)); } return myLocalHost; } /* Validate name * Accepts: domain name * Returns: T if valid, NIL otherwise */ char *tcp_name_valid (char *s) { int c; char *ret,*tail; /* must be non-empty and not too long */ if ((ret = (s && *s) ? s : NIL) && (tail = ret + NETMAXHOST)) { /* must be alnum, dot, or hyphen */ while ((c = *s++) && (s <= tail) && (((c >= 'A') && (c <= 'Z')) || ((c >= 'a') && (c <= 'z')) || ((c >= '0') && (c <= '9')) || (c == '-') || (c == '.'))); if (c) ret = NIL; } return ret; } alpine-2.10+dfsg/imap/src/osdep/wce/mkauths.bat0000600000175000017500000000172411512502124023111 0ustar paulproteuspaulproteus@ECHO OFF REM ======================================================================== REM Copyright 1988-2006 University of Washington REM REM Licensed under the Apache License, Version 2.0 (the "License"); REM you may not use this file except in compliance with the License. REM You may obtain a copy of the License at REM REM http://www.apache.org/licenses/LICENSE-2.0 REM REM REM ======================================================================== REM Program: Authenticator Linkage Generator for DOS and Windows REM REM Author: Mark Crispin REM Networks and Distributed Computing REM Computing & Communications REM University of Washington REM Administration Building, AG-44 REM Seattle, WA 98195 REM Internet: MRC@CAC.Washington.EDU REM REM Date: 6 December 1995 REM Last Edited:30 August 2006 REM Erase old authenticators list IF EXIST AUTHS.C DEL AUTHS.C REM Now define the new list FOR %%D IN (%1 %2 %3 %4 %5 %6 %7 %8 %9) DO CALL MKAUTAUX %%D EXIT 0 alpine-2.10+dfsg/imap/src/osdep/wce/drivers.bat0000600000175000017500000000170311512502124023110 0ustar paulproteuspaulproteus@ECHO OFF REM ======================================================================== REM Copyright 1988-2006 University of Washington REM REM Licensed under the Apache License, Version 2.0 (the "License"); REM you may not use this file except in compliance with the License. REM You may obtain a copy of the License at REM REM http://www.apache.org/licenses/LICENSE-2.0 REM REM REM ======================================================================== REM Program: Driver Linkage Generator for DOS/NT REM REM Author: Mark Crispin REM Networks and Distributed Computing REM Computing & Communications REM University of Washington REM Administration Building, AG-44 REM Seattle, WA 98195 REM Internet: MRC@CAC.Washington.EDU REM REM Date: 11 October 1989 REM Last Edited:30 August 2006 REM Erase old driver linkage IF EXIST LINKAGE.* DEL LINKAGE.* REM Now define the new list FOR %%D IN (%1 %2 %3 %4 %5 %6 %7 %8 %9) DO CALL DRIVRAUX %%D EXIT 0 alpine-2.10+dfsg/imap/src/osdep/wce/makefile.wce0000600000175000017500000000505411512502124023222 0ustar paulproteuspaulproteus# ======================================================================== # Copyright 1988-2006 University of Washington # # Licensed under the Apache License, Version 2.0 (the "License"); # you may not use this file except in compliance with the License. # You may obtain a copy of the License at # # http://www.apache.org/licenses/LICENSE-2.0 # # # ======================================================================== # Program: Portable C client makefile -- WCE version # # Author: Mark Crispin # Networks and Distributed Computing # Computing & Communications # University of Washington # Administration Building, AG-44 # Seattle, WA 98195 # Internet: MRC@CAC.Washington.EDU # # Date: 11 May 1989 # Last Edited: 30 August 2006 EXTRAAUTHENTICATORS= DEFAULTAUTHENTICATORS=ext md5 pla log EXTRADRIVERS = DRIVERS = imap nntp pop3 DEFAULTDRIVER = dummy CFLAGS= /MT /W3 /D_SH3_ -nologo $(EXTRACFLAGS) CC = shcl CCLIENTLIB= cclient.lib all: $(CCLIENTLIB) .c.obj: $(CC) -c $(CFLAGS) $*.c osdep.h: os_wce.h copy os_wce.h osdep.h drivers $(EXTRADRIVERS) $(DRIVERS) dummy setproto $(DEFAULTDRIVER) $(DEFAULTDRIVER) mkauths $(EXTRAAUTHENTICATORS) $(DEFAULTAUTHENTICATORS) mail.obj: mail.h misc.h osdep.h mail.c misc.obj: mail.h misc.h misc.c flstring.obj: mail.h misc.h osdep.h flstring.h flstring.c netmsg.obj: mail.h misc.h netmsg.h osdep.h netmsg.c newsrc.obj: mail.h misc.h newsrc.h osdep.h newsrc.c rfc822.obj: mail.h rfc822.h misc.h rfc822.c smanager.obj: mail.h misc.h smanager.c utf8.obj: mail.h misc.h osdep.h utf8.h utf8aux.obj: mail.h misc.h osdep.h utf8.h imap4r1.obj: mail.h imap4r1.h misc.h osdep.h imap4r1.c nntp.obj: mail.h nntp.h smtp.h rfc822.h misc.h osdep.h nntp.c pop3.obj: mail.h pop3.h rfc822.h misc.h osdep.h pop3.c smtp.obj: mail.h smtp.h rfc822.h misc.h osdep.h smtp.c os_wce.obj: mail.h osdep.h env_wce.h fs.h ftl.h nl.h tcp.h tcp_wce.h \ os_wce.c fs_wce.c ftl_wce.c nl_wce.c env_wce.c tcp_wce.c \ auth_md5.c auth_log.c pmatch.c dummywce.obj: mail.h dummy.h misc.h osdep.h dummywce.c $(CCLIENTLIB): mail.obj misc.obj flstring.obj netmsg.obj \ newsrc.obj rfc822.obj smanager.obj utf8.obj utf8aux.obj \ imap4r1.obj nntp.obj pop3.obj smtp.obj os_wce.obj \ dummywce.obj erase $(CCLIENTLIB) LIB /NOLOGO /OUT:cclient.lib \ mail.obj misc.obj flstring.obj netmsg.obj \ newsrc.obj rfc822.obj smanager.obj utf8.obj utf8aux.obj \ imap4r1.obj nntp.obj pop3.obj smtp.obj os_wce.obj \ dummywce.obj clean: del *.lib *.obj linkage.* osdep.* auths.c *.exe *.exp || rem # A monument to a hack of long ago and far away... love: @echo not war? alpine-2.10+dfsg/imap/src/osdep/wce/setproto.bat0000600000175000017500000000163111512502124023311 0ustar paulproteuspaulproteus@ECHO OFF REM ======================================================================== REM Copyright 1988-2006 University of Washington REM REM Licensed under the Apache License, Version 2.0 (the "License"); REM you may not use this file except in compliance with the License. REM You may obtain a copy of the License at REM REM http://www.apache.org/licenses/LICENSE-2.0 REM REM REM ======================================================================== REM Program: Set default prototype for DOS/NT REM REM Author: Mark Crispin REM Networks and Distributed Computing REM Computing & Communications REM University of Washington REM Administration Building, AG-44 REM Seattle, WA 98195 REM Internet: MRC@CAC.Washington.EDU REM REM Date: 9 October 1995 REM Last Edited: 30 August 2006 REM Set the default drivers ECHO #define CREATEPROTO %1proto >> LINKAGE.H ECHO #define APPENDPROTO %2proto >> LINKAGE.H alpine-2.10+dfsg/imap/src/osdep/wce/env_wce.c0000600000175000017500000001753011512502124022541 0ustar paulproteuspaulproteus/* ======================================================================== * Copyright 1988-2006 University of Washington * * Licensed under the Apache License, Version 2.0 (the "License"); * you may not use this file except in compliance with the License. * You may obtain a copy of the License at * * http://www.apache.org/licenses/LICENSE-2.0 * * * ======================================================================== */ /* * Program: WCE environment routines * * Author: Mark Crispin * Networks and Distributed Computing * Computing & Communications * University of Washington * Administration Building, AG-44 * Seattle, WA 98195 * Internet: MRC@CAC.Washington.EDU * * Date: 1 August 1988 * Last Edited: 30 August 2006 */ static char *myUserName = NIL; /* user name */ static char *myLocalHost = NIL; /* local host name */ static char *myClientHost = NIL;/* client host name */ static char *myServerHost = NIL;/* server host name */ static char *myHomeDir = NIL; /* home directory name */ static char *myNewsrc = NIL; /* newsrc file name */ static char *sysInbox = NIL; /* system inbox name */ static long list_max_level = 5; /* maximum level of list recursion */ static short no822tztext = NIL; /* disable RFC [2]822 timezone text */ /* home namespace */ static NAMESPACE nshome = {"",'\\',NIL,NIL}; /* namespace list */ static NAMESPACE *nslist[3] = {&nshome,NIL,NIL}; static long alarm_countdown = 0;/* alarm count down */ static void (*alarm_rang) (); /* alarm interrupt function */ static unsigned int rndm = 0; /* initial `random' number */ /* Dummy definitions to prevent errors */ #define server_login(user,pass,authuser,argc,argv) NIL #define authserver_login(user,authuser,argc,argv) NIL #define myusername() "" #define MD5ENABLE "\\.nosuch.." #include "pmatch.c" /* include wildcard pattern matcher */ /* Environment manipulate parameters * Accepts: function code * function-dependent value * Returns: function-dependent return value */ void *env_parameters (long function,void *value) { void *ret = NIL; switch ((int) function) { case GET_NAMESPACE: ret = (void *) nslist; break; case SET_HOMEDIR: myHomeDir = cpystr ((char *) value); case GET_HOMEDIR: ret = (void *) myHomeDir; break; case SET_LOCALHOST: myLocalHost = cpystr ((char *) value); case GET_LOCALHOST: ret = (void *) myLocalHost; break; case SET_NEWSRC: if (myNewsrc) fs_give ((void **) &myNewsrc); myNewsrc = cpystr ((char *) value); case GET_NEWSRC: if (!myNewsrc) { /* set news file name if not defined */ char tmp[MAILTMPLEN]; sprintf (tmp,"%s\\NEWSRC",myhomedir ()); myNewsrc = cpystr (tmp); } ret = (void *) myNewsrc; break; case SET_SYSINBOX: if (sysInbox) fs_give ((void **) &sysInbox); sysInbox = cpystr ((char *) value); case GET_SYSINBOX: ret = (void *) sysInbox; break; case SET_LISTMAXLEVEL: list_max_level = (long) value; case GET_LISTMAXLEVEL: ret = (void *) list_max_level; break; case SET_DISABLE822TZTEXT: no822tztext = value ? T : NIL; case GET_DISABLE822TZTEXT: ret = (void *) (no822tztext ? VOIDT : NIL); break; } return ret; } /* Write current time * Accepts: destination string * optional format of day-of-week prefix * format of date and time * flag whether to append symbolic timezone */ static void do_date (char *date,char *prefix,char *fmt,int suffix) { time_t tn = time (0); struct tm *t = gmtime (&tn); int zone = t->tm_hour * 60 + t->tm_min; int julian = t->tm_yday; t = localtime (&tn); /* get local time now */ /* minus UTC minutes since midnight */ zone = t->tm_hour * 60 + t->tm_min - zone; /* julian can be one of: * 36x local time is December 31, UTC is January 1, offset -24 hours * 1 local time is 1 day ahead of UTC, offset +24 hours * 0 local time is same day as UTC, no offset * -1 local time is 1 day behind UTC, offset -24 hours * -36x local time is January 1, UTC is December 31, offset +24 hours */ if (julian = t->tm_yday -julian) zone += ((julian < 0) == (abs (julian) == 1)) ? -24*60 : 24*60; if (prefix) { /* want day of week? */ sprintf (date,prefix,days[t->tm_wday]); date += strlen (date); /* make next sprintf append */ } /* output the date */ sprintf (date,fmt,t->tm_mday,months[t->tm_mon],t->tm_year+1900, t->tm_hour,t->tm_min,t->tm_sec,zone/60,abs (zone) % 60); if (suffix) { /* append timezone suffix if desired */ char *tz; tzset (); /* get timezone from TZ environment stuff */ tz = tzname[daylight ? (((struct tm *) t)->tm_isdst > 0) : 0]; if (tz && tz[0]) sprintf (date + strlen (date)," (%s)",tz); } } /* Write current time in RFC 822 format * Accepts: destination string */ void rfc822_date (char *date) { do_date (date,"%s, ","%d %s %d %02d:%02d:%02d %+03d%02d", no822tztext ? NIL : T); } /* Write current time in internal format * Accepts: destination string */ void internal_date (char *date) { do_date (date,NIL,"%02d-%s-%d %02d:%02d:%02d %+03d%02d",NIL); } /* Return random number */ long random () { if (!rndm) srand (rndm = (unsigned) time (0L)); return (long) rand (); } /* Return default drive * Returns: default drive */ static char *defaultDrive (void) { char *s; return ((s = getenv ("SystemDrive")) && *s) ? s : "C:"; } /* Return home drive from environment variables * Returns: home drive */ static char *homeDrive (void) { char *s; return ((s = getenv ("HOMEDRIVE")) && *s) ? s : defaultDrive (); } /* Return home path from environment variables * Accepts: path to write into * Returns: home path or NIL if it can't be determined */ static char *homePath (char *path) { int i; char *s; if (!((s = getenv ("HOMEPATH")) && (i = strlen (s)))) return NIL; if (((s[i-1] == '\\') || (s[i-1] == '/'))) s[i-1] = '\0'; sprintf (path,"%s%s",homeDrive (),s); return path; } /* Return my home directory name * Returns: my home directory name */ char *myhomedir () { char tmp[MAILTMPLEN]; /* initialize if first time */ if (!myHomeDir) myHomeDir = homePath (tmp); return myHomeDir ? myHomeDir : homeDrive (); } /* Return system standard INBOX * Accepts: buffer string */ char *sysinbox () { char tmp[MAILTMPLEN]; if (!sysInbox) { /* initialize if first time */ sprintf (tmp,"%s\\INBOX",myhomedir ()); sysInbox = cpystr (tmp); /* system inbox is from mail spool */ } return sysInbox; } /* Return mailbox file name * Accepts: destination buffer * mailbox name * Returns: file name */ char *mailboxfile (char *dst,char *name) { char *dir = myhomedir (); *dst = '\0'; /* default to empty string */ if (((name[0] == 'I') || (name[0] == 'i')) && ((name[1] == 'N') || (name[1] == 'n')) && ((name[2] == 'B') || (name[2] == 'b')) && ((name[3] == 'O') || (name[3] == 'o')) && ((name[4] == 'X') || (name[4] == 'x')) && !name[5]) name = NIL; /* reject namespace names or names with / */ if (name && ((*name == '#') || strchr (name,'/'))) return NIL; else if (!name) return dst; /* driver selects the INBOX name */ /* absolute path name? */ else if ((*name == '\\') || (name[1] == ':')) return strcpy (dst,name); /* build resulting name */ sprintf (dst,"%s\\%s",dir,name); return dst; /* return it */ } /* Determine default prototype stream to user * Accepts: type (NIL for create, T for append) * Returns: default prototype stream */ MAILSTREAM *default_proto (long type) { extern MAILSTREAM CREATEPROTO,APPENDPROTO; return type ? &APPENDPROTO : &CREATEPROTO; } /* Emulator for BSD syslog() routine * Accepts: priority * message * parameters */ void syslog (int priority,const char *message,...) { } /* Emulator for BSD openlog() routine * Accepts: identity * options * facility */ void openlog (const char *ident,int logopt,int facility) { } alpine-2.10+dfsg/imap/src/osdep/wce/nl_wce.c0000600000175000017500000000331711512502124022360 0ustar paulproteuspaulproteus/* ======================================================================== * Copyright 1988-2006 University of Washington * * Licensed under the Apache License, Version 2.0 (the "License"); * you may not use this file except in compliance with the License. * You may obtain a copy of the License at * * http://www.apache.org/licenses/LICENSE-2.0 * * * ======================================================================== */ /* * Program: Windows/TOPS-20 newline routines * * Author: Mark Crispin * Networks and Distributed Computing * Computing & Communications * University of Washington * Administration Building, AG-44 * Seattle, WA 98195 * Internet: MRC@CAC.Washington.EDU * * Date: 1 August 1988 * Last Edited: 30 August 2006 */ /* Copy string with CRLF newlines * Accepts: destination string * pointer to size of destination string buffer * source string * length of source string * Returns: length of copied string */ unsigned long strcrlfcpy (unsigned char **dst,unsigned long *dstl, unsigned char *src,unsigned long srcl) { /* flush destination buffer if too small */ if (*dst && (srcl > *dstl)) fs_give ((void **) dst); if (!*dst) { /* make a new buffer if needed */ *dst = (char *) fs_get ((size_t) (*dstl = srcl) + 1); if (dstl) *dstl = srcl; /* return new buffer length to main program */ } /* copy strings */ if (srcl) memcpy (*dst,src,(size_t) srcl); *(*dst + srcl) = '\0'; /* tie off destination */ return srcl; /* return length */ } /* Length of string after strcrlfcpy applied * Accepts: source string * Returns: length of string */ unsigned long strcrlflen (STRING *s) { return SIZE (s); /* no-brainer on DOS! */ } alpine-2.10+dfsg/imap/src/osdep/wce/fs_wce.c0000600000175000017500000000260011512502124022351 0ustar paulproteuspaulproteus/* ======================================================================== * Copyright 1988-2006 University of Washington * * Licensed under the Apache License, Version 2.0 (the "License"); * you may not use this file except in compliance with the License. * You may obtain a copy of the License at * * http://www.apache.org/licenses/LICENSE-2.0 * * * ======================================================================== */ /* * Program: Free storage management routines * * Author: Mark Crispin * Networks and Distributed Computing * Computing & Communications * University of Washington * Administration Building, AG-44 * Seattle, WA 98195 * Internet: MRC@CAC.Washington.EDU * * Date: 1 August 1988 * Last Edited: 30 August 2006 */ /* Get a block of free storage * Accepts: size of desired block * Returns: free storage block */ void *fs_get (size_t size) { void *block = malloc (size ? size : (size_t) 1); if (!block) fatal ("Out of memory"); return (block); } /* Resize a block of free storage * Accepts: ** pointer to current block * new size */ void fs_resize (void **block,size_t size) { if (!(*block = realloc (*block,size ? size : (size_t) 1))) fatal ("Can't resize memory"); } /* Return a block of free storage * Accepts: ** pointer to free storage block */ void fs_give (void **block) { free (*block); *block = NIL; } alpine-2.10+dfsg/imap/src/osdep/wce/os_wce.c0000600000175000017500000000221011512502124022357 0ustar paulproteuspaulproteus/* ======================================================================== * Copyright 1988-2006 University of Washington * * Licensed under the Apache License, Version 2.0 (the "License"); * you may not use this file except in compliance with the License. * You may obtain a copy of the License at * * http://www.apache.org/licenses/LICENSE-2.0 * * * ======================================================================== */ /* * Program: Operating-system dependent routines -- WCE version * * Author: Mark Crispin * Networks and Distributed Computing * Computing & Communications * University of Washington * Administration Building, AG-44 * Seattle, WA 98195 * Internet: MRC@CAC.Washington.EDU * * Date: 11 April 1989 * Last Edited: 30 August 2006 */ #include "tcp_wce.h" /* must be before osdep includes tcp.h */ #include "mail.h" #include "osdep.h" #include #include #include #include #include #include #include "misc.h" #include "fs_wce.c" #include "ftl_wce.c" #include "nl_wce.c" #include "env_wce.c" #include "tcp_wce.c" #include "auths.c" alpine-2.10+dfsg/imap/src/osdep/wce/os_wce.h0000600000175000017500000000245011512502124022372 0ustar paulproteuspaulproteus/* ======================================================================== * Copyright 1988-2006 University of Washington * * Licensed under the Apache License, Version 2.0 (the "License"); * you may not use this file except in compliance with the License. * You may obtain a copy of the License at * * http://www.apache.org/licenses/LICENSE-2.0 * * * ======================================================================== */ /* * Program: Operating-system dependent routines -- WCE version * * Author: Mark Crispin * Networks and Distributed Computing * Computing & Communications * University of Washington * Administration Building, AG-44 * Seattle, WA 98195 * Internet: MRC@CAC.Washington.EDU * * Date: 11 May 1989 * Last Edited: 30 August 2006 */ #include #include #include /* missing in string.h */ _CRTIMP char * __cdecl strpbrk (const char *, const char *); _CRTIMP char * __cdecl strrchr(const char *, int); #include #undef ERROR #include #undef ERROR #define ERROR (long) 2 /* must match mail.h */ #include #include #define gethostid clock #define WSA_VERSION ((1 << 8) | 1) #include "env_wce.h" #include "fs.h" #include "ftl.h" #include "nl.h" #include "tcp.h" #undef noErr #undef MAC alpine-2.10+dfsg/imap/src/osdep/wce/pmatch.c0000600000175000017500000000545411512502124022371 0ustar paulproteuspaulproteus/* ======================================================================== * Copyright 1988-2006 University of Washington * * Licensed under the Apache License, Version 2.0 (the "License"); * you may not use this file except in compliance with the License. * You may obtain a copy of the License at * * http://www.apache.org/licenses/LICENSE-2.0 * * * ======================================================================== */ /* * Program: IMAP Wildcard Matching Routines (case-independent) * * Author: Mark Crispin * Networks and Distributed Computing * Computing & Communications * University of Washington * Administration Building, AG-44 * Seattle, WA 98195 * Internet: MRC@CAC.Washington.EDU * * Date: 15 June 2000 * Last Edited: 30 August 2006 */ /* Wildcard pattern match * Accepts: base string * pattern string * delimiter character * Returns: T if pattern matches base, else NIL */ long pmatch_full (unsigned char *s,unsigned char *pat,unsigned char delim) { switch (*pat) { case '%': /* non-recursive */ /* % at end, OK if no inferiors */ if (!pat[1]) return (delim && strchr (s,delim)) ? NIL : T; /* scan remainder of string until delimiter */ do if (pmatch_full (s,pat+1,delim)) return T; while ((*s != delim) && *s++); break; case '*': /* match 0 or more characters */ if (!pat[1]) return T; /* * at end, unconditional match */ /* scan remainder of string */ do if (pmatch_full (s,pat+1,delim)) return T; while (*s++); break; case '\0': /* end of pattern */ return *s ? NIL : T; /* success if also end of base */ default: /* match this character */ return compare_uchar (*pat,*s) ? NIL : pmatch_full (s+1,pat+1,delim); } return NIL; } /* Directory pattern match * Accepts: base string * pattern string * delimiter character * Returns: T if base is a matching directory of pattern, else NIL */ long dmatch (unsigned char *s,unsigned char *pat,unsigned char delim) { switch (*pat) { case '%': /* non-recursive */ if (!*s) return T; /* end of base means have a subset match */ if (!*++pat) return NIL; /* % at end, no inferiors permitted */ /* scan remainder of string until delimiter */ do if (dmatch (s,pat,delim)) return T; while ((*s != delim) && *s++); if (*s && !s[1]) return T; /* ends with delimiter, must be subset */ return dmatch (s,pat,delim);/* do new scan */ case '*': /* match 0 or more characters */ return T; /* unconditional match */ case '\0': /* end of pattern */ break; default: /* match this character */ if (*s) return compare_uchar (*pat,*s) ? NIL : dmatch (s+1,pat+1,delim); /* end of base, return if at delimiter */ else if (*pat == delim) return T; break; } return NIL; } alpine-2.10+dfsg/imap/src/osdep/wce/tcp_wce.h0000600000175000017500000000243711512502124022544 0ustar paulproteuspaulproteus/* ======================================================================== * Copyright 1988-2006 University of Washington * * Licensed under the Apache License, Version 2.0 (the "License"); * you may not use this file except in compliance with the License. * You may obtain a copy of the License at * * http://www.apache.org/licenses/LICENSE-2.0 * * * ======================================================================== */ /* * Program: Winsock TCP/IP routines * * Author: Mike Seibel from Unix version by Mark Crispin * Computing & Communications * University of Washington * Administration Building, AG-44 * Seattle, WA 98195 * Internet: MRC@CAC.Washington.EDU * * Date: 11 April 1989 * Last Edited: 30 August 2006 */ /* TCP input buffer -- must be large enough to prevent overflow */ #define BUFLEN 8192 /* TCP I/O stream (must be before osdep.h is included) */ #define TCPSTREAM struct tcp_stream TCPSTREAM { char *host; /* host name */ char *remotehost; /* remote host name */ unsigned long port; /* port number */ char *localhost; /* local host name */ int tcpsi; /* input tcp socket */ int tcpso; /* output tcp socket */ long ictr; /* input counter */ char *iptr; /* input pointer */ char ibuf[BUFLEN]; /* input buffer */ }; alpine-2.10+dfsg/imap/src/osdep/tops-20/0000700000175000017500000000000011512502152021366 5ustar paulproteuspaulproteusalpine-2.10+dfsg/imap/src/osdep/tops-20/fs_t20.c0000600000175000017500000000260011512502123022625 0ustar paulproteuspaulproteus/* ======================================================================== * Copyright 1988-2006 University of Washington * * Licensed under the Apache License, Version 2.0 (the "License"); * you may not use this file except in compliance with the License. * You may obtain a copy of the License at * * http://www.apache.org/licenses/LICENSE-2.0 * * * ======================================================================== */ /* * Program: Free storage management routines * * Author: Mark Crispin * Networks and Distributed Computing * Computing & Communications * University of Washington * Administration Building, AG-44 * Seattle, WA 98195 * Internet: MRC@CAC.Washington.EDU * * Date: 1 August 1988 * Last Edited: 30 August 2006 */ /* Get a block of free storage * Accepts: size of desired block * Returns: free storage block */ void *fs_get (size_t size) { void *block = malloc (size ? size : (size_t) 1); if (!block) fatal ("Out of memory"); return (block); } /* Resize a block of free storage * Accepts: ** pointer to current block * new size */ void fs_resize (void **block,size_t size) { if (!(*block = realloc (*block,size ? size : (size_t) 1))) fatal ("Can't resize memory"); } /* Return a block of free storage * Accepts: ** pointer to free storage block */ void fs_give (void **block) { free (*block); *block = NIL; } alpine-2.10+dfsg/imap/src/osdep/tops-20/ftl_t20.c0000600000175000017500000000167311512502123023013 0ustar paulproteuspaulproteus/* ======================================================================== * Copyright 1988-2006 University of Washington * * Licensed under the Apache License, Version 2.0 (the "License"); * you may not use this file except in compliance with the License. * You may obtain a copy of the License at * * http://www.apache.org/licenses/LICENSE-2.0 * * * ======================================================================== */ /* * Program: DOS/VMS/TOPS-20 crash management routines * * Author: Mark Crispin * Networks and Distributed Computing * Computing & Communications * University of Washington * Administration Building, AG-44 * Seattle, WA 98195 * Internet: MRC@CAC.Washington.EDU * * Date: 1 August 1988 * Last Edited: 30 August 2006 */ /* Report a fatal error * Accepts: string to output */ void fatal (char *string) { mm_fatal (string); /* pass up the string */ abort (); /* die horribly */ } alpine-2.10+dfsg/imap/src/osdep/tops-20/log_t20.c0000600000175000017500000000431711512502123023005 0ustar paulproteuspaulproteus/* ======================================================================== * Copyright 1988-2006 University of Washington * * Licensed under the Apache License, Version 2.0 (the "License"); * you may not use this file except in compliance with the License. * You may obtain a copy of the License at * * http://www.apache.org/licenses/LICENSE-2.0 * * * ======================================================================== */ /* * Program: TOPS-20 server login * * Author: Mark Crispin * Networks and Distributed Computing * Computing & Communications * University of Washington * Administration Building, AG-44 * Seattle, WA 98195 * Internet: MRC@CAC.Washington.EDU * * Date: 1 August 1988 * Last Edited: 30 August 2006 */ /* Dedication: * This file is dedicated with affection to the TOPS-20 operating system, which * set standards for user and programmer friendliness that have still not been * equaled by more `modern' operating systems. * Wasureru mon ka!!!! */ /* Server log in * Accepts: user name string * password string * authenticating user name string * argument count * argument vector * Returns: T if password validated, NIL otherwise */ long server_login (char *user,char *pass,char *authuser,int argc,char *argv[]) { int uid; int argblk[5]; if (authuser && *authuser) { /* not available */ syslog (LOG_NOTICE|LOG_AUTH, "Login %s failed: invalid authentication ID %s host=%.80s", user,authuser,tcp_clienthost ()); sleep (3); return NIL; } argblk[1] = RC_EMO; /* require exact match */ argblk[2] = (int) (user-1); /* user name */ argblk[3] = 0; /* no stepping */ if (!jsys (RCUSR,argblk)) return NIL; uid = argblk[1] = argblk[3]; /* user number */ argblk[2] = (int) (pass-1); /* password */ argblk[3] = 0; /* no special account */ if (!jsys (LOGIN,argblk)) return NIL; return T; } /* Authenticated server log in * Accepts: user name string * authenticating user name string * argument count * argument vector * Returns: T if password validated, NIL otherwise */ long authserver_login (char *user,char *authuser,int argc,char *argv[]) { return NIL; /* how to implement this on TOPS-20??? */ } alpine-2.10+dfsg/imap/src/osdep/tops-20/dummy.h0000600000175000017500000000276411512502123022703 0ustar paulproteuspaulproteus/* ======================================================================== * Copyright 1988-2006 University of Washington * * Licensed under the Apache License, Version 2.0 (the "License"); * you may not use this file except in compliance with the License. * You may obtain a copy of the License at * * http://www.apache.org/licenses/LICENSE-2.0 * * * ======================================================================== */ /* * Program: Dummy routines * * Author: Mark Crispin * Networks and Distributed Computing * Computing & Communications * University of Washington * Administration Building, AG-44 * Seattle, WA 98195 * Internet: MRC@CAC.Washington.EDU * * Date: 9 May 1991 * Last Edited: 30 August 2006 */ /* Exported function prototypes */ void dummy_scan (MAILSTREAM *stream,char *ref,char *pat,char *contents); void dummy_list (MAILSTREAM *stream,char *ref,char *pat); void dummy_lsub (MAILSTREAM *stream,char *ref,char *pat); long scan_contents (DRIVER *dtb,char *name,char *contents, unsigned long csiz,unsigned long fsiz); long dummy_scan_contents (char *name,char *contents,unsigned long csiz, unsigned long fsiz); long dummy_create (MAILSTREAM *stream,char *mailbox); long dummy_create_path (MAILSTREAM *stream,char *path,long dirmode); long dummy_delete (MAILSTREAM *stream,char *mailbox); long dummy_rename (MAILSTREAM *stream,char *old,char *newname); char *dummy_file (char *dst,char *name); long dummy_canonicalize (char *tmp,char *ref,char *pat); alpine-2.10+dfsg/imap/src/osdep/tops-20/tcp_t20.h0000600000175000017500000000304611512502123023015 0ustar paulproteuspaulproteus/* ======================================================================== * Copyright 1988-2006 University of Washington * * Licensed under the Apache License, Version 2.0 (the "License"); * you may not use this file except in compliance with the License. * You may obtain a copy of the License at * * http://www.apache.org/licenses/LICENSE-2.0 * * * ======================================================================== */ /* * Program: TOPS-20 TCP/IP routines * * Author: Mark Crispin * Networks and Distributed Computing * Computing & Communications * University of Washington * Administration Building, AG-44 * Seattle, WA 98195 * Internet: MRC@CAC.Washington.EDU * * Date: 1 August 1988 * Last Edited: 30 August 2006 */ /* Dedication: * This file is dedicated with affection to the TOPS-20 operating system, which * set standards for user and programmer friendliness that have still not been * equaled by more `modern' operating systems. * Wasureru mon ka!!!! */ /* TCP input buffer */ #define BUFLEN 8192 /* TCP I/O stream (must be before osdep.h is included) */ #define TCPSTREAM struct tcp_stream TCPSTREAM { char *host; /* host name */ unsigned long port; /* port number */ char *localhost; /* local host name */ int jfn; /* jfn for connection */ char ibuf[BUFLEN]; /* input buffer */ }; /* All of these should be in JSYS.H, but just in case... */ #ifndef _GTHPN #define _GTHPN 12 #endif #ifndef _GTDPN #define _GTDPN 12 #endif #ifndef GTDOM #define GTDOM (FLD (1,JSYS_CLASS) | 501 #endif alpine-2.10+dfsg/imap/src/osdep/tops-20/dummyt20.c0000600000175000017500000001573311512502123023224 0ustar paulproteuspaulproteus/* ======================================================================== * Copyright 1988-2006 University of Washington * * Licensed under the Apache License, Version 2.0 (the "License"); * you may not use this file except in compliance with the License. * You may obtain a copy of the License at * * http://www.apache.org/licenses/LICENSE-2.0 * * * ======================================================================== */ /* * Program: Dummy routines for TOPS-20 * * Author: Mark Crispin * Networks and Distributed Computing * Computing & Communications * University of Washington * Administration Building, AG-44 * Seattle, WA 98195 * Internet: MRC@CAC.Washington.EDU * * Date: 13 June 1995 * Last Edited: 30 August 2006 */ #include #include #include "mail.h" #include "osdep.h" #include "dummy.h" #include "misc.h" /* Function prototypes */ DRIVER *dummy_valid (char *name); void *dummy_parameters (long function,void *value); MAILSTREAM *dummy_open (MAILSTREAM *stream); void dummy_close (MAILSTREAM *stream,long options); long dummy_ping (MAILSTREAM *stream); void dummy_check (MAILSTREAM *stream); long dummy_expunge (MAILSTREAM *stream,char *sequence,long options); long dummy_copy (MAILSTREAM *stream,char *sequence,char *mailbox,long options); long dummy_append (MAILSTREAM *stream,char *mailbox,append_t af,void *data); /* Dummy routines */ /* Driver dispatch used by MAIL */ DRIVER dummydriver = { "dummy", /* driver name */ DR_LOCAL|DR_MAIL, /* driver flags */ (DRIVER *) NIL, /* next driver */ dummy_valid, /* mailbox is valid for us */ dummy_parameters, /* manipulate parameters */ dummy_scan, /* scan mailboxes */ dummy_list, /* list mailboxes */ dummy_lsub, /* list subscribed mailboxes */ NIL, /* subscribe to mailbox */ NIL, /* unsubscribe from mailbox */ dummy_create, /* create mailbox */ dummy_delete, /* delete mailbox */ dummy_rename, /* rename mailbox */ mail_status_default, /* status of mailbox */ dummy_open, /* open mailbox */ dummy_close, /* close mailbox */ NIL, /* fetch message "fast" attributes */ NIL, /* fetch message flags */ NIL, /* fetch overview */ NIL, /* fetch message structure */ NIL, /* fetch header */ NIL, /* fetch text */ NIL, /* fetch message data */ NIL, /* unique identifier */ NIL, /* message number from UID */ NIL, /* modify flags */ NIL, /* per-message modify flags */ NIL, /* search for message based on criteria */ NIL, /* sort messages */ NIL, /* thread messages */ dummy_ping, /* ping mailbox to see if still alive */ dummy_check, /* check for new messages */ dummy_expunge, /* expunge deleted messages */ dummy_copy, /* copy messages to another mailbox */ dummy_append, /* append string message to mailbox */ NIL /* garbage collect stream */ }; /* prototype stream */ MAILSTREAM dummyproto = {&dummydriver}; /* Dummy validate mailbox * Accepts: mailbox name * Returns: our driver if name is valid, NIL otherwise */ DRIVER *dummy_valid (char *name) { /* must be valid local mailbox */ return (name && *name && (*name != '{') && !compare_cstring (name,"INBOX")) ? &dummydriver : NIL; } /* Dummy manipulate driver parameters * Accepts: function code * function-dependent value * Returns: function-dependent return value */ void *dummy_parameters (long function,void *value) { return NIL; } /* Dummy scan mailboxes * Accepts: mail stream * reference * pattern to search * string to scan */ void dummy_scan (MAILSTREAM *stream,char *ref,char *pat,char *contents) { /* return silently */ } /* Dummy list mailboxes * Accepts: mail stream * reference * pattern to search */ void dummy_list (MAILSTREAM *stream,char *ref,char *pat) { /* return silently */ } /* Dummy list subscribed mailboxes * Accepts: mail stream * reference * pattern to search */ void dummy_lsub (MAILSTREAM *stream,char *ref,char *pat) { /* return silently */ } /* Dummy create mailbox * Accepts: mail stream * mailbox name to create * driver type to use * Returns: T on success, NIL on failure */ long dummy_create (MAILSTREAM *stream,char *mailbox) { return NIL; /* always fails */ } /* Dummy delete mailbox * Accepts: mail stream * mailbox name to delete * Returns: T on success, NIL on failure */ long dummy_delete (MAILSTREAM *stream,char *mailbox) { return NIL; /* always fails */ } /* Mail rename mailbox * Accepts: mail stream * old mailbox name * new mailbox name * Returns: T on success, NIL on failure */ long dummy_rename (MAILSTREAM *stream,char *old,char *newname) { return NIL; /* always fails */ } /* Dummy open * Accepts: stream to open * Returns: stream on success, NIL on failure */ MAILSTREAM *dummy_open (MAILSTREAM *stream) { char tmp[MAILTMPLEN]; /* OP_PROTOTYPE call or silence */ if (!stream || stream->silent) return NIL; if (compare_cstring (stream->mailbox,"INBOX")) { sprintf (tmp,"Not a mailbox: %s",stream->mailbox); mm_log (tmp,ERROR); return NIL; /* always fails */ } if (!stream->silent) { /* only if silence not requested */ mail_exists (stream,0); /* say there are 0 messages */ mail_recent (stream,0); stream->uid_validity = time (0); } stream->inbox = T; /* note that it's an INBOX */ return stream; /* return success */ } /* Dummy close * Accepts: MAIL stream * options */ void dummy_close (MAILSTREAM *stream,long options) { /* return silently */ } /* Dummy ping mailbox * Accepts: MAIL stream * Returns: T if stream alive, else NIL * No-op for readonly files, since read/writer can expunge it from under us! */ long dummy_ping (MAILSTREAM *stream) { return T; } /* Dummy check mailbox * Accepts: MAIL stream * No-op for readonly files, since read/writer can expunge it from under us! */ void dummy_check (MAILSTREAM *stream) { dummy_ping (stream); /* invoke ping */ } /* Dummy expunge mailbox * Accepts: MAIL stream * sequence to expunge if non-NIL * expunge options * Returns: T, always */ long dummy_expunge (MAILSTREAM *stream,char *sequence,long options) { return LONGT; } /* Dummy copy message(s) * Accepts: MAIL stream * sequence * destination mailbox * options * Returns: T if copy successful, else NIL */ long dummy_copy (MAILSTREAM *stream,char *sequence,char *mailbox,long options) { if ((options & CP_UID) ? mail_uid_sequence (stream,sequence) : mail_sequence (stream,sequence)) fatal ("Impossible dummy_copy"); return NIL; } /* Dummy append message string * Accepts: mail stream * destination mailbox * append callback function * data for callback * Returns: T on success, NIL on failure */ long dummy_append (MAILSTREAM *stream,char *mailbox,append_t af,void *data) { char tmp[MAILTMPLEN]; sprintf (tmp,"Can't append to %s",mailbox); mm_log (tmp,ERROR); /* pass up error */ return NIL; /* always fails */ } alpine-2.10+dfsg/imap/src/osdep/tops-20/os_t20.h0000600000175000017500000000247511512502123022655 0ustar paulproteuspaulproteus/* ======================================================================== * Copyright 1988-2007 University of Washington * * Licensed under the Apache License, Version 2.0 (the "License"); * you may not use this file except in compliance with the License. * You may obtain a copy of the License at * * http://www.apache.org/licenses/LICENSE-2.0 * * * ======================================================================== */ /* * Program: Operating-system dependent routines -- TOPS-20 version * * Author: Mark Crispin * Networks and Distributed Computing * Computing & Communications * University of Washington * Administration Building, AG-44 * Seattle, WA 98195 * Internet: MRC@CAC.Washington.EDU * * Date: 1 August 1988 * Last Edited: 30 January 2007 */ /* Dedication: * This file is dedicated with affection to the TOPS-20 operating system, which * set standards for user and programmer friendliness that have still not been * equaled by more `modern' operating systems. * Wasureru mon ka!!!! */ #include #include #include #include #include #include "env_t20.h" #include "fs.h" #include "ftl.h" #include "nl.h" #include "tcp.h" long gethostid (void); char *getpass (const char *prompt); #define strtok_r(a,b,c) strtok(a,b) alpine-2.10+dfsg/imap/src/osdep/tops-20/tcp_t20.c0000600000175000017500000002433611512502123023015 0ustar paulproteuspaulproteus/* ======================================================================== * Copyright 1988-2008 University of Washington * * Licensed under the Apache License, Version 2.0 (the "License"); * you may not use this file except in compliance with the License. * You may obtain a copy of the License at * * http://www.apache.org/licenses/LICENSE-2.0 * * * ======================================================================== */ /* * Program: TOPS-20 TCP/IP routines * * Author: Mark Crispin * Networks and Distributed Computing * Computing & Communications * University of Washington * Administration Building, AG-44 * Seattle, WA 98195 * Internet: MRC@CAC.Washington.EDU * * Date: 1 August 1988 * Last Edited: 13 January 2008 */ /* Dedication: * This file is dedicated with affection to the TOPS-20 operating system, which * set standards for user and programmer friendliness that have still not been * equaled by more `modern' operating systems. * Wasureru mon ka!!!! */ static char *tcp_getline_work (TCPSTREAM *stream,unsigned long *size, long *contd); /* TCP/IP manipulate parameters * Accepts: function code * function-dependent value * Returns: function-dependent return value */ void *tcp_parameters (long function,void *value) { return NIL; } /* TCP/IP open * Accepts: host name * contact service name * contact port number * Returns: TCP stream if success else NIL */ TCPSTREAM *tcp_open (char *host,char *service,unsigned long port) { char *s,tmp[MAILTMPLEN]; TCPSTREAM *stream = NIL; int argblk[5],jfn; unsigned long i,j,k,l; char file[MAILTMPLEN]; port &= 0xffff; /* erase flags */ /* domain literal? */ if (host[0] == '[' && host[strlen (host)-1] == ']') { if (((i = strtoul (s = host+1,&s,10)) <= 255) && *s++ == '.' && ((j = strtoul (s,&s,10)) <= 255) && *s++ == '.' && ((k = strtoul (s,&s,10)) <= 255) && *s++ == '.' && ((l = strtoul (s,&s,10)) <= 255) && *s++ == ']' && !*s) { argblk[3] = (i << 24) + (j << 16) + (k << 8) + l; sprintf (tmp,"[%lu.%lu.%lu.%lu]",i,j,k,l); } else { sprintf (tmp,"Bad format domain-literal: %.80s",host); mm_log (tmp,ERROR); return NIL; } } else { /* host name */ argblk[1] = _GTHPN; /* get IP address and primary name */ argblk[2] = (int) (host-1); /* pointer to host */ argblk[4] = (int) (tmp-1); if (!jsys (GTHST,argblk)) { /* first try DEC's domain way */ argblk[1] = _GTHPN; /* get IP address and primary name */ argblk[2] = (int) (host-1); argblk[4] = (int) (tmp-1); if (!jsys (GTDOM,argblk)){/* try the CHIVES domain way */ argblk[1] = _GTHSN; /* failed, do the host table then */ if (!jsys (GTHST,argblk)) { sprintf (tmp,"No such host as %s",host); mm_log (tmp,ERROR); return NIL; } argblk[1] = _GTHNS; /* convert number to string */ argblk[2] = (int) (tmp-1); /* get the official name */ if (!jsys (GTHST,argblk)) strcpy (tmp,host); } } } sprintf (file,"TCP:.%o-%d;PERSIST:30;CONNECTION:ACTIVE",argblk[3],port); argblk[1] = GJ_SHT; /* short form GTJFN% */ argblk[2] = (int) (file-1); /* pointer to file name */ /* get JFN for TCP: file */ if (!jsys (GTJFN,argblk)) fatal ("Unable to create TCP JFN"); jfn = argblk[1]; /* note JFN for later */ /* want 8-bit bidirectional I/O */ argblk[2] = OF_RD|OF_WR|(FLD (8,monsym("OF%BSZ"))); if (!jsys (OPENF,argblk)) { sprintf (file,"Can't connect to %s,%d server",tmp,port); mm_log (file,ERROR); return NIL; } /* create TCP/IP stream */ stream = (TCPSTREAM *) fs_get (sizeof (TCPSTREAM)); stream->host = cpystr (tmp); /* copy official host name */ argblk[1] = _GTHNS; /* convert number to string */ argblk[2] = (int) (tmp-1); argblk[3] = -1; /* want local host */ if (!jsys (GTHST,argblk)) strcpy (tmp,"LOCAL"); stream->localhost = cpystr (tmp); stream->port = port; /* save port number */ stream->jfn = jfn; /* init JFN */ return stream; } /* TCP/IP authenticated open * Accepts: NETMBX specifier * service name * returned user name buffer * Returns: TCP/IP stream if success else NIL */ TCPSTREAM *tcp_aopen (NETMBX *mb,char *service,char *usrbuf) { return NIL; } /* TCP receive line * Accepts: TCP stream * Returns: text line string or NIL if failure */ char *tcp_getline (TCPSTREAM *stream) { unsigned long n,contd; char *ret = tcp_getline_work (stream,&n,&contd); if (ret && contd) { /* got a line needing continuation? */ STRINGLIST *stl = mail_newstringlist (); STRINGLIST *stc = stl; do { /* collect additional lines */ stc->text.data = (unsigned char *) ret; stc->text.size = n; stc = stc->next = mail_newstringlist (); ret = tcp_getline_work (stream,&n,&contd); } while (ret && contd); if (ret) { /* stash final part of line on list */ stc->text.data = (unsigned char *) ret; stc->text.size = n; /* determine how large a buffer we need */ for (n = 0, stc = stl; stc; stc = stc->next) n += stc->text.size; ret = fs_get (n + 1); /* copy parts into buffer */ for (n = 0, stc = stl; stc; n += stc->text.size, stc = stc->next) memcpy (ret + n,stc->text.data,stc->text.size); ret[n] = '\0'; } mail_free_stringlist (&stl);/* either way, done with list */ } return ret; } /* TCP receive line or partial line * Accepts: TCP stream * pointer to return size * pointer to return continuation flag * Returns: text line string, size and continuation flag, or NIL if failure */ static char *tcp_getline_work (TCPSTREAM *stream,unsigned long *size, long *contd) { int argblk[5]; unsigned long n,m; char *ret,*stp,*st; *contd = NIL; /* assume no continuation */ argblk[1] = stream->jfn; /* read from TCP */ /* pointer to buffer */ argblk[2] = (int) (stream->ibuf - 1); argblk[3] = BUFLEN; /* max number of bytes to read */ argblk[4] = '\012'; /* terminate on LF */ if (!jsys (SIN,argblk)) return NIL; n = BUFLEN - argblk[3]; /* number of bytes read */ /* got a complete line? */ if ((stream->ibuf[n - 2] == '\015') && (stream->ibuf[n - 1] == '\012')) { memcpy ((ret = (char *) fs_get (n)),stream->ibuf,*size = n - 2); ret[n - 2] = '\0'; /* tie off string with null */ return ret; } /* copy partial string */ memcpy ((ret = (char *) fs_get (n)),stream->ibuf,*size = n); /* special case of newline broken by buffer */ if ((stream->ibuf[n - 1] == '\015') && jsys (BIN,argblk) && (argblk[2] == '\012')) { /* was it? */ ret[n - 1] = '\0'; /* tie off string with null */ } /* otherwise back up */ else if (!jsys (BKJFN,argblk)) fs_give ((void **) &ret); else *contd = LONGT; /* continuation needed */ return ret; } /* TCP/IP receive buffer * Accepts: TCP/IP stream * size in bytes * buffer to read into * Returns: T if success, NIL otherwise */ long tcp_getbuffer (TCPSTREAM *stream,unsigned long size,char *buffer) { int argblk[5]; argblk[1] = stream->jfn; /* read from TCP */ argblk[2] = (int) (buffer-1); /* pointer to buffer */ argblk[3] = -size; /* number of bytes to read */ if (!jsys (SIN,argblk)) return NIL; buffer[size] = '\0'; /* tie off text */ return T; } /* TCP/IP send string as record * Accepts: TCP/IP stream * string pointer * Returns: T if success else NIL */ long tcp_soutr (TCPSTREAM *stream,char *string) { int argblk[5]; argblk[1] = stream->jfn; /* write to TCP */ argblk[2] = (int) (string-1); /* pointer to buffer */ argblk[3] = 0; /* write until NUL */ if (!jsys (SOUTR,argblk)) return NIL; return T; } /* TCP/IP send string * Accepts: TCP/IP stream * string pointer * byte count * Returns: T if success else NIL */ long tcp_sout (TCPSTREAM *stream,char *string,unsigned long size) { int argblk[5]; argblk[1] = stream->jfn; /* write to TCP */ argblk[2] = (int) (string-1); /* pointer to buffer */ argblk[3] = -size; /* write this many bytes */ if (!jsys (SOUTR,argblk)) return NIL; return T; } /* TCP/IP close * Accepts: TCP/IP stream */ void tcp_close (TCPSTREAM *stream) { int argblk[5]; argblk[1] = stream->jfn; /* close TCP */ jsys (CLOSF,argblk); /* flush host names */ fs_give ((void **) &stream->host); fs_give ((void **) &stream->localhost); fs_give ((void **) &stream); /* flush the stream */ } /* TCP/IP return host for this stream * Accepts: TCP/IP stream * Returns: host name for this stream */ char *tcp_host (TCPSTREAM *stream) { return stream->host; /* return host name */ } /* TCP/IP return remote host for this stream * Accepts: TCP/IP stream * Returns: host name for this stream */ char *tcp_remotehost (TCPSTREAM *stream) { return stream->host; /* return host name */ } /* TCP/IP return port for this stream * Accepts: TCP/IP stream * Returns: port number for this stream */ unsigned long tcp_port (TCPSTREAM *stream) { return stream->port; /* return port number */ } /* TCP/IP return local host for this stream * Accepts: TCP/IP stream * Returns: local host name for this stream */ char *tcp_localhost (TCPSTREAM *stream) { return stream->localhost; /* return local host name */ } /* TCP/IP return canonical form of host name * Accepts: host name * Returns: canonical form of host name */ char *tcp_canonical (char *name) { int argblk[5]; static char tmp[MAILTMPLEN]; /* look like domain literal? */ if (name[0] == '[' && name[strlen (name) - 1] == ']') return name; argblk[1] = _GTHPN; /* get IP address and primary name */ argblk[2] = (int) (name-1); /* pointer to host */ argblk[4] = (int) (tmp-1); /* pointer to return destination */ if (!jsys (GTHST,argblk)) { /* first try DEC's domain way */ argblk[1] = _GTHPN; /* get IP address and primary name */ argblk[2] = (int) (name-1); argblk[4] = (int) (tmp-1); if (!jsys (GTDOM,argblk)) { /* try the CHIVES domain way */ argblk[1] = _GTHSN; /* failed, do the host table then */ if (!jsys (GTHST,argblk)) return name; argblk[1] = _GTHNS; /* convert number to string */ argblk[2] = (int) (tmp-1); /* get the official name */ if (!jsys (GTHST,argblk)) return name; } } return tmp; } /* TCP/IP get client host name (server calls only) * Returns: client host name */ char *tcp_clienthost () { return "UNKNOWN"; } alpine-2.10+dfsg/imap/src/osdep/tops-20/nl_t20.c0000600000175000017500000000331711512502123022634 0ustar paulproteuspaulproteus/* ======================================================================== * Copyright 1988-2006 University of Washington * * Licensed under the Apache License, Version 2.0 (the "License"); * you may not use this file except in compliance with the License. * You may obtain a copy of the License at * * http://www.apache.org/licenses/LICENSE-2.0 * * * ======================================================================== */ /* * Program: Windows/TOPS-20 newline routines * * Author: Mark Crispin * Networks and Distributed Computing * Computing & Communications * University of Washington * Administration Building, AG-44 * Seattle, WA 98195 * Internet: MRC@CAC.Washington.EDU * * Date: 1 August 1988 * Last Edited: 30 August 2006 */ /* Copy string with CRLF newlines * Accepts: destination string * pointer to size of destination string buffer * source string * length of source string * Returns: length of copied string */ unsigned long strcrlfcpy (unsigned char **dst,unsigned long *dstl, unsigned char *src,unsigned long srcl) { /* flush destination buffer if too small */ if (*dst && (srcl > *dstl)) fs_give ((void **) dst); if (!*dst) { /* make a new buffer if needed */ *dst = (char *) fs_get ((size_t) (*dstl = srcl) + 1); if (dstl) *dstl = srcl; /* return new buffer length to main program */ } /* copy strings */ if (srcl) memcpy (*dst,src,(size_t) srcl); *(*dst + srcl) = '\0'; /* tie off destination */ return srcl; /* return length */ } /* Length of string after strcrlfcpy applied * Accepts: source string * Returns: length of string */ unsigned long strcrlflen (STRING *s) { return SIZE (s); /* no-brainer on DOS! */ } alpine-2.10+dfsg/imap/src/osdep/tops-20/env_t20.h0000600000175000017500000000450511512502123023020 0ustar paulproteuspaulproteus/* ======================================================================== * Copyright 1988-2006 University of Washington * * Licensed under the Apache License, Version 2.0 (the "License"); * you may not use this file except in compliance with the License. * You may obtain a copy of the License at * * http://www.apache.org/licenses/LICENSE-2.0 * * * ======================================================================== */ /* * Program: TOPS-20 environment routines * * Author: Mark Crispin * Networks and Distributed Computing * Computing & Communications * University of Washington * Administration Building, AG-44 * Seattle, WA 98195 * Internet: MRC@CAC.Washington.EDU * * Date: 25 May 1995 * Last Edited: 30 August 2006 */ /* Dedication: * This file is dedicated with affection to the TOPS-20 operating system, which * set standards for user and programmer friendliness that have still not been * equaled by more `modern' operating systems. * Wasureru mon ka!!!! */ #define SUBSCRIPTIONFILE(t) sprintf (t,"%s\\SUBSCRIPTIONS.TXT",myhomedir ()) #define SUBSCRIPTIONTEMP(t) sprintf (t,"%s\\SUBSCRIPTIONS.TMP",myhomedir ()) /* Function prototypes */ #include "env.h" char *myusername_full (unsigned long *flags); #define MU_LOGGEDIN 0 #define MU_NOTLOGGEDIN 1 #define MU_ANONYMOUS 2 #define myusername() \ myusername_full (NIL) /* syslog() emulation */ #define LOG_MAIL (2<<3) /* mail system */ #define LOG_DAEMON (3<<3) /* system daemons */ #define LOG_AUTH (4<<3) /* security/authorization messages */ #define LOG_EMERG 0 /* system is unusable */ #define LOG_ALERT 1 /* action must be taken immediately */ #define LOG_CRIT 2 /* critical conditions */ #define LOG_ERR 3 /* error conditions */ #define LOG_WARNING 4 /* warning conditions */ #define LOG_NOTICE 5 /* normal but signification condition */ #define LOG_INFO 6 /* informational */ #define LOG_DEBUG 7 /* debug-level messages */ #define LOG_PID 0x01 /* log the pid with each message */ #define LOG_CONS 0x02 /* log on the console if errors in sending */ #define LOG_ODELAY 0x04 /* delay open until syslog() is called */ #define LOG_NDELAY 0x08 /* don't delay open */ #define LOG_NOWAIT 0x10 /* if forking to log on console, don't wait() */ void openlog (const char *ident,int logopt,int facility); void syslog (int priority,const char *message,...); alpine-2.10+dfsg/imap/src/osdep/tops-20/env_t20.c0000600000175000017500000001346311512502123023016 0ustar paulproteuspaulproteus/* ======================================================================== * Copyright 1988-2006 University of Washington * * Licensed under the Apache License, Version 2.0 (the "License"); * you may not use this file except in compliance with the License. * You may obtain a copy of the License at * * http://www.apache.org/licenses/LICENSE-2.0 * * * ======================================================================== */ /* * Program: Environment routines -- TOPS-20 version * * Author: Mark Crispin * Networks and Distributed Computing * Computing & Communications * University of Washington * Administration Building, AG-44 * Seattle, WA 98195 * Internet: MRC@CAC.Washington.EDU * * Date: 1 August 1988 * Last Edited: 30 August 2006 */ /* Dedication: * This file is dedicated with affection to the TOPS-20 operating system, which * set standards for user and programmer friendliness that have still not been * equaled by more `modern' operating systems. * Wasureru mon ka!!!! */ /* c-client environment parameters */ static char *myUserName = NIL; /* user name */ static char *myHomeDir = NIL; /* home directory name */ static char *myLocalHost = NIL; /* local host name */ static char *myNewsrc = NIL; /* newsrc file name */ static short no822tztext = NIL; /* disable RFC [2]822 timezone text */ #include "pmatch.c" /* include wildcard pattern matcher */ /* Environment manipulate parameters * Accepts: function code * function-dependent value * Returns: function-dependent return value */ void *env_parameters (long function,void *value) { void *ret = NIL; switch ((int) function) { case SET_USERNAME: if (myUserName) fs_give ((void **) &myUserName); myUserName = cpystr ((char *) value); case GET_USERNAME: ret = (void *) myUserName; break; case SET_HOMEDIR: if (myHomeDir) fs_give ((void **) &myHomeDir); myHomeDir = cpystr ((char *) value); case GET_HOMEDIR: ret = (void *) myHomeDir; break; case SET_LOCALHOST: if (myLocalHost) fs_give ((void **) &myLocalHost); myLocalHost = cpystr ((char *) value); case GET_LOCALHOST: ret = (void *) myLocalHost; break; case SET_NEWSRC: if (myNewsrc) fs_give ((void **) &myNewsrc); myNewsrc = cpystr ((char *) value); case GET_NEWSRC: ret = (void *) myNewsrc; break; case SET_DISABLE822TZTEXT: no822tztext = value ? T : NIL; case GET_DISABLE822TZTEXT: ret = (void *) (no822tztext ? VOIDT : NIL); break; } return ret; } /* Write current time in RFC 822 format * Accepts: destination string */ void rfc822_date (char *date) { char *s; int argblk[4]; argblk[1] = (int) (date-1); argblk[2] = -1; /* time now */ argblk[3] = OT_822; /* want RFC [2]822 format */ jsys (ODTIM,argblk); /* suppress time zone text if desired */ if (no822tztext && (s = strstr (date," ("))) *s = NIL; } /* Write current time in internal format * Accepts: destination string */ void internal_date (char *date) { int argblk[5]; argblk[1] = (int) (date-1); argblk[2] = -1; /* time now */ argblk[3] = OT_4YR; /* output in 4-digit year format */ jsys (ODTIM,argblk); argblk[2] = ' '; /* delimit with space */ jsys (BOUT,argblk); argblk[2] = -1; /* time now */ argblk[4] = 0; /* no flags */ jsys (ODCNV,argblk); /* get time zone */ argblk[2] = ((argblk[4] & 077000000) >> 18) * -100; /* add an hour if summer time */ if (argblk[4] & IC_ADS) argblk[2] += 100; argblk[3] = 0340005000012; jsys (NOUT,argblk); } /* Return my user name * Accepts: pointer to optional flags * Returns: my user name */ char *myusername_full (unsigned long *flags) { if (!myUserName) { /* get user name if don't have it yet */ char tmp[MAILTMPLEN]; int argblk[5],i; jsys (GJINF,argblk); /* get job poop */ if (!(i = argblk[1])) { /* remember user number */ if (flags) *flags = MU_NOTLOGGEDIN; return "SYSTEM"; /* not logged in */ } argblk[1] = (int) (tmp-1); /* destination */ argblk[2] = i; /* user number */ jsys (DIRST,argblk); /* get user name string */ myUserName = cpystr (tmp); /* copy user name */ argblk[1] = 0; /* no flags */ argblk[2] = i; /* user number */ argblk[3] = 0; /* no stepping */ jsys (RCDIR,argblk); /* get home directory */ argblk[1] = (int) (tmp-1); /* destination */ argblk[2] = argblk[3]; /* home directory number */ jsys (DIRST,argblk); /* get home directory string */ myHomeDir = cpystr (tmp); /* copy home directory */ if (!myNewsrc) { /* set news file name if not defined */ sprintf (tmp,"%sNEWSRC",myhomedir ()); myNewsrc = cpystr (tmp); } if (flags) *flags = MU_LOGGEDIN; } return myUserName; } /* Return my local host name * Returns: my local host name */ char *mylocalhost () { if (!myLocalHost) { /* initialize if first time */ char tmp[MAILTMPLEN]; int argblk[5]; argblk[1] = _GTHNS; /* convert number to string */ argblk[2] = (int) (tmp-1); argblk[3] = -1; /* want local host */ if (!jsys (GTHST,argblk)) strcpy (tmp,"LOCAL"); myLocalHost = cpystr (tmp); } return myLocalHost; } /* Return my home directory name * Returns: my home directory name */ char *myhomedir () { if (!myHomeDir) myusername ();/* initialize if first time */ return myHomeDir ? myHomeDir : ""; } /* Determine default prototype stream to user * Accepts: type (NIL for create, T for append) * Returns: default prototype stream */ MAILSTREAM *default_proto (long type) { return NIL; /* no default prototype */ } /* Emulator for BSD syslog() routine * Accepts: priority * message * parameters */ void syslog (int priority,const char *message,...) { } /* Emulator for BSD openlog() routine * Accepts: identity * options * facility */ void openlog (const char *ident,int logopt,int facility) { } alpine-2.10+dfsg/imap/src/osdep/tops-20/shortsym.h0000600000175000017500000004323111512502123023432 0ustar paulproteuspaulproteus/* ======================================================================== * Copyright 1988-2008 University of Washington * * Licensed under the Apache License, Version 2.0 (the "License"); * you may not use this file except in compliance with the License. * You may obtain a copy of the License at * * http://www.apache.org/licenses/LICENSE-2.0 * * * ======================================================================== */ /* * Program: Definitions for compilers with 6-letter symbol limits * * Author: Mark Crispin * Networks and Distributed Computing * Computing & Communications * University of Washington * Administration Building, AG-44 * Seattle, WA 98195 * Internet: MRC@CAC.Washington.EDU * * Date: 24 May 1995 * Last Edited: 1 January 2008 */ #define auth_link a_link #define auth_log a_log #define auth_login_client al_cli #define auth_login_server al_ser #define auth_ext a_ext #define auth_external_client ae_cli #define auth_external_server ae_ser #define auth_md5 a_md5 #define auth_md5_valid a5_val #define auth_md5_client a5_cli #define auth_md5_server a5_ser #define auth_pla a_pla #define auth_plain_client ap_cli #define auth_plain_server ap_ser #define authenticate a_auth #define authserver_login a_serv #define body_encodings bencds #define body_types btypes #define compare_csizedtext cm_szt #define compare_cstring cm_str #define compare_uchar cm_uch #define compare_ulong cm_uln #define default_proto d_prot #define dummy_append d_appn #define dummy_canonicalize d_cano #define dummy_check d_chck #define dummy_close d_clos #define dummy_copy d_copy #define dummy_create d_crea #define dummy_create_path d_crep #define dummy_delete d_del #define dummy_expunge d_exp #define dummy_file d_fil #define dummy_list d_list #define dummy_list_work d_lstw #define dummy_listed d_lstd #define dummy_lsub d_lsub #define dummy_open d_open #define dummy_parameters d_parm #define dummy_ping d_ping #define dummy_rename d_ren #define dummy_scan d_scan #define dummy_search d_srch #define dummy_subscribe d_subs #define dummy_valid d_val #define env_parameters e_parm #define fatal fatal #define file_string fl_str #define file_string_init fl_ini #define file_string_next fl_nxt #define file_string_setpos fl_sps #define fs_get f_get #define fs_give f_give #define fs_resize f_rsiz #define hash_create h_crea #define hash_destory h_dest #define hash_index h_indx #define hash_lookup h_lkup #define hash_add h_add #define hash_lookup_and_add h_lad #define imap_OK i_OK #define imap_acl_work i_aclw #define imap_append i_appn #define imap_append_single i_apps #define imap_anon i_anon #define imap_auth i_auth #define imap_cache i_cach #define imap_cap i_cap #define imap_capability i_capa #define imap_challenge i_chln #define imap_check i_chck #define imap_close i_clos #define imap_copy i_copy #define imap_create i_crea #define imap_delete i_del #define imap_deleteacl i_dacl #define imap_expunge i_expn #define imap_fake i_fake #define imap_fast i_fast #define imap_fetch i_fetc #define imap_flag i_flag #define imap_flags i_flgs #define imap_gc i_gc #define imap_gc_body ig_bdy #define imap_getacl i_gacl #define imap_getquota i_gqot #define imap_getquotaroot i_gqtr #define imap_host i_host #define imap_list i_list #define imap_listrights i_lrgh #define imap_list_work il_wrk #define imap_login i_logn #define imap_lsub i_lsub #define imap_manage i_man #define imap_msgdata i_msgd #define imap_msgno i_msgn #define imap_myrights i_mrgh #define imap_open i_open #define imap_parameters i_parm #define imap_parse_address ip_adr #define imap_parse_adrlist ip_adl #define imap_parse_astring ip_ast #define imap_parse_body ip_bdy #define imap_parse_body_parameter ipb_pa #define imap_parse_body_structure ipb_st #define imap_parse_capabilities ip_cap #define imap_parse_disposition ip_dsp #define imap_parse_envelope ip_env #define imap_parse_extension ip_ext #define imap_parse_flags ip_flg #define imap_parse_header ip_hdr #define imap_parse_language ip_lng #define imap_parse_namespace ip_nam #define imap_parse_reply ip_rep #define imap_parse_response ip_rsp #define imap_parse_string ip_str #define imap_parse_stringlist ip_stl #define imap_parse_thread ip_thr #define imap_parse_unsolicited ip_uns #define imap_parse_user_flag ipu_fl #define imap_ping i_ping #define imap_reform_sequence i_rfrs #define imap_rename i_ren #define imap_reply i_rep #define imap_response i_rspn #define imap_scan i_scan #define imap_search i_srch #define imap_send i_send #define imap_send_astring is_ast #define imap_send_literal is_lit #define imap_send_sdate iss_da #define imap_send_slist iss_sl #define imap_send_spgm iss_pg #define imap_send_spgm_trim iss_pt #define imap_send_sset iss_st #define imap_send_sset_work iss_sw #define imap_setacl i_sacl #define imap_setquota i_sqot #define imap_sort i_sort #define imap_sout i_sout #define imap_soutr i_sotr #define imap_status i_stat #define imap_structure i_stru #define imap_subscribe i_sub #define imap_thread i_thrd #define imap_thread_work i_thrw #define imap_uid i_uid #define imap_unsubscribe i_uns #define imap_valid i_val #define internal_date in_dat #define mail_append_full m_appn #define mail_append_multiple m_appm #define mail_append_set m_apps #define mail_auth m_auth #define mail_body m_body #define mail_cdate m_cdat #define mail_check m_chck #define mail_close_full m_clos #define mail_copy_full m_copy #define mail_create m_crea #define mail_criteria m_crit #define mail_criteria_date mc_dat #define mail_criteria_string mc_str #define mail_date m_date #define mail_debug m_dbug #define mail_delete m_del #define mail_dlog m_dlog #define mail_elt m_elt #define mail_exists m_exst #define mail_expunge_full m_expn #define mail_expunged m_expd #define mail_fetch_body fs_bdy #define mail_fetch_fast mf_fst #define mail_fetch_flags mf_flg #define mail_fetch_header mf_hdr #define mail_fetch_message mf_msg #define mail_fetch_mime mf_mim #define mail_fetch_overview mf_ovr #define mail_fetch_overview_sequence mf_ovs #define mail_fetch_overview_default mf_ovd #define mail_fetch_structure mf_str #define mail_fetch_text mf_txt #define mail_fetch_text_return mf_txr #define mail_fetch_string_return mf_tsr #define mail_fetchfrom mf_frm #define mail_fetchsubject mf_sub #define mail_filter m_filt #define mail_flag m_flag #define mail_free_acl mr_acl #define mail_free_address mr_add #define mail_free_body mr_bdy #define mail_free_body_data mrb_da #define mail_free_body_parameter mrb_pr #define mail_free_body_part mrb_pt #define mail_free_cache mr_cac #define mail_free_elt mr_elt #define mail_free_envelope mr_env #define mail_free_handle mr_han #define mail_free_namespace mr_nsp #define mail_free_quotalist mr_qtl #define mail_free_searchheader mrs_hd #define mail_free_searchor mrs_or #define mail_free_searchpgm mrs_pg #define mail_free_searchpgmlist mrs_pl #define mail_free_searchset mrs_st #define mail_free_sortpgm mr_spg #define mail_free_stringlist mr_sls #define mail_free_threadnode mr_thn #define mail_gc m_gc #define mail_gc_msg m_gcm #define mail_gc_body m_gcb #define mail_initbody m_ibdy #define mail_link m_link #define mail_list m_list #define mail_lock m_lock #define mail_longdate ml_lda #define mail_lookup_auth m_laut #define mail_lookup_auth_name m_latn #define mail_lsub m_lsub #define mail_makehandle m_mhdl #define mail_match_lines m_mlns #define mail_msgno m_msgn #define mail_newacl mn_acl #define mail_newaddr mn_add #define mail_newbody mn_bdy #define mail_newbody_parameter mnb_pr #define mail_newbody_part mnb_pt #define mail_newbody_message_part mnb_mp #define mail_new_cache_elt mn_elt #define mail_newenvelope mn_env #define mail_newmsg mn_msg #define mail_newquotalist mn_qtl #define mail_newsearchheader mns_hd #define mail_newsearchor mns_or #define mail_newsearchpgm mns_pg #define mail_newsearchpgmlist mns_pl #define mail_newsearchset mns_st #define mail_newsortpgm mn_spg #define mail_newstringlist mn_sls #define mail_newthreadnode mn_thr #define mail_nodebug m_ndbg #define mail_open m_open #define mail_parameters m_parm #define mail_parse_date mp_dat #define mail_parse_flags mp_flg #define mail_parse_set mp_set #define mail_partial_body mpt_bd #define mail_partial_text mpt_tx #define mail_ping m_ping #define mail_read m_read #define mail_recent m_rcent #define mail_rename m_ren #define mail_scan m_scan #define mail_search_addr ms_adr #define mail_search_body ms_bdy #define mail_search_default ms_def #define mail_search_full m_srch #define mail_search_gets ms_gts #define mail_search_header ms_hdr #define mail_search_header_text ms_hdt #define mail_search_keyword ms_key #define mail_search_msg ms_msg #define mail_search_string ms_str #define mail_search_string_work ms_stw #define mail_search_text ms_txt #define mail_sequence m_seq #define mail_shortdate m_shtd #define mail_skip_fwd msk_fw #define mail_skip_re msk_re #define mail_sort ml_srt #define mail_sort_cache ms_csh #define mail_sort_compare ms_cmp #define mail_sort_loadcache ms_lcs #define mail_sort_msgs ms_mgs #define mail_status m_stat #define mail_status_default m_stad #define mail_stream m_strm #define mail_string m_strg #define mail_string_init mt_ini #define mail_string_next mt_nxt #define mail_string_setpos mt_sps #define mail_strip_subject mst_sb #define mail_strip_subject_wsp mst_ws #define mail_strip_subject_blob mst_bl #define mail_subscribe m_sub #define mail_thread m_thr #define mail_threadlist mt_lst #define mail_thread_c2node mt_c2n #define mail_thread_check_child mt_ckc #define mail_thread_compare_date mtc_da #define mail_thread_loadcache mt_ldc #define mail_thread_msgs mt_mgs #define mail_thread_orderedsubject mt_osb #define mail_thread_parse_msgid mtp_mi #define mail_thread_parse_references mtp_rf #define mail_thread_prune_dummy mt_prd #define mail_thread_references mt_ref #define mail_thread_sort mt_srt #define mail_uid m_uid #define mail_uid_sequence mu_seq #define mail_unlock m_unl #define mail_unsubscribe m_uns #define mail_usable_network_stream m_usns #define mail_utf7_valid m_ut7v #define mail_valid m_val #define mail_valid_net mv_net #define mail_valid_net_parse mvn_pr #define mail_valid_net_parse_work mvn_pw #define mail_versioncheck m_vers #define mailboxfile mbxfil #define md5_init m5_ini #define md5_update m5_upd #define md5_final m5_fin #define mime2_decode m2_dec #define mime2_text m2_txt #define mime2_token m2_tok #define mm_cache mm_cac #define mm_critical mm_crt #define mm_diskerror mm_dse #define mm_dlog mm_dlg #define mm_exists mm_exs #define mm_expunged mm_exp #define mm_fatal mm_ftl #define mm_flags mm_flg #define mm_list mm_lst #define mm_log mm_log #define mm_login mm_lgi #define mm_lsub mm_lsb #define mm_mailbox mm_mbx #define mm_nocritical mm_ncr #define mm_notify mm_not #define mm_searched mm_src #define myhomedir myhome #define mylocalhost myhost #define myusername_full myuser #define net_aopen nt_aop #define net_close nt_cls #define net_getbuffer nt_gtb #define net_getdata nt_gtd #define net_getline nt_gtl #define net_host nt_hst #define net_localhost nt_lhs #define net_open nt_opn #define net_port nt_prt #define net_sout nt_sot #define net_soutr nt_str #define netmsg_read nm_rea #define netmsg_slurp nm_slr #define netmsg_slurp_text nm_slt #define newsrc_check_uid nsc_ui #define newsrc_create ns_crea #define newsrc_error ns_err #define newsrc_lsub ns_lsub #define newsrc_newmessages ns_nms #define newsrc_newstate ns_nst #define newsrc_read ns_rea #define newsrc_status ns_sta #define newsrc_update ns_upd #define newsrc_write ns_wri #define newsrc_write_error ns_wer #define nntp_append n_appn #define nntp_canonicalize n_cano #define nntp_check n_chck #define nntp_close n_clos #define nntp_copy n_copy #define nntp_create n_crea #define nntp_delete n_del #define nntp_expunge n_expn #define nntp_fake n_fake #define nntp_fetchfast nf_fst #define nntp_fetchflags nf_flg #define nntp_fetchmessage nf_msg #define nntp_flagmsg n_fmsg #define nntp_gc n_gc #define nntp_getmap n_gmap #define nntp_header n_head #define nntp_isvalid n_isvl #define nntp_list n_list #define nntp_lsub n_lsub #define nntp_mail n_mail #define nntp_mclose n_mcls #define nntp_mopen n_mopn #define nntp_open_full n_open #define nntp_over n_ovr #define nntp_overview n_over #define nntp_parameters n_parm #define nntp_parsestructure n_pars #define nntp_parse_overview n_povr #define nntp_ping n_ping #define nntp_rename n_ren #define nntp_reply n_repl #define nntp_scan n_scan #define nntp_search n_srch #define nntp_search_msg ns_msg #define nntp_send n_send #define nntp_send_auth ns_aut #define nntp_send_auth_work ns_atw #define nntp_send_work n_sndw #define nntp_sort n_sort #define nntp_sort_loadcache ns_lcs #define nntp_soutr n_sout #define nntp_status n_stat #define nntp_subscribe n_sub #define nntp_text n_text #define nntp_text_slurp nt_slp #define nntp_thread n_thrd #define nntp_unsubscribe n_uns #define nntp_valid n_val #define pop3_append p_appn #define pop3_auth p_auth #define pop3_cache p_cach #define pop3_challenge p_chal #define pop3_check p_chck #define pop3_close p_clos #define pop3_copy p_copy #define pop3_create p_crea #define pop3_delete p_del #define pop3_expunge p_exp #define pop3_fake p_fake #define pop3_fetchfast pf_fst #define pop3_fetchflags pf_flg #define pop3_fetchmessage pf_msg #define pop3_gc p_gc #define pop3_list p_list #define pop3_lsub p_lsub #define pop3_open p_open #define pop3_parameters p_parm #define pop3_parsestructure p_pars #define pop3_ping p_ping #define pop3_rename p_ren #define pop3_reply p_rep #define pop3_response p_resp #define pop3_scan p_scan #define pop3_send p_send #define pop3_send_num ps_num #define pop3_status p_stat #define pop3_subscribe p_sub #define pop3_unsubscribe p_uns #define pop3_valid p_val #define rfc822_8bit r #define rfc822_address r_addr #define rfc822_address_line ra_lin #define rfc822_base64 r_b64 #define rfc822_binary r_bin #define rfc822_cat r_cat #define rfc822_contents r_cont #define rfc822_cpy r_cpy #define rfc822_cpy_adr rc_adr #define rfc822_date r_date #define rfc822_default_subtype rd_sub #define rfc822_encode_body_7bit reb_7b #define rfc822_encode_body_8bit reb_8b #define rfc822_header r_head #define rfc822_header_line rh_lin #define rfc822_output r_out #define rfc822_output_address ro_adr #define rfc822_output_address_line roa_ln #define rfc822_output_address_list roa_li #define rfc822_output_body ro_bdy #define rfc822_output_body_header rob_hd #define rfc822_output_full ro_ful #define rfc822_output_flush ro_flu #define rfc822_output_header ro_hdr #define rfc822_output_header_line roh_ln #define rfc822_output_cat ro_cat #define rfc822_output_parameter ro_par #define rfc822_output_stringlist ro_stl #define rfc822_output_text ro_txt #define rfc822_parse_address rp_adr #define rfc822_parse_addrspec rp_ads #define rfc822_parse_adrlist rp_adl #define rfc822_parse_content rp_cnt #define rfc822_parse_content_header rpc_hd #define rfc822_parse_group rp_grp #define rfc822_parse_mailbox rp_mbx #define rfc822_parse_msg_full rp_msg #define rfc822_parse_parameter rp_par #define rfc822_parse_phrase rp_phr #define rfc822_parse_routeaddr rp_rte #define rfc822_parse_word rp_wrd #define rfc822_phraseonly r_poly #define rfc822_qprint r_qpnt #define rfc822_quote r_quot #define rfc822_skip_comment rs_cmt #define rfc822_skipws rs_ws #define rfc822_timezone r_tz #define rfc822_write_address_full rw_adr #define rfc822_write_body_header rwbh_8 #define server_input_wait s_iwat #define server_login s_log #define server_init s_init #define sm_read sm_rd #define sm_subscribe sm_sub #define sm_unsubscribe sm_uns #define smtp_auth s_auth #define smtp_challenge s_chal #define smtp_close s_clos #define smtp_ehlo s_ehlo #define smtp_fake s_fake #define smtp_mail s_mail #define smtp_open_full s_open #define smtp_rcpt s_rcpt #define smtp_reply s_repl #define smtp_response s_resp #define smtp_send s_send #define smtp_send_auth ss_aut #define smtp_send_auth_work ss_atw #define smtp_send_work ss_wrk #define smtp_soutr s_str #define strcrlfcpy sc_cpy #define strcrlflen sc_len #define tcp_aopen t_aopn #define tcp_canonical t_cnon #define tcp_clientaddr t_cadr #define tcp_clienthost t_chst #define tcp_clientport t_cprt #define tcp_close t_clos #define tcp_getbuffer tg_buf #define tcp_getdata tg_dat #define tcp_getline tg_lin #define tcp_host t_host #define tcp_localhost t_lhst #define tcp_open t_open #define tcp_parameters t_parameters #define tcp_port t_port #define tcp_remotehost t_rhst #define tcp_serveraddr t_sadr #define tcp_serverhost t_shst #define tcp_serverport t_sprt #define tcp_sout t_sout #define tcp_soutr t_str #define textcpy txcopy #define textcpystring txcpst #define textcpyoffstring txcpos #define ucs4_cs_get u4_csg #define ucs4_decompose u4_dcm #define ucs4_decompose_recursive u4_dcr #define ucs4_rmapbuf u4r_bf #define ucs4_rmaplen u4r_ln #define ucs4_rmaptext u4r_tx #define ucs4_titlecase u4_tcs #define ucs4_width u4_wid #define utf8_badcharset u8_bcs #define utf8_charset u8_chs #define utf8_cstext u8_cst #define utf8_cstocstext u8_cct #define utf8_from_mutf7 u8fmu7 #define utf8_get u8_get #define utf8_get_raw u8_gtr #define utf8_iso2022text u8_i22 #define utf8_mime2text u8_mi2 #define utf8_put u8_put #define utf8_rmap u8_rmp #define utf8_rmap_cs u8r_cs #define utf8_rmap_gen u8r_gn #define utf8_rmapsize u8r_sz #define utf8_rmaptext u8r_tx #define utf8_script u8_scr #define utf8_searchpgm u8_spg #define utf8_size u8_siz #define utf8_stringlist u8_lst #define utf8_text u8_txt #define utf8_text_2022 u8t_22 #define utf8_text_8859_1 u8t_we #define utf8_text_1byte0 u8t_10 #define utf8_text_1byte u8t_1b #define utf8_text_1byte8 u8t_18 #define utf8_text_cs ut8_cs #define utf8_text_euc u8t_eu #define utf8_text_dbyte u8t_db #define utf8_text_dbyte2 u8t_d2 #define utf8_text_sjis u8t_sj #define utf8_text_ucs2 u8t_u2 #define utf8_text_ucs4 ut8_u4 #define utf8_text_utf7 ut8_u7 #define utf8_text_utf8 ut8_u8 #define utf8_text_utf16 ut8_16 #define utf8_to_mutf7 u8tmu7 #define utf8_validate u8_val #define utf8_textwidth u8_twd alpine-2.10+dfsg/imap/src/osdep/tops-20/linkage.c0000600000175000017500000000243411512502123023147 0ustar paulproteuspaulproteus/* ======================================================================== * Copyright 1988-2007 University of Washington * * Licensed under the Apache License, Version 2.0 (the "License"); * you may not use this file except in compliance with the License. * You may obtain a copy of the License at * * http://www.apache.org/licenses/LICENSE-2.0 * * * ======================================================================== */ /* * Program: Default driver linkage * * Author: Mark Crispin * Networks and Distributed Computing * Computing & Communications * University of Washington * Administration Building, AG-44 * Seattle, WA 98195 * Internet: MRC@CAC.Washington.EDU * * Date: 13 June 1995 * Last Edited: 23 May 2007 */ mail_link (&imapdriver); /* link in the imap driver */ mail_link (&nntpdriver); /* link in the nntp driver */ mail_link (&pop3driver); /* link in the pop3 driver */ mail_link (&dummydriver); /* link in the dummy driver */ auth_link (&auth_ext); /* link in the ext authenticator */ auth_link (&auth_md5); /* link in the md5 authenticator */ auth_link (&auth_pla); /* link in the plain authenticator */ auth_link (&auth_log); /* link in the log authenticator */ mail_versioncheck (CCLIENTVERSION); /* validate version */ alpine-2.10+dfsg/imap/src/osdep/tops-20/linkage.h0000600000175000017500000000174311512502123023156 0ustar paulproteuspaulproteus/* ======================================================================== * Copyright 1988-2006 University of Washington * * Licensed under the Apache License, Version 2.0 (the "License"); * you may not use this file except in compliance with the License. * You may obtain a copy of the License at * * http://www.apache.org/licenses/LICENSE-2.0 * * * ======================================================================== */ /* * Program: Default driver linkage * * Author: Mark Crispin * Networks and Distributed Computing * Computing & Communications * University of Washington * Administration Building, AG-44 * Seattle, WA 98195 * Internet: MRC@CAC.Washington.EDU * * Date: 13 June 1995 * Last Edited: 30 August 2006 */ extern DRIVER imapdriver; extern DRIVER nntpdriver; extern DRIVER pop3driver; extern DRIVER dummydriver; extern AUTHENTICATOR auth_ext; extern AUTHENTICATOR auth_log; extern AUTHENTICATOR auth_md5; extern AUTHENTICATOR auth_pla; alpine-2.10+dfsg/imap/src/osdep/tops-20/pmatch.c0000600000175000017500000000545411512502123023016 0ustar paulproteuspaulproteus/* ======================================================================== * Copyright 1988-2006 University of Washington * * Licensed under the Apache License, Version 2.0 (the "License"); * you may not use this file except in compliance with the License. * You may obtain a copy of the License at * * http://www.apache.org/licenses/LICENSE-2.0 * * * ======================================================================== */ /* * Program: IMAP Wildcard Matching Routines (case-independent) * * Author: Mark Crispin * Networks and Distributed Computing * Computing & Communications * University of Washington * Administration Building, AG-44 * Seattle, WA 98195 * Internet: MRC@CAC.Washington.EDU * * Date: 15 June 2000 * Last Edited: 30 August 2006 */ /* Wildcard pattern match * Accepts: base string * pattern string * delimiter character * Returns: T if pattern matches base, else NIL */ long pmatch_full (unsigned char *s,unsigned char *pat,unsigned char delim) { switch (*pat) { case '%': /* non-recursive */ /* % at end, OK if no inferiors */ if (!pat[1]) return (delim && strchr (s,delim)) ? NIL : T; /* scan remainder of string until delimiter */ do if (pmatch_full (s,pat+1,delim)) return T; while ((*s != delim) && *s++); break; case '*': /* match 0 or more characters */ if (!pat[1]) return T; /* * at end, unconditional match */ /* scan remainder of string */ do if (pmatch_full (s,pat+1,delim)) return T; while (*s++); break; case '\0': /* end of pattern */ return *s ? NIL : T; /* success if also end of base */ default: /* match this character */ return compare_uchar (*pat,*s) ? NIL : pmatch_full (s+1,pat+1,delim); } return NIL; } /* Directory pattern match * Accepts: base string * pattern string * delimiter character * Returns: T if base is a matching directory of pattern, else NIL */ long dmatch (unsigned char *s,unsigned char *pat,unsigned char delim) { switch (*pat) { case '%': /* non-recursive */ if (!*s) return T; /* end of base means have a subset match */ if (!*++pat) return NIL; /* % at end, no inferiors permitted */ /* scan remainder of string until delimiter */ do if (dmatch (s,pat,delim)) return T; while ((*s != delim) && *s++); if (*s && !s[1]) return T; /* ends with delimiter, must be subset */ return dmatch (s,pat,delim);/* do new scan */ case '*': /* match 0 or more characters */ return T; /* unconditional match */ case '\0': /* end of pattern */ break; default: /* match this character */ if (*s) return compare_uchar (*pat,*s) ? NIL : dmatch (s+1,pat+1,delim); /* end of base, return if at delimiter */ else if (*pat == delim) return T; break; } return NIL; } alpine-2.10+dfsg/imap/src/osdep/tops-20/build.ctl0000600000175000017500000000312711512502123023174 0ustar paulproteuspaulproteus! ======================================================================== ! Copyright 1988-2006 University of Washington ! ! Licensed under the Apache License, Version 2.0 (the "License"); ! you may not use this file except in compliance with the License. ! You may obtain a copy of the License at ! ! http://www.apache.org/licenses/LICENSE-2.0 ! ! ! ======================================================================== ! Program: Portable C client build for TOPS-20 ! ! Author: Mark Crispin ! Networks and Distributed Computing ! Computing & Communications ! University of Washington ! Administration Building, AG-44 ! Seattle, WA 98195 ! Internet: MRC@CAC.Washington.EDU ! ! Date: 11 May 1989 ! Last Edited: 30 August 2006 ! ! Set environment @DEFINE SYS: PS:,SYS: ! ! Build c-client library ! @COPY OS_T20.* OSDEP.* @CCX -c -m -w=note MAIL.C DUMMYT20.C IMAP4R1.C SMTP.C NNTP.C POP3.C RFC822.C MISC.C OSDEP.C FLSTRING.C SMANAGER.C NEWSRC.C NETMSG.C UTF8.C UTF8AUX.C ! ! Build c-client library file. Should use MAKLIB, but MAKLIB barfs on MAIL.REL ! @DELETE CCLINT.REL @APPEND MAIL.REL,DUMMYT20.REL,IMAP4R1.REL,SMTP.REL,NNTP.REL,POP3.REL,RFC822.REL,MISC.REL,OSDEP.REL,FLSTRING.REL,SMANAGER.REL,NEWSRC.REL,NETMSG.REL,UTF8.REL,UTF8AUX.REL CCLINT.REL ! ! Build MTEST library test program ! @CCX -c -m -w=note MTEST.C @LINK */SET:.HIGH.:200000 *C:LIBCKX.REL *MTEST.REL *CCLINT.REL *MTEST/SAVE */GO ! ! Build MAILUTIL ! @CCX -c -m -w=note MAILUTIL.C @RENAME MAILUTIL.REL MUTIL.REL @LINK */SET:.HIGH.:200000 *C:LIBCKX.REL *MUTIL.REL *CCLINT.REL *MUTIL/SAVE */GO @RESET @RENAME MUTIL.EXE MAILUTIL.EXE alpine-2.10+dfsg/imap/src/osdep/tops-20/os_t20.c0000600000175000017500000000466311512502123022651 0ustar paulproteuspaulproteus/* ======================================================================== * Copyright 1988-2006 University of Washington * * Licensed under the Apache License, Version 2.0 (the "License"); * you may not use this file except in compliance with the License. * You may obtain a copy of the License at * * http://www.apache.org/licenses/LICENSE-2.0 * * * ======================================================================== */ /* * Program: Operating-system dependent routines -- TOPS-20 version * * Author: Mark Crispin * Networks and Distributed Computing * Computing & Communications * University of Washington * Administration Building, AG-44 * Seattle, WA 98195 * Internet: MRC@CAC.Washington.EDU * * Date: 1 August 1988 * Last Edited: 30 August 2006 */ /* Dedication: * This file is dedicated with affection to the TOPS-20 operating system, which * set standards for user and programmer friendliness that have still not been * equaled by more `modern' operating systems. * Wasureru mon ka!!!! */ #include "mail.h" #include /* must be before tcp_t20.h */ #include "tcp_t20.h" /* must be before osdep include tcp.h */ #include #include "osdep.h" #include #include "misc.h" #include #include #include #include #include "fs_t20.c" #include "ftl_t20.c" #include "nl_t20.c" #include "env_t20.c" #include "tcp_t20.c" #include "log_t20.c" #define MD5ENABLE "PS:CRAM-MD5.PWD" #include "auth_md5.c" #include "auth_ext.c" #include "auth_pla.c" #include "auth_log.c" /* Emulator for UNIX gethostid() call * Returns: host id */ long gethostid () { int argblk[5]; #ifndef _APRID #define _APRID 28 #endif argblk[1] = _APRID; jsys (GETAB,argblk); return (long) argblk[1]; } /* Emulator for UNIX getpass() call * Accepts: prompt * Returns: password */ #define PWDLEN 128 /* used by Linux */ char *getpass (const char *prompt) { char *s; static char pwd[PWDLEN]; int argblk[5],mode; argblk[1] = (int) (prompt-1); /* prompt user */ jsys (PSOUT,argblk); argblk[1] = _PRIIN; /* get current TTY mode */ jsys (RFMOD,argblk); mode = argblk[2]; /* save for later */ argblk[2] &= ~06000; jsys (SFMOD,argblk); jsys (STPAR,argblk); fgets (pwd,PWDLEN-1,stdin); pwd[PWDLEN-1] = '\0'; if (s = strchr (pwd,'\n')) *s = '\0'; putchar ('\n'); argblk[2] = mode; jsys (SFMOD,argblk); jsys (STPAR,argblk); return pwd; } alpine-2.10+dfsg/imap/src/osdep/amiga/0000700000175000017500000000000011512502152021240 5ustar paulproteuspaulproteusalpine-2.10+dfsg/imap/src/osdep/amiga/nl_ami.c0000600000175000017500000000507711512502124022655 0ustar paulproteuspaulproteus/* ======================================================================== * Copyright 1988-2006 University of Washington * * Licensed under the Apache License, Version 2.0 (the "License"); * you may not use this file except in compliance with the License. * You may obtain a copy of the License at * * http://www.apache.org/licenses/LICENSE-2.0 * * * ======================================================================== */ /* * Program: UNIX/VMS newline routines * * Author: Mark Crispin * Networks and Distributed Computing * Computing & Communications * University of Washington * Administration Building, AG-44 * Seattle, WA 98195 * Internet: MRC@CAC.Washington.EDU * * Date: 1 August 1988 * Last Edited: 30 August 2006 */ /* Copy string with CRLF newlines * Accepts: destination string * pointer to size of destination string buffer * source string * length of source string * Returns: length of copied string */ unsigned long strcrlfcpy (unsigned char **dst,unsigned long *dstl, unsigned char *src,unsigned long srcl) { long i = srcl * 2,j; unsigned char c,*d = src; if (*dst) { /* candidate destination provided? */ /* count NLs if doesn't fit worst-case */ if (i > *dstl) for (i = j = srcl; j; --j) if (*d++ == '\012') i++; /* still too small, must reset destination */ if (i > *dstl) fs_give ((void **) dst); } /* make a new buffer if needed */ if (!*dst) *dst = (char *) fs_get ((*dstl = i) + 1); d = *dst; /* destination string */ if (srcl) do { /* main copy loop */ if ((c = *src++) < '\016') { /* prepend CR to LF */ if (c == '\012') *d++ = '\015'; /* unlikely CR */ else if ((c == '\015') && (srcl > 1) && (*src == '\012')) { *d++ = c; /* copy the CR */ c = *src++; /* grab the LF */ --srcl; /* adjust the count */ } } *d++ = c; /* copy character */ } while (--srcl); *d = '\0'; /* tie off destination */ return d - *dst; /* return length */ } /* Length of string after strcrlfcpy applied * Accepts: source string * Returns: length of string */ unsigned long strcrlflen (STRING *s) { unsigned long pos = GETPOS (s); unsigned long i = SIZE (s); unsigned long j = i; while (j--) switch (SNX (s)) {/* search for newlines */ case '\015': /* unlikely carriage return */ if (j && (CHR (s) == '\012')) { SNX (s); /* eat the line feed */ j--; } break; case '\012': /* line feed? */ i++; default: /* ordinary chararacter */ break; } SETPOS (s,pos); /* restore old position */ return i; } alpine-2.10+dfsg/imap/src/osdep/amiga/mtx.c0000600000175000017500000013214111512502124022217 0ustar paulproteuspaulproteus/* ======================================================================== * Copyright 1988-2007 University of Washington * * Licensed under the Apache License, Version 2.0 (the "License"); * you may not use this file except in compliance with the License. * You may obtain a copy of the License at * * http://www.apache.org/licenses/LICENSE-2.0 * * * ======================================================================== */ /* * Program: MTX mail routines * * Author: Mark Crispin * Networks and Distributed Computing * Computing & Communications * University of Washington * Administration Building, AG-44 * Seattle, WA 98195 * Internet: MRC@CAC.Washington.EDU * * Date: 22 May 1990 * Last Edited: 11 October 2007 */ /* FILE TIME SEMANTICS * * The atime is the last read time of the file. * The mtime is the last flags update time of the file. * The ctime is the last write time of the file. */ #include #include #include extern int errno; /* just in case */ #include "mail.h" #include "osdep.h" #include #include #include #include "misc.h" #include "dummy.h" #include "fdstring.h" /* MTX I/O stream local data */ typedef struct mtx_local { unsigned int shouldcheck: 1; /* if ping should do a check instead */ unsigned int mustcheck: 1; /* if ping must do a check instead */ int fd; /* file descriptor for I/O */ off_t filesize; /* file size parsed */ time_t filetime; /* last file time */ time_t lastsnarf; /* last snarf time */ unsigned char *buf; /* temporary buffer */ unsigned long buflen; /* current size of temporary buffer */ } MTXLOCAL; /* Convenient access to local data */ #define LOCAL ((MTXLOCAL *) stream->local) /* Function prototypes */ DRIVER *mtx_valid (char *name); int mtx_isvalid (char *name,char *tmp); void *mtx_parameters (long function,void *value); void mtx_scan (MAILSTREAM *stream,char *ref,char *pat,char *contents); void mtx_list (MAILSTREAM *stream,char *ref,char *pat); void mtx_lsub (MAILSTREAM *stream,char *ref,char *pat); long mtx_create (MAILSTREAM *stream,char *mailbox); long mtx_delete (MAILSTREAM *stream,char *mailbox); long mtx_rename (MAILSTREAM *stream,char *old,char *newname); long mtx_status (MAILSTREAM *stream,char *mbx,long flags); MAILSTREAM *mtx_open (MAILSTREAM *stream); void mtx_close (MAILSTREAM *stream,long options); void mtx_flags (MAILSTREAM *stream,char *sequence,long flags); char *mtx_header (MAILSTREAM *stream,unsigned long msgno, unsigned long *length,long flags); long mtx_text (MAILSTREAM *stream,unsigned long msgno,STRING *bs,long flags); void mtx_flag (MAILSTREAM *stream,char *sequence,char *flag,long flags); void mtx_flagmsg (MAILSTREAM *stream,MESSAGECACHE *elt); long mtx_ping (MAILSTREAM *stream); void mtx_check (MAILSTREAM *stream); void mtx_snarf (MAILSTREAM *stream); long mtx_expunge (MAILSTREAM *stream,char *sequence,long options); long mtx_copy (MAILSTREAM *stream,char *sequence,char *mailbox,long options); long mtx_append (MAILSTREAM *stream,char *mailbox,append_t af,void *data); char *mtx_file (char *dst,char *name); long mtx_parse (MAILSTREAM *stream); MESSAGECACHE *mtx_elt (MAILSTREAM *stream,unsigned long msgno); void mtx_read_flags (MAILSTREAM *stream,MESSAGECACHE *elt); void mtx_update_status (MAILSTREAM *stream,unsigned long msgno,long syncflag); unsigned long mtx_hdrpos (MAILSTREAM *stream,unsigned long msgno, unsigned long *size); /* MTX mail routines */ /* Driver dispatch used by MAIL */ DRIVER mtxdriver = { "mtx", /* driver name */ /* driver flags */ DR_LOCAL|DR_MAIL|DR_CRLF|DR_NOSTICKY|DR_LOCKING, (DRIVER *) NIL, /* next driver */ mtx_valid, /* mailbox is valid for us */ mtx_parameters, /* manipulate parameters */ mtx_scan, /* scan mailboxes */ mtx_list, /* list mailboxes */ mtx_lsub, /* list subscribed mailboxes */ NIL, /* subscribe to mailbox */ NIL, /* unsubscribe from mailbox */ dummy_create, /* create mailbox */ mtx_delete, /* delete mailbox */ mtx_rename, /* rename mailbox */ mtx_status, /* status of mailbox */ mtx_open, /* open mailbox */ mtx_close, /* close mailbox */ mtx_flags, /* fetch message "fast" attributes */ mtx_flags, /* fetch message flags */ NIL, /* fetch overview */ NIL, /* fetch message envelopes */ mtx_header, /* fetch message header */ mtx_text, /* fetch message body */ NIL, /* fetch partial message text */ NIL, /* unique identifier */ NIL, /* message number */ mtx_flag, /* modify flags */ mtx_flagmsg, /* per-message modify flags */ NIL, /* search for message based on criteria */ NIL, /* sort messages */ NIL, /* thread messages */ mtx_ping, /* ping mailbox to see if still alive */ mtx_check, /* check for new messages */ mtx_expunge, /* expunge deleted messages */ mtx_copy, /* copy messages to another mailbox */ mtx_append, /* append string message to mailbox */ NIL /* garbage collect stream */ }; /* prototype stream */ MAILSTREAM mtxproto = {&mtxdriver}; /* MTX mail validate mailbox * Accepts: mailbox name * Returns: our driver if name is valid, NIL otherwise */ DRIVER *mtx_valid (char *name) { char tmp[MAILTMPLEN]; return mtx_isvalid (name,tmp) ? &mtxdriver : NIL; } /* MTX mail test for valid mailbox * Accepts: mailbox name * Returns: T if valid, NIL otherwise */ int mtx_isvalid (char *name,char *tmp) { int fd; int ret = NIL; char *s,file[MAILTMPLEN]; struct stat sbuf; time_t tp[2]; errno = EINVAL; /* assume invalid argument */ /* if file, get its status */ if ((s = mtx_file (file,name)) && !stat (s,&sbuf)) { if (!sbuf.st_size) { /* allow empty file if INBOX */ if ((s = mailboxfile (tmp,name)) && !*s) ret = T; else errno = 0; /* empty file */ } else if ((fd = open (file,O_RDONLY,NIL)) >= 0) { memset (tmp,'\0',MAILTMPLEN); if ((read (fd,tmp,64) >= 0) && (s = strchr (tmp,'\015')) && (s[1] == '\012')) { /* valid format? */ *s = '\0'; /* tie off header */ /* must begin with dd-mmm-yy" */ ret = (((tmp[2] == '-' && tmp[6] == '-') || (tmp[1] == '-' && tmp[5] == '-')) && (s = strchr (tmp+18,',')) && strchr (s+2,';')) ? T : NIL; } else errno = -1; /* bogus format */ close (fd); /* close the file */ /* \Marked status? */ if (sbuf.st_ctime > sbuf.st_atime) { tp[0] = sbuf.st_atime; /* preserve atime and mtime */ tp[1] = sbuf.st_mtime; utime (file,tp); /* set the times */ } } } /* in case INBOX but not mtx format */ else if ((errno == ENOENT) && !compare_cstring (name,"INBOX")) errno = -1; return ret; /* return what we should */ } /* MTX manipulate driver parameters * Accepts: function code * function-dependent value * Returns: function-dependent return value */ void *mtx_parameters (long function,void *value) { void *ret = NIL; switch ((int) function) { case GET_INBOXPATH: if (value) ret = mtx_file ((char *) value,"INBOX"); break; } return ret; } /* MTX mail scan mailboxes * Accepts: mail stream * reference * pattern to search * string to scan */ void mtx_scan (MAILSTREAM *stream,char *ref,char *pat,char *contents) { if (stream) dummy_scan (NIL,ref,pat,contents); } /* MTX mail list mailboxes * Accepts: mail stream * reference * pattern to search */ void mtx_list (MAILSTREAM *stream,char *ref,char *pat) { if (stream) dummy_list (NIL,ref,pat); } /* MTX mail list subscribed mailboxes * Accepts: mail stream * reference * pattern to search */ void mtx_lsub (MAILSTREAM *stream,char *ref,char *pat) { if (stream) dummy_lsub (NIL,ref,pat); } /* MTX mail delete mailbox * Accepts: MAIL stream * mailbox name to delete * Returns: T on success, NIL on failure */ long mtx_delete (MAILSTREAM *stream,char *mailbox) { return mtx_rename (stream,mailbox,NIL); } /* MTX mail rename mailbox * Accepts: MAIL stream * old mailbox name * new mailbox name (or NIL for delete) * Returns: T on success, NIL on failure */ long mtx_rename (MAILSTREAM *stream,char *old,char *newname) { long ret = T; char c,*s,tmp[MAILTMPLEN],file[MAILTMPLEN],lock[MAILTMPLEN]; int fd,ld; struct stat sbuf; if (!mtx_file (file,old) || (newname && (!((s = mailboxfile (tmp,newname)) && *s) || ((s = strrchr (tmp,'/')) && !s[1])))) { sprintf (tmp,newname ? "Can't rename mailbox %.80s to %.80s: invalid name" : "Can't delete mailbox %.80s: invalid name", old,newname); MM_LOG (tmp,ERROR); return NIL; } else if ((fd = open (file,O_RDWR,NIL)) < 0) { sprintf (tmp,"Can't open mailbox %.80s: %s",old,strerror (errno)); MM_LOG (tmp,ERROR); return NIL; } /* get exclusive parse/append permission */ if ((ld = lockfd (fd,lock,LOCK_EX)) < 0) { MM_LOG ("Unable to lock rename mailbox",ERROR); return NIL; } /* lock out other users */ if (flock (fd,LOCK_EX|LOCK_NB)) { close (fd); /* couldn't lock, give up on it then */ sprintf (tmp,"Mailbox %.80s is in use by another process",old); MM_LOG (tmp,ERROR); unlockfd (ld,lock); /* release exclusive parse/append permission */ return NIL; } if (newname) { /* want rename? */ if (s = strrchr (tmp,'/')) {/* found superior to destination name? */ c = *++s; /* remember first character of inferior */ *s = '\0'; /* tie off to get just superior */ /* name doesn't exist, create it */ if ((stat (tmp,&sbuf) || ((sbuf.st_mode & S_IFMT) != S_IFDIR)) && !dummy_create_path (stream,tmp,get_dir_protection (newname))) ret = NIL; else *s = c; /* restore full name */ } /* rename the file */ if (ret && rename (file,tmp)) { sprintf (tmp,"Can't rename mailbox %.80s to %.80s: %s",old,newname, strerror (errno)); MM_LOG (tmp,ERROR); ret = NIL; /* set failure */ } } else if (unlink (file)) { sprintf (tmp,"Can't delete mailbox %.80s: %s",old,strerror (errno)); MM_LOG (tmp,ERROR); ret = NIL; /* set failure */ } flock (fd,LOCK_UN); /* release lock on the file */ close (fd); /* close the file */ unlockfd (ld,lock); /* release exclusive parse/append permission */ /* recreate file if renamed INBOX */ if (ret && !compare_cstring (old,"INBOX")) dummy_create (NIL,"INBOX.MTX"); return ret; /* return success */ } /* Mtx Mail status * Accepts: mail stream * mailbox name * status flags * Returns: T on success, NIL on failure */ long mtx_status (MAILSTREAM *stream,char *mbx,long flags) { MAILSTATUS status; unsigned long i; MAILSTREAM *tstream = NIL; MAILSTREAM *systream = NIL; /* make temporary stream (unless this mbx) */ if (!stream && !(stream = tstream = mail_open (NIL,mbx,OP_READONLY|OP_SILENT))) return NIL; status.flags = flags; /* return status values */ status.messages = stream->nmsgs; status.recent = stream->recent; if (flags & SA_UNSEEN) /* must search to get unseen messages */ for (i = 1,status.unseen = 0; i <= stream->nmsgs; i++) if (!mail_elt (stream,i)->seen) status.unseen++; status.uidnext = stream->uid_last + 1; status.uidvalidity = stream->uid_validity; /* calculate post-snarf results */ if (!status.recent && stream->inbox && (systream = mail_open (NIL,sysinbox (),OP_READONLY|OP_SILENT))) { status.messages += systream->nmsgs; status.recent += systream->recent; if (flags & SA_UNSEEN) /* must search to get unseen messages */ for (i = 1; i <= systream->nmsgs; i++) if (!mail_elt (systream,i)->seen) status.unseen++; /* kludge but probably good enough */ status.uidnext += systream->nmsgs; } MM_STATUS(stream,mbx,&status);/* pass status to main program */ if (tstream) mail_close (tstream); if (systream) mail_close (systream); return T; /* success */ } /* MTX mail open * Accepts: stream to open * Returns: stream on success, NIL on failure */ MAILSTREAM *mtx_open (MAILSTREAM *stream) { int fd,ld; char tmp[MAILTMPLEN]; blocknotify_t bn = (blocknotify_t) mail_parameters (NIL,GET_BLOCKNOTIFY,NIL); /* return prototype for OP_PROTOTYPE call */ if (!stream) return user_flags (&mtxproto); if (stream->local) fatal ("mtx recycle stream"); user_flags (stream); /* set up user flags */ /* canonicalize the mailbox name */ if (!mtx_file (tmp,stream->mailbox)) { sprintf (tmp,"Can't open - invalid name: %.80s",stream->mailbox); MM_LOG (tmp,ERROR); } if (stream->rdonly || (fd = open (tmp,O_RDWR,NIL)) < 0) { if ((fd = open (tmp,O_RDONLY,NIL)) < 0) { sprintf (tmp,"Can't open mailbox: %.80s",strerror (errno)); MM_LOG (tmp,ERROR); return NIL; } else if (!stream->rdonly) { /* got it, but readonly */ MM_LOG ("Can't get write access to mailbox, access is readonly",WARN); stream->rdonly = T; } } stream->local = fs_get (sizeof (MTXLOCAL)); LOCAL->fd = fd; /* bind the file */ LOCAL->buf = (char *) fs_get (CHUNKSIZE); LOCAL->buflen = CHUNKSIZE - 1; /* note if an INBOX or not */ stream->inbox = !compare_cstring (stream->mailbox,"INBOX"); fs_give ((void **) &stream->mailbox); stream->mailbox = cpystr (tmp); /* get shared parse permission */ if ((ld = lockfd (fd,tmp,LOCK_SH)) < 0) { MM_LOG ("Unable to lock open mailbox",ERROR); return NIL; } (*bn) (BLOCK_FILELOCK,NIL); flock (LOCAL->fd,LOCK_SH); /* lock the file */ (*bn) (BLOCK_NONE,NIL); unlockfd (ld,tmp); /* release shared parse permission */ LOCAL->filesize = 0; /* initialize parsed file size */ /* time not set up yet */ LOCAL->lastsnarf = LOCAL->filetime = 0; LOCAL->mustcheck = LOCAL->shouldcheck = NIL; stream->sequence++; /* bump sequence number */ /* parse mailbox */ stream->nmsgs = stream->recent = 0; if (mtx_ping (stream) && !stream->nmsgs) MM_LOG ("Mailbox is empty",(long) NIL); if (!LOCAL) return NIL; /* failure if stream died */ stream->perm_seen = stream->perm_deleted = stream->perm_flagged = stream->perm_answered = stream->perm_draft = stream->rdonly ? NIL : T; stream->perm_user_flags = stream->rdonly ? NIL : 0xffffffff; return stream; /* return stream to caller */ } /* MTX mail close * Accepts: MAIL stream * close options */ void mtx_close (MAILSTREAM *stream,long options) { if (stream && LOCAL) { /* only if a file is open */ int silent = stream->silent; stream->silent = T; /* note this stream is dying */ if (options & CL_EXPUNGE) mtx_expunge (stream,NIL,NIL); stream->silent = silent; /* restore previous status */ flock (LOCAL->fd,LOCK_UN); /* unlock local file */ close (LOCAL->fd); /* close the local file */ /* free local text buffer */ if (LOCAL->buf) fs_give ((void **) &LOCAL->buf); /* nuke the local data */ fs_give ((void **) &stream->local); stream->dtb = NIL; /* log out the DTB */ } } /* MTX mail fetch flags * Accepts: MAIL stream * sequence * option flags * Sniffs at file to see if some other process changed the flags */ void mtx_flags (MAILSTREAM *stream,char *sequence,long flags) { unsigned long i; if (mtx_ping (stream) && /* ping mailbox, get new status for messages */ ((flags & FT_UID) ? mail_uid_sequence (stream,sequence) : mail_sequence (stream,sequence))) for (i = 1; i <= stream->nmsgs; i++) if (mail_elt (stream,i)->sequence) mtx_elt (stream,i); } /* MTX mail fetch message header * Accepts: MAIL stream * message # to fetch * pointer to returned header text length * option flags * Returns: message header in RFC822 format */ char *mtx_header (MAILSTREAM *stream,unsigned long msgno,unsigned long *length, long flags) { *length = 0; /* default to empty */ if (flags & FT_UID) return "";/* UID call "impossible" */ /* get to header position */ lseek (LOCAL->fd,mtx_hdrpos (stream,msgno,length),L_SET); /* is buffer big enough? */ if (*length > LOCAL->buflen) { fs_give ((void **) &LOCAL->buf); LOCAL->buf = (char *) fs_get ((LOCAL->buflen = *length) + 1); } LOCAL->buf[*length] = '\0'; /* tie off string */ /* slurp the data */ read (LOCAL->fd,LOCAL->buf,*length); return (char *) LOCAL->buf; } /* MTX mail fetch message text (body only) * Accepts: MAIL stream * message # to fetch * pointer to returned header text length * option flags * Returns: T, always */ long mtx_text (MAILSTREAM *stream,unsigned long msgno,STRING *bs,long flags) { FDDATA d; unsigned long i,j; MESSAGECACHE *elt; /* UID call "impossible" */ if (flags & FT_UID) return NIL; elt = mtx_elt (stream,msgno); /* get message status */ /* if message not seen */ if (!(flags & FT_PEEK) && !elt->seen) { elt->seen = T; /* mark message as seen */ /* recalculate status */ mtx_update_status (stream,msgno,NIL); MM_FLAGS (stream,msgno); } /* find header position */ i = mtx_hdrpos (stream,msgno,&j); d.fd = LOCAL->fd; /* set up file descriptor */ d.pos = i + j; d.chunk = LOCAL->buf; /* initial buffer chunk */ d.chunksize = CHUNKSIZE; INIT (bs,fd_string,&d,elt->rfc822_size - j); return T; /* success */ } /* MTX mail modify flags * Accepts: MAIL stream * sequence * flag(s) * option flags */ void mtx_flag (MAILSTREAM *stream,char *sequence,char *flag,long flags) { time_t tp[2]; struct stat sbuf; if (!stream->rdonly) { /* make sure the update takes */ fsync (LOCAL->fd); fstat (LOCAL->fd,&sbuf); /* get current write time */ tp[1] = LOCAL->filetime = sbuf.st_mtime; tp[0] = time (0); /* make sure read comes after all that */ utime (stream->mailbox,tp); } } /* MTX mail per-message modify flags * Accepts: MAIL stream * message cache element */ void mtx_flagmsg (MAILSTREAM *stream,MESSAGECACHE *elt) { struct stat sbuf; /* maybe need to do a checkpoint? */ if (LOCAL->filetime && !LOCAL->shouldcheck) { fstat (LOCAL->fd,&sbuf); /* get current write time */ if (LOCAL->filetime < sbuf.st_mtime) LOCAL->shouldcheck = T; LOCAL->filetime = 0; /* don't do this test for any other messages */ } /* recalculate status */ mtx_update_status (stream,elt->msgno,NIL); } /* MTX mail ping mailbox * Accepts: MAIL stream * Returns: T if stream still alive, NIL if not */ long mtx_ping (MAILSTREAM *stream) { unsigned long i = 1; long r = T; int ld; char lock[MAILTMPLEN]; struct stat sbuf; if (stream && LOCAL) { /* only if stream already open */ fstat (LOCAL->fd,&sbuf); /* get current file poop */ if (LOCAL->filetime && !(LOCAL->mustcheck || LOCAL->shouldcheck) && (LOCAL->filetime < sbuf.st_mtime)) LOCAL->shouldcheck = T; /* check for changed message status */ if (LOCAL->mustcheck || LOCAL->shouldcheck) { LOCAL->filetime = sbuf.st_mtime; if (LOCAL->shouldcheck) /* babble when we do this unilaterally */ MM_NOTIFY (stream,"[CHECK] Checking for flag updates",NIL); while (i <= stream->nmsgs) mtx_elt (stream,i++); LOCAL->mustcheck = LOCAL->shouldcheck = NIL; } /* get shared parse/append permission */ if ((sbuf.st_size != LOCAL->filesize) && ((ld = lockfd (LOCAL->fd,lock,LOCK_SH)) >= 0)) { /* parse resulting mailbox */ r = (mtx_parse (stream)) ? T : NIL; unlockfd (ld,lock); /* release shared parse/append permission */ } if (LOCAL) { /* stream must still be alive */ /* snarf if this is a read-write inbox */ if (stream->inbox && !stream->rdonly) { mtx_snarf (stream); fstat (LOCAL->fd,&sbuf);/* see if file changed now */ if ((sbuf.st_size != LOCAL->filesize) && ((ld = lockfd (LOCAL->fd,lock,LOCK_SH)) >= 0)) { /* parse resulting mailbox */ r = (mtx_parse (stream)) ? T : NIL; unlockfd (ld,lock); /* release shared parse/append permission */ } } } } return r; /* return result of the parse */ } /* MTX mail check mailbox (reparses status too) * Accepts: MAIL stream */ void mtx_check (MAILSTREAM *stream) { /* mark that a check is desired */ if (LOCAL) LOCAL->mustcheck = T; if (mtx_ping (stream)) MM_LOG ("Check completed",(long) NIL); } /* MTX mail snarf messages from system inbox * Accepts: MAIL stream */ void mtx_snarf (MAILSTREAM *stream) { unsigned long i = 0; unsigned long j,r,hdrlen,txtlen; struct stat sbuf; char *hdr,*txt,lock[MAILTMPLEN],tmp[MAILTMPLEN]; MESSAGECACHE *elt; MAILSTREAM *sysibx = NIL; int ld; /* give up if can't get exclusive permission */ if ((time (0) >= (LOCAL->lastsnarf + (long) mail_parameters (NIL,GET_SNARFINTERVAL,NIL))) && strcmp (sysinbox (),stream->mailbox) && ((ld = lockfd (LOCAL->fd,lock,LOCK_EX)) >= 0)) { MM_CRITICAL (stream); /* go critical */ /* sizes match and anything in sysinbox? */ if (!stat (sysinbox (),&sbuf) && sbuf.st_size && !fstat (LOCAL->fd,&sbuf) && (sbuf.st_size == LOCAL->filesize) && (sysibx = mail_open (sysibx,sysinbox (),OP_SILENT)) && (!sysibx->rdonly) && (r = sysibx->nmsgs)) { /* yes, go to end of file in our mailbox */ lseek (LOCAL->fd,sbuf.st_size,L_SET); /* for each message in sysibx mailbox */ while (r && (++i <= sysibx->nmsgs)) { /* snarf message from system INBOX */ hdr = cpystr (mail_fetchheader_full (sysibx,i,NIL,&hdrlen,NIL)); txt = mail_fetchtext_full (sysibx,i,&txtlen,FT_PEEK); /* if have a message */ if (j = hdrlen + txtlen) { /* calculate header line */ mail_date (LOCAL->buf,elt = mail_elt (sysibx,i)); sprintf (LOCAL->buf + strlen (LOCAL->buf), ",%lu;0000000000%02o\015\012",j,(unsigned) ((fSEEN * elt->seen) + (fDELETED * elt->deleted) + (fFLAGGED * elt->flagged) + (fANSWERED * elt->answered) + (fDRAFT * elt->draft))); /* copy message */ if ((write (LOCAL->fd,LOCAL->buf,strlen (LOCAL->buf)) < 0) || (write (LOCAL->fd,hdr,hdrlen) < 0) || (write (LOCAL->fd,txt,txtlen) < 0)) r = 0; } fs_give ((void **) &hdr); } /* make sure all the updates take */ if (fsync (LOCAL->fd)) r = 0; if (r) { /* delete all the messages we copied */ if (r == 1) strcpy (tmp,"1"); else sprintf (tmp,"1:%lu",r); mail_flag (sysibx,tmp,"\\Deleted",ST_SET); mail_expunge (sysibx); /* now expunge all those messages */ } else { sprintf (LOCAL->buf,"Can't copy new mail: %s",strerror (errno)); MM_LOG (LOCAL->buf,WARN); ftruncate (LOCAL->fd,sbuf.st_size); } fstat (LOCAL->fd,&sbuf); /* yes, get current file size */ LOCAL->filetime = sbuf.st_mtime; } if (sysibx) mail_close (sysibx); MM_NOCRITICAL (stream); /* release critical */ unlockfd (ld,lock); /* release exclusive parse/append permission */ LOCAL->lastsnarf = time (0);/* note time of last snarf */ } } /* MTX mail expunge mailbox * Accepts: MAIL stream * sequence to expunge if non-NIL * expunge options * Returns: T, always */ long mtx_expunge (MAILSTREAM *stream,char *sequence,long options) { long ret; time_t tp[2]; struct stat sbuf; off_t pos = 0; int ld; unsigned long i = 1; unsigned long j,k,m,recent; unsigned long n = 0; unsigned long delta = 0; char lock[MAILTMPLEN]; MESSAGECACHE *elt; blocknotify_t bn = (blocknotify_t) mail_parameters (NIL,GET_BLOCKNOTIFY,NIL); if (!(ret = (sequence ? ((options & EX_UID) ? mail_uid_sequence (stream,sequence) : mail_sequence (stream,sequence)) : LONGT) && mtx_ping (stream))); /* parse sequence if given, ping stream */ else if (stream->rdonly) MM_LOG ("Expunge ignored on readonly mailbox",WARN); else { if (LOCAL->filetime && !LOCAL->shouldcheck) { fstat (LOCAL->fd,&sbuf); /* get current write time */ if (LOCAL->filetime < sbuf.st_mtime) LOCAL->shouldcheck = T; } /* The cretins who designed flock() created a window of vulnerability in * upgrading locks from shared to exclusive or downgrading from exclusive * to shared. Rather than maintain the lock at shared status at a minimum, * flock() actually *releases* the former lock. Obviously they never talked * to any database guys. Fortunately, we have the parse/append permission * lock. If we require this lock before going exclusive on the mailbox, * another process can not sneak in and steal the exclusive mailbox lock on * us, because it will block on trying to get parse/append permission first. */ /* get exclusive parse/append permission */ if ((ld = lockfd (LOCAL->fd,lock,LOCK_EX)) < 0) MM_LOG ("Unable to lock expunge mailbox",ERROR); /* make sure see any newly-arrived messages */ else if (!mtx_parse (stream)); /* get exclusive access */ else if (flock (LOCAL->fd,LOCK_EX|LOCK_NB)) { (*bn) (BLOCK_FILELOCK,NIL); flock (LOCAL->fd,LOCK_SH);/* recover previous lock */ (*bn) (BLOCK_NONE,NIL); MM_LOG ("Can't expunge because mailbox is in use by another process", ERROR); unlockfd (ld,lock); /* release exclusive parse/append permission */ } else { MM_CRITICAL (stream); /* go critical */ recent = stream->recent; /* get recent now that pinged and locked */ /* for each message */ while (i <= stream->nmsgs) { /* get cache element */ elt = mtx_elt (stream,i); /* number of bytes to smash or preserve */ k = elt->private.special.text.size + elt->rfc822_size; /* if need to expunge this message */ if (elt->deleted && (sequence ? elt->sequence : T)) { /* if recent, note one less recent message */ if (elt->recent) --recent; delta += k; /* number of bytes to delete */ /* notify upper levels */ mail_expunged (stream,i); n++; /* count up one more expunged message */ } else if (i++ && delta) {/* preserved message */ /* first byte to preserve */ j = elt->private.special.offset; do { /* read from source position */ m = min (k,LOCAL->buflen); lseek (LOCAL->fd,j,L_SET); read (LOCAL->fd,LOCAL->buf,m); pos = j - delta; /* write to destination position */ lseek (LOCAL->fd,pos,L_SET); while (T) { lseek (LOCAL->fd,pos,L_SET); if (write (LOCAL->fd,LOCAL->buf,m) > 0) break; MM_NOTIFY (stream,strerror (errno),WARN); MM_DISKERROR (stream,errno,T); } pos += m; /* new position */ j += m; /* next chunk, perhaps */ } while (k -= m); /* until done */ /* note the new address of this text */ elt->private.special.offset -= delta; } /* preserved but no deleted messages */ else pos = elt->private.special.offset + k; } if (n) { /* truncate file after last message */ if (pos != (LOCAL->filesize -= delta)) { sprintf (LOCAL->buf, "Calculated size mismatch %lu != %lu, delta = %lu", (unsigned long) pos,(unsigned long) LOCAL->filesize,delta); MM_LOG (LOCAL->buf,WARN); LOCAL->filesize = pos;/* fix it then */ } ftruncate (LOCAL->fd,LOCAL->filesize); sprintf (LOCAL->buf,"Expunged %lu messages",n); /* output the news */ MM_LOG (LOCAL->buf,(long) NIL); } else MM_LOG ("No messages deleted, so no update needed",(long) NIL); fsync (LOCAL->fd); /* force disk update */ fstat (LOCAL->fd,&sbuf); /* get new write time */ tp[1] = LOCAL->filetime = sbuf.st_mtime; tp[0] = time (0); /* reset atime to now */ utime (stream->mailbox,tp); MM_NOCRITICAL (stream); /* release critical */ /* notify upper level of new mailbox size */ mail_exists (stream,stream->nmsgs); mail_recent (stream,recent); (*bn) (BLOCK_FILELOCK,NIL); flock (LOCAL->fd,LOCK_SH);/* allow sharers again */ (*bn) (BLOCK_NONE,NIL); unlockfd (ld,lock); /* release exclusive parse/append permission */ } } return ret; } /* MTX mail copy message(s) * Accepts: MAIL stream * sequence * destination mailbox * copy options * Returns: T if success, NIL if failed */ long mtx_copy (MAILSTREAM *stream,char *sequence,char *mailbox,long options) { struct stat sbuf; time_t tp[2]; MESSAGECACHE *elt; unsigned long i,j,k; long ret = LONGT; int fd,ld; char file[MAILTMPLEN],lock[MAILTMPLEN]; mailproxycopy_t pc = (mailproxycopy_t) mail_parameters (stream,GET_MAILPROXYCOPY,NIL); /* make sure valid mailbox */ if (!mtx_isvalid (mailbox,LOCAL->buf)) switch (errno) { case ENOENT: /* no such file? */ MM_NOTIFY (stream,"[TRYCREATE] Must create mailbox before copy",NIL); return NIL; case 0: /* merely empty file? */ break; case EACCES: /* file protected */ sprintf (LOCAL->buf,"Can't access destination: %.80s",mailbox); MM_LOG (LOCAL->buf,ERROR); return NIL; case EINVAL: if (pc) return (*pc) (stream,sequence,mailbox,options); sprintf (LOCAL->buf,"Invalid MTX-format mailbox name: %.80s",mailbox); MM_LOG (LOCAL->buf,ERROR); return NIL; default: if (pc) return (*pc) (stream,sequence,mailbox,options); sprintf (LOCAL->buf,"Not a MTX-format mailbox: %.80s",mailbox); MM_LOG (LOCAL->buf,ERROR); return NIL; } if (!((options & CP_UID) ? mail_uid_sequence (stream,sequence) : mail_sequence (stream,sequence))) return NIL; /* got file? */ if ((fd = open (mtx_file (file,mailbox),O_RDWR,NIL)) < 0) { sprintf (LOCAL->buf,"Unable to open copy mailbox: %s",strerror (errno)); MM_LOG (LOCAL->buf,ERROR); return NIL; } MM_CRITICAL (stream); /* go critical */ /* get exclusive parse/append permission */ if (flock (fd,LOCK_SH) || ((ld = lockfd (fd,lock,LOCK_EX)) < 0)) { MM_LOG ("Unable to lock copy mailbox",ERROR); MM_NOCRITICAL (stream); return NIL; } fstat (fd,&sbuf); /* get current file size */ lseek (fd,sbuf.st_size,L_SET);/* move to end of file */ /* for each requested message */ for (i = 1; ret && (i <= stream->nmsgs); i++) if ((elt = mail_elt (stream,i))->sequence) { lseek (LOCAL->fd,elt->private.special.offset,L_SET); /* number of bytes to copy */ k = elt->private.special.text.size + elt->rfc822_size; do { /* read from source position */ j = min (k,LOCAL->buflen); read (LOCAL->fd,LOCAL->buf,j); if (write (fd,LOCAL->buf,j) < 0) ret = NIL; } while (ret && (k -= j));/* until done */ } /* make sure all the updates take */ if (!(ret && (ret = !fsync (fd)))) { sprintf (LOCAL->buf,"Unable to write message: %s",strerror (errno)); MM_LOG (LOCAL->buf,ERROR); ftruncate (fd,sbuf.st_size); } if (ret) tp[0] = time (0) - 1;/* set atime to now-1 if successful copy */ /* else preserve \Marked status */ else tp[0] = (sbuf.st_ctime > sbuf.st_atime) ? sbuf.st_atime : time(0); tp[1] = sbuf.st_mtime; /* preserve mtime */ utime (file,tp); /* set the times */ close (fd); /* close the file */ unlockfd (ld,lock); /* release exclusive parse/append permission */ MM_NOCRITICAL (stream); /* release critical */ /* delete all requested messages */ if (ret && (options & CP_MOVE)) { for (i = 1; i <= stream->nmsgs; i++) if ((elt = mtx_elt (stream,i))->sequence) { elt->deleted = T; /* mark message deleted */ /* recalculate status */ mtx_update_status (stream,i,NIL); } if (!stream->rdonly) { /* make sure the update takes */ fsync (LOCAL->fd); fstat (LOCAL->fd,&sbuf); /* get current write time */ tp[1] = LOCAL->filetime = sbuf.st_mtime; tp[0] = time (0); /* make sure atime remains greater */ utime (stream->mailbox,tp); } } if (ret && mail_parameters (NIL,GET_COPYUID,NIL)) MM_LOG ("Can not return meaningful COPYUID with this mailbox format",WARN); return ret; } /* MTX mail append message from stringstruct * Accepts: MAIL stream * destination mailbox * append callback * data for callback * Returns: T if append successful, else NIL */ long mtx_append (MAILSTREAM *stream,char *mailbox,append_t af,void *data) { struct stat sbuf; int fd,ld,c; char *flags,*date,tmp[MAILTMPLEN],file[MAILTMPLEN],lock[MAILTMPLEN]; time_t tp[2]; FILE *df; MESSAGECACHE elt; long f; unsigned long i,uf; STRING *message; long ret = LONGT; /* default stream to prototype */ if (!stream) stream = user_flags (&mtxproto); /* make sure valid mailbox */ if (!mtx_isvalid (mailbox,tmp)) switch (errno) { case ENOENT: /* no such file? */ if (!compare_cstring (mailbox,"INBOX")) dummy_create (NIL,"INBOX.MTX"); else { MM_NOTIFY (stream,"[TRYCREATE] Must create mailbox before append",NIL); return NIL; } /* falls through */ case 0: /* merely empty file? */ break; case EACCES: /* file protected */ sprintf (tmp,"Can't access destination: %.80s",mailbox); MM_LOG (tmp,ERROR); return NIL; case EINVAL: sprintf (tmp,"Invalid MTX-format mailbox name: %.80s",mailbox); MM_LOG (tmp,ERROR); return NIL; default: sprintf (tmp,"Not a MTX-format mailbox: %.80s",mailbox); MM_LOG (tmp,ERROR); return NIL; } /* get first message */ if (!MM_APPEND (af) (stream,data,&flags,&date,&message)) return NIL; /* open destination mailbox */ if (((fd = open (mtx_file (file,mailbox),O_WRONLY|O_APPEND,NIL)) < 0) || !(df = fdopen (fd,"ab"))) { sprintf (tmp,"Can't open append mailbox: %s",strerror (errno)); MM_LOG (tmp,ERROR); return NIL; } /* get parse/append permission */ if (flock (fd,LOCK_SH) || ((ld = lockfd (fd,lock,LOCK_EX)) < 0)) { MM_LOG ("Unable to lock append mailbox",ERROR); close (fd); return NIL; } MM_CRITICAL (stream); /* go critical */ fstat (fd,&sbuf); /* get current file size */ errno = 0; do { /* parse flags */ if (!SIZE (message)) { /* guard against zero-length */ MM_LOG ("Append of zero-length message",ERROR); ret = NIL; break; } f = mail_parse_flags (stream,flags,&i); /* reverse bits (dontcha wish we had CIRC?) */ for (uf = 0; i; uf |= 1 << (29 - find_rightmost_bit (&i))); if (date) { /* parse date if given */ if (!mail_parse_date (&elt,date)) { sprintf (tmp,"Bad date in append: %.80s",date); MM_LOG (tmp,ERROR); ret = NIL; /* mark failure */ break; } mail_date (tmp,&elt); /* write preseved date */ } else internal_date (tmp); /* get current date in IMAP format */ /* write header */ if (fprintf (df,"%s,%lu;%010lo%02lo\015\012",tmp,i = SIZE (message),uf, (unsigned long) f) < 0) ret = NIL; else { /* write message */ if (i) do c = 0xff & SNX (message); while ((putc (c,df) != EOF) && --i); /* get next message */ if (i || !MM_APPEND (af) (stream,data,&flags,&date,&message)) ret = NIL; } } while (ret && message); /* if error... */ if (!ret || (fflush (df) == EOF)) { ftruncate (fd,sbuf.st_size);/* revert file */ close (fd); /* make sure fclose() doesn't corrupt us */ if (errno) { sprintf (tmp,"Message append failed: %s",strerror (errno)); MM_LOG (tmp,ERROR); } ret = NIL; } if (ret) tp[0] = time (0) - 1;/* set atime to now-1 if successful copy */ /* else preserve \Marked status */ else tp[0] = (sbuf.st_ctime > sbuf.st_atime) ? sbuf.st_atime : time(0); tp[1] = sbuf.st_mtime; /* preserve mtime */ utime (file,tp); /* set the times */ fclose (df); /* close the file */ unlockfd (ld,lock); /* release exclusive parse/append permission */ MM_NOCRITICAL (stream); /* release critical */ if (ret && mail_parameters (NIL,GET_APPENDUID,NIL)) MM_LOG ("Can not return meaningful APPENDUID with this mailbox format", WARN); return ret; } /* Internal routines */ /* MTX mail generate file string * Accepts: temporary buffer to write into * mailbox name string * Returns: local file string or NIL if failure */ char *mtx_file (char *dst,char *name) { char tmp[MAILTMPLEN]; char *s = mailboxfile (dst,name); /* return our standard inbox */ return (s && !*s) ? mailboxfile (dst,mtx_isvalid ("~/INBOX",tmp) ? "~/INBOX" : "INBOX.MTX") : s; } /* MTX mail parse mailbox * Accepts: MAIL stream * Returns: T if parse OK * NIL if failure, stream aborted */ long mtx_parse (MAILSTREAM *stream) { struct stat sbuf; MESSAGECACHE *elt = NIL; unsigned char c,*s,*t,*x; char tmp[MAILTMPLEN]; unsigned long i,j; long curpos = LOCAL->filesize; long nmsgs = stream->nmsgs; long recent = stream->recent; short added = NIL; short silent = stream->silent; fstat (LOCAL->fd,&sbuf); /* get status */ if (sbuf.st_size < curpos) { /* sanity check */ sprintf (tmp,"Mailbox shrank from %lu to %lu!", (unsigned long) curpos,(unsigned long) sbuf.st_size); MM_LOG (tmp,ERROR); mtx_close (stream,NIL); return NIL; } stream->silent = T; /* don't pass up exists events yet */ while (sbuf.st_size - curpos){/* while there is stuff to parse */ /* get to that position in the file */ lseek (LOCAL->fd,curpos,L_SET); if ((i = read (LOCAL->fd,LOCAL->buf,64)) <= 0) { sprintf (tmp,"Unable to read internal header at %lu, size = %lu: %s", (unsigned long) curpos,(unsigned long) sbuf.st_size, i ? strerror (errno) : "no data read"); MM_LOG (tmp,ERROR); mtx_close (stream,NIL); return NIL; } LOCAL->buf[i] = '\0'; /* tie off buffer just in case */ if (!((s = strchr (LOCAL->buf,'\015')) && (s[1] == '\012'))) { sprintf (tmp,"Unable to find CRLF at %lu in %lu bytes, text: %s", (unsigned long) curpos,i,(char *) LOCAL->buf); MM_LOG (tmp,ERROR); mtx_close (stream,NIL); return NIL; } *s = '\0'; /* tie off header line */ i = (s + 2) - LOCAL->buf; /* note start of text offset */ if (!((s = strchr (LOCAL->buf,',')) && (t = strchr (s+1,';')))) { sprintf (tmp,"Unable to parse internal header at %lu: %s", (unsigned long) curpos,(char *) LOCAL->buf); MM_LOG (tmp,ERROR); mtx_close (stream,NIL); return NIL; } *s++ = '\0'; *t++ = '\0'; /* tie off fields */ added = T; /* note that a new message was added */ /* swell the cache */ mail_exists (stream,++nmsgs); /* instantiate an elt for this message */ (elt = mail_elt (stream,nmsgs))->valid = T; elt->private.uid = ++stream->uid_last; /* note file offset of header */ elt->private.special.offset = curpos; /* in case error */ elt->private.special.text.size = 0; /* header size not known yet */ elt->private.msg.header.text.size = 0; x = s; /* parse the header components */ if (mail_parse_date (elt,LOCAL->buf) && (elt->rfc822_size = strtoul (s,(char **) &s,10)) && (!(s && *s)) && isdigit (t[0]) && isdigit (t[1]) && isdigit (t[2]) && isdigit (t[3]) && isdigit (t[4]) && isdigit (t[5]) && isdigit (t[6]) && isdigit (t[7]) && isdigit (t[8]) && isdigit (t[9]) && isdigit (t[10]) && isdigit (t[11]) && !t[12]) elt->private.special.text.size = i; else { /* oops */ sprintf (tmp,"Unable to parse internal header elements at %ld: %s,%s;%s", curpos,(char *) LOCAL->buf,(char *) x,(char *) t); MM_LOG (tmp,ERROR); mtx_close (stream,NIL); return NIL; } /* make sure didn't run off end of file */ if ((curpos += (elt->rfc822_size + i)) > sbuf.st_size) { sprintf (tmp,"Last message (at %lu) runs past end of file (%lu > %lu)", elt->private.special.offset,(unsigned long) curpos, (unsigned long) sbuf.st_size); MM_LOG (tmp,ERROR); mtx_close (stream,NIL); return NIL; } c = t[10]; /* remember first system flags byte */ t[10] = '\0'; /* tie off flags */ j = strtoul (t,NIL,8); /* get user flags value */ t[10] = c; /* restore first system flags byte */ /* set up all valid user flags (reversed!) */ while (j) if (((i = 29 - find_rightmost_bit (&j)) < NUSERFLAGS) && stream->user_flags[i]) elt->user_flags |= 1 << i; /* calculate system flags */ if ((j = ((t[10]-'0') * 8) + t[11]-'0') & fSEEN) elt->seen = T; if (j & fDELETED) elt->deleted = T; if (j & fFLAGGED) elt->flagged = T; if (j & fANSWERED) elt->answered = T; if (j & fDRAFT) elt->draft = T; if (!(j & fOLD)) { /* newly arrived message? */ elt->recent = T; recent++; /* count up a new recent message */ /* mark it as old */ mtx_update_status (stream,nmsgs,NIL); } } fsync (LOCAL->fd); /* make sure all the fOLD flags take */ /* update parsed file size and time */ LOCAL->filesize = sbuf.st_size; fstat (LOCAL->fd,&sbuf); /* get status again to ensure time is right */ LOCAL->filetime = sbuf.st_mtime; if (added && !stream->rdonly){/* make sure atime updated */ time_t tp[2]; tp[0] = time (0); tp[1] = LOCAL->filetime; utime (stream->mailbox,tp); } stream->silent = silent; /* can pass up events now */ mail_exists (stream,nmsgs); /* notify upper level of new mailbox size */ mail_recent (stream,recent); /* and of change in recent messages */ return LONGT; /* return the winnage */ } /* MTX get cache element with status updating from file * Accepts: MAIL stream * message number * Returns: cache element */ MESSAGECACHE *mtx_elt (MAILSTREAM *stream,unsigned long msgno) { MESSAGECACHE *elt = mail_elt (stream,msgno); struct { /* old flags */ unsigned int seen : 1; unsigned int deleted : 1; unsigned int flagged : 1; unsigned int answered : 1; unsigned int draft : 1; unsigned long user_flags; } old; old.seen = elt->seen; old.deleted = elt->deleted; old.flagged = elt->flagged; old.answered = elt->answered; old.draft = elt->draft; old.user_flags = elt->user_flags; mtx_read_flags (stream,elt); if ((old.seen != elt->seen) || (old.deleted != elt->deleted) || (old.flagged != elt->flagged) || (old.answered != elt->answered) || (old.draft != elt->draft) || (old.user_flags != elt->user_flags)) MM_FLAGS (stream,msgno); /* let top level know */ return elt; } /* MTX read flags from file * Accepts: MAIL stream * Returns: cache element */ void mtx_read_flags (MAILSTREAM *stream,MESSAGECACHE *elt) { unsigned long i,j; /* noop if readonly and have valid flags */ if (stream->rdonly && elt->valid) return; /* set the seek pointer */ lseek (LOCAL->fd,(off_t) elt->private.special.offset + elt->private.special.text.size - 14,L_SET); /* read the new flags */ if (read (LOCAL->fd,LOCAL->buf,12) < 0) { sprintf (LOCAL->buf,"Unable to read new status: %s",strerror (errno)); fatal (LOCAL->buf); } /* calculate system flags */ i = (((LOCAL->buf[10]-'0') * 8) + LOCAL->buf[11]-'0'); elt->seen = i & fSEEN ? T : NIL; elt->deleted = i & fDELETED ? T : NIL; elt->flagged = i & fFLAGGED ? T : NIL; elt->answered = i & fANSWERED ? T : NIL; elt->draft = i & fDRAFT ? T : NIL; LOCAL->buf[10] = '\0'; /* tie off flags */ j = strtoul(LOCAL->buf,NIL,8);/* get user flags value */ /* set up all valid user flags (reversed!) */ while (j) if (((i = 29 - find_rightmost_bit (&j)) < NUSERFLAGS) && stream->user_flags[i]) elt->user_flags |= 1 << i; elt->valid = T; /* have valid flags now */ } /* MTX update status string * Accepts: MAIL stream * message number * flag saying whether or not to sync */ void mtx_update_status (MAILSTREAM *stream,unsigned long msgno,long syncflag) { time_t tp[2]; struct stat sbuf; MESSAGECACHE *elt = mail_elt (stream,msgno); unsigned long j,k = 0; /* readonly */ if (stream->rdonly || !elt->valid) mtx_read_flags (stream,elt); else { /* readwrite */ j = elt->user_flags; /* get user flags */ /* reverse bits (dontcha wish we had CIRC?) */ while (j) k |= 1 << (29 - find_rightmost_bit (&j)); /* print new flag string */ sprintf (LOCAL->buf,"%010lo%02o",k,(unsigned) (fOLD + (fSEEN * elt->seen) + (fDELETED * elt->deleted) + (fFLAGGED * elt->flagged) + (fANSWERED * elt->answered) + (fDRAFT * elt->draft))); /* get to that place in the file */ lseek (LOCAL->fd,(off_t) elt->private.special.offset + elt->private.special.text.size - 14,L_SET); /* write new flags */ write (LOCAL->fd,LOCAL->buf,12); if (syncflag) { /* sync if requested */ fsync (LOCAL->fd); fstat (LOCAL->fd,&sbuf); /* get new write time */ tp[1] = LOCAL->filetime = sbuf.st_mtime; tp[0] = time (0); /* make sure read is later */ utime (stream->mailbox,tp); } } } /* MTX locate header for a message * Accepts: MAIL stream * message number * pointer to returned header size * Returns: position of header in file */ unsigned long mtx_hdrpos (MAILSTREAM *stream,unsigned long msgno, unsigned long *size) { unsigned long siz; long i = 0; int q = 0; char *s,tmp[MAILTMPLEN]; MESSAGECACHE *elt = mtx_elt (stream,msgno); unsigned long ret = elt->private.special.offset + elt->private.special.text.size; /* is header size known? */ if (!(*size = elt->private.msg.header.text.size)) { lseek (LOCAL->fd,ret,L_SET);/* get to header position */ /* search message for CRLF CRLF */ for (siz = 1,s = tmp; siz <= elt->rfc822_size; siz++) { /* read another buffer as necessary */ if ((--i <= 0) && /* buffer empty? */ (read (LOCAL->fd,s = tmp, i = min (elt->rfc822_size - siz,(long) MAILTMPLEN)) < 0)) return ret; /* I/O error? */ switch (q) { /* sniff at buffer */ case 0: /* first character */ q = (*s++ == '\015') ? 1 : 0; break; case 1: /* second character */ q = (*s++ == '\012') ? 2 : 0; break; case 2: /* third character */ q = (*s++ == '\015') ? 3 : 0; break; case 3: /* fourth character */ if (*s++ == '\012') { /* have the sequence? */ /* yes, note for later */ elt->private.msg.header.text.size = *size = siz; return ret; } q = 0; /* lost... */ break; } } /* header consumes entire message */ elt->private.msg.header.text.size = *size = elt->rfc822_size; } return ret; } alpine-2.10+dfsg/imap/src/osdep/amiga/gr_waitp.c0000600000175000017500000000207111512502124023221 0ustar paulproteuspaulproteus/* ======================================================================== * Copyright 1988-2006 University of Washington * * Licensed under the Apache License, Version 2.0 (the "License"); * you may not use this file except in compliance with the License. * You may obtain a copy of the License at * * http://www.apache.org/licenses/LICENSE-2.0 * * * ======================================================================== */ /* * Program: UNIX Grim PID Reaper -- waitpid() version * * Author: Mark Crispin * Networks and Distributed Computing * Computing & Communications * University of Washington * Administration Building, AG-44 * Seattle, WA 98195 * Internet: MRC@CAC.Washington.EDU * * Date: 30 November 1993 * Last Edited: 30 August 2006 */ /* Grim PID reaper * Accepts: process ID * kill request flag * status return value */ void grim_pid_reap_status (int pid,int killreq,void *status) { if (killreq) kill(pid,SIGHUP);/* kill if not already dead */ while ((waitpid (pid,status,NIL) < 0) && (errno != ECHILD)); } alpine-2.10+dfsg/imap/src/osdep/amiga/mmdf.c0000600000175000017500000026254111512502124022342 0ustar paulproteuspaulproteus/* ======================================================================== * Copyright 1988-2008 University of Washington * * Licensed under the Apache License, Version 2.0 (the "License"); * you may not use this file except in compliance with the License. * You may obtain a copy of the License at * * http://www.apache.org/licenses/LICENSE-2.0 * * * ======================================================================== */ /* * Program: MMDF mail routines * * Author: Mark Crispin * UW Technology * University of Washington * Seattle, WA 98195 * Internet: MRC@Washington.EDU * * Date: 20 December 1989 * Last Edited: 27 March 2008 */ #include #include #include extern int errno; /* just in case */ #include #include "mail.h" #include "osdep.h" #include #include #include "pseudo.h" #include "fdstring.h" #include "misc.h" #include "dummy.h" /* Supposedly, this page has everything the MMDF driver needs to know about * the MMDF delimiter. By changing these macros, the MMDF driver should * change with it. Note that if you change the length of MMDFHDRTXT you * also need to change the ISMMDF and RETIFMMDFWRD macros to reflect the new * size. */ /* Useful MMDF constants */ #define MMDFCHR '\01' /* MMDF character */ #define MMDFCHRS 0x01010101 /* MMDF header character spread in a word */ /* MMDF header text */ #define MMDFHDRTXT "\01\01\01\01\n" /* length of MMDF header text */ #define MMDFHDRLEN (sizeof (MMDFHDRTXT) - 1) /* Validate MMDF header * Accepts: pointer to candidate string to validate as an MMDF header * Returns: T if valid; else NIL */ #define ISMMDF(s) \ ((*(s) == MMDFCHR) && ((s)[1] == MMDFCHR) && ((s)[2] == MMDFCHR) && \ ((s)[3] == MMDFCHR) && ((s)[4] == '\n')) /* Return if a 32-bit word has the start of an MMDF header * Accepts: pointer to word of four bytes to validate as an MMDF header * Returns: pointer to MMDF header, else proceeds */ #define RETIFMMDFWRD(s) { \ if (s[3] == MMDFCHR) { \ if ((s[4] == MMDFCHR) && (s[5] == MMDFCHR) && (s[6] == MMDFCHR) && \ (s[7] == '\n')) return s + 3; \ else if (s[2] == MMDFCHR) { \ if ((s[4] == MMDFCHR) && (s[5] == MMDFCHR) && (s[6] == '\n')) \ return s + 2; \ else if (s[1] == MMDFCHR) { \ if ((s[4] == MMDFCHR) && (s[5] == '\n')) return s + 1; \ else if ((*s == MMDFCHR) && (s[4] == '\n')) return s; \ } \ } \ } \ } /* Validate line * Accepts: pointer to candidate string to validate as a From header * return pointer to end of date/time field * return pointer to offset from t of time (hours of ``mmm dd hh:mm'') * return pointer to offset from t of time zone (if non-zero) * Returns: t,ti,zn set if valid From string, else ti is NIL */ #define VALID(s,x,ti,zn) { \ ti = 0; \ if ((*s == 'F') && (s[1] == 'r') && (s[2] == 'o') && (s[3] == 'm') && \ (s[4] == ' ')) { \ for (x = s + 5; *x && *x != '\n'; x++); \ if (*x) { \ if (x - s >= 41) { \ for (zn = -1; x[zn] != ' '; zn--); \ if ((x[zn-1] == 'm') && (x[zn-2] == 'o') && (x[zn-3] == 'r') && \ (x[zn-4] == 'f') && (x[zn-5] == ' ') && (x[zn-6] == 'e') && \ (x[zn-7] == 't') && (x[zn-8] == 'o') && (x[zn-9] == 'm') && \ (x[zn-10] == 'e') && (x[zn-11] == 'r') && (x[zn-12] == ' '))\ x += zn - 12; \ } \ if (x - s >= 27) { \ if (x[-5] == ' ') { \ if (x[-8] == ':') zn = 0,ti = -5; \ else if (x[-9] == ' ') ti = zn = -9; \ else if ((x[-11] == ' ') && ((x[-10]=='+') || (x[-10]=='-'))) \ ti = zn = -11; \ } \ else if (x[-4] == ' ') { \ if (x[-9] == ' ') zn = -4,ti = -9; \ } \ else if (x[-6] == ' ') { \ if ((x[-11] == ' ') && ((x[-5] == '+') || (x[-5] == '-'))) \ zn = -6,ti = -11; \ } \ if (ti && !((x[ti - 3] == ':') && \ (x[ti -= ((x[ti - 6] == ':') ? 9 : 6)] == ' ') && \ (x[ti - 3] == ' ') && (x[ti - 7] == ' ') && \ (x[ti - 11] == ' '))) ti = 0; \ } \ } \ } \ } /* You are not expected to understand this macro, but read the next page if * you are not faint of heart. * * Known formats to the VALID macro are: * From user Wed Dec 2 05:53 1992 * BSD From user Wed Dec 2 05:53:22 1992 * SysV From user Wed Dec 2 05:53 PST 1992 * rn From user Wed Dec 2 05:53:22 PST 1992 * From user Wed Dec 2 05:53 -0700 1992 * emacs From user Wed Dec 2 05:53:22 -0700 1992 * From user Wed Dec 2 05:53 1992 PST * From user Wed Dec 2 05:53:22 1992 PST * From user Wed Dec 2 05:53 1992 -0700 * Solaris From user Wed Dec 2 05:53:22 1992 -0700 * * Plus all of the above with `` remote from xxx'' after it. Thank you very * much, smail and Solaris, for making my life considerably more complicated. */ /* * What? You want to understand the VALID macro anyway? Alright, since you * insist. Actually, it isn't really all that difficult, provided that you * take it step by step. * * Line 1 Initializes the return ti value to failure (0); * Lines 2-3 Validates that the 1st-5th characters are ``From ''. * Lines 4-5 Validates that there is an end of line and points x at it. * Lines 6-13 First checks to see if the line is at least 41 characters long. * If so, it scans backwards to find the rightmost space. From * that point, it scans backwards to see if the string matches * `` remote from''. If so, it sets x to point to the space at * the start of the string. * Line 14 Makes sure that there are at least 27 characters in the line. * Lines 15-20 Checks if the date/time ends with the year (there is a space * five characters back). If there is a colon three characters * further back, there is no timezone field, so zn is set to 0 * and ti is set in front of the year. Otherwise, there must * either to be a space four characters back for a three-letter * timezone, or a space six characters back followed by a + or - * for a numeric timezone; in either case, zn and ti become the * offset of the space immediately before it. * Lines 21-23 Are the failure case for line 14. If there is a space four * characters back, it is a three-letter timezone; there must be a * space for the year nine characters back. zn is the zone * offset; ti is the offset of the space. * Lines 24-27 Are the failure case for line 20. If there is a space six * characters back, it is a numeric timezone; there must be a * space eleven characters back and a + or - five characters back. * zn is the zone offset; ti is the offset of the space. * Line 28-31 If ti is valid, make sure that the string before ti is of the * form www mmm dd hh:mm or www mmm dd hh:mm:ss, otherwise * invalidate ti. There must be a colon three characters back * and a space six or nine characters back (depending upon * whether or not the character six characters back is a colon). * There must be a space three characters further back (in front * of the day), one seven characters back (in front of the month), * and one eleven characters back (in front of the day of week). * ti is set to be the offset of the space before the time. * * Why a macro? It gets invoked a *lot* in a tight loop. On some of the * newer pipelined machines it is faster being open-coded than it would be if * subroutines are called. * * Why does it scan backwards from the end of the line, instead of doing the * much easier forward scan? There is no deterministic way to parse the * ``user'' field, because it may contain unquoted spaces! Yes, I tested it to * see if unquoted spaces were possible. They are, and I've encountered enough * evil mail to be totally unwilling to trust that ``it will never happen''. */ /* Build parameters */ #define KODRETRY 15 /* kiss-of-death retry in seconds */ #define LOCKTIMEOUT 5 /* lock timeout in minutes */ /* MMDF I/O stream local data */ typedef struct mmdf_local { unsigned int dirty : 1; /* disk copy needs updating */ unsigned int ddirty : 1; /* double-dirty, ping becomes checkpoint */ unsigned int pseudo : 1; /* uses a pseudo message */ unsigned int appending : 1; /* don't mark new messages as old */ int fd; /* mailbox file descriptor */ int ld; /* lock file descriptor */ char *lname; /* lock file name */ off_t filesize; /* file size parsed */ time_t filetime; /* last file time */ unsigned char *buf; /* temporary buffer */ unsigned long buflen; /* current size of temporary buffer */ unsigned long uid; /* current text uid */ SIZEDTEXT text; /* current text */ unsigned long textlen; /* current text length */ char *line; /* returned line */ char *linebuf; /* line readin buffer */ unsigned long linebuflen; /* current line readin buffer length */ } MMDFLOCAL; /* Convenient access to local data */ #define LOCAL ((MMDFLOCAL *) stream->local) /* MMDF protected file structure */ typedef struct mmdf_file { MAILSTREAM *stream; /* current stream */ off_t curpos; /* current file position */ off_t protect; /* protected position */ off_t filepos; /* current last written file position */ char *buf; /* overflow buffer */ size_t buflen; /* current overflow buffer length */ char *bufpos; /* current buffer position */ } MMDFFILE; /* Function prototypes */ DRIVER *mmdf_valid (char *name); long mmdf_isvalid (char *name,char *tmp); long mmdf_isvalid_fd (int fd,char *tmp); void *mmdf_parameters (long function,void *value); void mmdf_scan (MAILSTREAM *stream,char *ref,char *pat,char *contents); void mmdf_list (MAILSTREAM *stream,char *ref,char *pat); void mmdf_lsub (MAILSTREAM *stream,char *ref,char *pat); long mmdf_create (MAILSTREAM *stream,char *mailbox); long mmdf_delete (MAILSTREAM *stream,char *mailbox); long mmdf_rename (MAILSTREAM *stream,char *old,char *newname); MAILSTREAM *mmdf_open (MAILSTREAM *stream); void mmdf_close (MAILSTREAM *stream,long options); char *mmdf_header (MAILSTREAM *stream,unsigned long msgno, unsigned long *length,long flags); long mmdf_text (MAILSTREAM *stream,unsigned long msgno,STRING *bs,long flags); char *mmdf_text_work (MAILSTREAM *stream,MESSAGECACHE *elt, unsigned long *length,long flags); void mmdf_flagmsg (MAILSTREAM *stream,MESSAGECACHE *elt); long mmdf_ping (MAILSTREAM *stream); void mmdf_check (MAILSTREAM *stream); long mmdf_expunge (MAILSTREAM *stream,char *sequence,long options); long mmdf_copy (MAILSTREAM *stream,char *sequence,char *mailbox,long options); long mmdf_append (MAILSTREAM *stream,char *mailbox,append_t af,void *data); int mmdf_collect_msg (MAILSTREAM *stream,FILE *sf,char *flags,char *date, STRING *msg); int mmdf_append_msgs (MAILSTREAM *stream,FILE *sf,FILE *df,SEARCHSET *set); void mmdf_abort (MAILSTREAM *stream); char *mmdf_file (char *dst,char *name); int mmdf_lock (char *file,int flags,int mode,DOTLOCK *lock,int op); void mmdf_unlock (int fd,MAILSTREAM *stream,DOTLOCK *lock); int mmdf_parse (MAILSTREAM *stream,DOTLOCK *lock,int op); char *mmdf_mbxline (MAILSTREAM *stream,STRING *bs,unsigned long *size); unsigned long mmdf_pseudo (MAILSTREAM *stream,char *hdr); unsigned long mmdf_xstatus (MAILSTREAM *stream,char *status,MESSAGECACHE *elt, unsigned long uid,long flag); long mmdf_rewrite (MAILSTREAM *stream,unsigned long *nexp,DOTLOCK *lock, long flags); long mmdf_extend (MAILSTREAM *stream,unsigned long size); void mmdf_write (MMDFFILE *f,char *s,unsigned long i); void mmdf_phys_write (MMDFFILE *f,char *buf,size_t size); /* MMDF mail routines */ /* Driver dispatch used by MAIL */ DRIVER mmdfdriver = { "mmdf", /* driver name */ /* driver flags */ DR_LOCAL|DR_MAIL|DR_LOCKING|DR_NONEWMAILRONLY|DR_XPOINT, (DRIVER *) NIL, /* next driver */ mmdf_valid, /* mailbox is valid for us */ mmdf_parameters, /* manipulate parameters */ mmdf_scan, /* scan mailboxes */ mmdf_list, /* list mailboxes */ mmdf_lsub, /* list subscribed mailboxes */ NIL, /* subscribe to mailbox */ NIL, /* unsubscribe from mailbox */ mmdf_create, /* create mailbox */ mmdf_delete, /* delete mailbox */ mmdf_rename, /* rename mailbox */ mail_status_default, /* status of mailbox */ mmdf_open, /* open mailbox */ mmdf_close, /* close mailbox */ NIL, /* fetch message "fast" attributes */ NIL, /* fetch message flags */ NIL, /* fetch overview */ NIL, /* fetch message envelopes */ mmdf_header, /* fetch message header */ mmdf_text, /* fetch message text */ NIL, /* fetch partial message text */ NIL, /* unique identifier */ NIL, /* message number */ NIL, /* modify flags */ mmdf_flagmsg, /* per-message modify flags */ NIL, /* search for message based on criteria */ NIL, /* sort messages */ NIL, /* thread messages */ mmdf_ping, /* ping mailbox to see if still alive */ mmdf_check, /* check for new messages */ mmdf_expunge, /* expunge deleted messages */ mmdf_copy, /* copy messages to another mailbox */ mmdf_append, /* append string message to mailbox */ NIL /* garbage collect stream */ }; /* prototype stream */ MAILSTREAM mmdfproto = {&mmdfdriver}; char *mmdfhdr = MMDFHDRTXT; /* MMDF header */ /* MMDF mail validate mailbox * Accepts: mailbox name * Returns: our driver if name is valid, NIL otherwise */ DRIVER *mmdf_valid (char *name) { char tmp[MAILTMPLEN]; return mmdf_isvalid (name,tmp) ? &mmdfdriver : NIL; } /* MMDF mail test for valid mailbox name * Accepts: mailbox name * scratch buffer * Returns: T if valid, NIL otherwise */ long mmdf_isvalid (char *name,char *tmp) { int fd; int ret = NIL; char *t,file[MAILTMPLEN]; struct stat sbuf; time_t tp[2]; errno = EINVAL; /* assume invalid argument */ /* must be non-empty file */ if ((t = dummy_file (file,name)) && !stat (t,&sbuf)) { if (!sbuf.st_size)errno = 0;/* empty file */ else if ((fd = open (file,O_RDONLY,NIL)) >= 0) { /* error -1 for invalid format */ if (!(ret = mmdf_isvalid_fd (fd,tmp))) errno = -1; close (fd); /* close the file */ /* \Marked status? */ if ((sbuf.st_ctime > sbuf.st_atime) || (sbuf.st_mtime > sbuf.st_atime)) { tp[0] = sbuf.st_atime; /* preserve atime and mtime */ tp[1] = sbuf.st_mtime; utime (file,tp); /* set the times */ } } } return ret; /* return what we should */ } /* MMDF mail test for valid mailbox * Accepts: file descriptor * scratch buffer * Returns: T if valid, NIL otherwise */ long mmdf_isvalid_fd (int fd,char *tmp) { int ret = NIL; memset (tmp,'\0',MAILTMPLEN); if (read (fd,tmp,MAILTMPLEN-1) >= 0) ret = ISMMDF (tmp) ? T : NIL; return ret; /* return what we should */ } /* MMDF manipulate driver parameters * Accepts: function code * function-dependent value * Returns: function-dependent return value */ void *mmdf_parameters (long function,void *value) { void *ret = NIL; switch ((int) function) { case GET_INBOXPATH: if (value) ret = dummy_file ((char *) value,"INBOX"); break; } return ret; } /* MMDF mail scan mailboxes * Accepts: mail stream * reference * pattern to search * string to scan */ void mmdf_scan (MAILSTREAM *stream,char *ref,char *pat,char *contents) { if (stream) dummy_scan (NIL,ref,pat,contents); } /* MMDF mail list mailboxes * Accepts: mail stream * reference * pattern to search */ void mmdf_list (MAILSTREAM *stream,char *ref,char *pat) { if (stream) dummy_list (NIL,ref,pat); } /* MMDF mail list subscribed mailboxes * Accepts: mail stream * reference * pattern to search */ void mmdf_lsub (MAILSTREAM *stream,char *ref,char *pat) { if (stream) dummy_lsub (NIL,ref,pat); } /* MMDF mail create mailbox * Accepts: MAIL stream * mailbox name to create * Returns: T on success, NIL on failure */ long mmdf_create (MAILSTREAM *stream,char *mailbox) { char *s,mbx[MAILTMPLEN],tmp[MAILTMPLEN]; long ret = NIL; int i,fd; time_t ti = time (0); if (!(s = dummy_file (mbx,mailbox))) { sprintf (tmp,"Can't create %.80s: invalid name",mailbox); MM_LOG (tmp,ERROR); } /* create underlying file */ else if (dummy_create_path (stream,s,get_dir_protection (mailbox))) { /* done if dir-only or whiner */ if (((s = strrchr (s,'/')) && !s[1]) || mail_parameters (NIL,GET_USERHASNOLIFE,NIL)) ret = T; else if ((fd = open (mbx,O_WRONLY, (long) mail_parameters (NIL,GET_MBXPROTECTION,NIL))) < 0) { sprintf (tmp,"Can't reopen mailbox node %.80s: %s",mbx,strerror (errno)); MM_LOG (tmp,ERROR); unlink (mbx); /* delete the file */ } else { /* initialize header */ memset (tmp,'\0',MAILTMPLEN); sprintf (tmp,"%sFrom %s %sDate: ",mmdfhdr,pseudo_from,ctime (&ti)); rfc822_date (s = tmp + strlen (tmp)); sprintf (s += strlen (s), /* write the pseudo-header */ "\nFrom: %s <%s@%s>\nSubject: %s\nX-IMAP: %010lu 0000000000", pseudo_name,pseudo_from,mylocalhost (),pseudo_subject, (unsigned long) ti); for (i = 0; i < NUSERFLAGS; ++i) if (default_user_flag (i)) sprintf (s += strlen (s)," %s",default_user_flag (i)); sprintf (s += strlen (s),"\nStatus: RO\n\n%s\n%s",pseudo_msg,mmdfhdr); if (write (fd,tmp,strlen (tmp)) > 0) ret = T; else { sprintf (tmp,"Can't initialize mailbox node %.80s: %s",mbx, strerror (errno)); MM_LOG (tmp,ERROR); unlink (mbx); /* delete the file */ } close (fd); /* close file */ } } /* set proper protections */ return ret ? set_mbx_protections (mailbox,mbx) : NIL; } /* MMDF mail delete mailbox * Accepts: MAIL stream * mailbox name to delete * Returns: T on success, NIL on failure */ long mmdf_delete (MAILSTREAM *stream,char *mailbox) { return mmdf_rename (stream,mailbox,NIL); } /* MMDF mail rename mailbox * Accepts: MAIL stream * old mailbox name * new mailbox name (or NIL for delete) * Returns: T on success, NIL on failure */ long mmdf_rename (MAILSTREAM *stream,char *old,char *newname) { long ret = NIL; char c,*s = NIL; char tmp[MAILTMPLEN],file[MAILTMPLEN],lock[MAILTMPLEN]; DOTLOCK lockx; int fd,ld; long i; struct stat sbuf; MM_CRITICAL (stream); /* get the c-client lock */ if (!dummy_file (file,old) || (newname && (!((s = mailboxfile (tmp,newname)) && *s) || ((s = strrchr (tmp,'/')) && !s[1])))) sprintf (tmp,newname ? "Can't rename mailbox %.80s to %.80s: invalid name" : "Can't delete mailbox %.80s: invalid name", old,newname); /* lock out other c-clients */ else if ((ld = lockname (lock,file,LOCK_EX|LOCK_NB,&i)) < 0) sprintf (tmp,"Mailbox %.80s is in use by another process",old); else { if ((fd = mmdf_lock (file,O_RDWR, (long) mail_parameters (NIL,GET_MBXPROTECTION,NIL), &lockx,LOCK_EX)) < 0) sprintf (tmp,"Can't lock mailbox %.80s: %s",old,strerror (errno)); else { if (newname) { /* want rename? */ /* found superior to destination name? */ if (s = strrchr (s,'/')) { c = *++s; /* remember first character of inferior */ *s = '\0'; /* tie off to get just superior */ /* name doesn't exist, create it */ if ((stat (tmp,&sbuf) || ((sbuf.st_mode & S_IFMT) != S_IFDIR)) && !dummy_create_path (stream,tmp,get_dir_protection (newname))) { mmdf_unlock (fd,NIL,&lockx); mmdf_unlock (ld,NIL,NIL); unlink (lock); MM_NOCRITICAL (stream); return ret; /* return success or failure */ } *s = c; /* restore full name */ } if (rename (file,tmp)) sprintf (tmp,"Can't rename mailbox %.80s to %.80s: %s",old,newname, strerror (errno)); else ret = T; /* set success */ } else if (unlink (file)) sprintf (tmp,"Can't delete mailbox %.80s: %s",old,strerror (errno)); else ret = T; /* set success */ mmdf_unlock (fd,NIL,&lockx); } mmdf_unlock (ld,NIL,NIL); /* flush the lock */ unlink (lock); } MM_NOCRITICAL (stream); /* no longer critical */ if (!ret) MM_LOG (tmp,ERROR); /* log error */ return ret; /* return success or failure */ } /* MMDF mail open * Accepts: Stream to open * Returns: Stream on success, NIL on failure */ MAILSTREAM *mmdf_open (MAILSTREAM *stream) { long i; int fd; char tmp[MAILTMPLEN]; DOTLOCK lock; long retry; /* return prototype for OP_PROTOTYPE call */ if (!stream) return user_flags (&mmdfproto); retry = stream->silent ? 1 : KODRETRY; if (stream->local) fatal ("mmdf recycle stream"); stream->local = memset (fs_get (sizeof (MMDFLOCAL)),0,sizeof (MMDFLOCAL)); /* note if an INBOX or not */ stream->inbox = !compare_cstring (stream->mailbox,"INBOX"); /* canonicalize the stream mailbox name */ if (!dummy_file (tmp,stream->mailbox)) { sprintf (tmp,"Can't open - invalid name: %.80s",stream->mailbox); MM_LOG (tmp,ERROR); return NIL; } /* flush old name */ fs_give ((void **) &stream->mailbox); /* save canonical name */ stream->mailbox = cpystr (tmp); LOCAL->fd = LOCAL->ld = -1; /* no file or state locking yet */ LOCAL->buf = (char *) fs_get (CHUNKSIZE); LOCAL->buflen = CHUNKSIZE - 1; LOCAL->text.data = (unsigned char *) fs_get (CHUNKSIZE); LOCAL->text.size = CHUNKSIZE - 1; LOCAL->linebuf = (char *) fs_get (CHUNKSIZE); LOCAL->linebuflen = CHUNKSIZE - 1; stream->sequence++; /* bump sequence number */ /* make lock for read/write access */ if (!stream->rdonly) while (retry) { /* try to lock file */ if ((fd = lockname (tmp,stream->mailbox,LOCK_EX|LOCK_NB,&i)) < 0) { /* suppressing kiss-of-death? */ if (stream->nokod) retry = 0; /* no, first time through? */ else if (retry-- == KODRETRY) { /* learned other guy's PID and can signal? */ if (i && !kill ((int) i,SIGUSR2)) { sprintf (tmp,"Trying to get mailbox lock from process %ld",i); MM_LOG (tmp,WARN); } else retry = 0; /* give up */ } if (!stream->silent) { /* nothing if silent stream */ if (retry) sleep (1); /* wait a second before trying again */ else MM_LOG ("Mailbox is open by another process, access is readonly", WARN); } } else { /* got the lock, nobody else can alter state */ LOCAL->ld = fd; /* note lock's fd and name */ LOCAL->lname = cpystr (tmp); /* make sure mode OK (don't use fchmod()) */ chmod (LOCAL->lname,(long) mail_parameters (NIL,GET_LOCKPROTECTION,NIL)); if (stream->silent) i = 0;/* silent streams won't accept KOD */ else { /* note our PID in the lock */ sprintf (tmp,"%d",getpid ()); write (fd,tmp,(i = strlen (tmp))+1); } ftruncate (fd,i); /* make sure tied off */ fsync (fd); /* make sure it's available */ retry = 0; /* no more need to try */ } } /* parse mailbox */ stream->nmsgs = stream->recent = 0; /* will we be able to get write access? */ if ((LOCAL->ld >= 0) && access (stream->mailbox,W_OK) && (errno == EACCES)) { MM_LOG ("Can't get write access to mailbox, access is readonly",WARN); flock (LOCAL->ld,LOCK_UN); /* release the lock */ close (LOCAL->ld); /* close the lock file */ LOCAL->ld = -1; /* no more lock fd */ unlink (LOCAL->lname); /* delete it */ } /* reset UID validity */ stream->uid_validity = stream->uid_last = 0; if (stream->silent && !stream->rdonly && (LOCAL->ld < 0)) mmdf_abort (stream); /* abort if can't get RW silent stream */ /* parse mailbox */ else if (mmdf_parse (stream,&lock,LOCK_SH)) { mmdf_unlock (LOCAL->fd,stream,&lock); mail_unlock (stream); MM_NOCRITICAL (stream); /* done with critical */ } if (!LOCAL) return NIL; /* failure if stream died */ /* make sure upper level knows readonly */ stream->rdonly = (LOCAL->ld < 0); /* notify about empty mailbox */ if (!(stream->nmsgs || stream->silent)) MM_LOG ("Mailbox is empty",NIL); if (!stream->rdonly) { /* flags stick if readwrite */ stream->perm_seen = stream->perm_deleted = stream->perm_flagged = stream->perm_answered = stream->perm_draft = T; if (!stream->uid_nosticky) {/* users with lives get permanent keywords */ stream->perm_user_flags = 0xffffffff; /* and maybe can create them too! */ stream->kwd_create = stream->user_flags[NUSERFLAGS-1] ? NIL : T; } } return stream; /* return stream alive to caller */ } /* MMDF mail close * Accepts: MAIL stream * close options */ void mmdf_close (MAILSTREAM *stream,long options) { int silent = stream->silent; stream->silent = T; /* go silent */ /* expunge if requested */ if (options & CL_EXPUNGE) mmdf_expunge (stream,NIL,NIL); /* else dump final checkpoint */ else if (LOCAL->dirty) mmdf_check (stream); stream->silent = silent; /* restore old silence state */ mmdf_abort (stream); /* now punt the file and local data */ } /* MMDF mail fetch message header * Accepts: MAIL stream * message # to fetch * pointer to returned header text length * option flags * Returns: message header in RFC822 format */ /* lines to filter from header */ static STRINGLIST *mmdf_hlines = NIL; char *mmdf_header (MAILSTREAM *stream,unsigned long msgno, unsigned long *length,long flags) { MESSAGECACHE *elt; unsigned char *s,*t,*tl; *length = 0; /* default to empty */ if (flags & FT_UID) return "";/* UID call "impossible" */ elt = mail_elt (stream,msgno);/* get cache */ if (!mmdf_hlines) { /* once only code */ STRINGLIST *lines = mmdf_hlines = mail_newstringlist (); lines->text.size = strlen ((char *) (lines->text.data = (unsigned char *) "Status")); lines = lines->next = mail_newstringlist (); lines->text.size = strlen ((char *) (lines->text.data = (unsigned char *) "X-Status")); lines = lines->next = mail_newstringlist (); lines->text.size = strlen ((char *) (lines->text.data = (unsigned char *) "X-Keywords")); lines = lines->next = mail_newstringlist (); lines->text.size = strlen ((char *) (lines->text.data = (unsigned char *) "X-UID")); lines = lines->next = mail_newstringlist (); lines->text.size = strlen ((char *) (lines->text.data = (unsigned char *) "X-IMAP")); lines = lines->next = mail_newstringlist (); lines->text.size = strlen ((char *) (lines->text.data = (unsigned char *) "X-IMAPbase")); } /* go to header position */ lseek (LOCAL->fd,elt->private.special.offset + elt->private.msg.header.offset,L_SET); if (flags & FT_INTERNAL) { /* initial data OK? */ if (elt->private.msg.header.text.size > LOCAL->buflen) { fs_give ((void **) &LOCAL->buf); LOCAL->buf = (char *) fs_get ((LOCAL->buflen = elt->private.msg.header.text.size) + 1); } /* read message */ read (LOCAL->fd,LOCAL->buf,elt->private.msg.header.text.size); /* got text, tie off string */ LOCAL->buf[*length = elt->private.msg.header.text.size] = '\0'; /* squeeze out CRs (in case from PC) */ for (s = t = LOCAL->buf,tl = LOCAL->buf + *length; t < tl; t++) if (*t != '\r') *s++ = *t; *s = '\0'; *length = s - LOCAL->buf; /* adjust length */ } else { /* need to make a CRLF version */ read (LOCAL->fd,s = (char *) fs_get (elt->private.msg.header.text.size+1), elt->private.msg.header.text.size); /* tie off string, and convert to CRLF */ s[elt->private.msg.header.text.size] = '\0'; *length = strcrlfcpy (&LOCAL->buf,&LOCAL->buflen,s, elt->private.msg.header.text.size); fs_give ((void **) &s); /* free readin buffer */ /* squeeze out spurious CRs */ for (s = t = LOCAL->buf,tl = LOCAL->buf + *length; t < tl; t++) if ((*t != '\r') || (t[1] == '\n')) *s++ = *t; *s = '\0'; *length = s - LOCAL->buf; /* adjust length */ } *length = mail_filter (LOCAL->buf,*length,mmdf_hlines,FT_NOT); return (char *) LOCAL->buf; /* return processed copy */ } /* MMDF mail fetch message text * Accepts: MAIL stream * message # to fetch * pointer to returned stringstruct * option flags * Returns: T on success, NIL if failure */ long mmdf_text (MAILSTREAM *stream,unsigned long msgno,STRING *bs,long flags) { char *s; unsigned long i; MESSAGECACHE *elt; /* UID call "impossible" */ if (flags & FT_UID) return NIL; elt = mail_elt (stream,msgno);/* get cache element */ /* if message not seen */ if (!(flags & FT_PEEK) && !elt->seen) { /* mark message seen and dirty */ elt->seen = elt->private.dirty = LOCAL->dirty = T; MM_FLAGS (stream,msgno); } s = mmdf_text_work (stream,elt,&i,flags); INIT (bs,mail_string,s,i); /* set up stringstruct */ return T; /* success */ } /* MMDF mail fetch message text worker routine * Accepts: MAIL stream * message cache element * pointer to returned header text length * option flags */ char *mmdf_text_work (MAILSTREAM *stream,MESSAGECACHE *elt, unsigned long *length,long flags) { FDDATA d; STRING bs; unsigned char c,*s,*t,*tl,tmp[CHUNKSIZE]; /* go to text position */ lseek (LOCAL->fd,elt->private.special.offset + elt->private.msg.text.offset,L_SET); if (flags & FT_INTERNAL) { /* initial data OK? */ if (elt->private.msg.text.text.size > LOCAL->buflen) { fs_give ((void **) &LOCAL->buf); LOCAL->buf = (char *) fs_get ((LOCAL->buflen = elt->private.msg.text.text.size) + 1); } /* read message */ read (LOCAL->fd,LOCAL->buf,elt->private.msg.text.text.size); /* got text, tie off string */ LOCAL->buf[*length = elt->private.msg.text.text.size] = '\0'; /* squeeze out CRs (in case from PC) */ for (s = t = LOCAL->buf,tl = LOCAL->buf + *length; t < tl; t++) if (*t != '\r') *s++ = *t; *s = '\0'; *length = s - LOCAL->buf; /* adjust length */ return (char *) LOCAL->buf; } /* have it cached already? */ if (elt->private.uid != LOCAL->uid) { /* not cached, cache it now */ LOCAL->uid = elt->private.uid; /* is buffer big enough? */ if (elt->rfc822_size > LOCAL->text.size) { /* excessively conservative, but the right thing is too hard to do */ fs_give ((void **) &LOCAL->text.data); LOCAL->text.data = (unsigned char *) fs_get ((LOCAL->text.size = elt->rfc822_size) + 1); } d.fd = LOCAL->fd; /* yes, set up file descriptor */ d.pos = elt->private.special.offset + elt->private.msg.text.offset; d.chunk = tmp; /* initial buffer chunk */ d.chunksize = CHUNKSIZE; /* file chunk size */ INIT (&bs,fd_string,&d,elt->private.msg.text.text.size); for (s = (char *) LOCAL->text.data; SIZE (&bs);) switch (c = SNX (&bs)) { case '\r': /* carriage return seen */ break; case '\n': *s++ = '\r'; /* insert a CR */ default: *s++ = c; /* copy characters */ } *s = '\0'; /* tie off buffer */ /* calculate length of cached data */ LOCAL->textlen = s - LOCAL->text.data; } *length = LOCAL->textlen; /* return from cache */ return (char *) LOCAL->text.data; } /* MMDF per-message modify flag * Accepts: MAIL stream * message cache element */ void mmdf_flagmsg (MAILSTREAM *stream,MESSAGECACHE *elt) { /* only after finishing */ if (elt->valid) elt->private.dirty = LOCAL->dirty = T; } /* MMDF mail ping mailbox * Accepts: MAIL stream * Returns: T if stream alive, else NIL */ long mmdf_ping (MAILSTREAM *stream) { DOTLOCK lock; struct stat sbuf; long reparse; /* big no-op if not readwrite */ if (LOCAL && (LOCAL->ld >= 0) && !stream->lock) { if (stream->rdonly) { /* does he want to give up readwrite? */ /* checkpoint if we changed something */ if (LOCAL->dirty) mmdf_check (stream); flock (LOCAL->ld,LOCK_UN);/* release readwrite lock */ close (LOCAL->ld); /* close the readwrite lock file */ LOCAL->ld = -1; /* no more readwrite lock fd */ unlink (LOCAL->lname); /* delete the readwrite lock file */ } else { /* see if need to reparse */ if (!(reparse = (long) mail_parameters (NIL,GET_NETFSSTATBUG,NIL))) { /* get current mailbox size */ if (LOCAL->fd >= 0) fstat (LOCAL->fd,&sbuf); else if (stat (stream->mailbox,&sbuf)) { sprintf (LOCAL->buf,"Mailbox stat failed, aborted: %s", strerror (errno)); MM_LOG (LOCAL->buf,ERROR); mmdf_abort (stream); return NIL; } reparse = (sbuf.st_size != LOCAL->filesize); } /* parse if mailbox changed */ if ((LOCAL->ddirty || reparse) && mmdf_parse (stream,&lock,LOCK_EX)) { /* force checkpoint if double-dirty */ if (LOCAL->ddirty) mmdf_rewrite (stream,NIL,&lock,NIL); /* unlock mailbox */ else mmdf_unlock (LOCAL->fd,stream,&lock); mail_unlock (stream); /* and stream */ /* done with critical */ MM_NOCRITICAL (stream); } } } return LOCAL ? LONGT : NIL; /* return if still alive */ } /* MMDF mail check mailbox * Accepts: MAIL stream */ void mmdf_check (MAILSTREAM *stream) { DOTLOCK lock; /* parse and lock mailbox */ if (LOCAL && (LOCAL->ld >= 0) && !stream->lock && mmdf_parse (stream,&lock,LOCK_EX)) { /* any unsaved changes? */ if (LOCAL->dirty && mmdf_rewrite (stream,NIL,&lock,NIL)) { if (!stream->silent) MM_LOG ("Checkpoint completed",NIL); } /* no checkpoint needed, just unlock */ else mmdf_unlock (LOCAL->fd,stream,&lock); mail_unlock (stream); /* unlock the stream */ MM_NOCRITICAL (stream); /* done with critical */ } } /* MMDF mail expunge mailbox * Accepts: MAIL stream * sequence to expunge if non-NIL * expunge options * Returns: T, always */ long mmdf_expunge (MAILSTREAM *stream,char *sequence,long options) { long ret; unsigned long i; DOTLOCK lock; char *msg = NIL; if (ret = (sequence ? ((options & EX_UID) ? mail_uid_sequence (stream,sequence) : mail_sequence (stream,sequence)) : LONGT) && LOCAL && (LOCAL->ld >= 0) && !stream->lock && mmdf_parse (stream,&lock,LOCK_EX)) { /* check expunged messages if not dirty */ for (i = 1; !LOCAL->dirty && (i <= stream->nmsgs); i++) { MESSAGECACHE *elt = mail_elt (stream,i); if (mail_elt (stream,i)->deleted) LOCAL->dirty = T; } if (!LOCAL->dirty) { /* not dirty and no expunged messages */ mmdf_unlock (LOCAL->fd,stream,&lock); msg = "No messages deleted, so no update needed"; } else if (mmdf_rewrite (stream,&i,&lock,sequence ? LONGT : NIL)) { if (i) sprintf (msg = LOCAL->buf,"Expunged %lu messages",i); else msg = "Mailbox checkpointed, but no messages expunged"; } /* rewrite failed */ else mmdf_unlock (LOCAL->fd,stream,&lock); mail_unlock (stream); /* unlock the stream */ MM_NOCRITICAL (stream); /* done with critical */ if (msg && !stream->silent) MM_LOG (msg,NIL); } else if (!stream->silent) MM_LOG ("Expunge ignored on readonly mailbox",WARN); return ret; } /* MMDF mail copy message(s) * Accepts: MAIL stream * sequence * destination mailbox * copy options * Returns: T if copy successful, else NIL */ long mmdf_copy (MAILSTREAM *stream,char *sequence,char *mailbox,long options) { struct stat sbuf; int fd; char *s,file[MAILTMPLEN]; DOTLOCK lock; time_t tp[2]; unsigned long i,j; MESSAGECACHE *elt; long ret = T; mailproxycopy_t pc = (mailproxycopy_t) mail_parameters (stream,GET_MAILPROXYCOPY,NIL); copyuid_t cu = (copyuid_t) (mail_parameters (NIL,GET_USERHASNOLIFE,NIL) ? NIL : mail_parameters (NIL,GET_COPYUID,NIL)); SEARCHSET *source = cu ? mail_newsearchset () : NIL; SEARCHSET *dest = cu ? mail_newsearchset () : NIL; MAILSTREAM *tstream = NIL; if (!((options & CP_UID) ? mail_uid_sequence (stream,sequence) : mail_sequence (stream,sequence))) return NIL; /* make sure destination is valid */ if (!(mmdf_valid (mailbox) || !errno)) switch (errno) { case ENOENT: /* no such file? */ if (compare_cstring (mailbox,"INBOX")) { MM_NOTIFY (stream,"[TRYCREATE] Must create mailbox before copy",NIL); return NIL; } if (pc) return (*pc) (stream,sequence,mailbox,options); mmdf_create (NIL,"INBOX");/* create empty INBOX */ case EACCES: /* file protected */ sprintf (LOCAL->buf,"Can't access destination: %.80s",mailbox); MM_LOG (LOCAL->buf,ERROR); return NIL; case EINVAL: if (pc) return (*pc) (stream,sequence,mailbox,options); sprintf (LOCAL->buf,"Invalid MMDF-format mailbox name: %.80s",mailbox); MM_LOG (LOCAL->buf,ERROR); return NIL; default: if (pc) return (*pc) (stream,sequence,mailbox,options); sprintf (LOCAL->buf,"Not a MMDF-format mailbox: %.80s",mailbox); MM_LOG (LOCAL->buf,ERROR); return NIL; } /* try to open rewrite for UIDPLUS */ if ((tstream = mail_open_work (&mmdfdriver,NIL,mailbox, OP_SILENT|OP_NOKOD)) && tstream->rdonly) tstream = mail_close (tstream); if (cu && !tstream) { /* wanted a COPYUID? */ sprintf (LOCAL->buf,"Unable to write-open mailbox for COPYUID: %.80s", mailbox); MM_LOG (LOCAL->buf,WARN); cu = NIL; /* don't try to do COPYUID */ } LOCAL->buf[0] = '\0'; MM_CRITICAL (stream); /* go critical */ if ((fd = mmdf_lock (dummy_file (file,mailbox),O_WRONLY|O_APPEND, (long) mail_parameters (NIL,GET_MBXPROTECTION,NIL), &lock,LOCK_EX)) < 0) { MM_NOCRITICAL (stream); /* done with critical */ sprintf (LOCAL->buf,"Can't open destination mailbox: %s",strerror (errno)); MM_LOG (LOCAL->buf,ERROR); /* log the error */ return NIL; /* failed */ } fstat (fd,&sbuf); /* get current file size */ /* write all requested messages to mailbox */ for (i = 1; ret && (i <= stream->nmsgs); i++) if ((elt = mail_elt (stream,i))->sequence) { lseek (LOCAL->fd,elt->private.special.offset,L_SET); read (LOCAL->fd,LOCAL->buf,elt->private.special.text.size); if (write (fd,LOCAL->buf,elt->private.special.text.size) < 0) ret = NIL; else { /* internal header succeeded */ s = mmdf_header (stream,i,&j,FT_INTERNAL); /* header size, sans trailing newline */ if (j && (s[j - 2] == '\n')) j--; if (write (fd,s,j) < 0) ret = NIL; else { /* message header succeeded */ j = tstream ? /* write UIDPLUS data if have readwrite */ mmdf_xstatus (stream,LOCAL->buf,elt,++(tstream->uid_last),LONGT) : mmdf_xstatus (stream,LOCAL->buf,elt,NIL,NIL); if (write (fd,LOCAL->buf,j) < 0) ret = NIL; else { /* message status succeeded */ s = mmdf_text_work (stream,elt,&j,FT_INTERNAL); if ((write (fd,s,j) < 0) || (write (fd,mmdfhdr,MMDFHDRLEN) < 0)) ret = NIL; else if (cu) { /* need to pass back new UID? */ mail_append_set (source,mail_uid (stream,i)); mail_append_set (dest,tstream->uid_last); } } } } } if (!ret || fsync (fd)) { /* force out the update */ sprintf (LOCAL->buf,"Message copy failed: %s",strerror (errno)); ftruncate (fd,sbuf.st_size); ret = NIL; } /* force UIDVALIDITY assignment now */ if (tstream && !tstream->uid_validity) tstream->uid_validity = time (0); /* return sets if doing COPYUID */ if (cu && ret) (*cu) (stream,mailbox,tstream->uid_validity,source,dest); else { /* flush any sets we may have built */ mail_free_searchset (&source); mail_free_searchset (&dest); } tp[1] = time (0); /* set mtime to now */ if (ret) tp[0] = tp[1] - 1; /* set atime to now-1 if successful copy */ else tp[0] = /* else preserve \Marked status */ ((sbuf.st_ctime > sbuf.st_atime) || (sbuf.st_mtime > sbuf.st_atime)) ? sbuf.st_atime : tp[1]; utime (file,tp); /* set the times */ mmdf_unlock (fd,NIL,&lock); /* unlock and close mailbox */ if (tstream) { /* update last UID if we can */ MMDFLOCAL *local = (MMDFLOCAL *) tstream->local; local->dirty = T; /* do a rewrite */ local->appending = T; /* but not at the cost of marking as old */ tstream = mail_close (tstream); } /* log the error */ if (!ret) MM_LOG (LOCAL->buf,ERROR); /* delete if requested message */ else if (options & CP_MOVE) for (i = 1; i <= stream->nmsgs; i++) if ((elt = mail_elt (stream,i))->sequence) elt->deleted = elt->private.dirty = LOCAL->dirty = T; MM_NOCRITICAL (stream); /* release critical */ return ret; } /* MMDF mail append message from stringstruct * Accepts: MAIL stream * destination mailbox * append callback * data for callback * Returns: T if append successful, else NIL */ #define BUFLEN 8*MAILTMPLEN long mmdf_append (MAILSTREAM *stream,char *mailbox,append_t af,void *data) { struct stat sbuf; int fd; unsigned long i; char *flags,*date,buf[BUFLEN],tmp[MAILTMPLEN],file[MAILTMPLEN]; time_t tp[2]; FILE *sf,*df; MESSAGECACHE elt; DOTLOCK lock; STRING *message; unsigned long uidlocation = 0; appenduid_t au = (appenduid_t) (mail_parameters (NIL,GET_USERHASNOLIFE,NIL) ? NIL : mail_parameters (NIL,GET_APPENDUID,NIL)); SEARCHSET *dst = au ? mail_newsearchset () : NIL; long ret = LONGT; MAILSTREAM *tstream = NIL; /* default stream to prototype */ if (!stream) { /* stream specified? */ stream = &mmdfproto; /* no, default stream to prototype */ for (i = 0; i < NUSERFLAGS && stream->user_flags[i]; ++i) fs_give ((void **) &stream->user_flags[i]); } if (!mmdf_valid (mailbox)) switch (errno) { case ENOENT: /* no such file? */ if (compare_cstring (mailbox,"INBOX")) { MM_NOTIFY (stream,"[TRYCREATE] Must create mailbox before append",NIL); return NIL; } mmdf_create (NIL,"INBOX"); /* create empty INBOX */ case 0: /* merely empty file? */ tstream = stream; break; case EACCES: /* file protected */ sprintf (tmp,"Can't access destination: %.80s",mailbox); MM_LOG (tmp,ERROR); return NIL; case EINVAL: sprintf (tmp,"Invalid MMDF-format mailbox name: %.80s",mailbox); MM_LOG (tmp,ERROR); return NIL; default: sprintf (tmp,"Not a MMDF-format mailbox: %.80s",mailbox); MM_LOG (tmp,ERROR); return NIL; } /* get sniffing stream for keywords */ else if (!(tstream = mail_open (NIL,mailbox, OP_READONLY|OP_SILENT|OP_NOKOD|OP_SNIFF))) { sprintf (tmp,"Unable to examine mailbox for APPEND: %.80s",mailbox); MM_LOG (tmp,ERROR); return NIL; } /* get first message */ if (!MM_APPEND (af) (tstream,data,&flags,&date,&message)) return NIL; if (!(sf = tmpfile ())) { /* must have scratch file */ sprintf (tmp,".%lx.%lx",(unsigned long) time (0),(unsigned long)getpid ()); if (!stat (tmp,&sbuf) || !(sf = fopen (tmp,"wb+"))) { sprintf (tmp,"Unable to create scratch file: %.80s",strerror (errno)); MM_LOG (tmp,ERROR); return NIL; } unlink (tmp); } do { /* parse date */ if (!date) rfc822_date (date = tmp); if (!mail_parse_date (&elt,date)) { sprintf (tmp,"Bad date in append: %.80s",date); MM_LOG (tmp,ERROR); } else { /* user wants to suppress time zones? */ if (mail_parameters (NIL,GET_NOTIMEZONES,NIL)) { time_t when = mail_longdate (&elt); date = ctime (&when); /* use traditional date */ } /* use POSIX-style date */ else date = mail_cdate (tmp,&elt); if (!SIZE (message)) MM_LOG ("Append of zero-length message",ERROR); else if (!mmdf_collect_msg (tstream,sf,flags,date,message)) { sprintf (tmp,"Error writing scratch file: %.80s",strerror (errno)); MM_LOG (tmp,ERROR); } /* get next message */ else if (MM_APPEND (af) (tstream,data,&flags,&date,&message)) continue; } fclose (sf); /* punt scratch file */ return NIL; /* give up */ } while (message); /* until no more messages */ if (fflush (sf)) { sprintf (tmp,"Error finishing scratch file: %.80s",strerror (errno)); MM_LOG (tmp,ERROR); fclose (sf); /* punt scratch file */ return NIL; /* give up */ } i = ftell (sf); /* size of scratch file */ if (tstream != stream) tstream = mail_close (tstream); MM_CRITICAL (stream); /* go critical */ /* try to open readwrite for UIDPLUS */ if ((tstream = mail_open_work (&mmdfdriver,NIL,mailbox, OP_SILENT|OP_NOKOD)) && tstream->rdonly) tstream = mail_close (tstream); if (au && !tstream) { /* wanted an APPENDUID? */ sprintf (tmp,"Unable to re-open mailbox for APPENDUID: %.80s",mailbox); MM_LOG (tmp,WARN); au = NIL; } if (((fd = mmdf_lock (dummy_file (file,mailbox),O_WRONLY|O_APPEND, (long) mail_parameters (NIL,GET_MBXPROTECTION,NIL), &lock,LOCK_EX)) < 0) || !(df = fdopen (fd,"ab"))) { MM_NOCRITICAL (stream); /* done with critical */ sprintf (tmp,"Can't open append mailbox: %s",strerror (errno)); MM_LOG (tmp,ERROR); return NIL; } fstat (fd,&sbuf); /* get current file size */ rewind (sf); tp[1] = time (0); /* set mtime to now */ /* write all messages */ if (!mmdf_append_msgs (tstream,sf,df,au ? dst : NIL) || (fflush (df) == EOF) || fsync (fd)) { sprintf (buf,"Message append failed: %s",strerror (errno)); MM_LOG (buf,ERROR); ftruncate (fd,sbuf.st_size); tp[0] = /* preserve \Marked status */ ((sbuf.st_ctime > sbuf.st_atime) || (sbuf.st_mtime > sbuf.st_atime)) ? sbuf.st_atime : tp[1]; ret = NIL; /* return error */ } else tp[0] = tp[1] - 1; /* set atime to now-1 if successful copy */ utime (file,tp); /* set the times */ fclose (sf); /* done with scratch file */ /* force UIDVALIDITY assignment now */ if (tstream && !tstream->uid_validity) tstream->uid_validity = time (0); /* return sets if doing APPENDUID */ if (au && ret) (*au) (mailbox,tstream->uid_validity,dst); else mail_free_searchset (&dst); mmdf_unlock (fd,NIL,&lock); /* unlock and close mailbox */ fclose (df); if (tstream) { /* update last UID if we can */ MMDFLOCAL *local = (MMDFLOCAL *) tstream->local; local->dirty = T; /* do a rewrite */ local->appending = T; /* but not at the cost of marking as old */ tstream = mail_close (tstream); } MM_NOCRITICAL (stream); /* release critical */ return ret; } /* Collect and write single message to append scratch file * Accepts: MAIL stream * scratch file * flags * date * message stringstruct * Returns: NIL if write error, else T */ int mmdf_collect_msg (MAILSTREAM *stream,FILE *sf,char *flags,char *date, STRING *msg) { unsigned char *s,*t; unsigned long uf; long f = mail_parse_flags (stream,flags,&uf); /* write metadata, note date ends with NL */ if (fprintf (sf,"%ld %lu %s",f,SIZE (msg) + 1,date) < 0) return NIL; while (uf) /* write user flags */ if ((s = stream->user_flags[find_rightmost_bit (&uf)]) && (fprintf (sf," %s",s) < 0)) return NIL; if (putc ('\n',sf) == EOF) return NIL; while (SIZE (msg)) { /* copy text to scratch file */ for (s = (unsigned char *) msg->curpos, t = s + msg->cursize; s < t; ++s) if (!*s) *s = 0x80; /* disallow NUL */ /* write buffered text */ if (fwrite (msg->curpos,1,msg->cursize,sf) == msg->cursize) SETPOS (msg,GETPOS (msg) + msg->cursize); else return NIL; /* failed */ } /* write trailing newline and return */ return (putc ('\n',sf) == EOF) ? NIL : T; } /* Append messages from scratch file to mailbox * Accepts: MAIL stream * source file * destination file * uidset to update if non-NIL * Returns: T if success, NIL if failure */ int mmdf_append_msgs (MAILSTREAM *stream,FILE *sf,FILE *df,SEARCHSET *set) { int c; long f; unsigned long i,j; char *x,tmp[MAILTMPLEN]; int hdrp = T; /* get message metadata line */ while (fgets (tmp,MAILTMPLEN,sf)) { if (!(isdigit (tmp[0]) && strchr (tmp,'\n'))) return NIL; f = strtol (tmp,&x,10); /* get flags */ if (!((*x++ == ' ') && isdigit (*x))) return NIL; i = strtoul (x,&x,10); /* get message size */ if ((*x++ != ' ') || /* build initial header */ (fprintf (df,"%sFrom %s@%s %sStatus: ",mmdfhdr,myusername(), mylocalhost(),x) < 0) || (f&fSEEN && (putc ('R',df) == EOF)) || (fputs ("\nX-Status: ",df) == EOF) || (f&fDELETED && (putc ('D',df) == EOF)) || (f&fFLAGGED && (putc ('F',df) == EOF)) || (f&fANSWERED && (putc ('A',df) == EOF)) || (f&fDRAFT && (putc ('T',df) == EOF)) || (fputs ("\nX-Keywords:",df) == EOF)) return NIL; /* copy keywords */ while ((c = getc (sf)) != '\n') switch (c) { case EOF: return NIL; default: if (putc (c,df) == EOF) return NIL; } if ((putc ('\n',df) == EOF) || (set && (fprintf (df,"X-UID: %lu\n",++(stream->uid_last)) < 0))) return NIL; for (c = '\n'; i && fgets (tmp,MAILTMPLEN,sf); c = tmp[j-1]) { /* get read line length */ if (i < (j = strlen (tmp))) fatal ("mmdf_append_msgs overrun"); i -= j; /* number of bytes left */ /* squish out ^A and CRs (note copies NUL) */ for (x = tmp; x = strpbrk (x,"\01\r"); --j) memmove (x,x+1,j-(x-tmp)); if (!j) continue; /* do nothing if line emptied */ /* start of line? */ if ((c == '\n')) switch (tmp[0]) { case 'S': case 's': /* possible "Status:" */ if (hdrp && (j > 6) && ((tmp[1] == 't') || (tmp[1] == 'T')) && ((tmp[2] == 'a') || (tmp[2] == 'A')) && ((tmp[3] == 't') || (tmp[3] == 'T')) && ((tmp[4] == 'u') || (tmp[4] == 'U')) && ((tmp[5] == 's') || (tmp[5] == 'S')) && (tmp[6] == ':') && (fputs ("X-Original-",df) == EOF)) return NIL; break; case 'X': case 'x': /* possible X-??? header */ if (hdrp && (tmp[1] == '-') && /* possible X-UID: */ (((j > 5) && ((tmp[2] == 'U') || (tmp[2] == 'u')) && ((tmp[3] == 'I') || (tmp[3] == 'i')) && ((tmp[4] == 'D') || (tmp[4] == 'd')) && (tmp[5] == ':')) || /* possible X-IMAP: */ ((j > 6) && ((tmp[2] == 'I') || (tmp[2] == 'i')) && ((tmp[3] == 'M') || (tmp[3] == 'm')) && ((tmp[4] == 'A') || (tmp[4] == 'a')) && ((tmp[5] == 'P') || (tmp[5] == 'p')) && ((tmp[6] == ':') || /* or X-IMAPbase: */ ((j > 10) && ((tmp[6] == 'b') || (tmp[6] == 'B')) && ((tmp[7] == 'a') || (tmp[7] == 'A')) && ((tmp[8] == 's') || (tmp[8] == 'S')) && ((tmp[9] == 'e') || (tmp[9] == 'E')) && (tmp[10] == ':')))) || /* possible X-Status: */ ((j > 8) && ((tmp[2] == 'S') || (tmp[2] == 's')) && ((tmp[3] == 't') || (tmp[3] == 'T')) && ((tmp[4] == 'a') || (tmp[4] == 'A')) && ((tmp[5] == 't') || (tmp[5] == 'T')) && ((tmp[6] == 'u') || (tmp[6] == 'U')) && ((tmp[7] == 's') || (tmp[7] == 'S')) && (tmp[8] == ':')) || /* possible X-Keywords: */ ((j > 10) && ((tmp[2] == 'K') || (tmp[2] == 'k')) && ((tmp[3] == 'e') || (tmp[3] == 'E')) && ((tmp[4] == 'y') || (tmp[4] == 'Y')) && ((tmp[5] == 'w') || (tmp[5] == 'W')) && ((tmp[6] == 'o') || (tmp[6] == 'O')) && ((tmp[7] == 'r') || (tmp[7] == 'R')) && ((tmp[8] == 'd') || (tmp[8] == 'D')) && ((tmp[9] == 's') || (tmp[9] == 'S')) && (tmp[10] == ':'))) && (fputs ("X-Original-",df) == EOF)) return NIL; break; case '\n': /* blank line */ hdrp = NIL; break; default: /* nothing to do */ break; } /* just write the line */ if (fwrite (tmp,1,j,df) != j) return NIL; } /* make sure read entire msg & wrote trailer */ if (i || (fputs (mmdfhdr,df) == EOF)) return NIL; /* update set */ if (stream) mail_append_set (set,stream->uid_last); } return T; } /* Internal routines */ /* MMDF mail abort stream * Accepts: MAIL stream */ void mmdf_abort (MAILSTREAM *stream) { if (LOCAL) { /* only if a file is open */ if (LOCAL->fd >= 0) close (LOCAL->fd); if (LOCAL->ld >= 0) { /* have a mailbox lock? */ flock (LOCAL->ld,LOCK_UN);/* yes, release the lock */ close (LOCAL->ld); /* close the lock file */ unlink (LOCAL->lname); /* and delete it */ } if (LOCAL->lname) fs_give ((void **) &LOCAL->lname); /* free local text buffers */ if (LOCAL->buf) fs_give ((void **) &LOCAL->buf); if (LOCAL->text.data) fs_give ((void **) &LOCAL->text.data); if (LOCAL->linebuf) fs_give ((void **) &LOCAL->linebuf); if (LOCAL->line) fs_give ((void **) &LOCAL->line); /* nuke the local data */ fs_give ((void **) &stream->local); stream->dtb = NIL; /* log out the DTB */ } } /* MMDF open and lock mailbox * Accepts: file name to open/lock * file open mode * destination buffer for lock file name * type of locking operation (LOCK_SH or LOCK_EX) */ int mmdf_lock (char *file,int flags,int mode,DOTLOCK *lock,int op) { int fd; blocknotify_t bn = (blocknotify_t) mail_parameters (NIL,GET_BLOCKNOTIFY,NIL); (*bn) (BLOCK_FILELOCK,NIL); /* try locking the easy way */ if (dotlock_lock (file,lock,-1)) { /* got dotlock file, easy open */ if ((fd = open (file,flags,mode)) >= 0) flock (fd,op); else dotlock_unlock (lock); /* open failed, free the dotlock */ } /* no dot lock file, open file now */ else if ((fd = open (file,flags,mode)) >= 0) { /* try paranoid way to make a dot lock file */ if (dotlock_lock (file,lock,fd)) { close (fd); /* get fresh fd in case of timing race */ if ((fd = open (file,flags,mode)) >= 0) flock (fd,op); /* open failed, free the dotlock */ else dotlock_unlock (lock); } else flock (fd,op); /* paranoid way failed, just flock() it */ } (*bn) (BLOCK_NONE,NIL); return fd; } /* MMDF unlock and close mailbox * Accepts: file descriptor * (optional) mailbox stream to check atime/mtime * (optional) lock file name */ void mmdf_unlock (int fd,MAILSTREAM *stream,DOTLOCK *lock) { if (stream) { /* need to muck with times? */ struct stat sbuf; time_t tp[2]; time_t now = time (0); fstat (fd,&sbuf); /* get file times */ if (LOCAL->ld >= 0) { /* yes, readwrite session? */ tp[0] = now; /* set atime to now */ /* set mtime to (now - 1) if necessary */ tp[1] = (now > sbuf.st_mtime) ? sbuf.st_mtime : now - 1; } else if (stream->recent) { /* readonly with recent messages */ if ((sbuf.st_atime >= sbuf.st_mtime) || (sbuf.st_atime >= sbuf.st_ctime)) /* keep past mtime, whack back atime */ tp[0] = (tp[1] = (sbuf.st_mtime < now) ? sbuf.st_mtime : now) - 1; else now = 0; /* no time change needed */ } /* readonly with no recent messages */ else if ((sbuf.st_atime < sbuf.st_mtime) || (sbuf.st_atime < sbuf.st_ctime)) { tp[0] = now; /* set atime to now */ /* set mtime to (now - 1) if necessary */ tp[1] = (now > sbuf.st_mtime) ? sbuf.st_mtime : now - 1; } else now = 0; /* no time change needed */ /* set the times, note change */ if (now && !utime (stream->mailbox,tp)) LOCAL->filetime = tp[1]; } flock (fd,LOCK_UN); /* release flock'ers */ if (!stream) close (fd); /* close the file if no stream */ dotlock_unlock (lock); /* flush the lock file if any */ } /* MMDF mail parse and lock mailbox * Accepts: MAIL stream * space to write lock file name * type of locking operation * Returns: T if parse OK, critical & mailbox is locked shared; NIL if failure */ int mmdf_parse (MAILSTREAM *stream,DOTLOCK *lock,int op) { int ti,zn,m; unsigned long i,j,k; unsigned char c,*s,*t,*u,tmp[MAILTMPLEN],date[30]; int retain = T; unsigned long nmsgs = stream->nmsgs; unsigned long prevuid = nmsgs ? mail_elt (stream,nmsgs)->private.uid : 0; unsigned long recent = stream->recent; unsigned long oldnmsgs = stream->nmsgs; short silent = stream->silent; short pseudoseen = NIL; struct stat sbuf; STRING bs; FDDATA d; MESSAGECACHE *elt; mail_lock (stream); /* guard against recursion or pingers */ /* toss out previous descriptor */ if (LOCAL->fd >= 0) close (LOCAL->fd); MM_CRITICAL (stream); /* open and lock mailbox (shared OK) */ if ((LOCAL->fd = mmdf_lock (stream->mailbox,(LOCAL->ld >= 0) ? O_RDWR : O_RDONLY, (long)mail_parameters(NIL,GET_MBXPROTECTION,NIL), lock,op)) < 0) { sprintf (tmp,"Mailbox open failed, aborted: %s",strerror (errno)); MM_LOG (tmp,ERROR); mmdf_abort (stream); mail_unlock (stream); MM_NOCRITICAL (stream); /* done with critical */ return NIL; } fstat (LOCAL->fd,&sbuf); /* get status */ /* validate change in size */ if (sbuf.st_size < LOCAL->filesize) { sprintf (tmp,"Mailbox shrank from %lu to %lu bytes, aborted", (unsigned long) LOCAL->filesize,(unsigned long) sbuf.st_size); MM_LOG (tmp,ERROR); /* this is pretty bad */ mmdf_unlock (LOCAL->fd,stream,lock); mmdf_abort (stream); mail_unlock (stream); MM_NOCRITICAL (stream); /* done with critical */ return NIL; } /* new data? */ else if (i = sbuf.st_size - LOCAL->filesize) { d.fd = LOCAL->fd; /* yes, set up file descriptor */ d.pos = LOCAL->filesize; /* get to that position in the file */ d.chunk = LOCAL->buf; /* initial buffer chunk */ d.chunksize = CHUNKSIZE; /* file chunk size */ INIT (&bs,fd_string,&d,i); /* initialize stringstruct */ /* skip leading whitespace for broken MTAs */ while (((c = CHR (&bs)) == '\n') || (c == '\r') || (c == ' ') || (c == '\t')) SNX (&bs); if (SIZE (&bs)) { /* read new data */ /* remember internal header position */ j = LOCAL->filesize + GETPOS (&bs); s = mmdf_mbxline (stream,&bs,&i); stream->silent = T; /* quell main program new message events */ do { /* read MMDF header */ if (!(i && ISMMDF (s))){/* see if valid MMDF header */ sprintf (tmp,"Unexpected changes to mailbox (try restarting): %.20s", (char *) s); /* see if we can back up to a line */ if (i && (j > MMDFHDRLEN)) { SETPOS (&bs,j -= MMDFHDRLEN); /* read previous line */ s = mmdf_mbxline (stream,&bs,&i); /* kill the error if it looks good */ if (i && ISMMDF (s)) tmp[0] = '\0'; } if (tmp[0]) { MM_LOG (tmp,ERROR); mmdf_unlock (LOCAL->fd,stream,lock); mmdf_abort (stream); mail_unlock (stream); MM_NOCRITICAL (stream); return NIL; } } /* instantiate first new message */ mail_exists (stream,++nmsgs); (elt = mail_elt (stream,nmsgs))->valid = T; recent++; /* assume recent by default */ elt->recent = T; /* note position/size of internal header */ elt->private.special.offset = j; elt->private.special.text.size = i; s = mmdf_mbxline (stream,&bs,&i); ti = 0; /* assume not a valid date */ zn = 0,t = NIL; if (i) VALID (s,t,ti,zn); if (ti) { /* generate plausible IMAPish date string */ /* this is also part of header */ elt->private.special.text.size += i; date[2] = date[6] = date[20] = '-'; date[11] = ' '; date[14] = date[17] = ':'; /* dd */ date[0] = t[ti - 2]; date[1] = t[ti - 1]; /* mmm */ date[3] = t[ti - 6]; date[4] = t[ti - 5]; date[5] = t[ti - 4]; /* hh */ date[12] = t[ti + 1]; date[13] = t[ti + 2]; /* mm */ date[15] = t[ti + 4]; date[16] = t[ti + 5]; if (t[ti += 6]==':'){ /* ss */ date[18] = t[++ti]; date[19] = t[++ti]; ti++; /* move to space */ } else date[18] = date[19] = '0'; /* yy -- advance over timezone if necessary */ if (zn == ti) ti += (((t[zn+1] == '+') || (t[zn+1] == '-')) ? 6 : 4); date[7] = t[ti + 1]; date[8] = t[ti + 2]; date[9] = t[ti + 3]; date[10] = t[ti + 4]; /* zzz */ t = zn ? (t + zn + 1) : (unsigned char *) "LCL"; date[21] = *t++; date[22] = *t++; date[23] = *t++; if ((date[21] != '+') && (date[21] != '-')) date[24] = '\0'; else { /* numeric time zone */ date[24] = *t++; date[25] = *t++; date[26] = '\0'; date[20] = ' '; } /* set internal date */ if (!mail_parse_date (elt,date)) { sprintf (tmp,"Unable to parse internal date: %s",(char *) date); MM_LOG (tmp,WARN); } } else { /* make date from file date */ struct tm *tm = gmtime (&sbuf.st_mtime); elt->day = tm->tm_mday; elt->month = tm->tm_mon + 1; elt->year = tm->tm_year + 1900 - BASEYEAR; elt->hours = tm->tm_hour; elt->minutes = tm->tm_min; elt->seconds = tm->tm_sec; elt->zhours = 0; elt->zminutes = 0; t = NIL; /* suppress line read */ } /* header starts here */ elt->private.msg.header.offset = elt->private.special.text.size; do { /* look for message body */ j = GETPOS (&bs); /* note position before line */ if (t) s = t = mmdf_mbxline (stream,&bs,&i); else t = s; /* this line read was suppressed */ if (ISMMDF (s)) { /* found terminator in header? */ SETPOS (&bs,j); /* oops, back up before line */ /* must insert a newline */ elt->private.spare.data++; break; /* punt */ } /* this line is part of header */ elt->private.msg.header.text.size += i; if (i) switch (*s) { /* check header lines */ case 'X': /* possible X-???: line */ if (s[1] == '-') { /* must be immediately followed by hyphen */ /* X-Status: becomes Status: in S case */ if (s[2] == 'S' && s[3] == 't' && s[4] == 'a' && s[5] == 't' && s[6] == 'u' && s[7] == 's' && s[8] == ':') s += 2; /* possible X-Keywords */ else if (s[2] == 'K' && s[3] == 'e' && s[4] == 'y' && s[5] == 'w' && s[6] == 'o' && s[7] == 'r' && s[8] == 'd' && s[9] == 's' && s[10] == ':') { SIZEDTEXT uf; retain = NIL; /* don't retain continuation */ s += 11; /* flush leading whitespace */ while (*s && (*s != '\n') && ((*s != '\r') || (s[1] != '\n'))){ while (*s == ' ') s++; /* find end of keyword */ if (!(u = strpbrk (s," \n\r"))) u = s + strlen (s); /* got a keyword? */ if ((k = (u - s)) && (k <= MAXUSERFLAG)) { uf.data = (unsigned char *) s; uf.size = k; for (j = 0; (j < NUSERFLAGS) && stream->user_flags[j]; ++j) if (!compare_csizedtext (stream->user_flags[j],&uf)) { elt->user_flags |= ((long) 1) << j; break; } } s = u; /* advance to next keyword */ } break; } /* possible X-IMAP */ else if ((s[2] == 'I') && (s[3] == 'M') && (s[4] == 'A') && (s[5] == 'P') && ((m = (s[6] == ':')) || ((s[6] == 'b') && (s[7] == 'a') && (s[8] == 's') && (s[9] == 'e') && (s[10] == ':')))) { retain = NIL; /* don't retain continuation */ if ((nmsgs == 1) && !stream->uid_validity) { /* advance to data */ s += m ? 7 : 11; /* flush whitespace */ while (*s == ' ') s++; j = 0; /* slurp UID validity */ /* found a digit? */ while (isdigit (*s)) { j *= 10; /* yes, add it in */ j += *s++ - '0'; } /* flush whitespace */ while (*s == ' ') s++; /* must have valid UID validity and UID last */ if (j && isdigit (*s)) { /* pseudo-header seen if X-IMAP */ if (m) pseudoseen = LOCAL->pseudo = T; /* save UID validity */ stream->uid_validity = j; j = 0; /* slurp UID last */ while (isdigit (*s)) { j *= 10; /* yes, add it in */ j += *s++ - '0'; } /* save UID last */ stream->uid_last = j; /* process keywords */ for (j = 0; (*s != '\n') && ((*s != '\r')||(s[1] != '\n')); s = u,j++) { /* flush leading whitespace */ while (*s == ' ') s++; u = strpbrk (s," \n\r"); /* got a keyword? */ if ((j < NUSERFLAGS) && (k = (u - s)) && (k <= MAXUSERFLAG)) { if (stream->user_flags[j]) fs_give ((void **) &stream->user_flags[j]); stream->user_flags[j] = (char *) fs_get (k + 1); strncpy (stream->user_flags[j],s,k); stream->user_flags[j][k] = '\0'; } } } } break; } /* possible X-UID */ else if (s[2] == 'U' && s[3] == 'I' && s[4] == 'D' && s[5] == ':') { retain = NIL; /* don't retain continuation */ /* only believe if have a UID validity */ if (stream->uid_validity && ((nmsgs > 1) || !pseudoseen)) { s += 6; /* advance to UID value */ /* flush whitespace */ while (*s == ' ') s++; j = 0; /* found a digit? */ while (isdigit (*s)) { j *= 10; /* yes, add it in */ j += *s++ - '0'; } /* flush remainder of line */ while (*s != '\n') s++; /* make sure not duplicated */ if (elt->private.uid) sprintf (tmp,"Message %lu UID %lu already has UID %lu", pseudoseen ? elt->msgno - 1 : elt->msgno, j,elt->private.uid); /* make sure UID doesn't go backwards */ else if (j <= prevuid) sprintf (tmp,"Message %lu UID %lu less than %lu", pseudoseen ? elt->msgno - 1 : elt->msgno, j,prevuid + 1); #if 0 /* this is currently broken by UIDPLUS */ /* or skip by mailbox's recorded last */ else if (j > stream->uid_last) sprintf (tmp,"Message %lu UID %lu greater than last %lu", pseudoseen ? elt->msgno - 1 : elt->msgno, j,stream->uid_last); #endif else { /* normal UID case */ prevuid = elt->private.uid = j; #if 1 /* temporary kludge for UIDPLUS */ if (prevuid > stream->uid_last) { stream->uid_last = prevuid; LOCAL->ddirty = LOCAL->dirty = T; } #endif break; /* exit this cruft */ } MM_LOG (tmp,WARN); /* invalidate UID validity */ stream->uid_validity = 0; elt->private.uid = 0; } break; } } /* otherwise fall into S case */ case 'S': /* possible Status: line */ if (s[0] == 'S' && s[1] == 't' && s[2] == 'a' && s[3] == 't' && s[4] == 'u' && s[5] == 's' && s[6] == ':') { retain = NIL; /* don't retain continuation */ s += 6; /* advance to status flags */ do switch (*s++) {/* parse flags */ case 'R': /* message read */ elt->seen = T; break; case 'O': /* message old */ if (elt->recent) { elt->recent = NIL; recent--; /* it really wasn't recent */ } break; case 'D': /* message deleted */ elt->deleted = T; break; case 'F': /* message flagged */ elt->flagged = T; break; case 'A': /* message answered */ elt->answered = T; break; case 'T': /* message is a draft */ elt->draft = T; break; default: /* some other crap */ break; } while (*s && (*s != '\n') && ((*s != '\r') || (s[1] != '\n'))); break; /* all done */ } /* otherwise fall into default case */ default: /* ordinary header line */ if ((*s == 'S') || (*s == 's') || (((*s == 'X') || (*s == 'x')) && (s[1] == '-'))) { unsigned char *e,*v; /* must match what mail_filter() does */ for (u = s,v = tmp,e = u + min (i,MAILTMPLEN - 1); (u < e) && ((c = (*u ? *u : (*u = ' '))) != ':') && ((c > ' ') || ((c != ' ') && (c != '\t') && (c != '\r') && (c != '\n'))); *v++ = *u++); *v = '\0'; /* tie off */ /* matches internal header? */ if (!compare_cstring (tmp,"STATUS") || !compare_cstring (tmp,"X-STATUS") || !compare_cstring (tmp,"X-KEYWORDS") || !compare_cstring (tmp,"X-UID") || !compare_cstring (tmp,"X-IMAP") || !compare_cstring (tmp,"X-IMAPBASE")) { char err[MAILTMPLEN]; sprintf (err,"Discarding bogus %s header in message %lu", (char *) tmp,elt->msgno); MM_LOG (err,WARN); retain = NIL; /* don't retain continuation */ break; /* different case or something */ } } /* retain or non-continuation? */ if (retain || ((*s != ' ') && (*s != '\t'))) { retain = T; /* retaining continuation now */ /* line length in LF format newline */ for (j = k = 0; j < i; ++j) if (s[j] != '\r') ++k; /* "internal" header size */ elt->private.spare.data += k; /* message size */ elt->rfc822_size += k + 1; } else { char err[MAILTMPLEN]; sprintf (err,"Discarding bogus continuation in msg %lu: %.80s", elt->msgno,(char *) s); if (u = strpbrk (err,"\r\n")) *u = '\0'; MM_LOG (err,WARN); break; /* different case or something */ } break; } } while (i && (*t != '\n') && ((*t != '\r') || (t[1] != '\n'))); /* "internal" header sans trailing newline */ if (i) elt->private.spare.data--; /* assign a UID if none found */ if (((nmsgs > 1) || !pseudoseen) && !elt->private.uid) { prevuid = elt->private.uid = ++stream->uid_last; elt->private.dirty = T; } else elt->private.dirty = elt->recent; /* note size of header, location of text */ elt->private.msg.header.text.size = (elt->private.msg.text.offset = (LOCAL->filesize + GETPOS (&bs)) - elt->private.special.offset) - elt->private.special.text.size; /* note current position */ j = LOCAL->filesize + GETPOS (&bs); if (i) do { /* look for next message */ s = mmdf_mbxline (stream,&bs,&i); if (i) { /* got new data? */ if (ISMMDF (s)) break; else { /* not a header line, add it to message */ elt->rfc822_size += i; for (j = 0; j < i; ++j) switch (s[j]) { case '\r': /* squeeze out CRs */ elt->rfc822_size -= 1; break; case '\n': /* LF becomes CRLF */ elt->rfc822_size += 1; break; default: break; } /* update current position */ j = LOCAL->filesize + GETPOS (&bs); } } } while (i); /* until found a header */ elt->private.msg.text.text.size = j - (elt->private.special.offset + elt->private.msg.text.offset); if (i) { /* get next header line */ /* remember first internal header position */ j = LOCAL->filesize + GETPOS (&bs); s = mmdf_mbxline (stream,&bs,&i); } /* until end of buffer */ } while (!stream->sniff && i); if (pseudoseen) { /* flush pseudo-message if present */ /* decrement recent count */ if (mail_elt (stream,1)->recent) recent--; /* and the exists count */ mail_exists (stream,nmsgs--); mail_expunged(stream,1);/* fake an expunge of that message */ } /* need to start a new UID validity? */ if (!stream->uid_validity) { stream->uid_validity = time (0); /* in case a whiner with no life */ if (mail_parameters (NIL,GET_USERHASNOLIFE,NIL)) stream->uid_nosticky = T; else if (nmsgs) { /* don't bother if empty file */ /* make dirty to restart UID epoch */ LOCAL->ddirty = LOCAL->dirty = T; /* need to rewrite msg 1 if not pseudo */ if (!LOCAL->pseudo) mail_elt (stream,1)->private.dirty = T; MM_LOG ("Assigning new unique identifiers to all messages",NIL); } } stream->nmsgs = oldnmsgs; /* whack it back down */ stream->silent = silent; /* restore old silent setting */ /* notify upper level of new mailbox sizes */ mail_exists (stream,nmsgs); mail_recent (stream,recent); /* mark dirty so O flags are set */ if (recent) LOCAL->dirty = T; } } /* no change, don't babble if never got time */ else if (LOCAL->filetime && LOCAL->filetime != sbuf.st_mtime) MM_LOG ("New mailbox modification time but apparently no changes",WARN); /* update parsed file size and time */ LOCAL->filesize = sbuf.st_size; LOCAL->filetime = sbuf.st_mtime; return T; /* return the winnage */ } /* MMDF read line from mailbox * Accepts: mail stream * stringstruct * pointer to line size * Returns: pointer to input line */ char *mmdf_mbxline (MAILSTREAM *stream,STRING *bs,unsigned long *size) { unsigned long i,j,k,m; char *s,*t,*te; char *ret = ""; /* flush old buffer */ if (LOCAL->line) fs_give ((void **) &LOCAL->line); /* if buffer needs refreshing */ if (!bs->cursize) SETPOS (bs,GETPOS (bs)); if (SIZE (bs)) { /* find newline */ /* end of fast scan */ te = (t = (s = bs->curpos) + bs->cursize) - 12; while (s < te) if ((*s++ == '\n') || (*s++ == '\n') || (*s++ == '\n') || (*s++ == '\n') || (*s++ == '\n') || (*s++ == '\n') || (*s++ == '\n') || (*s++ == '\n') || (*s++ == '\n') || (*s++ == '\n') || (*s++ == '\n') || (*s++ == '\n')) { --s; /* back up */ break; /* exit loop */ } /* final character-at-a-time scan */ while ((s < t) && (*s != '\n')) ++s; /* difficult case if line spans buffer */ if ((i = s - bs->curpos) == bs->cursize) { /* have space in line buffer? */ if (i > LOCAL->linebuflen) { fs_give ((void **) &LOCAL->linebuf); LOCAL->linebuf = (char *) fs_get (LOCAL->linebuflen = i); } /* remember what we have so far */ memcpy (LOCAL->linebuf,bs->curpos,i); /* load next buffer */ SETPOS (bs,k = GETPOS (bs) + i); /* end of fast scan */ te = (t = (s = bs->curpos) + bs->cursize) - 12; /* fast scan in overlap buffer */ while (s < te) if ((*s++ == '\n') || (*s++ == '\n') || (*s++ == '\n') || (*s++ == '\n') || (*s++ == '\n') || (*s++ == '\n') || (*s++ == '\n') || (*s++ == '\n') || (*s++ == '\n') || (*s++ == '\n') || (*s++ == '\n') || (*s++ == '\n')) { --s; /* back up */ break; /* exit loop */ } /* final character-at-a-time scan */ while ((s < t) && (*s != '\n')) ++s; /* huge line? */ if ((j = s - bs->curpos) == bs->cursize) { SETPOS (bs,GETPOS (bs) + j); /* look for end of line (s-l-o-w!!) */ for (m = SIZE (bs); m && (SNX (bs) != '\n'); --m,++j); SETPOS (bs,k); /* go back to where it started */ } /* got size of data, make buffer for return */ ret = LOCAL->line = (char *) fs_get (i + j + 2); /* copy first chunk */ memcpy (ret,LOCAL->linebuf,i); while (j) { /* copy remainder */ if (!bs->cursize) SETPOS (bs,GETPOS (bs)); memcpy (ret + i,bs->curpos,k = min (j,bs->cursize)); i += k; /* account for this much read in */ j -= k; bs->curpos += k; /* increment new position */ bs->cursize -= k; /* eat that many bytes */ } /* read newline at end */ if (SIZE (bs)) ret[i++] = SNX (bs); ret[i] = '\0'; /* makes debugging easier */ } else { /* this is easy */ ret = bs->curpos; /* string it at this position */ bs->curpos += ++i; /* increment new position */ bs->cursize -= i; /* eat that many bytes */ } *size = i; /* return that to user */ } else *size = 0; /* end of data, return empty */ /* embedded MMDF header at end of line? */ if ((*size > sizeof (MMDFHDRTXT)) && (s = ret + *size - (i = sizeof (MMDFHDRTXT) - 1)) && ISMMDF (s)) { SETPOS (bs,GETPOS (bs) - i);/* back up to start of MMDF header */ *size -= i; /* reduce length of line */ ret[*size - 1] = '\n'; /* force newline at end */ } return ret; } /* MMDF make pseudo-header * Accepts: MAIL stream * buffer to write pseudo-header * Returns: length of pseudo-header */ unsigned long mmdf_pseudo (MAILSTREAM *stream,char *hdr) { int i; char *s,tmp[MAILTMPLEN]; time_t now = time (0); rfc822_fixed_date (tmp); sprintf (hdr,"%sFrom %s %.24s\nDate: %s\nFrom: %s <%s@%.80s>\nSubject: %s\nMessage-ID: <%lu@%.80s>\nX-IMAP: %010lu %010lu", mmdfhdr,pseudo_from,ctime (&now), tmp,pseudo_name,pseudo_from,mylocalhost (),pseudo_subject, (unsigned long) now,mylocalhost (),stream->uid_validity, stream->uid_last); for (s = hdr + strlen (hdr),i = 0; i < NUSERFLAGS; ++i) if (stream->user_flags[i]) sprintf (s += strlen (s)," %s",stream->user_flags[i]); sprintf (s += strlen (s),"\nStatus: RO\n\n%s\n%s",pseudo_msg,mmdfhdr); return strlen (hdr); } /* MMDF make status string * Accepts: MAIL stream * destination string to write * message cache entry * UID to write if non-zero (else use elt->private.uid) * non-zero flag to write UID (.LT. 0 to write UID base info too) * Returns: length of string */ unsigned long mmdf_xstatus (MAILSTREAM *stream,char *status,MESSAGECACHE *elt, unsigned long uid,long flag) { char *t,stack[64]; char *s = status; unsigned long n; int pad = 50; int sticky = uid ? T : !stream->uid_nosticky; /* This used to use sprintf(), but thanks to certain cretinous C libraries with horribly slow implementations of sprintf() I had to change it to this mess. At least it should be fast. */ if ((flag < 0) && sticky) { /* need to write X-IMAPbase: header? */ *s++ = 'X'; *s++ = '-'; *s++ = 'I'; *s++ = 'M'; *s++ = 'A'; *s++ = 'P'; *s++ = 'b'; *s++ = 'a'; *s++ = 's'; *s++ = 'e'; *s++ = ':'; *s++ = ' '; t = stack; n = stream->uid_validity; /* push UID validity digits on the stack */ do *t++ = (char) (n % 10) + '0'; while (n /= 10); /* pop UID validity digits from stack */ while (t > stack) *s++ = *--t; *s++ = ' '; n = stream->uid_last; /* push UID last digits on the stack */ do *t++ = (char) (n % 10) + '0'; while (n /= 10); /* pop UID last digits from stack */ while (t > stack) *s++ = *--t; for (n = 0; n < NUSERFLAGS; ++n) if (t = stream->user_flags[n]) for (*s++ = ' '; *t; *s++ = *t++); *s++ = '\n'; pad += 30; /* increased padding if have IMAPbase */ } *s++ = 'S'; *s++ = 't'; *s++ = 'a'; *s++ = 't'; *s++ = 'u'; *s++ = 's'; *s++ = ':'; *s++ = ' '; if (elt->seen) *s++ = 'R'; /* only write O if have a UID */ if (flag && (!elt->recent || !LOCAL->appending)) *s++ = 'O'; *s++ = '\n'; *s++ = 'X'; *s++ = '-'; *s++ = 'S'; *s++ = 't'; *s++ = 'a'; *s++ = 't'; *s++ = 'u'; *s++ = 's'; *s++ = ':'; *s++ = ' '; if (elt->deleted) *s++ = 'D'; if (elt->flagged) *s++ = 'F'; if (elt->answered) *s++ = 'A'; if (elt->draft) *s++ = 'T'; *s++ = '\n'; if (sticky) { /* only do this if UIDs sticky */ *s++ = 'X'; *s++ = '-'; *s++ = 'K'; *s++ = 'e'; *s++ = 'y'; *s++ = 'w'; *s++ = 'o'; *s++ = 'r'; *s++ = 'd'; *s++ = 's'; *s++ = ':'; if (n = elt->user_flags) do { *s++ = ' '; for (t = stream->user_flags[find_rightmost_bit (&n)]; *t; *s++ = *t++); } while (n); n = s - status; /* get size of stuff so far */ /* pad X-Keywords to make size constant */ if (n < pad) for (n = pad - n; n > 0; --n) *s++ = ' '; *s++ = '\n'; if (flag) { /* want to include UID? */ t = stack; /* push UID digits on the stack */ n = uid ? uid : elt->private.uid; do *t++ = (char) (n % 10) + '0'; while (n /= 10); *s++ = 'X'; *s++ = '-'; *s++ = 'U'; *s++ = 'I'; *s++ = 'D'; *s++ = ':'; *s++ = ' '; /* pop UID from stack */ while (t > stack) *s++ = *--t; *s++ = '\n'; } } *s++ = '\n'; *s = '\0'; /* end of extended message status */ return s - status; /* return size of resulting string */ } /* Rewrite mailbox file * Accepts: MAIL stream, must be critical and locked * return pointer to number of expunged messages if want expunge * lock file name * expunge sequence, not deleted flag * Returns: T if success and mailbox unlocked, NIL if failure */ #define OVERFLOWBUFLEN 8192 /* initial overflow buffer length */ long mmdf_rewrite (MAILSTREAM *stream,unsigned long *nexp,DOTLOCK *lock, long flags) { MESSAGECACHE *elt; MMDFFILE f; char *s; time_t tp[2]; long ret,flag; unsigned long i,j; unsigned long recent = stream->recent; unsigned long size = LOCAL->pseudo ? mmdf_pseudo (stream,LOCAL->buf) : 0; if (nexp) *nexp = 0; /* initially nothing expunged */ /* calculate size of mailbox after rewrite */ for (i = 1,flag = LOCAL->pseudo ? 1 : -1; i <= stream->nmsgs; i++) { elt = mail_elt (stream,i); /* get cache */ if (!(nexp && elt->deleted && (flags ? elt->sequence : T))) { /* add RFC822 size of this message */ size += elt->private.special.text.size + elt->private.spare.data + mmdf_xstatus (stream,LOCAL->buf,elt,NIL,flag) + elt->private.msg.text.text.size + MMDFHDRLEN; flag = 1; /* only count X-IMAPbase once */ } } /* no messages, has a life, and no pseudo */ if (!size && !mail_parameters (NIL,GET_USERHASNOLIFE,NIL)) { LOCAL->pseudo = T; /* so make a pseudo-message now */ size = mmdf_pseudo (stream,LOCAL->buf); } /* extend the file as necessary */ if (ret = mmdf_extend (stream,size)) { /* Set up buffered I/O file structure * curpos current position being written through buffering * filepos current position being written physically to the disk * bufpos current position being written in the buffer * protect current maximum position that can be written to the disk * before buffering is forced * The code tries to buffer so that that disk is written in multiples of * OVERBLOWBUFLEN bytes. */ f.stream = stream; /* note mail stream */ f.curpos = f.filepos = 0; /* start of file */ f.protect = stream->nmsgs ? /* initial protection pointer */ mail_elt (stream,1)->private.special.offset : 8192; f.bufpos = f.buf = (char *) fs_get (f.buflen = OVERFLOWBUFLEN); if (LOCAL->pseudo) /* update pseudo-header */ mmdf_write (&f,LOCAL->buf,mmdf_pseudo (stream,LOCAL->buf)); /* loop through all messages */ for (i = 1,flag = LOCAL->pseudo ? 1 : -1; i <= stream->nmsgs;) { elt = mail_elt (stream,i);/* get cache */ /* expunge this message? */ if (nexp && elt->deleted && (flags ? elt->sequence : T)) { /* one less recent message */ if (elt->recent) --recent; mail_expunged(stream,i);/* notify upper levels */ ++*nexp; /* count up one more expunged message */ } else { /* preserve this message */ i++; /* advance to next message */ if ((flag < 0) || /* need to rewrite message? */ elt->private.dirty || (f.curpos != elt->private.special.offset) || (elt->private.msg.header.text.size != (elt->private.spare.data + mmdf_xstatus (stream,LOCAL->buf,elt,NIL,flag)))) { unsigned long newoffset = f.curpos; /* yes, seek to internal header */ lseek (LOCAL->fd,elt->private.special.offset,L_SET); read (LOCAL->fd,LOCAL->buf,elt->private.special.text.size); /* see if need to squeeze out a CR */ if (LOCAL->buf[elt->private.special.text.size - 2] == '\r') { LOCAL->buf[--elt->private.special.text.size - 1] = '\n'; --size; /* squeezed out a CR from PC */ } /* protection pointer moves to RFC822 header */ f.protect = elt->private.special.offset + elt->private.msg.header.offset; /* write internal header */ mmdf_write (&f,LOCAL->buf,elt->private.special.text.size); /* get RFC822 header */ s = mmdf_header (stream,elt->msgno,&j,FT_INTERNAL); /* in case this got decremented */ elt->private.msg.header.offset = elt->private.special.text.size; /* header size, sans trailing newline */ if ((j < 2) || (s[j - 2] == '\n')) j--; /* this can happen if CRs were squeezed */ if (j < elt->private.spare.data) { /* so fix up counts */ size -= elt->private.spare.data - j; elt->private.spare.data = j; } else if (j != elt->private.spare.data) fatal ("header size inconsistent"); /* protection pointer moves to RFC822 text */ f.protect = elt->private.special.offset + elt->private.msg.text.offset; mmdf_write (&f,s,j); /* write RFC822 header */ /* write status and UID */ mmdf_write (&f,LOCAL->buf, j = mmdf_xstatus (stream,LOCAL->buf,elt,NIL,flag)); flag = 1; /* only write X-IMAPbase once */ /* new file header size */ elt->private.msg.header.text.size = elt->private.spare.data + j; /* did text move? */ if (f.curpos != f.protect) { /* get message text */ s = mmdf_text_work (stream,elt,&j,FT_INTERNAL); /* this can happen if CRs were squeezed */ if (j < elt->private.msg.text.text.size) { /* so fix up counts */ size -= elt->private.msg.text.text.size - j; elt->private.msg.text.text.size = j; } /* can't happen it says here */ else if (j > elt->private.msg.text.text.size) fatal ("text size inconsistent"); /* new text offset, status/UID may change it */ elt->private.msg.text.offset = f.curpos - newoffset; /* protection pointer moves to next message */ f.protect = (i <= stream->nmsgs) ? mail_elt (stream,i)->private.special.offset : (f.curpos + j + MMDFHDRLEN); mmdf_write (&f,s,j);/* write text */ /* write trailing newline */ mmdf_write (&f,mmdfhdr,MMDFHDRLEN); } else { /* tie off header and status */ mmdf_write (&f,NIL,NIL); f.curpos = f.protect =/* restart everything at end of message */ f.filepos += elt->private.msg.text.text.size + MMDFHDRLEN; } /* new internal header offset */ elt->private.special.offset = newoffset; elt->private.dirty =NIL;/* message is now clean */ } else { /* no need to rewrite this message */ /* tie off previous message if needed */ mmdf_write (&f,NIL,NIL); f.curpos = f.protect =/* restart everything at end of message */ f.filepos += elt->private.special.text.size + elt->private.msg.header.text.size + elt->private.msg.text.text.size + MMDFHDRLEN; } } } mmdf_write (&f,NIL,NIL); /* tie off final message */ if (size != f.filepos) fatal ("file size inconsistent"); fs_give ((void **) &f.buf); /* free buffer */ /* make sure tied off */ ftruncate (LOCAL->fd,LOCAL->filesize = size); fsync (LOCAL->fd); /* make sure the updates take */ if (size && (flag < 0)) fatal ("lost UID base information"); /* no longer dirty */ LOCAL->ddirty = LOCAL->dirty = NIL; /* notify upper level of new mailbox sizes */ mail_exists (stream,stream->nmsgs); mail_recent (stream,recent); /* set atime to now, mtime a second earlier */ tp[1] = (tp[0] = time (0)) - 1; /* set the times, note change */ if (!utime (stream->mailbox,tp)) LOCAL->filetime = tp[1]; close (LOCAL->fd); /* close and reopen file */ if ((LOCAL->fd = open (stream->mailbox,O_RDWR, (long) mail_parameters (NIL,GET_MBXPROTECTION,NIL))) < 0) { sprintf (LOCAL->buf,"Mailbox open failed, aborted: %s",strerror (errno)); MM_LOG (LOCAL->buf,ERROR); mmdf_abort (stream); } dotlock_unlock (lock); /* flush the lock file */ } return ret; /* return state from algorithm */ } /* Extend MMDF mailbox file * Accepts: MAIL stream * new desired size * Return: T if success, else NIL */ long mmdf_extend (MAILSTREAM *stream,unsigned long size) { unsigned long i = (size > LOCAL->filesize) ? size - LOCAL->filesize : 0; if (i) { /* does the mailbox need to grow? */ if (i > LOCAL->buflen) { /* make sure have enough space */ /* this user won the lottery all right */ fs_give ((void **) &LOCAL->buf); LOCAL->buf = (char *) fs_get ((LOCAL->buflen = i) + 1); } memset (LOCAL->buf,'\0',i); /* get a block of nulls */ while (T) { /* until write successful or punt */ lseek (LOCAL->fd,LOCAL->filesize,L_SET); if ((write (LOCAL->fd,LOCAL->buf,i) >= 0) && !fsync (LOCAL->fd)) break; else { long e = errno; /* note error before doing ftruncate */ ftruncate (LOCAL->fd,LOCAL->filesize); if (MM_DISKERROR (stream,e,NIL)) { fsync (LOCAL->fd); /* user chose to punt */ sprintf (LOCAL->buf,"Unable to extend mailbox: %s",strerror (e)); if (!stream->silent) MM_LOG (LOCAL->buf,ERROR); return NIL; } } } } return LONGT; } /* Write data to buffered file * Accepts: buffered file pointer * file data or NIL to indicate "flush buffer" * date size (ignored for "flush buffer") * Does not return until success */ void mmdf_write (MMDFFILE *f,char *buf,unsigned long size) { unsigned long i,j,k; if (buf) { /* doing buffered write? */ i = f->bufpos - f->buf; /* yes, get size of current buffer data */ /* yes, have space in current buffer chunk? */ if (j = i ? ((f->buflen - i) % OVERFLOWBUFLEN) : f->buflen) { /* yes, fill up buffer as much as we can */ memcpy (f->bufpos,buf,k = min (j,size)); f->bufpos += k; /* new buffer position */ f->curpos += k; /* new current position */ if (j -= k) return; /* all done if still have buffer free space */ buf += k; /* full, get new unwritten data pointer */ size -= k; /* new data size */ i += k; /* new buffer data size */ } /* This chunk of the buffer is full. See if can make some space by * writing to the disk, if there's enough unprotected space to do so. * Try to fill out any unaligned chunk, along with any subsequent full * chunks that will fit in unprotected space. */ /* any unprotected space we can write to? */ if (j = min (i,f->protect - f->filepos)) { /* yes, filepos not at chunk boundary? */ if ((k = f->filepos % OVERFLOWBUFLEN) && ((k = OVERFLOWBUFLEN - k) < j)) j -= k; /* yes, and can write out partial chunk */ else k = 0; /* no partial chunk to write */ /* if at least a chunk free, write that too */ if (j > OVERFLOWBUFLEN) k += j - (j % OVERFLOWBUFLEN); if (k) { /* write data if there is anything we can */ mmdf_phys_write (f,f->buf,k); /* slide buffer */ if (i -= k) memmove (f->buf,f->buf + k,i); f->bufpos = f->buf + i; /* new end of buffer */ } } /* Have flushed the buffer as best as possible. All done if no more * data to write. Otherwise, if the buffer is empty AND if the unwritten * data is larger than a chunk AND the unprotected space is also larger * than a chunk, then write as many chunks as we can directly from the * data. Buffer the rest, expanding the buffer as needed. */ if (size) { /* have more data that we need to buffer? */ /* can write any of it to disk instead? */ if ((f->bufpos == f->buf) && ((j = min (f->protect - f->filepos,size)) > OVERFLOWBUFLEN)) { /* write as much as we can right now */ mmdf_phys_write (f,buf,j -= (j % OVERFLOWBUFLEN)); buf += j; /* new data pointer */ size -= j; /* new data size */ f->curpos += j; /* advance current pointer */ } if (size) { /* still have data that we need to buffer? */ /* yes, need to expand the buffer? */ if ((i = ((f->bufpos + size) - f->buf)) > f->buflen) { /* note current position in buffer */ j = f->bufpos - f->buf; i += OVERFLOWBUFLEN; /* yes, grow another chunk */ fs_resize ((void **) &f->buf,f->buflen = i - (i % OVERFLOWBUFLEN)); /* in case buffer relocated */ f->bufpos = f->buf + j; } /* buffer remaining data */ memcpy (f->bufpos,buf,size); f->bufpos += size; /* new end of buffer */ f->curpos += size; /* advance current pointer */ } } } else { /* flush buffer to disk */ mmdf_phys_write (f,f->buf,i = f->bufpos - f->buf); f->bufpos = f->buf; /* reset buffer */ /* update positions */ f->curpos = f->protect = f->filepos; } } /* Physical disk write * Accepts: buffered file pointer * buffer address * buffer size * Does not return until success */ void mmdf_phys_write (MMDFFILE *f,char *buf,size_t size) { MAILSTREAM *stream = f->stream; /* write data at desired position */ while (size && ((lseek (LOCAL->fd,f->filepos,L_SET) < 0) || (write (LOCAL->fd,buf,size) < 0))) { int e; char tmp[MAILTMPLEN]; sprintf (tmp,"Unable to write to mailbox: %s",strerror (e = errno)); MM_LOG (tmp,ERROR); MM_DISKERROR (NIL,e,T); /* serious problem, must retry */ } f->filepos += size; /* update file position */ } alpine-2.10+dfsg/imap/src/osdep/amiga/tcp_ami.c0000600000175000017500000006051011512502124023023 0ustar paulproteuspaulproteus/* ======================================================================== * Copyright 1988-2008 University of Washington * * Licensed under the Apache License, Version 2.0 (the "License"); * you may not use this file except in compliance with the License. * You may obtain a copy of the License at * * http://www.apache.org/licenses/LICENSE-2.0 * * * ======================================================================== */ /* * Program: Amiga TCP/IP routines * * Author: Mark Crispin * Networks and Distributed Computing * Computing & Communications * University of Washington * Administration Building, AG-44 * Seattle, WA 98195 * Internet: MRC@CAC.Washington.EDU * * Date: 1 August 1988 * Last Edited: 13 January 2008 */ #undef write /* don't use redefined write() */ static tcptimeout_t tmoh = NIL; /* TCP timeout handler routine */ static long ttmo_open = 0; /* TCP timeouts, in seconds */ static long ttmo_read = 0; static long ttmo_write = 0; static long allowreversedns = T;/* allow reverse DNS lookup */ static long tcpdebug = NIL; /* extra TCP debugging telemetry */ extern long maxposint; /* get this from write.c */ /* Local function prototypes */ int tcp_socket_open (struct sockaddr_in *sin,char *tmp,int *ctr,char *hst, unsigned long port); static char *tcp_getline_work (TCPSTREAM *stream,unsigned long *size, long *contd); long tcp_abort (TCPSTREAM *stream); char *tcp_name (struct sockaddr_in *sin,long flag); char *tcp_name_valid (char *s); /* TCP/IP manipulate parameters * Accepts: function code * function-dependent value * Returns: function-dependent return value */ void *tcp_parameters (long function,void *value) { void *ret = NIL; switch ((int) function) { case SET_TIMEOUT: tmoh = (tcptimeout_t) value; case GET_TIMEOUT: ret = (void *) tmoh; break; case SET_OPENTIMEOUT: ttmo_open = (long) value; case GET_OPENTIMEOUT: ret = (void *) ttmo_open; break; case SET_READTIMEOUT: ttmo_read = (long) value; case GET_READTIMEOUT: ret = (void *) ttmo_read; break; case SET_WRITETIMEOUT: ttmo_write = (long) value; case GET_WRITETIMEOUT: ret = (void *) ttmo_write; break; case SET_ALLOWREVERSEDNS: allowreversedns = (long) value; case GET_ALLOWREVERSEDNS: ret = (void *) allowreversedns; break; case SET_TCPDEBUG: tcpdebug = (long) value; case GET_TCPDEBUG: ret = (void *) tcpdebug; break; } return ret; } /* TCP/IP open * Accepts: host name * contact service name * contact port number and optional silent flag * Returns: TCP/IP stream if success else NIL */ TCPSTREAM *tcp_open (char *host,char *service,unsigned long port) { TCPSTREAM *stream = NIL; int i; int sock = -1; int ctr = 0; int silent = (port & NET_SILENT) ? T : NIL; int *ctrp = (port & NET_NOOPENTIMEOUT) ? NIL : &ctr; char *s; struct sockaddr_in sin; struct hostent *he; char hostname[MAILTMPLEN]; char tmp[MAILTMPLEN]; struct servent *sv = NIL; blocknotify_t bn = (blocknotify_t) mail_parameters (NIL,GET_BLOCKNOTIFY,NIL); void *data; port &= 0xffff; /* erase flags */ /* lookup service */ if (service && (sv = getservbyname (service,"tcp"))) port = ntohs (sin.sin_port = sv->s_port); /* copy port number in network format */ else sin.sin_port = htons (port); /* The domain literal form is used (rather than simply the dotted decimal as with other Amiga programs) because it has to be a valid "host name" in mailsystem terminology. */ /* look like domain literal? */ if (host[0] == '[' && host[(strlen (host))-1] == ']') { strcpy (hostname,host+1); /* yes, copy number part */ hostname[(strlen (hostname))-1] = '\0'; if ((sin.sin_addr.s_addr = inet_addr (hostname)) == -1) sprintf (tmp,"Bad format domain-literal: %.80s",host); else { sin.sin_family = AF_INET; /* family is always Internet */ strcpy (hostname,host); /* hostname is user's argument */ (*bn) (BLOCK_TCPOPEN,NIL); /* get an open socket for this system */ sock = tcp_socket_open (&sin,tmp,ctrp,hostname,port); (*bn) (BLOCK_NONE,NIL); } } else { /* lookup host name */ if (tcpdebug) { sprintf (tmp,"DNS resolution %.80s",host); mm_log (tmp,TCPDEBUG); } (*bn) (BLOCK_DNSLOOKUP,NIL);/* quell alarms */ data = (*bn) (BLOCK_SENSITIVE,NIL); if (!(he = gethostbyname (lcase (strcpy (hostname,host))))) sprintf (tmp,"No such host as %.80s",host); (*bn) (BLOCK_NONSENSITIVE,data); (*bn) (BLOCK_NONE,NIL); if (he) { /* DNS resolution won? */ if (tcpdebug) mm_log ("DNS resolution done",TCPDEBUG); /* copy address type */ sin.sin_family = he->h_addrtype; /* copy host name */ strcpy (hostname,he->h_name); #ifdef HOST_NOT_FOUND /* muliple addresses only on DNS systems */ for (sock = -1,i = 0; (sock < 0) && (s = he->h_addr_list[i]); i++) { if (i && !silent) mm_log (tmp,WARN); memcpy (&sin.sin_addr,s,he->h_length); (*bn) (BLOCK_TCPOPEN,NIL); sock = tcp_socket_open (&sin,tmp,ctrp,hostname,port); (*bn) (BLOCK_NONE,NIL); } #else /* the one true address then */ memcpy (&sin.sin_addr,he->h_addr,he->h_length); (*bn) (BLOCK_TCPOPEN,NIL); sock = tcp_socket_open (&sin,tmp,ctrp,hostname,port); (*bn) (BLOCK_NONE,NIL); #endif } } if (sock >= 0) { /* won */ stream = (TCPSTREAM *) memset (fs_get (sizeof (TCPSTREAM)),0, sizeof (TCPSTREAM)); stream->port = port; /* port number */ /* init sockets */ stream->tcpsi = stream->tcpso = sock; /* stash in the snuck-in byte */ if (stream->ictr = ctr) *(stream->iptr = stream->ibuf) = tmp[0]; /* copy official host name */ stream->host = cpystr (hostname); if (tcpdebug) mm_log ("Stream open and ready for read",TCPDEBUG); } else if (!silent) mm_log (tmp,ERROR); return stream; /* return success */ } /* Open a TCP socket * Accepts: Internet socket address block * scratch buffer * pointer to "first byte read in" storage or NIL * host name for error message * port number for error message * Returns: socket if success, else -1 with error string in scratch buffer */ int tcp_socket_open (struct sockaddr_in *sin,char *tmp,int *ctr,char *hst, unsigned long port) { int i,ti,sock,flgs; time_t now; struct protoent *pt = getprotobyname ("tcp"); fd_set fds,efds; struct timeval tmo; blocknotify_t bn = (blocknotify_t) mail_parameters (NIL,GET_BLOCKNOTIFY,NIL); void *data = (*bn) (BLOCK_SENSITIVE,NIL); sprintf (tmp,"Trying IP address [%s]",inet_ntoa (sin->sin_addr)); mm_log (tmp,NIL); /* make a socket */ if ((sock = socket (sin->sin_family,SOCK_STREAM,pt ? pt->p_proto : 0)) < 0) { sprintf (tmp,"Unable to create TCP socket: %s",strerror (errno)); (*bn) (BLOCK_NONSENSITIVE,data); return -1; } else if (sock >= FD_SETSIZE) {/* unselectable sockets are useless */ sprintf (tmp,"Unable to create selectable TCP socket (%d >= %d)", sock,FD_SETSIZE); (*bn) (BLOCK_NONSENSITIVE,data); close (sock); errno = EMFILE; return -1; } flgs = fcntl (sock,F_GETFL,0);/* get current socket flags */ /* set non-blocking if want open timeout */ if (ctr) fcntl (sock,F_SETFL,flgs | FNDELAY); /* open connection */ while ((i = connect (sock,(struct sockaddr *) sin, sizeof (struct sockaddr_in))) < 0 && (errno == EINTR)); (*bn) (BLOCK_NONSENSITIVE,data); if (i < 0) switch (errno) { /* failed? */ case EAGAIN: /* DG brain damage */ case EINPROGRESS: /* what we expect to happen */ case EALREADY: /* or another form of it */ case EISCONN: /* restart after interrupt? */ case EADDRINUSE: /* restart after interrupt? */ break; /* well, not really, it was interrupted */ default: sprintf (tmp,"Can't connect to %.80s,%lu: %s",hst,port,strerror (errno)); close (sock); /* flush socket */ return -1; } if (ctr) { /* want open timeout */ now = time (0); /* open timeout */ ti = ttmo_open ? now + ttmo_open : 0; tmo.tv_usec = 0; FD_ZERO (&fds); /* initialize selection vector */ FD_ZERO (&efds); /* handle errors too */ FD_SET (sock,&fds); /* block for error or readable */ FD_SET (sock,&efds); do { /* block under timeout */ tmo.tv_sec = ti ? ti - now : 0; i = select (sock+1,&fds,0,&efds,ti ? &tmo : 0); now = time (0); /* fake timeout if interrupt & time expired */ if ((i < 0) && (errno == EINTR) && ti && (ti <= now)) i = 0; } while ((i < 0) && (errno == EINTR)); if (i > 0) { /* success, make sure really connected */ fcntl (sock,F_SETFL,flgs);/* restore blocking status */ /* This used to be a zero-byte read(), but that crashes Solaris */ /* get socket status */ while (((i = *ctr = read (sock,tmp,1)) < 0) && (errno == EINTR)); } if (i <= 0) { /* timeout or error? */ i = i ? errno : ETIMEDOUT;/* determine error code */ close (sock); /* flush socket */ errno = i; /* return error code */ sprintf (tmp,"Connection failed to %.80s,%lu: %s",hst,port, strerror (errno)); return -1; } } return sock; /* return the socket */ } /* TCP/IP authenticated open * Accepts: host name * service name * returned user name buffer * Returns: TCP/IP stream if success else NIL */ TCPSTREAM *tcp_aopen (NETMBX *mb,char *service,char *usrbuf) { return NIL; /* disabled */ } /* TCP receive line * Accepts: TCP stream * Returns: text line string or NIL if failure */ char *tcp_getline (TCPSTREAM *stream) { unsigned long n,contd; char *ret = tcp_getline_work (stream,&n,&contd); if (ret && contd) { /* got a line needing continuation? */ STRINGLIST *stl = mail_newstringlist (); STRINGLIST *stc = stl; do { /* collect additional lines */ stc->text.data = (unsigned char *) ret; stc->text.size = n; stc = stc->next = mail_newstringlist (); ret = tcp_getline_work (stream,&n,&contd); } while (ret && contd); if (ret) { /* stash final part of line on list */ stc->text.data = (unsigned char *) ret; stc->text.size = n; /* determine how large a buffer we need */ for (n = 0, stc = stl; stc; stc = stc->next) n += stc->text.size; ret = fs_get (n + 1); /* copy parts into buffer */ for (n = 0, stc = stl; stc; n += stc->text.size, stc = stc->next) memcpy (ret + n,stc->text.data,stc->text.size); ret[n] = '\0'; } mail_free_stringlist (&stl);/* either way, done with list */ } return ret; } /* TCP receive line or partial line * Accepts: TCP stream * pointer to return size * pointer to return continuation flag * Returns: text line string, size and continuation flag, or NIL if failure */ static char *tcp_getline_work (TCPSTREAM *stream,unsigned long *size, long *contd) { unsigned long n; char *s,*ret,c,d; *contd = NIL; /* assume no continuation */ /* make sure have data */ if (!tcp_getdata (stream)) return NIL; for (s = stream->iptr, n = 0, c = '\0'; stream->ictr--; n++, c = d) { d = *stream->iptr++; /* slurp another character */ if ((c == '\015') && (d == '\012')) { ret = (char *) fs_get (n--); memcpy (ret,s,*size = n); /* copy into a free storage string */ ret[n] = '\0'; /* tie off string with null */ return ret; } } /* copy partial string from buffer */ memcpy ((ret = (char *) fs_get (n)),s,*size = n); /* get more data from the net */ if (!tcp_getdata (stream)) fs_give ((void **) &ret); /* special case of newline broken by buffer */ else if ((c == '\015') && (*stream->iptr == '\012')) { stream->iptr++; /* eat the line feed */ stream->ictr--; ret[*size = --n] = '\0'; /* tie off string with null */ } else *contd = LONGT; /* continuation needed */ return ret; } /* TCP/IP receive buffer * Accepts: TCP/IP stream * size in bytes * buffer to read into * Returns: T if success, NIL otherwise */ long tcp_getbuffer (TCPSTREAM *stream,unsigned long size,char *s) { unsigned long n; /* make sure socket still alive */ if (stream->tcpsi < 0) return NIL; /* can transfer bytes from buffer? */ if (n = min (size,stream->ictr)) { memcpy (s,stream->iptr,n); /* yes, slurp as much as we can from it */ s += n; /* update pointer */ stream->iptr +=n; size -= n; /* update # of bytes to do */ stream->ictr -=n; } if (size) { int i; fd_set fds,efds; struct timeval tmo; time_t t = time (0); blocknotify_t bn=(blocknotify_t) mail_parameters (NIL,GET_BLOCKNOTIFY,NIL); (*bn) (BLOCK_TCPREAD,NIL); while (size > 0) { /* until request satisfied */ time_t tl = time (0); time_t now = tl; time_t ti = ttmo_read ? now + ttmo_read : 0; if (tcpdebug) mm_log ("Reading TCP buffer",TCPDEBUG); tmo.tv_usec = 0; FD_ZERO (&fds); /* initialize selection vector */ FD_ZERO (&efds); /* handle errors too */ FD_SET (stream->tcpsi,&fds); FD_SET (stream->tcpsi,&efds); errno = NIL; /* block and read */ do { /* block under timeout */ tmo.tv_sec = ti ? ti - now : 0; i = select (stream->tcpsi+1,&fds,0,&efds,ti ? &tmo : 0); now = time (0); /* fake timeout if interrupt & time expired */ if ((i < 0) && (errno == EINTR) && ti && (ti <= now)) i = 0; } while ((i < 0) && (errno == EINTR)); if (i > 0) { /* select says there's data to read? */ while (((i = read (stream->tcpsi,s,(int) min (maxposint,size))) < 0) && (errno == EINTR)); if (i < 1) return tcp_abort (stream); s += i; /* point at new place to write */ size -= i; /* reduce byte count */ if (tcpdebug) mm_log ("Successfully read TCP buffer",TCPDEBUG); } else if (i || !tmoh || !(*tmoh) (now - t,now - tl)) return tcp_abort (stream); } (*bn) (BLOCK_NONE,NIL); } *s = '\0'; /* tie off string */ return T; } /* TCP/IP receive data * Accepts: TCP/IP stream * Returns: T if success, NIL otherwise */ long tcp_getdata (TCPSTREAM *stream) { int i; fd_set fds,efds; struct timeval tmo; time_t t = time (0); blocknotify_t bn = (blocknotify_t) mail_parameters (NIL,GET_BLOCKNOTIFY,NIL); if (stream->tcpsi < 0) return NIL; (*bn) (BLOCK_TCPREAD,NIL); while (stream->ictr < 1) { /* if nothing in the buffer */ time_t tl = time (0); /* start of request */ time_t now = tl; time_t ti = ttmo_read ? now + ttmo_read : 0; if (tcpdebug) mm_log ("Reading TCP data",TCPDEBUG); tmo.tv_usec = 0; FD_ZERO (&fds); /* initialize selection vector */ FD_ZERO (&efds); /* handle errors too */ FD_SET (stream->tcpsi,&fds);/* set bit in selection vector */ FD_SET(stream->tcpsi,&efds);/* set bit in error selection vector */ errno = NIL; /* block and read */ do { /* block under timeout */ tmo.tv_sec = ti ? ti - now : 0; i = select (stream->tcpsi+1,&fds,0,&efds,ti ? &tmo : 0); now = time (0); /* fake timeout if interrupt & time expired */ if ((i < 0) && (errno == EINTR) && ti && (ti <= now)) i = 0; } while ((i < 0) && (errno == EINTR)); if (i > 0) { /* got data? */ while (((i = read (stream->tcpsi,stream->ibuf,BUFLEN)) < 0) && (errno == EINTR)); if (i < 1) return tcp_abort (stream); stream->iptr = stream->ibuf;/* point at TCP buffer */ stream->ictr = i; /* set new byte count */ if (tcpdebug) mm_log ("Successfully read TCP data",TCPDEBUG); } else if (i || !tmoh || !(*tmoh) (now - t,now - tl)) return tcp_abort (stream);/* error or timeout no-continue */ } (*bn) (BLOCK_NONE,NIL); return T; } /* TCP/IP send string as record * Accepts: TCP/IP stream * string pointer * Returns: T if success else NIL */ long tcp_soutr (TCPSTREAM *stream,char *string) { return tcp_sout (stream,string,(unsigned long) strlen (string)); } /* TCP/IP send string * Accepts: TCP/IP stream * string pointer * byte count * Returns: T if success else NIL */ long tcp_sout (TCPSTREAM *stream,char *string,unsigned long size) { int i; fd_set fds,efds; struct timeval tmo; time_t t = time (0); blocknotify_t bn = (blocknotify_t) mail_parameters (NIL,GET_BLOCKNOTIFY,NIL); if (stream->tcpso < 0) return NIL; (*bn) (BLOCK_TCPWRITE,NIL); while (size > 0) { /* until request satisfied */ time_t tl = time (0); /* start of request */ time_t now = tl; time_t ti = ttmo_write ? now + ttmo_write : 0; if (tcpdebug) mm_log ("Writing to TCP",TCPDEBUG); tmo.tv_usec = 0; FD_ZERO (&fds); /* initialize selection vector */ FD_ZERO (&efds); /* handle errors too */ FD_SET (stream->tcpso,&fds);/* set bit in selection vector */ FD_SET(stream->tcpso,&efds);/* set bit in error selection vector */ errno = NIL; /* block and write */ do { /* block under timeout */ tmo.tv_sec = ti ? ti - now : 0; i = select (stream->tcpso+1,0,&fds,&efds,ti ? &tmo : 0); now = time (0); /* fake timeout if interrupt & time expired */ if ((i < 0) && (errno == EINTR) && ti && (ti <= now)) i = 0; } while ((i < 0) && (errno == EINTR)); if (i > 0) { /* OK to send data? */ while (((i = write (stream->tcpso,string,size)) < 0) &&(errno == EINTR)); if (i < 0) return tcp_abort (stream); size -= i; /* how much we sent */ string += i; if (tcpdebug) mm_log ("successfully wrote to TCP",TCPDEBUG); } else if (i || !tmoh || !(*tmoh) (now - t,now - tl)) return tcp_abort (stream);/* error or timeout no-continue */ } (*bn) (BLOCK_NONE,NIL); return T; /* all done */ } /* TCP/IP close * Accepts: TCP/IP stream */ void tcp_close (TCPSTREAM *stream) { tcp_abort (stream); /* nuke the stream */ /* flush host names */ if (stream->host) fs_give ((void **) &stream->host); if (stream->remotehost) fs_give ((void **) &stream->remotehost); if (stream->localhost) fs_give ((void **) &stream->localhost); fs_give ((void **) &stream); /* flush the stream */ } /* TCP/IP abort stream * Accepts: TCP/IP stream * Returns: NIL always */ long tcp_abort (TCPSTREAM *stream) { blocknotify_t bn = (blocknotify_t) mail_parameters (NIL,GET_BLOCKNOTIFY,NIL); if (stream->tcpsi >= 0) { /* no-op if no socket */ (*bn) (BLOCK_TCPCLOSE,NIL); close (stream->tcpsi); /* nuke the socket */ if (stream->tcpsi != stream->tcpso) close (stream->tcpso); stream->tcpsi = stream->tcpso = -1; } (*bn) (BLOCK_NONE,NIL); return NIL; } /* TCP/IP get host name * Accepts: TCP/IP stream * Returns: host name for this stream */ char *tcp_host (TCPSTREAM *stream) { return stream->host; /* use tcp_remotehost() if want guarantees */ } /* TCP/IP get remote host name * Accepts: TCP/IP stream * Returns: host name for this stream */ char *tcp_remotehost (TCPSTREAM *stream) { if (!stream->remotehost) { struct sockaddr_in sin; int sinlen = sizeof (struct sockaddr_in); stream->remotehost = /* get socket's peer name */ (getpeername (stream->tcpsi,(struct sockaddr *) &sin,(void *) &sinlen) || (sin.sin_family != AF_INET)) ? cpystr (stream->host) : tcp_name (&sin,NIL); } return stream->remotehost; } /* TCP/IP return port for this stream * Accepts: TCP/IP stream * Returns: port number for this stream */ unsigned long tcp_port (TCPSTREAM *stream) { return stream->port; /* return port number */ } /* TCP/IP get local host name * Accepts: TCP/IP stream * Returns: local host name */ char *tcp_localhost (TCPSTREAM *stream) { if (!stream->localhost) { struct sockaddr_in sin; int sinlen = sizeof (struct sockaddr_in); stream->localhost = /* get socket's name */ ((stream->port & 0xffff000) || getsockname (stream->tcpsi,(struct sockaddr *) &sin,(void *) &sinlen) || (sin.sin_family != AF_INET)) ? cpystr (mylocalhost ()) : tcp_name (&sin,NIL); } return stream->localhost; /* return local host name */ } /* TCP/IP get client host address (server calls only) * Returns: client host address */ static char *myClientAddr = NIL; char *tcp_clientaddr () { if (!myClientAddr) { struct sockaddr_in sin; int sinlen = sizeof (struct sockaddr_in); myClientAddr = /* get stdin's peer name */ cpystr (getpeername (0,(struct sockaddr *) &sin,(void *) &sinlen) ? "UNKNOWN" : ((sin.sin_family == AF_INET) ? inet_ntoa (sin.sin_addr) : "NON-IPv4")); } return myClientAddr; } /* TCP/IP get client host name (server calls only) * Returns: client host name */ static char *myClientHost = NIL; char *tcp_clienthost () { if (!myClientHost) { struct sockaddr_in sin; int sinlen = sizeof (struct sockaddr_in); myClientHost = /* get stdin's peer name */ getpeername (0,(struct sockaddr *) &sin,(void *) &sinlen) ? cpystr ("UNKNOWN") : ((sin.sin_family == AF_INET) ? tcp_name (&sin,T) : cpystr ("NON-IPv4")); } return myClientHost; } /* TCP/IP get server host address (server calls only) * Returns: server host address */ static char *myServerAddr = NIL; char *tcp_serveraddr () { if (!myServerAddr) { struct sockaddr_in sin; int sinlen = sizeof (struct sockaddr_in); myServerAddr = /* get stdin's peer name */ cpystr (getsockname (0,(struct sockaddr *) &sin,(void *) &sinlen) ? "UNKNOWN" : ((sin.sin_family == AF_INET) ? inet_ntoa (sin.sin_addr) : "NON-IPv4")); } return myServerAddr; } /* TCP/IP get server host name (server calls only) * Returns: server host name */ static char *myServerHost = NIL; static long myServerPort = -1; char *tcp_serverhost () { if (!myServerHost) { struct sockaddr_in sin; int sinlen = sizeof (struct sockaddr_in); /* get stdin's name */ if (getsockname (0,(struct sockaddr *) &sin,(void *) &sinlen) || (sin.sin_family != AF_INET)) myServerHost = cpystr (mylocalhost ()); else { myServerHost = tcp_name (&sin,NIL); myServerPort = ntohs (sin.sin_port); } } return myServerHost; } /* TCP/IP get server port number (server calls only) * Returns: server port number */ long tcp_serverport () { if (!myServerHost) tcp_serverhost (); return myServerPort; } /* TCP/IP return canonical form of host name * Accepts: host name * Returns: canonical form of host name */ char *tcp_canonical (char *name) { char *ret,host[MAILTMPLEN]; struct hostent *he; blocknotify_t bn = (blocknotify_t) mail_parameters (NIL,GET_BLOCKNOTIFY,NIL); void *data; /* look like domain literal? */ if (name[0] == '[' && name[strlen (name) - 1] == ']') return name; (*bn) (BLOCK_DNSLOOKUP,NIL); /* quell alarms */ data = (*bn) (BLOCK_SENSITIVE,NIL); if (tcpdebug) { sprintf (host,"DNS canonicalization %.80s",name); mm_log (host,TCPDEBUG); } /* note that Amiga requires lowercase! */ ret = (he = gethostbyname (lcase (strcpy (host,name)))) ? (char *) he->h_name : name; (*bn) (BLOCK_NONSENSITIVE,data); (*bn) (BLOCK_NONE,NIL); /* alarms OK now */ if (tcpdebug) mm_log ("DNS canonicalization done",TCPDEBUG); return ret; } /* TCP/IP return name from socket * Accepts: socket * verbose flag * Returns: cpystr name */ char *tcp_name (struct sockaddr_in *sin,long flag) { char *ret,*t,adr[MAILTMPLEN],tmp[MAILTMPLEN]; sprintf (ret = adr,"[%.80s]",inet_ntoa (sin->sin_addr)); if (allowreversedns) { struct hostent *he; blocknotify_t bn = (blocknotify_t)mail_parameters(NIL,GET_BLOCKNOTIFY,NIL); void *data; if (tcpdebug) { sprintf (tmp,"Reverse DNS resolution %s",adr); mm_log (tmp,TCPDEBUG); } (*bn) (BLOCK_DNSLOOKUP,NIL);/* quell alarms */ data = (*bn) (BLOCK_SENSITIVE,NIL); /* translate address to name */ if (t = tcp_name_valid ((he = gethostbyaddr ((char *) &sin->sin_addr, sizeof (struct in_addr), sin->sin_family)) ? (char *) he->h_name : NIL)) { /* produce verbose form if needed */ if (flag) sprintf (ret = tmp,"%s %s",t,adr); else ret = t; } (*bn) (BLOCK_NONSENSITIVE,data); (*bn) (BLOCK_NONE,NIL); /* alarms OK now */ if (tcpdebug) mm_log ("Reverse DNS resolution done",TCPDEBUG); } return cpystr (ret); } /* Validate name * Accepts: domain name * Returns: T if valid, NIL otherwise */ char *tcp_name_valid (char *s) { int c; char *ret,*tail; /* must be non-empty and not too long */ if ((ret = (s && *s) ? s : NIL) && (tail = ret + NETMAXHOST)) { /* must be alnum, dot, or hyphen */ while ((c = *s++) && (s <= tail) && (((c >= 'A') && (c <= 'Z')) || ((c >= 'a') && (c <= 'z')) || ((c >= '0') && (c <= '9')) || (c == '-') || (c == '.'))); if (c) ret = NIL; } return ret; } alpine-2.10+dfsg/imap/src/osdep/amiga/fdstring.h0000600000175000017500000000205711512502124023236 0ustar paulproteuspaulproteus/* ======================================================================== * Copyright 1988-2006 University of Washington * * Licensed under the Apache License, Version 2.0 (the "License"); * you may not use this file except in compliance with the License. * You may obtain a copy of the License at * * http://www.apache.org/licenses/LICENSE-2.0 * * * ======================================================================== */ /* * Program: File descriptor string routines * * Author: Mark Crispin * Networks and Distributed Computing * Computing & Communications * University of Washington * Administration Building, AG-44 * Seattle, WA 98195 * Internet: MRC@CAC.Washington.EDU * * Date: 15 April 1997 * Last Edited: 30 August 2006 */ /* Driver-dependent data passed to init method */ typedef struct fd_data { int fd; /* file descriptor */ unsigned long pos; /* initial position */ char *chunk; /* I/O buffer chunk */ unsigned long chunksize; /* I/O buffer chunk length */ } FDDATA; extern STRINGDRIVER fd_string; alpine-2.10+dfsg/imap/src/osdep/amiga/dummy.h0000600000175000017500000000276411512502124022556 0ustar paulproteuspaulproteus/* ======================================================================== * Copyright 1988-2006 University of Washington * * Licensed under the Apache License, Version 2.0 (the "License"); * you may not use this file except in compliance with the License. * You may obtain a copy of the License at * * http://www.apache.org/licenses/LICENSE-2.0 * * * ======================================================================== */ /* * Program: Dummy routines * * Author: Mark Crispin * Networks and Distributed Computing * Computing & Communications * University of Washington * Administration Building, AG-44 * Seattle, WA 98195 * Internet: MRC@CAC.Washington.EDU * * Date: 9 May 1991 * Last Edited: 30 August 2006 */ /* Exported function prototypes */ void dummy_scan (MAILSTREAM *stream,char *ref,char *pat,char *contents); void dummy_list (MAILSTREAM *stream,char *ref,char *pat); void dummy_lsub (MAILSTREAM *stream,char *ref,char *pat); long scan_contents (DRIVER *dtb,char *name,char *contents, unsigned long csiz,unsigned long fsiz); long dummy_scan_contents (char *name,char *contents,unsigned long csiz, unsigned long fsiz); long dummy_create (MAILSTREAM *stream,char *mailbox); long dummy_create_path (MAILSTREAM *stream,char *path,long dirmode); long dummy_delete (MAILSTREAM *stream,char *mailbox); long dummy_rename (MAILSTREAM *stream,char *old,char *newname); char *dummy_file (char *dst,char *name); long dummy_canonicalize (char *tmp,char *ref,char *pat); alpine-2.10+dfsg/imap/src/osdep/amiga/phile.c0000600000175000017500000004043711512502124022516 0ustar paulproteuspaulproteus/* ======================================================================== * Copyright 1988-2006 University of Washington * * Licensed under the Apache License, Version 2.0 (the "License"); * you may not use this file except in compliance with the License. * You may obtain a copy of the License at * * http://www.apache.org/licenses/LICENSE-2.0 * * * ======================================================================== */ /* * Program: File routines * * Author: Mark Crispin * Networks and Distributed Computing * Computing & Communications * University of Washington * Administration Building, AG-44 * Seattle, WA 98195 * Internet: MRC@CAC.Washington.EDU * * Date: 25 August 1993 * Last Edited: 9 May 2006 */ #include #include #include extern int errno; /* just in case */ #include #include "mail.h" #include "osdep.h" #include #include #include #include "rfc822.h" #include "misc.h" #include "dummy.h" /* Types returned from phile_type() */ #define PTYPEBINARY 0 /* binary data */ #define PTYPETEXT 1 /* textual data */ #define PTYPECRTEXT 2 /* textual data with CR */ #define PTYPE8 4 /* textual 8bit data */ #define PTYPEISO2022JP 8 /* textual Japanese */ #define PTYPEISO2022KR 16 /* textual Korean */ #define PTYPEISO2022CN 32 /* textual Chinese */ /* PHILE I/O stream local data */ typedef struct phile_local { ENVELOPE *env; /* file envelope */ BODY *body; /* file body */ char tmp[MAILTMPLEN]; /* temporary buffer */ } PHILELOCAL; /* Convenient access to local data */ #define LOCAL ((PHILELOCAL *) stream->local) /* Function prototypes */ DRIVER *phile_valid (char *name); int phile_isvalid (char *name,char *tmp); void *phile_parameters (long function,void *value); void phile_scan (MAILSTREAM *stream,char *ref,char *pat,char *contents); void phile_list (MAILSTREAM *stream,char *ref,char *pat); void phile_lsub (MAILSTREAM *stream,char *ref,char *pat); long phile_create (MAILSTREAM *stream,char *mailbox); long phile_delete (MAILSTREAM *stream,char *mailbox); long phile_rename (MAILSTREAM *stream,char *old,char *newname); long phile_status (MAILSTREAM *stream,char *mbx,long flags); MAILSTREAM *phile_open (MAILSTREAM *stream); int phile_type (unsigned char *s,unsigned long i,unsigned long *j); void phile_close (MAILSTREAM *stream,long options); ENVELOPE *phile_structure (MAILSTREAM *stream,unsigned long msgno,BODY **body, long flags); char *phile_header (MAILSTREAM *stream,unsigned long msgno, unsigned long *length,long flags); long phile_text (MAILSTREAM *stream,unsigned long msgno,STRING *bs,long flags); long phile_ping (MAILSTREAM *stream); void phile_check (MAILSTREAM *stream); long phile_expunge (MAILSTREAM *stream,char *sequence,long options); long phile_copy (MAILSTREAM *stream,char *sequence,char *mailbox,long options); long phile_append (MAILSTREAM *stream,char *mailbox,append_t af,void *data); /* File routines */ /* Driver dispatch used by MAIL */ DRIVER philedriver = { "phile", /* driver name */ /* driver flags */ DR_LOCAL|DR_READONLY|DR_NOSTICKY, (DRIVER *) NIL, /* next driver */ phile_valid, /* mailbox is valid for us */ phile_parameters, /* manipulate parameters */ phile_scan, /* scan mailboxes */ phile_list, /* list mailboxes */ phile_lsub, /* list subscribed mailboxes */ NIL, /* subscribe to mailbox */ NIL, /* unsubscribe from mailbox */ dummy_create, /* create mailbox */ dummy_delete, /* delete mailbox */ dummy_rename, /* rename mailbox */ phile_status, /* status of mailbox */ phile_open, /* open mailbox */ phile_close, /* close mailbox */ NIL, /* fetch message "fast" attributes */ NIL, /* fetch message flags */ NIL, /* fetch overview */ phile_structure, /* fetch message envelopes */ phile_header, /* fetch message header only */ phile_text, /* fetch message body only */ NIL, /* fetch partial message text */ NIL, /* unique identifier */ NIL, /* message number */ NIL, /* modify flags */ NIL, /* per-message modify flags */ NIL, /* search for message based on criteria */ NIL, /* sort messages */ NIL, /* thread messages */ phile_ping, /* ping mailbox to see if still alive */ phile_check, /* check for new messages */ phile_expunge, /* expunge deleted messages */ phile_copy, /* copy messages to another mailbox */ phile_append, /* append string message to mailbox */ NIL /* garbage collect stream */ }; /* prototype stream */ MAILSTREAM phileproto = {&philedriver}; /* File validate mailbox * Accepts: mailbox name * Returns: our driver if name is valid, NIL otherwise */ DRIVER *phile_valid (char *name) { char tmp[MAILTMPLEN]; return phile_isvalid (name,tmp) ? &philedriver : NIL; } /* File test for valid mailbox * Accepts: mailbox name * Returns: T if valid, NIL otherwise */ int phile_isvalid (char *name,char *tmp) { struct stat sbuf; char *s; /* INBOX never accepted, any other name is */ return ((s = mailboxfile (tmp,name)) && *s && !stat (s,&sbuf) && !(sbuf.st_mode & S_IFDIR) && /* only allow empty files if no empty proto or if #ftp */ (sbuf.st_size || !default_proto (T) || ((*name == '#') && ((name[1] == 'f') || (name[1] == 'F')) && ((name[2] == 't') || (name[2] == 'T')) && ((name[3] == 'p') || (name[3] == 'P')) && (name[4] == '/')))); } /* File manipulate driver parameters * Accepts: function code * function-dependent value * Returns: function-dependent return value */ void *phile_parameters (long function,void *value) { return NIL; } /* File mail scan mailboxes * Accepts: mail stream * reference * pattern to search * string to scan */ void phile_scan (MAILSTREAM *stream,char *ref,char *pat,char *contents) { if (stream) dummy_scan (NIL,ref,pat,contents); } /* File list mailboxes * Accepts: mail stream * reference * pattern to search */ void phile_list (MAILSTREAM *stream,char *ref,char *pat) { if (stream) dummy_list (NIL,ref,pat); } /* File list subscribed mailboxes * Accepts: mail stream * reference * pattern to search */ void phile_lsub (MAILSTREAM *stream,char *ref,char *pat) { if (stream) dummy_lsub (NIL,ref,pat); } /* File status * Accepts: mail stream * mailbox name * status flags * Returns: T on success, NIL on failure */ long phile_status (MAILSTREAM *stream,char *mbx,long flags) { char *s,tmp[MAILTMPLEN]; MAILSTATUS status; struct stat sbuf; long ret = NIL; if ((s = mailboxfile (tmp,mbx)) && *s && !stat (s,&sbuf)) { status.flags = flags; /* return status values */ status.unseen = (stream && mail_elt (stream,1)->seen) ? 0 : 1; status.messages = status.recent = status.uidnext = 1; status.uidvalidity = sbuf.st_mtime; /* pass status to main program */ mm_status (stream,mbx,&status); ret = LONGT; /* success */ } return ret; } /* File open * Accepts: Stream to open * Returns: Stream on success, NIL on failure */ MAILSTREAM *phile_open (MAILSTREAM *stream) { int i,k,fd; unsigned long j,m; char *s,tmp[MAILTMPLEN]; struct passwd *pw; struct stat sbuf; struct tm *t; MESSAGECACHE *elt; SIZEDTEXT *buf; /* return prototype for OP_PROTOTYPE call */ if (!stream) return &phileproto; if (stream->local) fatal ("phile recycle stream"); /* open associated file */ if (!mailboxfile (tmp,stream->mailbox) || !tmp[0] || stat (tmp,&sbuf) || (fd = open (tmp,O_RDONLY,NIL)) < 0) { sprintf (tmp,"Unable to open file %s",stream->mailbox); mm_log (tmp,ERROR); return NIL; } fs_give ((void **) &stream->mailbox); stream->mailbox = cpystr (tmp); stream->local = fs_get (sizeof (PHILELOCAL)); mail_exists (stream,1); /* make sure upper level knows */ mail_recent (stream,1); elt = mail_elt (stream,1); /* instantiate cache element */ elt->valid = elt->recent = T; /* mark valid flags */ stream->sequence++; /* bump sequence number */ stream->rdonly = T; /* make sure upper level knows readonly */ /* instantiate a new envelope and body */ LOCAL->env = mail_newenvelope (); LOCAL->body = mail_newbody (); t = gmtime (&sbuf.st_mtime); /* get UTC time and Julian day */ i = t->tm_hour * 60 + t->tm_min; k = t->tm_yday; t = localtime(&sbuf.st_mtime);/* get local time */ /* calculate time delta */ i = t->tm_hour * 60 + t->tm_min - i; if (k = t->tm_yday - k) i += ((k < 0) == (abs (k) == 1)) ? -24*60 : 24*60; k = abs (i); /* time from UTC either way */ elt->hours = t->tm_hour; elt->minutes = t->tm_min; elt->seconds = t->tm_sec; elt->day = t->tm_mday; elt->month = t->tm_mon + 1; elt->year = t->tm_year - (BASEYEAR - 1900); elt->zoccident = (k == i) ? 0 : 1; elt->zhours = k/60; elt->zminutes = k % 60; sprintf (tmp,"%s, %d %s %d %02d:%02d:%02d %c%02d%02d", days[t->tm_wday],t->tm_mday,months[t->tm_mon],t->tm_year+1900, t->tm_hour,t->tm_min,t->tm_sec,elt->zoccident ? '-' : '+', elt->zhours,elt->zminutes); /* set up Date field */ LOCAL->env->date = cpystr (tmp); /* fill in From field from file owner */ LOCAL->env->from = mail_newaddr (); if (pw = getpwuid (sbuf.st_uid)) strcpy (tmp,pw->pw_name); else sprintf (tmp,"User-Number-%ld",(long) sbuf.st_uid); LOCAL->env->from->mailbox = cpystr (tmp); LOCAL->env->from->host = cpystr (mylocalhost ()); /* set subject to be mailbox name */ LOCAL->env->subject = cpystr (stream->mailbox); /* slurp the data */ (buf = &elt->private.special.text)->size = sbuf.st_size; read (fd,buf->data = (unsigned char *) fs_get (buf->size + 1),buf->size); buf->data[buf->size] = '\0'; close (fd); /* close the file */ /* analyze data type */ if (i = phile_type (buf->data,buf->size,&j)) { LOCAL->body->type = TYPETEXT; LOCAL->body->subtype = cpystr ("PLAIN"); if (!(i & PTYPECRTEXT)) { /* change Internet newline format as needed */ s = (char *) buf->data; /* make copy of UNIX-format string */ buf->data = NIL; /* zap the buffer */ buf->size = strcrlfcpy (&buf->data,&m,s,buf->size); fs_give ((void **) &s); /* flush original UNIX-format string */ } LOCAL->body->parameter = mail_newbody_parameter (); LOCAL->body->parameter->attribute = cpystr ("charset"); LOCAL->body->parameter->value = cpystr ((i & PTYPEISO2022JP) ? "ISO-2022-JP" : (i & PTYPEISO2022KR) ? "ISO-2022-KR" : (i & PTYPEISO2022CN) ? "ISO-2022-CN" : (i & PTYPE8) ? "X-UNKNOWN" : "US-ASCII"); LOCAL->body->encoding = (i & PTYPE8) ? ENC8BIT : ENC7BIT; LOCAL->body->size.lines = j; } else { /* binary data */ LOCAL->body->type = TYPEAPPLICATION; LOCAL->body->subtype = cpystr ("OCTET-STREAM"); LOCAL->body->parameter = mail_newbody_parameter (); LOCAL->body->parameter->attribute = cpystr ("name"); LOCAL->body->parameter->value = cpystr ((s = (strrchr (stream->mailbox,'/'))) ? s+1 : stream->mailbox); LOCAL->body->encoding = ENCBASE64; buf->data = rfc822_binary (s = (char *) buf->data,buf->size,&buf->size); fs_give ((void **) &s); /* flush originary binary contents */ } phile_header (stream,1,&j,NIL); LOCAL->body->size.bytes = LOCAL->body->contents.text.size = buf->size; elt->rfc822_size = j + buf->size; /* only one message ever... */ stream->uid_validity = sbuf.st_mtime; stream->uid_last = elt->private.uid = 1; return stream; /* return stream alive to caller */ } /* File determine data type * Accepts: data to examine * size of data * pointer to line count return * Returns: PTYPE mask of data type */ int phile_type (unsigned char *s,unsigned long i,unsigned long *j) { int ret = PTYPETEXT; char *charvec = "bbbbbbbaaalaacaabbbbbbbbbbbebbbbaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaabAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA"; *j = 0; /* no lines */ /* check type of every character */ while (i--) switch (charvec[*s++]) { case 'A': ret |= PTYPE8; /* 8bit character */ break; case 'a': break; /* ASCII character */ case 'b': return PTYPEBINARY; /* binary byte seen, stop immediately */ case 'c': ret |= PTYPECRTEXT; /* CR indicates Internet text */ break; case 'e': /* ESC */ if (*s == '$') { /* ISO-2022 sequence? */ switch (s[1]) { case 'B': case '@': ret |= PTYPEISO2022JP; break; case ')': switch (s[2]) { case 'A': case 'E': case 'G': ret |= PTYPEISO2022CN; break; case 'C': ret |= PTYPEISO2022KR; break; } case '*': switch (s[2]) { case 'H': ret |= PTYPEISO2022CN; break; } case '+': switch (s[2]) { case 'I': case 'J': case 'K': case 'L': case 'M': ret |= PTYPEISO2022CN; break; } } } break; case 'l': /* newline */ (*j)++; break; } return ret; /* return type of data */ } /* File close * Accepts: MAIL stream * close options */ void phile_close (MAILSTREAM *stream,long options) { if (LOCAL) { /* only if a file is open */ fs_give ((void **) &mail_elt (stream,1)->private.special.text.data); /* nuke the local data */ fs_give ((void **) &stream->local); stream->dtb = NIL; /* log out the DTB */ } } /* File fetch structure * Accepts: MAIL stream * message # to fetch * pointer to return body * option flags * Returns: envelope of this message, body returned in body value * * Fetches the "fast" information as well */ ENVELOPE *phile_structure (MAILSTREAM *stream,unsigned long msgno,BODY **body, long flags) { if (body) *body = LOCAL->body; return LOCAL->env; /* return the envelope */ } /* File fetch message header * Accepts: MAIL stream * message # to fetch * pointer to returned header text length * option flags * Returns: message header in RFC822 format */ char *phile_header (MAILSTREAM *stream,unsigned long msgno, unsigned long *length,long flags) { rfc822_header (LOCAL->tmp,LOCAL->env,LOCAL->body); *length = strlen (LOCAL->tmp); return LOCAL->tmp; } /* File fetch message text (body only) * Accepts: MAIL stream * message # to fetch * pointer to returned stringstruct * option flags * Returns: T, always */ long phile_text (MAILSTREAM *stream,unsigned long msgno,STRING *bs,long flags) { SIZEDTEXT *buf = &mail_elt (stream,msgno)->private.special.text; if (!(flags &FT_PEEK)) { /* mark message as seen */ mail_elt (stream,msgno)->seen = T; mm_flags (stream,msgno); } INIT (bs,mail_string,buf->data,buf->size); return T; } /* File ping mailbox * Accepts: MAIL stream * Returns: T if stream alive, else NIL * No-op for readonly files, since read/writer can expunge it from under us! */ long phile_ping (MAILSTREAM *stream) { return T; } /* File check mailbox * Accepts: MAIL stream * No-op for readonly files, since read/writer can expunge it from under us! */ void phile_check (MAILSTREAM *stream) { mm_log ("Check completed",NIL); } /* File expunge mailbox * Accepts: MAIL stream * sequence to expunge if non-NIL * expunge options * Returns: T if success, NIL if failure */ long phile_expunge (MAILSTREAM *stream,char *sequence,long options) { if (!stream->silent) mm_log ("Expunge ignored on readonly mailbox",NIL); return LONGT; } /* File copy message(s) * Accepts: MAIL stream * sequence * destination mailbox * copy options * Returns: T if copy successful, else NIL */ long phile_copy (MAILSTREAM *stream,char *sequence,char *mailbox,long options) { char tmp[MAILTMPLEN]; mailproxycopy_t pc = (mailproxycopy_t) mail_parameters (stream,GET_MAILPROXYCOPY,NIL); if (pc) return (*pc) (stream,sequence,mailbox,options); sprintf (tmp,"Can't copy - file \"%s\" is not in valid mailbox format", stream->mailbox); mm_log (tmp,ERROR); return NIL; } /* File append message from stringstruct * Accepts: MAIL stream * destination mailbox * append callback function * data for callback * Returns: T if append successful, else NIL */ long phile_append (MAILSTREAM *stream,char *mailbox,append_t af,void *data) { char tmp[MAILTMPLEN],file[MAILTMPLEN]; char *s = mailboxfile (file,mailbox); if (s && *s) sprintf (tmp,"Can't append - not in valid mailbox format: %.80s",s); else sprintf (tmp,"Can't append - invalid name: %.80s",mailbox); mm_log (tmp,ERROR); return NIL; } alpine-2.10+dfsg/imap/src/osdep/amiga/tenex.c0000600000175000017500000014130511512502124022534 0ustar paulproteuspaulproteus/* ======================================================================== * Copyright 1988-2007 University of Washington * * Licensed under the Apache License, Version 2.0 (the "License"); * you may not use this file except in compliance with the License. * You may obtain a copy of the License at * * http://www.apache.org/licenses/LICENSE-2.0 * * * ======================================================================== */ /* * Program: Tenex mail routines * * Author: Mark Crispin * Networks and Distributed Computing * Computing & Communications * University of Washington * Administration Building, AG-44 * Seattle, WA 98195 * Internet: MRC@CAC.Washington.EDU * * Date: 22 May 1990 * Last Edited: 11 October 2007 */ /* FILE TIME SEMANTICS * * The atime is the last read time of the file. * The mtime is the last flags update time of the file. * The ctime is the last write time of the file. * * TEXT SIZE SEMANTICS * * Most of the text sizes are in internal (LF-only) form, except for the * msg.text size. Beware. */ #include #include #include extern int errno; /* just in case */ #include "mail.h" #include "osdep.h" #include #include "misc.h" #include "dummy.h" /* TENEX I/O stream local data */ typedef struct tenex_local { unsigned int shouldcheck: 1; /* if ping should do a check instead */ unsigned int mustcheck: 1; /* if ping must do a check instead */ int fd; /* file descriptor for I/O */ off_t filesize; /* file size parsed */ time_t filetime; /* last file time */ time_t lastsnarf; /* local snarf time */ unsigned char *buf; /* temporary buffer */ unsigned long buflen; /* current size of temporary buffer */ unsigned long uid; /* current text uid */ SIZEDTEXT text; /* current text */ } TENEXLOCAL; /* Convenient access to local data */ #define LOCAL ((TENEXLOCAL *) stream->local) /* Function prototypes */ DRIVER *tenex_valid (char *name); int tenex_isvalid (char *name,char *tmp); void *tenex_parameters (long function,void *value); void tenex_scan (MAILSTREAM *stream,char *ref,char *pat,char *contents); void tenex_list (MAILSTREAM *stream,char *ref,char *pat); void tenex_lsub (MAILSTREAM *stream,char *ref,char *pat); long tenex_create (MAILSTREAM *stream,char *mailbox); long tenex_delete (MAILSTREAM *stream,char *mailbox); long tenex_rename (MAILSTREAM *stream,char *old,char *newname); long tenex_status (MAILSTREAM *stream,char *mbx,long flags); MAILSTREAM *tenex_open (MAILSTREAM *stream); void tenex_close (MAILSTREAM *stream,long options); void tenex_fast (MAILSTREAM *stream,char *sequence,long flags); void tenex_flags (MAILSTREAM *stream,char *sequence,long flags); char *tenex_header (MAILSTREAM *stream,unsigned long msgno, unsigned long *length,long flags); long tenex_text (MAILSTREAM *stream,unsigned long msgno,STRING *bs,long flags); void tenex_flag (MAILSTREAM *stream,char *sequence,char *flag,long flags); void tenex_flagmsg (MAILSTREAM *stream,MESSAGECACHE *elt); long tenex_ping (MAILSTREAM *stream); void tenex_check (MAILSTREAM *stream); void tenex_snarf (MAILSTREAM *stream); long tenex_expunge (MAILSTREAM *stream,char *sequence,long options); long tenex_copy (MAILSTREAM *stream,char *sequence,char *mailbox,long options); long tenex_append (MAILSTREAM *stream,char *mailbox,append_t af,void *data); unsigned long tenex_size (MAILSTREAM *stream,unsigned long m); char *tenex_file (char *dst,char *name); long tenex_parse (MAILSTREAM *stream); MESSAGECACHE *tenex_elt (MAILSTREAM *stream,unsigned long msgno); void tenex_read_flags (MAILSTREAM *stream,MESSAGECACHE *elt); void tenex_update_status (MAILSTREAM *stream,unsigned long msgno, long syncflag); unsigned long tenex_hdrpos (MAILSTREAM *stream,unsigned long msgno, unsigned long *size); /* Tenex mail routines */ /* Driver dispatch used by MAIL */ DRIVER tenexdriver = { "tenex", /* driver name */ DR_LOCAL|DR_MAIL|DR_NOSTICKY|DR_LOCKING, /* driver flags */ (DRIVER *) NIL, /* next driver */ tenex_valid, /* mailbox is valid for us */ tenex_parameters, /* manipulate parameters */ tenex_scan, /* scan mailboxes */ tenex_list, /* list mailboxes */ tenex_lsub, /* list subscribed mailboxes */ NIL, /* subscribe to mailbox */ NIL, /* unsubscribe from mailbox */ dummy_create, /* create mailbox */ tenex_delete, /* delete mailbox */ tenex_rename, /* rename mailbox */ tenex_status, /* status of mailbox */ tenex_open, /* open mailbox */ tenex_close, /* close mailbox */ tenex_fast, /* fetch message "fast" attributes */ tenex_flags, /* fetch message flags */ NIL, /* fetch overview */ NIL, /* fetch message envelopes */ tenex_header, /* fetch message header */ tenex_text, /* fetch message body */ NIL, /* fetch partial message text */ NIL, /* unique identifier */ NIL, /* message number */ tenex_flag, /* modify flags */ tenex_flagmsg, /* per-message modify flags */ NIL, /* search for message based on criteria */ NIL, /* sort messages */ NIL, /* thread messages */ tenex_ping, /* ping mailbox to see if still alive */ tenex_check, /* check for new messages */ tenex_expunge, /* expunge deleted messages */ tenex_copy, /* copy messages to another mailbox */ tenex_append, /* append string message to mailbox */ NIL /* garbage collect stream */ }; /* prototype stream */ MAILSTREAM tenexproto = {&tenexdriver}; /* Tenex mail validate mailbox * Accepts: mailbox name * Returns: our driver if name is valid, NIL otherwise */ DRIVER *tenex_valid (char *name) { char tmp[MAILTMPLEN]; return tenex_isvalid (name,tmp) ? &tenexdriver : NIL; } /* Tenex mail test for valid mailbox * Accepts: mailbox name * Returns: T if valid, NIL otherwise */ int tenex_isvalid (char *name,char *tmp) { int fd; int ret = NIL; char *s,file[MAILTMPLEN]; struct stat sbuf; time_t tp[2]; errno = EINVAL; /* assume invalid argument */ /* if file, get its status */ if ((s = tenex_file (file,name)) && !stat (s,&sbuf)) { if (!sbuf.st_size) { /* allow empty file if INBOX */ if ((s = mailboxfile (tmp,name)) && !*s) ret = T; else errno = 0; /* empty file */ } else if ((fd = open (file,O_RDONLY,NIL)) >= 0) { memset (tmp,'\0',MAILTMPLEN); if ((read (fd,tmp,64) >= 0) && (s = strchr (tmp,'\012')) && (s[-1] != '\015')) { /* valid format? */ *s = '\0'; /* tie off header */ /* must begin with dd-mmm-yy" */ ret = (((tmp[2] == '-' && tmp[6] == '-') || (tmp[1] == '-' && tmp[5] == '-')) && (s = strchr (tmp+18,',')) && strchr (s+2,';')) ? T : NIL; } else errno = -1; /* bogus format */ close (fd); /* close the file */ /* \Marked status? */ if (sbuf.st_ctime > sbuf.st_atime) { tp[0] = sbuf.st_atime; /* preserve atime and mtime */ tp[1] = sbuf.st_mtime; utime (file,tp); /* set the times */ } } } /* in case INBOX but not tenex format */ else if ((errno == ENOENT) && !compare_cstring (name,"INBOX")) errno = -1; return ret; /* return what we should */ } /* Tenex manipulate driver parameters * Accepts: function code * function-dependent value * Returns: function-dependent return value */ void *tenex_parameters (long function,void *value) { void *ret = NIL; switch ((int) function) { case GET_INBOXPATH: if (value) ret = tenex_file ((char *) value,"INBOX"); break; } return ret; } /* Tenex mail scan mailboxes * Accepts: mail stream * reference * pattern to search * string to scan */ void tenex_scan (MAILSTREAM *stream,char *ref,char *pat,char *contents) { if (stream) dummy_scan (NIL,ref,pat,contents); } /* Tenex mail list mailboxes * Accepts: mail stream * reference * pattern to search */ void tenex_list (MAILSTREAM *stream,char *ref,char *pat) { if (stream) dummy_list (NIL,ref,pat); } /* Tenex mail list subscribed mailboxes * Accepts: mail stream * reference * pattern to search */ void tenex_lsub (MAILSTREAM *stream,char *ref,char *pat) { if (stream) dummy_lsub (NIL,ref,pat); } /* Tenex mail delete mailbox * Accepts: MAIL stream * mailbox name to delete * Returns: T on success, NIL on failure */ long tenex_delete (MAILSTREAM *stream,char *mailbox) { return tenex_rename (stream,mailbox,NIL); } /* Tenex mail rename mailbox * Accepts: MAIL stream * old mailbox name * new mailbox name (or NIL for delete) * Returns: T on success, NIL on failure */ long tenex_rename (MAILSTREAM *stream,char *old,char *newname) { long ret = T; char c,*s,tmp[MAILTMPLEN],file[MAILTMPLEN],lock[MAILTMPLEN]; int fd,ld; struct stat sbuf; if (!tenex_file (file,old) || (newname && (!((s = mailboxfile (tmp,newname)) && *s) || ((s = strrchr (tmp,'/')) && !s[1])))) { sprintf (tmp,newname ? "Can't rename mailbox %.80s to %.80s: invalid name" : "Can't delete mailbox %.80s: invalid name", old,newname); MM_LOG (tmp,ERROR); return NIL; } else if ((fd = open (file,O_RDWR,NIL)) < 0) { sprintf (tmp,"Can't open mailbox %.80s: %s",old,strerror (errno)); MM_LOG (tmp,ERROR); return NIL; } /* get exclusive parse/append permission */ if ((ld = lockfd (fd,lock,LOCK_EX)) < 0) { MM_LOG ("Unable to lock rename mailbox",ERROR); return NIL; } /* lock out other users */ if (flock (fd,LOCK_EX|LOCK_NB)) { close (fd); /* couldn't lock, give up on it then */ sprintf (tmp,"Mailbox %.80s is in use by another process",old); MM_LOG (tmp,ERROR); unlockfd (ld,lock); /* release exclusive parse/append permission */ return NIL; } if (newname) { /* want rename? */ if (s = strrchr (tmp,'/')) {/* found superior to destination name? */ c = *++s; /* remember first character of inferior */ *s = '\0'; /* tie off to get just superior */ /* name doesn't exist, create it */ if ((stat (tmp,&sbuf) || ((sbuf.st_mode & S_IFMT) != S_IFDIR)) && !dummy_create_path (stream,tmp,get_dir_protection (newname))) ret = NIL; else *s = c; /* restore full name */ } /* rename the file */ if (ret && rename (file,tmp)) { sprintf (tmp,"Can't rename mailbox %.80s to %.80s: %s",old,newname, strerror (errno)); MM_LOG (tmp,ERROR); ret = NIL; /* set failure */ } } else if (unlink (file)) { sprintf (tmp,"Can't delete mailbox %.80s: %s",old,strerror (errno)); MM_LOG (tmp,ERROR); ret = NIL; /* set failure */ } flock (fd,LOCK_UN); /* release lock on the file */ close (fd); /* close the file */ unlockfd (ld,lock); /* release exclusive parse/append permission */ /* recreate file if renamed INBOX */ if (ret && !compare_cstring (old,"INBOX")) dummy_create (NIL,"mail.txt"); return ret; /* return success */ } /* Tenex Mail status * Accepts: mail stream * mailbox name * status flags * Returns: T on success, NIL on failure */ long tenex_status (MAILSTREAM *stream,char *mbx,long flags) { MAILSTATUS status; unsigned long i; MAILSTREAM *tstream = NIL; MAILSTREAM *systream = NIL; /* make temporary stream (unless this mbx) */ if (!stream && !(stream = tstream = mail_open (NIL,mbx,OP_READONLY|OP_SILENT))) return NIL; status.flags = flags; /* return status values */ status.messages = stream->nmsgs; status.recent = stream->recent; if (flags & SA_UNSEEN) /* must search to get unseen messages */ for (i = 1,status.unseen = 0; i <= stream->nmsgs; i++) if (!mail_elt (stream,i)->seen) status.unseen++; status.uidnext = stream->uid_last + 1; status.uidvalidity = stream->uid_validity; /* calculate post-snarf results */ if (!status.recent && stream->inbox && (systream = mail_open (NIL,sysinbox (),OP_READONLY|OP_SILENT))) { status.messages += systream->nmsgs; status.recent += systream->recent; if (flags & SA_UNSEEN) /* must search to get unseen messages */ for (i = 1; i <= systream->nmsgs; i++) if (!mail_elt (systream,i)->seen) status.unseen++; /* kludge but probably good enough */ status.uidnext += systream->nmsgs; } MM_STATUS(stream,mbx,&status);/* pass status to main program */ if (tstream) mail_close (tstream); if (systream) mail_close (systream); return T; /* success */ } /* Tenex mail open * Accepts: stream to open * Returns: stream on success, NIL on failure */ MAILSTREAM *tenex_open (MAILSTREAM *stream) { int fd,ld; char tmp[MAILTMPLEN]; blocknotify_t bn = (blocknotify_t) mail_parameters (NIL,GET_BLOCKNOTIFY,NIL); /* return prototype for OP_PROTOTYPE call */ if (!stream) return user_flags (&tenexproto); if (stream->local) fatal ("tenex recycle stream"); user_flags (stream); /* set up user flags */ /* canonicalize the mailbox name */ if (!tenex_file (tmp,stream->mailbox)) { sprintf (tmp,"Can't open - invalid name: %.80s",stream->mailbox); MM_LOG (tmp,ERROR); } if (stream->rdonly || (fd = open (tmp,O_RDWR,NIL)) < 0) { if ((fd = open (tmp,O_RDONLY,NIL)) < 0) { sprintf (tmp,"Can't open mailbox: %s",strerror (errno)); MM_LOG (tmp,ERROR); return NIL; } else if (!stream->rdonly) { /* got it, but readonly */ MM_LOG ("Can't get write access to mailbox, access is readonly",WARN); stream->rdonly = T; } } stream->local = fs_get (sizeof (TENEXLOCAL)); LOCAL->buf = (char *) fs_get (CHUNKSIZE); LOCAL->buflen = CHUNKSIZE - 1; LOCAL->text.data = (unsigned char *) fs_get (CHUNKSIZE); LOCAL->text.size = CHUNKSIZE - 1; /* note if an INBOX or not */ stream->inbox = !compare_cstring (stream->mailbox,"INBOX"); LOCAL->fd = fd; /* bind the file */ /* flush old name */ fs_give ((void **) &stream->mailbox); /* save canonical name */ stream->mailbox = cpystr (tmp); /* get shared parse permission */ if ((ld = lockfd (fd,tmp,LOCK_SH)) < 0) { MM_LOG ("Unable to lock open mailbox",ERROR); return NIL; } (*bn) (BLOCK_FILELOCK,NIL); flock (LOCAL->fd,LOCK_SH); /* lock the file */ (*bn) (BLOCK_NONE,NIL); unlockfd (ld,tmp); /* release shared parse permission */ LOCAL->filesize = 0; /* initialize parsed file size */ /* time not set up yet */ LOCAL->lastsnarf = LOCAL->filetime = 0; LOCAL->mustcheck = LOCAL->shouldcheck = NIL; stream->sequence++; /* bump sequence number */ /* parse mailbox */ stream->nmsgs = stream->recent = 0; if (tenex_ping (stream) && !stream->nmsgs) MM_LOG ("Mailbox is empty",(long) NIL); if (!LOCAL) return NIL; /* failure if stream died */ stream->perm_seen = stream->perm_deleted = stream->perm_flagged = stream->perm_answered = stream->perm_draft = stream->rdonly ? NIL : T; stream->perm_user_flags = stream->rdonly ? NIL : 0xffffffff; return stream; /* return stream to caller */ } /* Tenex mail close * Accepts: MAIL stream * close options */ void tenex_close (MAILSTREAM *stream,long options) { if (stream && LOCAL) { /* only if a file is open */ int silent = stream->silent; stream->silent = T; /* note this stream is dying */ if (options & CL_EXPUNGE) tenex_expunge (stream,NIL,NIL); stream->silent = silent; /* restore previous status */ flock (LOCAL->fd,LOCK_UN); /* unlock local file */ close (LOCAL->fd); /* close the local file */ /* free local text buffer */ if (LOCAL->buf) fs_give ((void **) &LOCAL->buf); if (LOCAL->text.data) fs_give ((void **) &LOCAL->text.data); /* nuke the local data */ fs_give ((void **) &stream->local); stream->dtb = NIL; /* log out the DTB */ } } /* Tenex mail fetch fast data * Accepts: MAIL stream * sequence * option flags */ void tenex_fast (MAILSTREAM *stream,char *sequence,long flags) { STRING bs; MESSAGECACHE *elt; unsigned long i; if (stream && LOCAL && ((flags & FT_UID) ? mail_uid_sequence (stream,sequence) : mail_sequence (stream,sequence))) for (i = 1; i <= stream->nmsgs; i++) if ((elt = mail_elt (stream,i))->sequence) { if (!elt->rfc822_size) { /* have header size yet? */ lseek (LOCAL->fd,elt->private.special.offset + elt->private.special.text.size,L_SET); /* resize bigbuf if necessary */ if (LOCAL->buflen < elt->private.msg.full.text.size) { fs_give ((void **) &LOCAL->buf); LOCAL->buflen = elt->private.msg.full.text.size; LOCAL->buf = (char *) fs_get (LOCAL->buflen + 1); } /* tie off string */ LOCAL->buf[elt->private.msg.full.text.size] = '\0'; /* read in the message */ read (LOCAL->fd,LOCAL->buf,elt->private.msg.full.text.size); INIT (&bs,mail_string,(void *) LOCAL->buf, elt->private.msg.full.text.size); /* calculate its CRLF size */ elt->rfc822_size = strcrlflen (&bs); } tenex_elt (stream,i); /* get current flags from file */ } } /* Tenex mail fetch flags * Accepts: MAIL stream * sequence * option flags * Sniffs at file to get flags */ void tenex_flags (MAILSTREAM *stream,char *sequence,long flags) { unsigned long i; if (stream && LOCAL && ((flags & FT_UID) ? mail_uid_sequence (stream,sequence) : mail_sequence (stream,sequence))) for (i = 1; i <= stream->nmsgs; i++) if (mail_elt (stream,i)->sequence) tenex_elt (stream,i); } /* TENEX mail fetch message header * Accepts: MAIL stream * message # to fetch * pointer to returned header text length * option flags * Returns: message header in RFC822 format */ char *tenex_header (MAILSTREAM *stream,unsigned long msgno, unsigned long *length,long flags) { char *s; unsigned long i; *length = 0; /* default to empty */ if (flags & FT_UID) return "";/* UID call "impossible" */ /* get to header position */ lseek (LOCAL->fd,tenex_hdrpos (stream,msgno,&i),L_SET); if (flags & FT_INTERNAL) { if (i > LOCAL->buflen) { /* resize if not enough space */ fs_give ((void **) &LOCAL->buf); LOCAL->buf = (char *) fs_get (LOCAL->buflen = i + 1); } /* slurp the data */ read (LOCAL->fd,LOCAL->buf,*length = i); } else { s = (char *) fs_get (i + 1);/* get readin buffer */ s[i] = '\0'; /* tie off string */ read (LOCAL->fd,s,i); /* slurp the data */ /* make CRLF copy of string */ *length = strcrlfcpy (&LOCAL->buf,&LOCAL->buflen,s,i); fs_give ((void **) &s); /* free readin buffer */ } return (char *) LOCAL->buf; } /* TENEX mail fetch message text (body only) * Accepts: MAIL stream * message # to fetch * pointer to returned stringstruct * option flags * Returns: T, always */ long tenex_text (MAILSTREAM *stream,unsigned long msgno,STRING *bs,long flags) { char *s; unsigned long i,j; MESSAGECACHE *elt; /* UID call "impossible" */ if (flags & FT_UID) return NIL; /* get message status */ elt = tenex_elt (stream,msgno); /* if message not seen */ if (!(flags & FT_PEEK) && !elt->seen) { elt->seen = T; /* mark message as seen */ /* recalculate status */ tenex_update_status (stream,msgno,T); MM_FLAGS (stream,msgno); } if (flags & FT_INTERNAL) { /* if internal representation wanted */ /* find header position */ i = tenex_hdrpos (stream,msgno,&j); if (i > LOCAL->buflen) { /* resize if not enough space */ fs_give ((void **) &LOCAL->buf); LOCAL->buf = (char *) fs_get (LOCAL->buflen = i + 1); } /* go to text position */ lseek (LOCAL->fd,i + j,L_SET); /* slurp the data */ read (LOCAL->fd,LOCAL->buf,i); /* set up stringstruct for internal */ INIT (bs,mail_string,LOCAL->buf,i); } else { /* normal form, previous text cached? */ if (elt->private.uid == LOCAL->uid) i = elt->private.msg.text.text.size; else { /* not cached, cache it now */ LOCAL->uid = elt->private.uid; /* find header position */ i = tenex_hdrpos (stream,msgno,&j); /* go to text position */ lseek (LOCAL->fd,i + j,L_SET); s = (char *) fs_get ((i = tenex_size (stream,msgno) - j) + 1); s[i] = '\0'; /* tie off string */ read (LOCAL->fd,s,i); /* slurp the data */ /* make CRLF copy of string */ i = elt->private.msg.text.text.size = strcrlfcpy (&LOCAL->text.data,&LOCAL->text.size,s,i); fs_give ((void **) &s); /* free readin buffer */ } /* set up stringstruct */ INIT (bs,mail_string,LOCAL->text.data,i); } return T; /* success */ } /* Tenex mail modify flags * Accepts: MAIL stream * sequence * flag(s) * option flags */ void tenex_flag (MAILSTREAM *stream,char *sequence,char *flag,long flags) { time_t tp[2]; struct stat sbuf; if (!stream->rdonly) { /* make sure the update takes */ fsync (LOCAL->fd); fstat (LOCAL->fd,&sbuf); /* get current write time */ tp[1] = LOCAL->filetime = sbuf.st_mtime; tp[0] = time (0); /* make sure read comes after all that */ utime (stream->mailbox,tp); } } /* Tenex mail per-message modify flags * Accepts: MAIL stream * message cache element */ void tenex_flagmsg (MAILSTREAM *stream,MESSAGECACHE *elt) { struct stat sbuf; /* maybe need to do a checkpoint? */ if (LOCAL->filetime && !LOCAL->shouldcheck) { fstat (LOCAL->fd,&sbuf); /* get current write time */ if (LOCAL->filetime < sbuf.st_mtime) LOCAL->shouldcheck = T; LOCAL->filetime = 0; /* don't do this test for any other messages */ } /* recalculate status */ tenex_update_status (stream,elt->msgno,NIL); } /* Tenex mail ping mailbox * Accepts: MAIL stream * Returns: T if stream still alive, NIL if not */ long tenex_ping (MAILSTREAM *stream) { unsigned long i = 1; long r = T; int ld; char lock[MAILTMPLEN]; struct stat sbuf; if (stream && LOCAL) { /* only if stream already open */ fstat (LOCAL->fd,&sbuf); /* get current file poop */ if (LOCAL->filetime && !(LOCAL->mustcheck || LOCAL->shouldcheck) && (LOCAL->filetime < sbuf.st_mtime)) LOCAL->shouldcheck = T; /* check for changed message status */ if (LOCAL->mustcheck || LOCAL->shouldcheck) { LOCAL->filetime = sbuf.st_mtime; if (LOCAL->shouldcheck) /* babble when we do this unilaterally */ MM_NOTIFY (stream,"[CHECK] Checking for flag updates",NIL); while (i <= stream->nmsgs) tenex_elt (stream,i++); LOCAL->mustcheck = LOCAL->shouldcheck = NIL; } /* get shared parse/append permission */ if ((sbuf.st_size != LOCAL->filesize) && ((ld = lockfd (LOCAL->fd,lock,LOCK_SH)) >= 0)) { /* parse resulting mailbox */ r = (tenex_parse (stream)) ? T : NIL; unlockfd (ld,lock); /* release shared parse/append permission */ } if (LOCAL) { /* stream must still be alive */ /* snarf if this is a read-write inbox */ if (stream->inbox && !stream->rdonly) { tenex_snarf (stream); fstat (LOCAL->fd,&sbuf);/* see if file changed now */ if ((sbuf.st_size != LOCAL->filesize) && ((ld = lockfd (LOCAL->fd,lock,LOCK_SH)) >= 0)) { /* parse resulting mailbox */ r = (tenex_parse (stream)) ? T : NIL; unlockfd (ld,lock); /* release shared parse/append permission */ } } } } return r; /* return result of the parse */ } /* Tenex mail check mailbox (reparses status too) * Accepts: MAIL stream */ void tenex_check (MAILSTREAM *stream) { /* mark that a check is desired */ if (LOCAL) LOCAL->mustcheck = T; if (tenex_ping (stream)) MM_LOG ("Check completed",(long) NIL); } /* Tenex mail snarf messages from system inbox * Accepts: MAIL stream */ void tenex_snarf (MAILSTREAM *stream) { unsigned long i = 0; unsigned long j,r,hdrlen,txtlen; struct stat sbuf; char *hdr,*txt,lock[MAILTMPLEN],tmp[MAILTMPLEN]; MESSAGECACHE *elt; MAILSTREAM *sysibx = NIL; int ld; /* give up if can't get exclusive permission */ if ((time (0) >= (LOCAL->lastsnarf + (long) mail_parameters (NIL,GET_SNARFINTERVAL,NIL))) && strcmp (sysinbox (),stream->mailbox) && ((ld = lockfd (LOCAL->fd,lock,LOCK_EX)) >= 0)) { MM_CRITICAL (stream); /* go critical */ /* sizes match and anything in sysinbox? */ if (!stat (sysinbox (),&sbuf) && sbuf.st_size && !fstat (LOCAL->fd,&sbuf) && (sbuf.st_size == LOCAL->filesize) && (sysibx = mail_open (sysibx,sysinbox (),OP_SILENT)) && (!sysibx->rdonly) && (r = sysibx->nmsgs)) { /* yes, go to end of file in our mailbox */ lseek (LOCAL->fd,sbuf.st_size,L_SET); /* for each message in sysibx mailbox */ while (r && (++i <= sysibx->nmsgs)) { /* snarf message from system INBOX */ hdr = cpystr (mail_fetchheader_full(sysibx,i,NIL,&hdrlen,FT_INTERNAL)); txt = mail_fetchtext_full (sysibx,i,&txtlen,FT_INTERNAL|FT_PEEK); /* if have a message */ if (j = hdrlen + txtlen) { /* calculate header line */ mail_date (LOCAL->buf,elt = mail_elt (sysibx,i)); sprintf (LOCAL->buf + strlen (LOCAL->buf), ",%lu;0000000000%02o\n",j,(unsigned) ((fSEEN * elt->seen) + (fDELETED * elt->deleted) + (fFLAGGED * elt->flagged) + (fANSWERED * elt->answered) + (fDRAFT * elt->draft))); /* copy message */ if ((write (LOCAL->fd,LOCAL->buf,strlen (LOCAL->buf)) < 0) || (write (LOCAL->fd,hdr,hdrlen) < 0) || (write (LOCAL->fd,txt,txtlen) < 0)) r = 0; } fs_give ((void **) &hdr); } /* make sure all the updates take */ if (fsync (LOCAL->fd)) r = 0; if (r) { /* delete all the messages we copied */ if (r == 1) strcpy (tmp,"1"); else sprintf (tmp,"1:%lu",r); mail_flag (sysibx,tmp,"\\Deleted",ST_SET); mail_expunge (sysibx); /* now expunge all those messages */ } else { sprintf (LOCAL->buf,"Can't copy new mail: %s",strerror (errno)); MM_LOG (LOCAL->buf,WARN); ftruncate (LOCAL->fd,sbuf.st_size); } fstat (LOCAL->fd,&sbuf); /* yes, get current file size */ LOCAL->filetime = sbuf.st_mtime; } if (sysibx) mail_close (sysibx); MM_NOCRITICAL (stream); /* release critical */ unlockfd (ld,lock); /* release exclusive parse/append permission */ LOCAL->lastsnarf = time (0);/* note time of last snarf */ } } /* Tenex mail expunge mailbox * Accepts: MAIL stream * sequence to expunge if non-NIL * expunge options * Returns: T, always */ long tenex_expunge (MAILSTREAM *stream,char *sequence,long options) { long ret; time_t tp[2]; struct stat sbuf; off_t pos = 0; int ld; unsigned long i = 1; unsigned long j,k,m,recent; unsigned long n = 0; unsigned long delta = 0; char lock[MAILTMPLEN]; MESSAGECACHE *elt; blocknotify_t bn = (blocknotify_t) mail_parameters (NIL,GET_BLOCKNOTIFY,NIL); if (!(ret = (sequence ? ((options & EX_UID) ? mail_uid_sequence (stream,sequence) : mail_sequence (stream,sequence)) : LONGT) && tenex_ping (stream))); /* parse sequence if given, ping stream */ else if (stream->rdonly) MM_LOG ("Expunge ignored on readonly mailbox",WARN); else { if (LOCAL->filetime && !LOCAL->shouldcheck) { fstat (LOCAL->fd,&sbuf); /* get current write time */ if (LOCAL->filetime < sbuf.st_mtime) LOCAL->shouldcheck = T; } /* The cretins who designed flock() created a window of vulnerability in * upgrading locks from shared to exclusive or downgrading from exclusive * to shared. Rather than maintain the lock at shared status at a minimum, * flock() actually *releases* the former lock. Obviously they never talked * to any database guys. Fortunately, we have the parse/append permission * lock. If we require this lock before going exclusive on the mailbox, * another process can not sneak in and steal the exclusive mailbox lock on * us, because it will block on trying to get parse/append permission first. */ /* get exclusive parse/append permission */ if ((ld = lockfd (LOCAL->fd,lock,LOCK_EX)) < 0) MM_LOG ("Unable to lock expunge mailbox",ERROR); /* make sure see any newly-arrived messages */ else if (!tenex_parse (stream)); /* get exclusive access */ else if (flock (LOCAL->fd,LOCK_EX|LOCK_NB)) { (*bn) (BLOCK_FILELOCK,NIL); flock (LOCAL->fd,LOCK_SH);/* recover previous lock */ (*bn) (BLOCK_NONE,NIL); MM_LOG ("Can't expunge because mailbox is in use by another process", ERROR); unlockfd (ld,lock); /* release exclusive parse/append permission */ } else { MM_CRITICAL (stream); /* go critical */ recent = stream->recent; /* get recent now that pinged and locked */ /* for each message */ while (i <= stream->nmsgs) { /* get cache element */ elt = tenex_elt (stream,i); /* number of bytes to smash or preserve */ k = elt->private.special.text.size + tenex_size (stream,i); /* if need to expunge this message */ if (elt->deleted && (sequence ? elt->sequence : T)) { /* if recent, note one less recent message */ if (elt->recent) --recent; delta += k; /* number of bytes to delete */ /* notify upper levels */ mail_expunged (stream,i); n++; /* count up one more expunged message */ } else if (i++ && delta) {/* preserved message */ /* first byte to preserve */ j = elt->private.special.offset; do { /* read from source position */ m = min (k,LOCAL->buflen); lseek (LOCAL->fd,j,L_SET); read (LOCAL->fd,LOCAL->buf,m); pos = j - delta; /* write to destination position */ lseek (LOCAL->fd,pos,L_SET); while (T) { lseek (LOCAL->fd,pos,L_SET); if (write (LOCAL->fd,LOCAL->buf,m) > 0) break; MM_NOTIFY (stream,strerror (errno),WARN); MM_DISKERROR (stream,errno,T); } pos += m; /* new position */ j += m; /* next chunk, perhaps */ } while (k -= m); /* until done */ /* note the new address of this text */ elt->private.special.offset -= delta; } /* preserved but no deleted messages */ else pos = elt->private.special.offset + k; } if (n) { /* truncate file after last message */ if (pos != (LOCAL->filesize -= delta)) { sprintf (LOCAL->buf, "Calculated size mismatch %lu != %lu, delta = %lu", (unsigned long) pos,(unsigned long) LOCAL->filesize,delta); MM_LOG (LOCAL->buf,WARN); LOCAL->filesize = pos;/* fix it then */ } ftruncate (LOCAL->fd,LOCAL->filesize); sprintf (LOCAL->buf,"Expunged %lu messages",n); /* output the news */ MM_LOG (LOCAL->buf,(long) NIL); } else MM_LOG ("No messages deleted, so no update needed",(long) NIL); fsync (LOCAL->fd); /* force disk update */ fstat (LOCAL->fd,&sbuf); /* get new write time */ tp[1] = LOCAL->filetime = sbuf.st_mtime; tp[0] = time (0); /* reset atime to now */ utime (stream->mailbox,tp); MM_NOCRITICAL (stream); /* release critical */ /* notify upper level of new mailbox size */ mail_exists (stream,stream->nmsgs); mail_recent (stream,recent); (*bn) (BLOCK_FILELOCK,NIL); flock (LOCAL->fd,LOCK_SH);/* allow sharers again */ (*bn) (BLOCK_NONE,NIL); unlockfd (ld,lock); /* release exclusive parse/append permission */ } } return LONGT; } /* Tenex mail copy message(s) * Accepts: MAIL stream * sequence * destination mailbox * copy options * Returns: T if success, NIL if failed */ long tenex_copy (MAILSTREAM *stream,char *sequence,char *mailbox,long options) { struct stat sbuf; time_t tp[2]; MESSAGECACHE *elt; unsigned long i,j,k; long ret = LONGT; int fd,ld; char file[MAILTMPLEN],lock[MAILTMPLEN]; mailproxycopy_t pc = (mailproxycopy_t) mail_parameters (stream,GET_MAILPROXYCOPY,NIL); /* make sure valid mailbox */ if (!tenex_isvalid (mailbox,LOCAL->buf)) switch (errno) { case ENOENT: /* no such file? */ MM_NOTIFY (stream,"[TRYCREATE] Must create mailbox before copy",NIL); return NIL; case 0: /* merely empty file? */ break; case EACCES: /* file protected */ sprintf (LOCAL->buf,"Can't access destination: %.80s",mailbox); MM_LOG (LOCAL->buf,ERROR); return NIL; case EINVAL: if (pc) return (*pc) (stream,sequence,mailbox,options); sprintf (LOCAL->buf,"Invalid Tenex-format mailbox name: %.80s",mailbox); MM_LOG (LOCAL->buf,ERROR); return NIL; default: if (pc) return (*pc) (stream,sequence,mailbox,options); sprintf (LOCAL->buf,"Not a Tenex-format mailbox: %.80s",mailbox); MM_LOG (LOCAL->buf,ERROR); return NIL; } if (!((options & CP_UID) ? mail_uid_sequence (stream,sequence) : mail_sequence (stream,sequence))) return NIL; /* got file? */ if ((fd = open (tenex_file(file,mailbox),O_RDWR,NIL)) < 0) { sprintf (LOCAL->buf,"Unable to open copy mailbox: %s",strerror (errno)); MM_LOG (LOCAL->buf,ERROR); return NIL; } MM_CRITICAL (stream); /* go critical */ /* get exclusive parse/append permission */ if (flock (fd,LOCK_SH) || ((ld = lockfd (fd,lock,LOCK_EX)) < 0)) { MM_LOG ("Unable to lock copy mailbox",ERROR); MM_NOCRITICAL (stream); return NIL; } fstat (fd,&sbuf); /* get current file size */ lseek (fd,sbuf.st_size,L_SET);/* move to end of file */ /* for each requested message */ for (i = 1; ret && (i <= stream->nmsgs); i++) if ((elt = mail_elt (stream,i))->sequence) { lseek (LOCAL->fd,elt->private.special.offset,L_SET); /* number of bytes to copy */ k = elt->private.special.text.size + tenex_size (stream,i); do { /* read from source position */ j = min (k,LOCAL->buflen); read (LOCAL->fd,LOCAL->buf,j); if (write (fd,LOCAL->buf,j) < 0) ret = NIL; } while (ret && (k -= j));/* until done */ } /* make sure all the updates take */ if (!(ret && (ret = !fsync (fd)))) { sprintf (LOCAL->buf,"Unable to write message: %s",strerror (errno)); MM_LOG (LOCAL->buf,ERROR); ftruncate (fd,sbuf.st_size); } if (ret) tp[0] = time (0) - 1;/* set atime to now-1 if successful copy */ /* else preserve \Marked status */ else tp[0] = (sbuf.st_ctime > sbuf.st_atime) ? sbuf.st_atime : time(0); tp[1] = sbuf.st_mtime; /* preserve mtime */ utime (file,tp); /* set the times */ close (fd); /* close the file */ unlockfd (ld,lock); /* release exclusive parse/append permission */ MM_NOCRITICAL (stream); /* release critical */ /* delete all requested messages */ if (ret && (options & CP_MOVE)) { for (i = 1; i <= stream->nmsgs; i++) if ((elt = tenex_elt (stream,i))->sequence) { elt->deleted = T; /* mark message deleted */ /* recalculate status */ tenex_update_status (stream,i,NIL); } if (!stream->rdonly) { /* make sure the update takes */ fsync (LOCAL->fd); fstat (LOCAL->fd,&sbuf); /* get current write time */ tp[1] = LOCAL->filetime = sbuf.st_mtime; tp[0] = time (0); /* make sure atime remains greater */ utime (stream->mailbox,tp); } } if (ret && mail_parameters (NIL,GET_COPYUID,NIL)) MM_LOG ("Can not return meaningful COPYUID with this mailbox format",WARN); return ret; } /* Tenex mail append message from stringstruct * Accepts: MAIL stream * destination mailbox * append callback * data for callback * Returns: T if append successful, else NIL */ long tenex_append (MAILSTREAM *stream,char *mailbox,append_t af,void *data) { struct stat sbuf; int fd,ld,c; char *flags,*date,tmp[MAILTMPLEN],file[MAILTMPLEN],lock[MAILTMPLEN]; time_t tp[2]; FILE *df; MESSAGECACHE elt; long f; unsigned long i,j,uf,size; STRING *message; long ret = LONGT; /* default stream to prototype */ if (!stream) stream = user_flags (&tenexproto); /* make sure valid mailbox */ if (!tenex_isvalid (mailbox,tmp)) switch (errno) { case ENOENT: /* no such file? */ if (!compare_cstring (mailbox,"INBOX")) dummy_create (NIL,"mail.txt"); else { MM_NOTIFY (stream,"[TRYCREATE] Must create mailbox before append",NIL); return NIL; } /* falls through */ case 0: /* merely empty file? */ break; case EACCES: /* file protected */ sprintf (tmp,"Can't access destination: %.80s",mailbox); MM_LOG (tmp,ERROR); return NIL; case EINVAL: sprintf (tmp,"Invalid TENEX-format mailbox name: %.80s",mailbox); MM_LOG (tmp,ERROR); return NIL; default: sprintf (tmp,"Not a TENEX-format mailbox: %.80s",mailbox); MM_LOG (tmp,ERROR); return NIL; } /* get first message */ if (!MM_APPEND (af) (stream,data,&flags,&date,&message)) return NIL; /* open destination mailbox */ if (((fd = open (tenex_file (file,mailbox),O_WRONLY|O_APPEND,NIL)) < 0) || !(df = fdopen (fd,"ab"))) { sprintf (tmp,"Can't open append mailbox: %s",strerror (errno)); MM_LOG (tmp,ERROR); return NIL; } /* get parse/append permission */ if (flock (fd,LOCK_SH) || ((ld = lockfd (fd,lock,LOCK_EX)) < 0)) { MM_LOG ("Unable to lock append mailbox",ERROR); close (fd); return NIL; } MM_CRITICAL (stream); /* go critical */ fstat (fd,&sbuf); /* get current file size */ errno = 0; do { /* parse flags */ if (!SIZE (message)) { /* guard against zero-length */ MM_LOG ("Append of zero-length message",ERROR); ret = NIL; break; } f = mail_parse_flags (stream,flags,&i); /* reverse bits (dontcha wish we had CIRC?) */ for (uf = 0; i; uf |= 1 << (29 - find_rightmost_bit (&i))); if (date) { /* parse date if given */ if (!mail_parse_date (&elt,date)) { sprintf (tmp,"Bad date in append: %.80s",date); MM_LOG (tmp,ERROR); ret = NIL; /* mark failure */ break; } mail_date (tmp,&elt); /* write preseved date */ } else internal_date (tmp); /* get current date in IMAP format */ i = GETPOS (message); /* remember current position */ for (j = SIZE (message), size = 0; j; --j) if (SNX (message) != '\015') ++size; SETPOS (message,i); /* restore position */ /* write header */ if (fprintf (df,"%s,%lu;%010lo%02lo\n",tmp,size,uf,(unsigned long) f) < 0) ret = NIL; else { /* write message */ while (size) if ((c = 0xff & SNX (message)) != '\015') { if (putc (c,df) != EOF) --size; else break; } /* get next message */ if (size || !MM_APPEND (af) (stream,data,&flags,&date,&message)) ret = NIL; } } while (ret && message); /* if error... */ if (!ret || (fflush (df) == EOF)) { ftruncate (fd,sbuf.st_size);/* revert file */ close (fd); /* make sure fclose() doesn't corrupt us */ if (errno) { sprintf (tmp,"Message append failed: %s",strerror (errno)); MM_LOG (tmp,ERROR); } ret = NIL; } if (ret) tp[0] = time (0) - 1;/* set atime to now-1 if successful copy */ /* else preserve \Marked status */ else tp[0] = (sbuf.st_ctime > sbuf.st_atime) ? sbuf.st_atime : time(0); tp[1] = sbuf.st_mtime; /* preserve mtime */ utime (file,tp); /* set the times */ fclose (df); /* close the file */ unlockfd (ld,lock); /* release exclusive parse/append permission */ MM_NOCRITICAL (stream); /* release critical */ if (ret && mail_parameters (NIL,GET_APPENDUID,NIL)) MM_LOG ("Can not return meaningful APPENDUID with this mailbox format", WARN); return ret; } /* Internal routines */ /* Tenex mail return internal message size in bytes * Accepts: MAIL stream * message # * Returns: internal size of message */ unsigned long tenex_size (MAILSTREAM *stream,unsigned long m) { MESSAGECACHE *elt = mail_elt (stream,m); return ((m < stream->nmsgs) ? mail_elt (stream,m+1)->private.special.offset : LOCAL->filesize) - (elt->private.special.offset + elt->private.special.text.size); } /* Tenex mail generate file string * Accepts: temporary buffer to write into * mailbox name string * Returns: local file string or NIL if failure */ char *tenex_file (char *dst,char *name) { char tmp[MAILTMPLEN]; char *s = mailboxfile (dst,name); /* return our standard inbox */ return (s && !*s) ? mailboxfile (dst,tenex_isvalid ("~/INBOX",tmp) ? "~/INBOX" : "mail.txt") : s; } /* Tenex mail parse mailbox * Accepts: MAIL stream * Returns: T if parse OK * NIL if failure, stream aborted */ long tenex_parse (MAILSTREAM *stream) { struct stat sbuf; MESSAGECACHE *elt = NIL; unsigned char c,*s,*t,*x; char tmp[MAILTMPLEN]; unsigned long i,j; long curpos = LOCAL->filesize; long nmsgs = stream->nmsgs; long recent = stream->recent; short added = NIL; short silent = stream->silent; fstat (LOCAL->fd,&sbuf); /* get status */ if (sbuf.st_size < curpos) { /* sanity check */ sprintf (tmp,"Mailbox shrank from %lu to %lu!", (unsigned long) curpos,(unsigned long) sbuf.st_size); MM_LOG (tmp,ERROR); tenex_close (stream,NIL); return NIL; } stream->silent = T; /* don't pass up exists events yet */ while (sbuf.st_size - curpos){/* while there is stuff to parse */ /* get to that position in the file */ lseek (LOCAL->fd,curpos,L_SET); if ((i = read (LOCAL->fd,LOCAL->buf,64)) <= 0) { sprintf (tmp,"Unable to read internal header at %lu, size = %lu: %s", (unsigned long) curpos,(unsigned long) sbuf.st_size, i ? strerror (errno) : "no data read"); MM_LOG (tmp,ERROR); tenex_close (stream,NIL); return NIL; } LOCAL->buf[i] = '\0'; /* tie off buffer just in case */ if (!(s = strchr (LOCAL->buf,'\012'))) { sprintf (tmp,"Unable to find newline at %lu in %lu bytes, text: %s", (unsigned long) curpos,i,(char *) LOCAL->buf); MM_LOG (tmp,ERROR); tenex_close (stream,NIL); return NIL; } *s = '\0'; /* tie off header line */ i = (s + 1) - LOCAL->buf; /* note start of text offset */ if (!((s = strchr (LOCAL->buf,',')) && (t = strchr (s+1,';')))) { sprintf (tmp,"Unable to parse internal header at %lu: %s", (unsigned long) curpos,(char *) LOCAL->buf); MM_LOG (tmp,ERROR); tenex_close (stream,NIL); return NIL; } *s++ = '\0'; *t++ = '\0'; /* tie off fields */ added = T; /* note that a new message was added */ /* swell the cache */ mail_exists (stream,++nmsgs); /* instantiate an elt for this message */ (elt = mail_elt (stream,nmsgs))->valid = T; elt->private.uid = ++stream->uid_last; /* note file offset of header */ elt->private.special.offset = curpos; /* in case error */ elt->private.special.text.size = 0; /* header size not known yet */ elt->private.msg.header.text.size = 0; x = s; /* parse the header components */ if (mail_parse_date (elt,LOCAL->buf) && (elt->private.msg.full.text.size = strtoul (s,(char **) &s,10)) && (!(s && *s)) && isdigit (t[0]) && isdigit (t[1]) && isdigit (t[2]) && isdigit (t[3]) && isdigit (t[4]) && isdigit (t[5]) && isdigit (t[6]) && isdigit (t[7]) && isdigit (t[8]) && isdigit (t[9]) && isdigit (t[10]) && isdigit (t[11]) && !t[12]) elt->private.special.text.size = i; else { /* oops */ sprintf (tmp,"Unable to parse internal header elements at %ld: %s,%s;%s", curpos,(char *) LOCAL->buf,(char *) x,(char *) t); MM_LOG (tmp,ERROR); tenex_close (stream,NIL); return NIL; } /* make sure didn't run off end of file */ if ((curpos += (elt->private.msg.full.text.size + i)) > sbuf.st_size) { sprintf (tmp,"Last message (at %lu) runs past end of file (%lu > %lu)", elt->private.special.offset,(unsigned long) curpos, (unsigned long) sbuf.st_size); MM_LOG (tmp,ERROR); tenex_close (stream,NIL); return NIL; } c = t[10]; /* remember first system flags byte */ t[10] = '\0'; /* tie off flags */ j = strtoul (t,NIL,8); /* get user flags value */ t[10] = c; /* restore first system flags byte */ /* set up all valid user flags (reversed!) */ while (j) if (((i = 29 - find_rightmost_bit (&j)) < NUSERFLAGS) && stream->user_flags[i]) elt->user_flags |= 1 << i; /* calculate system flags */ if ((j = ((t[10]-'0') * 8) + t[11]-'0') & fSEEN) elt->seen = T; if (j & fDELETED) elt->deleted = T; if (j & fFLAGGED) elt->flagged = T; if (j & fANSWERED) elt->answered = T; if (j & fDRAFT) elt->draft = T; if (!(j & fOLD)) { /* newly arrived message? */ elt->recent = T; recent++; /* count up a new recent message */ /* mark it as old */ tenex_update_status (stream,nmsgs,NIL); } } fsync (LOCAL->fd); /* make sure all the fOLD flags take */ /* update parsed file size and time */ LOCAL->filesize = sbuf.st_size; fstat (LOCAL->fd,&sbuf); /* get status again to ensure time is right */ LOCAL->filetime = sbuf.st_mtime; if (added && !stream->rdonly){/* make sure atime updated */ time_t tp[2]; tp[0] = time (0); tp[1] = LOCAL->filetime; utime (stream->mailbox,tp); } stream->silent = silent; /* can pass up events now */ mail_exists (stream,nmsgs); /* notify upper level of new mailbox size */ mail_recent (stream,recent); /* and of change in recent messages */ return LONGT; /* return the winnage */ } /* Tenex get cache element with status updating from file * Accepts: MAIL stream * message number * Returns: cache element */ MESSAGECACHE *tenex_elt (MAILSTREAM *stream,unsigned long msgno) { MESSAGECACHE *elt = mail_elt (stream,msgno); struct { /* old flags */ unsigned int seen : 1; unsigned int deleted : 1; unsigned int flagged : 1; unsigned int answered : 1; unsigned int draft : 1; unsigned long user_flags; } old; old.seen = elt->seen; old.deleted = elt->deleted; old.flagged = elt->flagged; old.answered = elt->answered; old.draft = elt->draft; old.user_flags = elt->user_flags; tenex_read_flags (stream,elt); if ((old.seen != elt->seen) || (old.deleted != elt->deleted) || (old.flagged != elt->flagged) || (old.answered != elt->answered) || (old.draft != elt->draft) || (old.user_flags != elt->user_flags)) MM_FLAGS (stream,msgno); /* let top level know */ return elt; } /* Tenex read flags from file * Accepts: MAIL stream * Returns: cache element */ void tenex_read_flags (MAILSTREAM *stream,MESSAGECACHE *elt) { unsigned long i,j; /* noop if readonly and have valid flags */ if (stream->rdonly && elt->valid) return; /* set the seek pointer */ lseek (LOCAL->fd,(off_t) elt->private.special.offset + elt->private.special.text.size - 13,L_SET); /* read the new flags */ if (read (LOCAL->fd,LOCAL->buf,12) < 0) { sprintf (LOCAL->buf,"Unable to read new status: %s",strerror (errno)); fatal (LOCAL->buf); } /* calculate system flags */ i = (((LOCAL->buf[10]-'0') * 8) + LOCAL->buf[11]-'0'); elt->seen = i & fSEEN ? T : NIL; elt->deleted = i & fDELETED ? T : NIL; elt->flagged = i & fFLAGGED ? T : NIL; elt->answered = i & fANSWERED ? T : NIL; elt->draft = i & fDRAFT ? T : NIL; LOCAL->buf[10] = '\0'; /* tie off flags */ j = strtoul(LOCAL->buf,NIL,8);/* get user flags value */ /* set up all valid user flags (reversed!) */ while (j) if (((i = 29 - find_rightmost_bit (&j)) < NUSERFLAGS) && stream->user_flags[i]) elt->user_flags |= 1 << i; elt->valid = T; /* have valid flags now */ } /* Tenex update status string * Accepts: MAIL stream * message number * flag saying whether or not to sync */ void tenex_update_status (MAILSTREAM *stream,unsigned long msgno,long syncflag) { time_t tp[2]; struct stat sbuf; MESSAGECACHE *elt = mail_elt (stream,msgno); unsigned long j,k = 0; /* readonly */ if (stream->rdonly || !elt->valid) tenex_read_flags (stream,elt); else { /* readwrite */ j = elt->user_flags; /* get user flags */ /* reverse bits (dontcha wish we had CIRC?) */ while (j) k |= 1 << (29 - find_rightmost_bit (&j)); /* print new flag string */ sprintf (LOCAL->buf,"%010lo%02o",k,(unsigned) (fOLD + (fSEEN * elt->seen) + (fDELETED * elt->deleted) + (fFLAGGED * elt->flagged) + (fANSWERED * elt->answered) + (fDRAFT * elt->draft))); /* get to that place in the file */ lseek (LOCAL->fd,(off_t) elt->private.special.offset + elt->private.special.text.size - 13,L_SET); /* write new flags */ write (LOCAL->fd,LOCAL->buf,12); if (syncflag) { /* sync if requested */ fsync (LOCAL->fd); fstat (LOCAL->fd,&sbuf); /* get new write time */ tp[1] = LOCAL->filetime = sbuf.st_mtime; tp[0] = time (0); /* make sure read is later */ utime (stream->mailbox,tp); } } } /* Tenex locate header for a message * Accepts: MAIL stream * message number * pointer to returned header size * Returns: position of header in file */ unsigned long tenex_hdrpos (MAILSTREAM *stream,unsigned long msgno, unsigned long *size) { unsigned long siz; long i = 0; char c = '\0'; char *s = NIL; MESSAGECACHE *elt = tenex_elt (stream,msgno); unsigned long ret = elt->private.special.offset + elt->private.special.text.size; unsigned long msiz = tenex_size (stream,msgno); /* is header size known? */ if (!(*size = elt->private.msg.header.text.size)) { lseek (LOCAL->fd,ret,L_SET);/* get to header position */ /* search message for LF LF */ for (siz = 0; siz < msiz; siz++) { if (--i <= 0) /* read another buffer as necessary */ read (LOCAL->fd,s = LOCAL->buf,i = min (msiz-siz,(long) MAILTMPLEN)); /* two newline sequence? */ if ((c == '\012') && (*s == '\012')) { /* yes, note for later */ elt->private.msg.header.text.size = (*size = siz + 1); return ret; /* return to caller */ } else c = *s++; /* next character */ } /* header consumes entire message */ elt->private.msg.header.text.size = *size = msiz; } return ret; } alpine-2.10+dfsg/imap/src/osdep/amiga/mh.c0000600000175000017500000011726311512502124022023 0ustar paulproteuspaulproteus/* ======================================================================== * Copyright 1988-2007 University of Washington * * Licensed under the Apache License, Version 2.0 (the "License"); * you may not use this file except in compliance with the License. * You may obtain a copy of the License at * * http://www.apache.org/licenses/LICENSE-2.0 * * * ======================================================================== */ /* * Program: MH mail routines * * Author(s): Mark Crispin * Networks and Distributed Computing * Computing & Communications * University of Washington * Administration Building, AG-44 * Seattle, WA 98195 * Internet: MRC@CAC.Washington.EDU * * Date: 23 February 1992 * Last Edited: 11 October 2007 */ #include #include #include extern int errno; /* just in case */ #include "mail.h" #include "osdep.h" #include #include #include #include "misc.h" #include "dummy.h" #include "fdstring.h" /* Build parameters */ #define MHINBOX "#mhinbox" /* corresponds to namespace in env_unix.c */ #define MHINBOXDIR "inbox" #define MHPROFILE ".mh_profile" #define MHCOMMA ',' #define MHSEQUENCE ".mh_sequence" #define MHSEQUENCES ".mh_sequences" #define MHPATH "Mail" /* mh_load_message() flags */ #define MLM_HEADER 0x1 /* load message text */ #define MLM_TEXT 0x2 /* load message text */ /* MH I/O stream local data */ typedef struct mh_local { char *dir; /* spool directory name */ unsigned char buf[CHUNKSIZE]; /* temporary buffer */ unsigned long cachedtexts; /* total size of all cached texts */ time_t scantime; /* last time directory scanned */ } MHLOCAL; /* Convenient access to local data */ #define LOCAL ((MHLOCAL *) stream->local) /* Function prototypes */ DRIVER *mh_valid (char *name); int mh_isvalid (char *name,char *tmp,long synonly); int mh_namevalid (char *name); char *mh_path (char *tmp); void *mh_parameters (long function,void *value); long mh_dirfmttest (char *name); void mh_scan (MAILSTREAM *stream,char *ref,char *pat,char *contents); void mh_list (MAILSTREAM *stream,char *ref,char *pat); void mh_lsub (MAILSTREAM *stream,char *ref,char *pat); void mh_list_work (MAILSTREAM *stream,char *dir,char *pat,long level); long mh_subscribe (MAILSTREAM *stream,char *mailbox); long mh_unsubscribe (MAILSTREAM *stream,char *mailbox); long mh_create (MAILSTREAM *stream,char *mailbox); long mh_delete (MAILSTREAM *stream,char *mailbox); long mh_rename (MAILSTREAM *stream,char *old,char *newname); MAILSTREAM *mh_open (MAILSTREAM *stream); void mh_close (MAILSTREAM *stream,long options); void mh_fast (MAILSTREAM *stream,char *sequence,long flags); void mh_load_message (MAILSTREAM *stream,unsigned long msgno,long flags); char *mh_header (MAILSTREAM *stream,unsigned long msgno,unsigned long *length, long flags); long mh_text (MAILSTREAM *stream,unsigned long msgno,STRING *bs,long flags); long mh_ping (MAILSTREAM *stream); void mh_check (MAILSTREAM *stream); long mh_expunge (MAILSTREAM *stream,char *sequence,long options); long mh_copy (MAILSTREAM *stream,char *sequence,char *mailbox, long options); long mh_append (MAILSTREAM *stream,char *mailbox,append_t af,void *data); int mh_select (struct direct *name); int mh_numsort (const void *d1,const void *d2); char *mh_file (char *dst,char *name); long mh_canonicalize (char *pattern,char *ref,char *pat); void mh_setdate (char *file,MESSAGECACHE *elt); /* MH mail routines */ /* Driver dispatch used by MAIL */ DRIVER mhdriver = { "mh", /* driver name */ /* driver flags */ DR_MAIL|DR_LOCAL|DR_NOFAST|DR_NAMESPACE|DR_NOSTICKY|DR_DIRFMT, (DRIVER *) NIL, /* next driver */ mh_valid, /* mailbox is valid for us */ mh_parameters, /* manipulate parameters */ mh_scan, /* scan mailboxes */ mh_list, /* find mailboxes */ mh_lsub, /* find subscribed mailboxes */ mh_subscribe, /* subscribe to mailbox */ mh_unsubscribe, /* unsubscribe from mailbox */ mh_create, /* create mailbox */ mh_delete, /* delete mailbox */ mh_rename, /* rename mailbox */ mail_status_default, /* status of mailbox */ mh_open, /* open mailbox */ mh_close, /* close mailbox */ mh_fast, /* fetch message "fast" attributes */ NIL, /* fetch message flags */ NIL, /* fetch overview */ NIL, /* fetch message envelopes */ mh_header, /* fetch message header */ mh_text, /* fetch message body */ NIL, /* fetch partial message text */ NIL, /* unique identifier */ NIL, /* message number */ NIL, /* modify flags */ NIL, /* per-message modify flags */ NIL, /* search for message based on criteria */ NIL, /* sort messages */ NIL, /* thread messages */ mh_ping, /* ping mailbox to see if still alive */ mh_check, /* check for new messages */ mh_expunge, /* expunge deleted messages */ mh_copy, /* copy messages to another mailbox */ mh_append, /* append string message to mailbox */ NIL /* garbage collect stream */ }; /* prototype stream */ MAILSTREAM mhproto = {&mhdriver}; static char *mh_profile = NIL; /* holds MH profile */ static char *mh_pathname = NIL; /* holds MH path name */ static long mh_once = 0; /* already snarled once */ static long mh_allow_inbox =NIL;/* allow INBOX as well as MHINBOX */ /* MH mail validate mailbox * Accepts: mailbox name * Returns: our driver if name is valid, NIL otherwise */ DRIVER *mh_valid (char *name) { char tmp[MAILTMPLEN]; return mh_isvalid (name,tmp,T) ? &mhdriver : NIL; } /* MH mail test for valid mailbox * Accepts: mailbox name * temporary buffer to use * syntax only test flag * Returns: T if valid, NIL otherwise */ int mh_isvalid (char *name,char *tmp,long synonly) { struct stat sbuf; char *s,*t,altname[MAILTMPLEN]; unsigned long i; int ret = NIL; errno = NIL; /* zap any error condition */ /* mh name? */ if ((mh_allow_inbox && !compare_cstring (name,"INBOX")) || !compare_cstring (name,MHINBOX) || ((name[0] == '#') && ((name[1] == 'm') || (name[1] == 'M')) && ((name[2] == 'h') || (name[2] == 'H')) && (name[3] == '/') && name[4])){ if (mh_path (tmp)) /* validate name if INBOX or not synonly */ ret = (synonly && compare_cstring (name,"INBOX")) ? T : ((stat (mh_file (tmp,name),&sbuf) == 0) && (sbuf.st_mode & S_IFMT) == S_IFDIR); else if (!mh_once++) { /* only report error once */ sprintf (tmp,"%.900s not found, mh format names disabled",mh_profile); mm_log (tmp,WARN); } } /* see if non-NS name within mh hierarchy */ else if ((name[0] != '#') && (s = mh_path (tmp)) && (i = strlen (s)) && (t = mailboxfile (tmp,name)) && !strncmp (t,s,i) && (tmp[i] == '/') && tmp[i+1]) { sprintf (altname,"#mh%.900s",tmp+i); /* can't do synonly here! */ ret = mh_isvalid (altname,tmp,NIL); } else errno = EINVAL; /* bogus name */ return ret; } /* MH mail test for valid mailbox * Accepts: mailbox name * Returns: T if valid, NIL otherwise */ int mh_namevalid (char *name) { char *s; if (name[0] == '#' && (name[1] == 'm' || name[1] == 'M') && (name[2] == 'h' || name[2] == 'H') && name[3] == '/') for (s = name; s && *s;) { /* make sure no all-digit nodes */ if (isdigit (*s)) s++; /* digit, check this node further... */ else if (*s == '/') break;/* all digit node, barf */ /* non-digit, skip to next node or return */ else if (!((s = strchr (s+1,'/')) && *++s)) return T; } return NIL; /* all numeric or empty node */ } /* Return MH path * Accepts: temporary buffer * Returns: MH path or NIL if MH disabled */ char *mh_path (char *tmp) { char *s,*t,*v,*r; int fd; struct stat sbuf; if (!mh_profile) { /* build mh_profile and mh_pathname now */ sprintf (tmp,"%s/%s",myhomedir (),MHPROFILE); if ((fd = open (mh_profile = cpystr (tmp),O_RDONLY,NIL)) >= 0) { fstat (fd,&sbuf); /* yes, get size and read file */ read (fd,(t = (char *) fs_get (sbuf.st_size + 1)),sbuf.st_size); close (fd); /* don't need the file any more */ t[sbuf.st_size] = '\0'; /* tie it off */ /* parse profile file */ for (s = strtok_r (t,"\r\n",&r); s && *s; s = strtok_r (NIL,"\r\n",&r)) { /* found space in line? */ if (v = strpbrk (s," \t")) { *v++ = '\0'; /* tie off, is keyword "Path:"? */ if (!compare_cstring (s,"Path:")) { /* skip whitespace */ while ((*v == ' ') || (*v == '\t')) ++v; /* absolute path? */ if (*v == '/') s = v; else sprintf (s = tmp,"%s/%s",myhomedir (),v); /* copy name */ mh_pathname = cpystr (s); break; /* don't need to look at rest of file */ } } } fs_give ((void **) &t); /* flush profile text */ if (!mh_pathname) { /* default path if not in the profile */ sprintf (tmp,"%s/%s",myhomedir (),MHPATH); mh_pathname = cpystr (tmp); } } } return mh_pathname; } /* MH manipulate driver parameters * Accepts: function code * function-dependent value * Returns: function-dependent return value */ void *mh_parameters (long function,void *value) { void *ret = NIL; switch ((int) function) { case GET_INBOXPATH: if (value) ret = mh_file ((char *) value,"INBOX"); break; case GET_DIRFMTTEST: ret = (void *) mh_dirfmttest; break; case SET_MHPROFILE: if (mh_profile) fs_give ((void **) &mh_profile); mh_profile = cpystr ((char *) value); case GET_MHPROFILE: ret = (void *) mh_profile; break; case SET_MHPATH: if (mh_pathname) fs_give ((void **) &mh_pathname); mh_pathname = cpystr ((char *) value); case GET_MHPATH: ret = (void *) mh_pathname; break; case SET_MHALLOWINBOX: mh_allow_inbox = value ? T : NIL; case GET_MHALLOWINBOX: ret = (void *) (mh_allow_inbox ? VOIDT : NIL); } return ret; } /* MH test for directory format internal node * Accepts: candidate node name * Returns: T if internal name, NIL otherwise */ long mh_dirfmttest (char *s) { int c; /* sequence(s) file is an internal name */ if (strcmp (s,MHSEQUENCE) && strcmp (s,MHSEQUENCES)) { if (*s == MHCOMMA) ++s; /* else comma + all numeric name */ /* success if all-numeric */ while (c = *s++) if (!isdigit (c)) return NIL; } return LONGT; } /* MH scan mailboxes * Accepts: mail stream * reference * pattern to search * string to scan */ void mh_scan (MAILSTREAM *stream,char *ref,char *pat,char *contents) { char *s,test[MAILTMPLEN],file[MAILTMPLEN]; long i = 0; if (!pat || !*pat) { /* empty pattern? */ if (mh_canonicalize (test,ref,"*")) { /* tie off name at root */ if (s = strchr (test,'/')) *++s = '\0'; else test[0] = '\0'; mm_list (stream,'/',test,LATT_NOSELECT); } } /* get canonical form of name */ else if (mh_canonicalize (test,ref,pat)) { if (contents) { /* maybe I'll implement this someday */ mm_log ("Scan not valid for mh mailboxes",ERROR); return; } if (test[3] == '/') { /* looking down levels? */ /* yes, found any wildcards? */ if (s = strpbrk (test,"%*")) { /* yes, copy name up to that point */ strncpy (file,test+4,i = s - (test+4)); file[i] = '\0'; /* tie off */ } else strcpy (file,test+4);/* use just that name then */ /* find directory name */ if (s = strrchr (file,'/')) { *s = '\0'; /* found, tie off at that point */ s = file; } /* do the work */ mh_list_work (stream,s,test,0); } /* always an INBOX */ if (!compare_cstring (test,MHINBOX)) mm_list (stream,NIL,MHINBOX,LATT_NOINFERIORS); } } /* MH list mailboxes * Accepts: mail stream * reference * pattern to search */ void mh_list (MAILSTREAM *stream,char *ref,char *pat) { mh_scan (stream,ref,pat,NIL); } /* MH list subscribed mailboxes * Accepts: mail stream * reference * pattern to search */ void mh_lsub (MAILSTREAM *stream,char *ref,char *pat) { void *sdb = NIL; char *s,test[MAILTMPLEN]; /* get canonical form of name */ if (mh_canonicalize (test,ref,pat) && (s = sm_read (&sdb))) { do if (pmatch_full (s,test,'/')) mm_lsub (stream,'/',s,NIL); while (s = sm_read (&sdb)); /* until no more subscriptions */ } } /* MH list mailboxes worker routine * Accepts: mail stream * directory name to search * search pattern * search level */ void mh_list_work (MAILSTREAM *stream,char *dir,char *pat,long level) { DIR *dp; struct direct *d; struct stat sbuf; char *cp,*np,curdir[MAILTMPLEN],name[MAILTMPLEN]; /* build MH name to search */ if (dir) sprintf (name,"#mh/%s/",dir); else strcpy (name,"#mh/"); /* make directory name, punt if bogus */ if (!mh_file (curdir,name)) return; cp = curdir + strlen (curdir);/* end of directory name */ np = name + strlen (name); /* end of MH name */ if (dp = opendir (curdir)) { /* open directory */ while (d = readdir (dp)) /* scan, ignore . and numeric names */ if ((d->d_name[0] != '.') && !mh_select (d)) { strcpy (cp,d->d_name); /* make directory name */ if (!stat (curdir,&sbuf) && ((sbuf.st_mode & S_IFMT) == S_IFDIR)) { strcpy (np,d->d_name);/* make mh name of directory name */ /* yes, an MH name if full match */ if (pmatch_full (name,pat,'/')) mm_list (stream,'/',name,NIL); /* check if should recurse */ if (dmatch (name,pat,'/') && (level < (long) mail_parameters (NIL,GET_LISTMAXLEVEL,NIL))) mh_list_work (stream,name+4,pat,level+1); } } closedir (dp); /* all done, flush directory */ } } /* MH mail subscribe to mailbox * Accepts: mail stream * mailbox to add to subscription list * Returns: T on success, NIL on failure */ long mh_subscribe (MAILSTREAM *stream,char *mailbox) { return sm_subscribe (mailbox); } /* MH mail unsubscribe to mailbox * Accepts: mail stream * mailbox to delete from subscription list * Returns: T on success, NIL on failure */ long mh_unsubscribe (MAILSTREAM *stream,char *mailbox) { return sm_unsubscribe (mailbox); } /* MH mail create mailbox * Accepts: mail stream * mailbox name to create * Returns: T on success, NIL on failure */ long mh_create (MAILSTREAM *stream,char *mailbox) { char tmp[MAILTMPLEN]; if (!mh_namevalid (mailbox)) /* validate name */ sprintf (tmp,"Can't create mailbox %.80s: invalid MH-format name",mailbox); /* must not already exist */ else if (mh_isvalid (mailbox,tmp,NIL)) sprintf (tmp,"Can't create mailbox %.80s: mailbox already exists",mailbox); else if (!mh_path (tmp)) return NIL; /* try to make it */ else if (!(mh_file (tmp,mailbox) && dummy_create_path (stream,strcat (tmp,"/"), get_dir_protection (mailbox)))) sprintf (tmp,"Can't create mailbox %.80s: %s",mailbox,strerror (errno)); else return LONGT; /* success */ mm_log (tmp,ERROR); return NIL; } /* MH mail delete mailbox * mailbox name to delete * Returns: T on success, NIL on failure */ long mh_delete (MAILSTREAM *stream,char *mailbox) { DIR *dirp; struct direct *d; int i; char tmp[MAILTMPLEN]; /* is mailbox valid? */ if (!mh_isvalid (mailbox,tmp,NIL)) { sprintf (tmp,"Can't delete mailbox %.80s: no such mailbox",mailbox); mm_log (tmp,ERROR); return NIL; } /* get name of directory */ i = strlen (mh_file (tmp,mailbox)); if (dirp = opendir (tmp)) { /* open directory */ tmp[i++] = '/'; /* now apply trailing delimiter */ /* massacre all mh owned files */ while (d = readdir (dirp)) if (mh_dirfmttest (d->d_name)) { strcpy (tmp + i,d->d_name); unlink (tmp); /* sayonara */ } closedir (dirp); /* flush directory */ } /* try to remove the directory */ if (rmdir (mh_file (tmp,mailbox))) { sprintf (tmp,"Can't delete mailbox %.80s: %s",mailbox,strerror (errno)); mm_log (tmp,WARN); } return T; /* return success */ } /* MH mail rename mailbox * Accepts: MH mail stream * old mailbox name * new mailbox name * Returns: T on success, NIL on failure */ long mh_rename (MAILSTREAM *stream,char *old,char *newname) { char c,*s,tmp[MAILTMPLEN],tmp1[MAILTMPLEN]; struct stat sbuf; /* old mailbox name must be valid */ if (!mh_isvalid (old,tmp,NIL)) sprintf (tmp,"Can't rename mailbox %.80s: no such mailbox",old); else if (!mh_namevalid (newname)) sprintf (tmp,"Can't rename to mailbox %.80s: invalid MH-format name", newname); /* new mailbox name must not be valid */ else if (mh_isvalid (newname,tmp,NIL)) sprintf (tmp,"Can't rename to mailbox %.80s: destination already exists", newname); /* success if can rename the directory */ else { /* found superior to destination name? */ if (s = strrchr (mh_file (tmp1,newname),'/')) { c = *++s; /* remember first character of inferior */ *s = '\0'; /* tie off to get just superior */ /* name doesn't exist, create it */ if ((stat (tmp1,&sbuf) || ((sbuf.st_mode & S_IFMT) != S_IFDIR)) && !dummy_create_path (stream,tmp1,get_dir_protection (newname))) return NIL; *s = c; /* restore full name */ } if (!rename (mh_file (tmp,old),tmp1)) return T; sprintf (tmp,"Can't rename mailbox %.80s to %.80s: %s", old,newname,strerror (errno)); } mm_log (tmp,ERROR); /* something failed */ return NIL; } /* MH mail open * Accepts: stream to open * Returns: stream on success, NIL on failure */ MAILSTREAM *mh_open (MAILSTREAM *stream) { char tmp[MAILTMPLEN]; if (!stream) return &mhproto; /* return prototype for OP_PROTOTYPE call */ if (stream->local) fatal ("mh recycle stream"); stream->local = fs_get (sizeof (MHLOCAL)); /* INBOXness is one of the following: * #mhinbox (case-independent) * #mh/inbox (mh is case-independent, inbox is case-dependent) * INBOX (case-independent */ stream->inbox = /* note if an INBOX or not */ (!compare_cstring (stream->mailbox,MHINBOX) || ((stream->mailbox[0] == '#') && ((stream->mailbox[1] == 'm') || (stream->mailbox[1] == 'M')) && ((stream->mailbox[2] == 'h') || (stream->mailbox[2] == 'H')) && (stream->mailbox[3] == '/') && !strcmp (stream->mailbox+4,MHINBOXDIR)) || !compare_cstring (stream->mailbox,"INBOX")) ? T : NIL; mh_file (tmp,stream->mailbox);/* get directory name */ LOCAL->dir = cpystr (tmp); /* copy directory name for later */ LOCAL->scantime = 0; /* not scanned yet */ LOCAL->cachedtexts = 0; /* no cached texts */ stream->sequence++; /* bump sequence number */ /* parse mailbox */ stream->nmsgs = stream->recent = 0; if (!mh_ping (stream)) return NIL; if (!(stream->nmsgs || stream->silent)) mm_log ("Mailbox is empty",(long) NIL); return stream; /* return stream to caller */ } /* MH mail close * Accepts: MAIL stream * close options */ void mh_close (MAILSTREAM *stream,long options) { if (LOCAL) { /* only if a file is open */ int silent = stream->silent; stream->silent = T; /* note this stream is dying */ if (options & CL_EXPUNGE) mh_expunge (stream,NIL,NIL); if (LOCAL->dir) fs_give ((void **) &LOCAL->dir); /* nuke the local data */ fs_give ((void **) &stream->local); stream->dtb = NIL; /* log out the DTB */ stream->silent = silent; /* reset silent state */ } } /* MH mail fetch fast information * Accepts: MAIL stream * sequence * option flags */ void mh_fast (MAILSTREAM *stream,char *sequence,long flags) { MESSAGECACHE *elt; unsigned long i; /* set up metadata for all messages */ if (stream && LOCAL && ((flags & FT_UID) ? mail_uid_sequence (stream,sequence) : mail_sequence (stream,sequence))) for (i = 1; i <= stream->nmsgs; i++) if ((elt = mail_elt (stream,i))->sequence && !(elt->day && elt->rfc822_size)) mh_load_message (stream,i,NIL); } /* MH load message into cache * Accepts: MAIL stream * message # * option flags */ void mh_load_message (MAILSTREAM *stream,unsigned long msgno,long flags) { unsigned long i,j,nlseen; int fd; unsigned char c,*t; struct stat sbuf; MESSAGECACHE *elt; FDDATA d; STRING bs; elt = mail_elt (stream,msgno);/* get elt */ /* build message file name */ sprintf (LOCAL->buf,"%s/%lu",LOCAL->dir,elt->private.uid); /* anything we need not currently cached? */ if ((!elt->day || !elt->rfc822_size || ((flags & MLM_HEADER) && !elt->private.msg.header.text.data) || ((flags & MLM_TEXT) && !elt->private.msg.text.text.data)) && ((fd = open (LOCAL->buf,O_RDONLY,NIL)) >= 0)) { fstat (fd,&sbuf); /* get file metadata */ d.fd = fd; /* set up file descriptor */ d.pos = 0; /* start of file */ d.chunk = LOCAL->buf; d.chunksize = CHUNKSIZE; INIT (&bs,fd_string,&d,sbuf.st_size); if (!elt->day) { /* set internaldate to file date */ struct tm *tm = gmtime (&sbuf.st_mtime); elt->day = tm->tm_mday; elt->month = tm->tm_mon + 1; elt->year = tm->tm_year + 1900 - BASEYEAR; elt->hours = tm->tm_hour; elt->minutes = tm->tm_min; elt->seconds = tm->tm_sec; elt->zhours = 0; elt->zminutes = 0; } if (!elt->rfc822_size) { /* know message size yet? */ for (i = 0, j = SIZE (&bs), nlseen = 0; j--; ) switch (SNX (&bs)) { case '\015': /* unlikely carriage return */ if (!j || (CHR (&bs) != '\012')) { i++; /* ugh, raw CR */ nlseen = NIL; break; } SNX (&bs); /* eat the line feed, drop in */ --j; case '\012': /* line feed? */ i += 2; /* count a CRLF */ /* header size known yet? */ if (!elt->private.msg.header.text.size && nlseen) { /* note position in file */ elt->private.special.text.size = GETPOS (&bs); /* and CRLF-adjusted size */ elt->private.msg.header.text.size = i; } nlseen = T; /* note newline seen */ break; default: /* ordinary chararacter */ i++; nlseen = NIL; break; } SETPOS (&bs,0); /* restore old position */ elt->rfc822_size = i; /* note that we have size now */ /* header is entire message if no delimiter */ if (!elt->private.msg.header.text.size) elt->private.msg.header.text.size = elt->rfc822_size; /* text is remainder of message */ elt->private.msg.text.text.size = elt->rfc822_size - elt->private.msg.header.text.size; } /* need to load cache with message data? */ if (((flags & MLM_HEADER) && !elt->private.msg.header.text.data) || ((flags & MLM_TEXT) && !elt->private.msg.text.text.data)) { /* purge cache if too big */ if (LOCAL->cachedtexts > max (stream->nmsgs * 4096,2097152)) { /* just can't keep that much */ mail_gc (stream,GC_TEXTS); LOCAL->cachedtexts = 0; } if ((flags & MLM_HEADER) && !elt->private.msg.header.text.data) { t = elt->private.msg.header.text.data = (unsigned char *) fs_get (elt->private.msg.header.text.size + 1); LOCAL->cachedtexts += elt->private.msg.header.text.size; /* read in message header */ for (i = 0; i < elt->private.msg.header.text.size; i++) switch (c = SNX (&bs)) { case '\015': /* unlikely carriage return */ *t++ = c; if ((CHR (&bs) == '\012')) { *t++ = SNX (&bs); i++; } break; case '\012': /* line feed? */ *t++ = '\015'; i++; default: *t++ = c; break; } *t = '\0'; /* tie off string */ if ((t - elt->private.msg.header.text.data) != elt->private.msg.header.text.size) fatal ("mh hdr size mismatch"); } if ((flags & MLM_TEXT) && !elt->private.msg.text.text.data) { t = elt->private.msg.text.text.data = (unsigned char *) fs_get (elt->private.msg.text.text.size + 1); SETPOS (&bs,elt->private.special.text.size); LOCAL->cachedtexts += elt->private.msg.text.text.size; /* read in message text */ for (i = 0; i < elt->private.msg.text.text.size; i++) switch (c = SNX (&bs)) { case '\015': /* unlikely carriage return */ *t++ = c; if ((CHR (&bs) == '\012')) { *t++ = SNX (&bs); i++; } break; case '\012': /* line feed? */ *t++ = '\015'; i++; default: *t++ = c; break; } *t = '\0'; /* tie off string */ if ((t - elt->private.msg.text.text.data) != elt->private.msg.text.text.size) fatal ("mh txt size mismatch"); } } close (fd); /* flush message file */ } } /* MH mail fetch message header * Accepts: MAIL stream * message # to fetch * pointer to returned header text length * option flags * Returns: message header in RFC822 format */ char *mh_header (MAILSTREAM *stream,unsigned long msgno,unsigned long *length, long flags) { MESSAGECACHE *elt; *length = 0; /* default to empty */ if (flags & FT_UID) return "";/* UID call "impossible" */ elt = mail_elt (stream,msgno);/* get elt */ if (!elt->private.msg.header.text.data) mh_load_message (stream,msgno,MLM_HEADER); *length = elt->private.msg.header.text.size; return (char *) elt->private.msg.header.text.data; } /* MH mail fetch message text (body only) * Accepts: MAIL stream * message # to fetch * pointer to returned stringstruct * option flags * Returns: T on success, NIL on failure */ long mh_text (MAILSTREAM *stream,unsigned long msgno,STRING *bs,long flags) { MESSAGECACHE *elt; /* UID call "impossible" */ if (flags & FT_UID) return NIL; elt = mail_elt (stream,msgno);/* get elt */ /* snarf message if don't have it yet */ if (!elt->private.msg.text.text.data) { mh_load_message (stream,msgno,MLM_TEXT); if (!elt->private.msg.text.text.data) return NIL; } if (!(flags & FT_PEEK)) { /* mark as seen */ mail_elt (stream,msgno)->seen = T; mm_flags (stream,msgno); } INIT (bs,mail_string,elt->private.msg.text.text.data, elt->private.msg.text.text.size); return T; } /* MH mail ping mailbox * Accepts: MAIL stream * Returns: T if stream alive, else NIL */ long mh_ping (MAILSTREAM *stream) { MAILSTREAM *sysibx = NIL; MESSAGECACHE *elt,*selt; struct stat sbuf; char *s,tmp[MAILTMPLEN]; int fd; unsigned long i,j,r; unsigned long old = stream->uid_last; long nmsgs = stream->nmsgs; long recent = stream->recent; int silent = stream->silent; if (stat (LOCAL->dir,&sbuf)) {/* directory exists? */ if (stream->inbox && /* no, create if INBOX */ dummy_create_path (stream,strcat (mh_file (tmp,MHINBOX),"/"), get_dir_protection ("INBOX"))) return T; sprintf (tmp,"Can't open mailbox %.80s: no such mailbox",stream->mailbox); mm_log (tmp,ERROR); return NIL; } stream->silent = T; /* don't pass up mm_exists() events yet */ if (sbuf.st_ctime != LOCAL->scantime) { struct direct **names = NIL; long nfiles = scandir (LOCAL->dir,&names,mh_select,mh_numsort); if (nfiles < 0) nfiles = 0; /* in case error */ /* note scanned now */ LOCAL->scantime = sbuf.st_ctime; /* scan directory */ for (i = 0; i < nfiles; ++i) { /* if newly seen, add to list */ if ((j = atoi (names[i]->d_name)) > old) { mail_exists (stream,++nmsgs); stream->uid_last = (elt = mail_elt (stream,nmsgs))->private.uid = j; elt->valid = T; /* note valid flags */ if (old) { /* other than the first pass? */ elt->recent = T; /* yup, mark as recent */ recent++; /* bump recent count */ } else { /* see if already read */ sprintf (tmp,"%s/%s",LOCAL->dir,names[i]->d_name); if (!stat (tmp,&sbuf) && (sbuf.st_atime > sbuf.st_mtime)) elt->seen = T; } } fs_give ((void **) &names[i]); } /* free directory */ if (s = (void *) names) fs_give ((void **) &s); } /* if INBOX, snarf from system INBOX */ if (stream->inbox && strcmp (sysinbox (),stream->mailbox)) { old = stream->uid_last; mm_critical (stream); /* go critical */ /* see if anything in system inbox */ if (!stat (sysinbox (),&sbuf) && sbuf.st_size && (sysibx = mail_open (sysibx,sysinbox (),OP_SILENT)) && !sysibx->rdonly && (r = sysibx->nmsgs)) { for (i = 1; i <= r; ++i) {/* for each message in sysinbox mailbox */ /* build file name we will use */ sprintf (LOCAL->buf,"%s/%lu",LOCAL->dir,++old); /* snarf message from Berkeley mailbox */ selt = mail_elt (sysibx,i); if (((fd = open (LOCAL->buf,O_WRONLY|O_CREAT|O_EXCL, (long) mail_parameters (NIL,GET_MBXPROTECTION,NIL))) >= 0) && (s = mail_fetchheader_full (sysibx,i,NIL,&j,FT_INTERNAL)) && (write (fd,s,j) == j) && (s = mail_fetchtext_full (sysibx,i,&j,FT_INTERNAL|FT_PEEK)) && (write (fd,s,j) == j) && !fsync (fd) && !close (fd)) { /* swell the cache */ mail_exists (stream,++nmsgs); stream->uid_last = /* create new elt, note its file number */ (elt = mail_elt (stream,nmsgs))->private.uid = old; recent++; /* bump recent count */ /* set up initial flags and date */ elt->valid = elt->recent = T; elt->seen = selt->seen; elt->deleted = selt->deleted; elt->flagged = selt->flagged; elt->answered = selt->answered; elt->draft = selt->draft; elt->day = selt->day;elt->month = selt->month;elt->year = selt->year; elt->hours = selt->hours;elt->minutes = selt->minutes; elt->seconds = selt->seconds; elt->zhours = selt->zhours; elt->zminutes = selt->zminutes; elt->zoccident = selt->zoccident; mh_setdate (LOCAL->buf,elt); sprintf (tmp,"%lu",i);/* delete it from the sysinbox */ mail_flag (sysibx,tmp,"\\Deleted",ST_SET); } else { /* failed to snarf */ if (fd) { /* did it ever get opened? */ close (fd); /* close descriptor */ unlink (LOCAL->buf);/* flush this file */ } sprintf (tmp,"Message copy to MH mailbox failed: %.80s", s,strerror (errno)); mm_log (tmp,ERROR); r = 0; /* stop the snarf in its tracks */ } } /* update scan time */ if (!stat (LOCAL->dir,&sbuf)) LOCAL->scantime = sbuf.st_ctime; mail_expunge (sysibx); /* now expunge all those messages */ } if (sysibx) mail_close (sysibx); mm_nocritical (stream); /* release critical */ } stream->silent = silent; /* can pass up events now */ mail_exists (stream,nmsgs); /* notify upper level of mailbox size */ mail_recent (stream,recent); return T; /* return that we are alive */ } /* MH mail check mailbox * Accepts: MAIL stream */ void mh_check (MAILSTREAM *stream) { /* Perhaps in the future this will preserve flags */ if (mh_ping (stream)) mm_log ("Check completed",(long) NIL); } /* MH mail expunge mailbox * Accepts: MAIL stream * sequence to expunge if non-NIL * expunge options * Returns: T, always */ long mh_expunge (MAILSTREAM *stream,char *sequence,long options) { long ret; MESSAGECACHE *elt; unsigned long i = 1; unsigned long n = 0; unsigned long recent = stream->recent; if (ret = sequence ? ((options & EX_UID) ? mail_uid_sequence (stream,sequence) : mail_sequence (stream,sequence)) : LONGT) { mm_critical (stream); /* go critical */ while (i <= stream->nmsgs) {/* for each message */ elt = mail_elt (stream,i);/* if deleted, need to trash it */ if (elt->deleted && (sequence ? elt->sequence : T)) { sprintf (LOCAL->buf,"%s/%lu",LOCAL->dir,elt->private.uid); if (unlink (LOCAL->buf)) {/* try to delete the message */ sprintf (LOCAL->buf,"Expunge of message %lu failed, aborted: %s",i, strerror (errno)); mm_log (LOCAL->buf,(long) NIL); break; } /* note uncached */ LOCAL->cachedtexts -= ((elt->private.msg.header.text.data ? elt->private.msg.header.text.size : 0) + (elt->private.msg.text.text.data ? elt->private.msg.text.text.size : 0)); mail_gc_msg (&elt->private.msg,GC_ENV | GC_TEXTS); /* if recent, note one less recent message */ if (elt->recent) --recent; /* notify upper levels */ mail_expunged (stream,i); n++; /* count up one more expunged message */ } else i++; /* otherwise try next message */ } if (n) { /* output the news if any expunged */ sprintf (LOCAL->buf,"Expunged %lu messages",n); mm_log (LOCAL->buf,(long) NIL); } else mm_log ("No messages deleted, so no update needed",(long) NIL); mm_nocritical (stream); /* release critical */ /* notify upper level of new mailbox size */ mail_exists (stream,stream->nmsgs); mail_recent (stream,recent); } return ret; } /* MH mail copy message(s) * Accepts: MAIL stream * sequence * destination mailbox * copy options * Returns: T if copy successful, else NIL */ long mh_copy (MAILSTREAM *stream,char *sequence,char *mailbox,long options) { FDDATA d; STRING st; MESSAGECACHE *elt; struct stat sbuf; int fd; unsigned long i; char flags[MAILTMPLEN],date[MAILTMPLEN]; appenduid_t au = (appenduid_t) mail_parameters (NIL,GET_APPENDUID,NIL); long ret = NIL; /* copy the messages */ if ((options & CP_UID) ? mail_uid_sequence (stream,sequence) : mail_sequence (stream,sequence)) for (i = 1; i <= stream->nmsgs; i++) if ((elt = mail_elt (stream,i))->sequence) { sprintf (LOCAL->buf,"%s/%lu",LOCAL->dir,elt->private.uid); if ((fd = open (LOCAL->buf,O_RDONLY,NIL)) < 0) return NIL; fstat (fd,&sbuf); /* get size of message */ if (!elt->day) { /* set internaldate to file date if needed */ struct tm *tm = gmtime (&sbuf.st_mtime); elt->day = tm->tm_mday; elt->month = tm->tm_mon + 1; elt->year = tm->tm_year + 1900 - BASEYEAR; elt->hours = tm->tm_hour; elt->minutes = tm->tm_min; elt->seconds = tm->tm_sec; elt->zhours = 0; elt->zminutes = 0; } d.fd = fd; /* set up file descriptor */ d.pos = 0; /* start of file */ d.chunk = LOCAL->buf; d.chunksize = CHUNKSIZE; /* kludge; mh_append would just strip CRs */ INIT (&st,fd_string,&d,sbuf.st_size); /* init flag string */ flags[0] = flags[1] = '\0'; if (elt->seen) strcat (flags," \\Seen"); if (elt->deleted) strcat (flags," \\Deleted"); if (elt->flagged) strcat (flags," \\Flagged"); if (elt->answered) strcat (flags," \\Answered"); if (elt->draft) strcat (flags," \\Draft"); flags[0] = '('; /* open list */ strcat (flags,")"); /* close list */ mail_date (date,elt); /* generate internal date */ if (au) mail_parameters (NIL,SET_APPENDUID,NIL); if ((ret = mail_append_full (NIL,mailbox,flags,date,&st)) && (options & CP_MOVE)) elt->deleted = T; if (au) mail_parameters (NIL,SET_APPENDUID,(void *) au); close (fd); } if (ret && mail_parameters (NIL,GET_COPYUID,NIL)) mm_log ("Can not return meaningful COPYUID with this mailbox format",WARN); return ret; /* return success */ } /* MH mail append message from stringstruct * Accepts: MAIL stream * destination mailbox * append callback * data for callback * Returns: T if append successful, else NIL */ long mh_append (MAILSTREAM *stream,char *mailbox,append_t af,void *data) { struct direct **names = NIL; int fd; char c,*flags,*date,*s,tmp[MAILTMPLEN]; STRING *message; MESSAGECACHE elt; FILE *df; long i,size,last,nfiles; long ret = LONGT; /* default stream to prototype */ if (!stream) stream = &mhproto; /* make sure valid mailbox */ if (!mh_isvalid (mailbox,tmp,NIL)) switch (errno) { case ENOENT: /* no such file? */ if (!((!compare_cstring (mailbox,MHINBOX) || !compare_cstring (mailbox,"INBOX")) && (mh_file (tmp,MHINBOX) && dummy_create_path (stream,strcat (tmp,"/"), get_dir_protection (mailbox))))) { mm_notify (stream,"[TRYCREATE] Must create mailbox before append",NIL); return NIL; } /* falls through */ case 0: /* merely empty file? */ break; case EINVAL: sprintf (tmp,"Invalid MH-format mailbox name: %.80s",mailbox); mm_log (tmp,ERROR); return NIL; default: sprintf (tmp,"Not a MH-format mailbox: %.80s",mailbox); mm_log (tmp,ERROR); return NIL; } /* get first message */ if (!(*af) (stream,data,&flags,&date,&message)) return NIL; if ((nfiles = scandir (tmp,&names,mh_select,mh_numsort)) > 0) { /* largest number */ last = atoi (names[nfiles-1]->d_name); for (i = 0; i < nfiles; ++i) /* free directory */ fs_give ((void **) &names[i]); } else last = 0; /* no messages here yet */ if (s = (void *) names) fs_give ((void **) &s); mm_critical (stream); /* go critical */ do { if (!SIZE (message)) { /* guard against zero-length */ mm_log ("Append of zero-length message",ERROR); ret = NIL; break; } if (date) { /* want to preserve date? */ /* yes, parse date into an elt */ if (!mail_parse_date (&elt,date)) { sprintf (tmp,"Bad date in append: %.80s",date); mm_log (tmp,ERROR); ret = NIL; break; } } mh_file (tmp,mailbox); /* build file name we will use */ sprintf (tmp + strlen (tmp),"/%ld",++last); if (((fd = open (tmp,O_WRONLY|O_CREAT|O_EXCL, (long)mail_parameters (NIL,GET_MBXPROTECTION,NIL))) < 0)|| !(df = fdopen (fd,"ab"))) { sprintf (tmp,"Can't open append message: %s",strerror (errno)); mm_log (tmp,ERROR); ret = NIL; break; } /* copy the data w/o CR's */ for (size = 0,i = SIZE (message); i && ret; --i) if (((c = SNX (message)) != '\015') && (putc (c,df) == EOF)) ret = NIL; /* close the file */ if (!ret || fclose (df)) { unlink (tmp); /* delete message */ sprintf (tmp,"Message append failed: %s",strerror (errno)); mm_log (tmp,ERROR); ret = NIL; } if (ret) { /* set the date for this message */ if (date) mh_setdate (tmp,&elt); /* get next message */ if (!(*af) (stream,data,&flags,&date,&message)) ret = NIL; } } while (ret && message); mm_nocritical (stream); /* release critical */ if (ret && mail_parameters (NIL,GET_APPENDUID,NIL)) mm_log ("Can not return meaningful APPENDUID with this mailbox format", WARN); return ret; } /* Internal routines */ /* MH file name selection test * Accepts: candidate directory entry * Returns: T to use file name, NIL to skip it */ int mh_select (struct direct *name) { char c; char *s = name->d_name; while (c = *s++) if (!isdigit (c)) return NIL; return T; } /* MH file name comparision * Accepts: first candidate directory entry * second candidate directory entry * Returns: negative if d1 < d2, 0 if d1 == d2, postive if d1 > d2 */ int mh_numsort (const void *d1,const void *d2) { return atoi ((*(struct direct **) d1)->d_name) - atoi ((*(struct direct **) d2)->d_name); } /* MH mail build file name * Accepts: destination string * source * Returns: destination */ char *mh_file (char *dst,char *name) { char *s; char *path = mh_path (dst); if (!path) fatal ("No mh path in mh_file()!"); /* INBOX becomes "inbox" in the MH path */ if (!compare_cstring (name,MHINBOX) || !compare_cstring (name,"INBOX")) sprintf (dst,"%.900s/%.80s",path,MHINBOXDIR); /* #mh names skip past prefix */ else if (*name == '#') sprintf (dst,"%.100s/%.900s",path,name + 4); else mailboxfile (dst,name); /* all other names */ /* tie off unnecessary trailing / */ if ((s = strrchr (dst,'/')) && !s[1] && (s[-1] == '/')) *s = '\0'; return dst; } /* MH canonicalize name * Accepts: buffer to write name * reference * pattern * Returns: T if success, NIL if failure */ long mh_canonicalize (char *pattern,char *ref,char *pat) { unsigned long i; char *s,tmp[MAILTMPLEN]; if (ref && *ref) { /* have a reference */ strcpy (pattern,ref); /* copy reference to pattern */ /* # overrides mailbox field in reference */ if (*pat == '#') strcpy (pattern,pat); /* pattern starts, reference ends, with / */ else if ((*pat == '/') && (pattern[strlen (pattern) - 1] == '/')) strcat (pattern,pat + 1); /* append, omitting one of the period */ else strcat (pattern,pat); /* anything else is just appended */ } else strcpy (pattern,pat); /* just have basic name */ if (mh_isvalid (pattern,tmp,T)) { /* count wildcards */ for (i = 0, s = pattern; *s; *s++) if ((*s == '*') || (*s == '%')) ++i; /* success if not too many */ if (i <= MAXWILDCARDS) return LONGT; mm_log ("Excessive wildcards in LIST/LSUB",ERROR); } return NIL; } /* Set date for message * Accepts: file name * elt containing date */ void mh_setdate (char *file,MESSAGECACHE *elt) { time_t tp[2]; tp[0] = time (0); /* atime is now */ tp[1] = mail_longdate (elt); /* modification time */ utime (file,tp); /* set the times */ } alpine-2.10+dfsg/imap/src/osdep/amiga/log_std.c0000600000175000017500000000217611512502124023046 0ustar paulproteuspaulproteus/* ======================================================================== * Copyright 1988-2006 University of Washington * * Licensed under the Apache License, Version 2.0 (the "License"); * you may not use this file except in compliance with the License. * You may obtain a copy of the License at * * http://www.apache.org/licenses/LICENSE-2.0 * * * ======================================================================== */ /* * Program: Standard login * * Author: Mark Crispin * Networks and Distributed Computing * Computing & Communications * University of Washington * Administration Building, AG-44 * Seattle, WA 98195 * Internet: MRC@CAC.Washington.EDU * * Date: 1 August 1988 * Last Edited: 30 August 2006 */ /* Log in * Accepts: login passwd struct * argument count * argument vector * Returns: T if success, NIL otherwise */ long loginpw (struct passwd *pw,int argc,char *argv[]) { uid_t uid = pw->pw_uid; char *name = cpystr (pw->pw_name); long ret = !(setgid (pw->pw_gid) || initgroups (name,pw->pw_gid) || setuid (uid)); fs_give ((void **) &name); return ret; } alpine-2.10+dfsg/imap/src/osdep/amiga/Makefile0000600000175000017500000001375511512502124022714 0ustar paulproteuspaulproteus# ======================================================================== # Copyright 1988-2006 University of Washington # # Licensed under the Apache License, Version 2.0 (the "License"); # you may not use this file except in compliance with the License. # You may obtain a copy of the License at # # http://www.apache.org/licenses/LICENSE-2.0 # # # ======================================================================== # Program: C client makefile for Amiga # # Author: Mark Crispin # Networks and Distributed Computing # Computing & Communications # University of Washington # Administration Building, AG-44 # Seattle, WA 98195 # Internet: MRC@CAC.Washington.EDU # # Date: 11 May 1989 # Last Edited: 5 November 2006 # Command line build parameters EXTRAAUTHENTICATORS= EXTRADRIVERS=mbox PASSWDTYPE=std # Build parameters normally set by the individual port AMICFLAGS=-O -DNO_INLINE_STDARG -Dunix AMILDFLAGS=/pine/libc.a -lamiga -lauto CHECKPW=std LOGINPW=std ACTIVEFILE=/UULib/News/Active SPOOLDIR=/usr/spool MAILSPOOL=/AmiTCP/Mail NEWSSPOOL=/UUNews MD5PWD="/etc/cram-md5.pwd" # Default formats for creating new mailboxes and for empty mailboxes in the # default namespace; must be set to the associated driver's prototype. # # The CREATEPROTO is the default format for new mailbox creation. # The EMPTYPROTO is the default format for handling zero-byte files. # # Normally, this is set by the individual port. # # NOTE: namespace formats (e.g. mh and news) can not be set as a default format # since they do not exist in the default namespace. Also, it is meaningless to # set certain other formats (e.g. mbx, mx, and mix) as the EMPTYPROTO since # these formats can never be empty files. CREATEPROTO=unixproto EMPTYPROTO=unixproto # Commands possibly overriden by the individual port ARRC=ar rc CC=cc LN=cp RANLIB=ranlib RM=rm -f # Standard distribution build parameters DEFAULTAUTHENTICATORS=ext md5 pla log DEFAULTDRIVERS=imap nntp pop3 mix mx mbx tenex mtx mh mmdf unix news phile CHUNKSIZE=65536 # Normally no need to change any of these ARCHIVE=c-client.a BINARIES=mail.o misc.o newsrc.o smanager.o osdep.o utf8.o utf8aux.o \ dummy.o pseudo.o netmsg.o flstring.o fdstring.o \ rfc822.o nntp.o smtp.o imap4r1.o pop3.o \ unix.o mbx.o mmdf.o tenex.o mtx.o news.o phile.o mh.o mx.o mix.o CFLAGS=$(BASECFLAGS) $(EXTRACFLAGS) MAKE=make MV=mv SHELL=/bin/sh # Primary build command BUILDOPTIONS= EXTRACFLAGS=$(EXTRACFLAGS) EXTRALDFLAGS=$(EXTRALDFLAGS)\ EXTRADRIVERS=$(EXTRADRIVERS) EXTRAAUTHENTICATORS=$(EXTRAAUTHENTICATORS)\ PASSWDTYPE=$(PASSWDTYPE) BUILD=$(MAKE) build $(BUILDOPTIONS) $(SPECIALS) # Here if no make argument established missing: osdep.h $(MAKE) $(ARCHIVE) CC=`cat CCTYPE` CFLAGS="`cat CFLAGS`" osdep.h: @echo You must specify what type of system @false # Current ports ami: # AmigaDOS $(BUILD) OS=$@ \ BASECFLAGS="-DOLD $(AMICFLAGS)" \ BASELDFLAGS="$(AMILDFLAGS) -lamitcp000" \ CC=gcc am2: # AmigaDOS with a 68020+ $(BUILD) OS=ami \ BASECFLAGS="-DOLD -m68020 $(AMICFLAGS)" \ BASELDFLAGS="$(AMILDFLAGS) -lamitcp" \ CC=gcc amn: # AmigaDOS with a 680x0 using "new" socket library $(BUILD) OS=ami \ BASELDFLAGS="$(AMILDFLAGS) -lnewamitcp000" \ CC=gcc ama: # AmigaDOS using AS225R2 $(BUILD) OS=ami \ MAILSPOOL=/INet/Mail \ BASECFLAGS="-m68020 $(AMICFLAGS)" \ BASELDFLAGS="$(AMILDFLAGS) -las225r2" \ CC=gcc # Build it! build: clean once ckp$(PASSWDTYPE) $(EXTRAAUTHENTICATORS) $(ARCHIVE) $(ARCHIVE): $(BINARIES) $(RM) $(ARCHIVE) || true $(ARRC) $(ARCHIVE) $(BINARIES) $(RANLIB) $(ARCHIVE) # Cleanup clean: $(RM) *.o linkage.[ch] auths.c $(ARCHIVE) osdep.* *TYPE *FLAGS || true # Dependencies dummy.o: mail.h misc.h osdep.h dummy.h fdstring.o: mail.h misc.h osdep.h fdstring.h flstring.o: mail.h misc.h osdep.h flstring.h imap4r1.o: mail.h misc.h osdep.h imap4r1.h rfc822.h mail.o: mail.h misc.h osdep.h rfc822.h linkage.h mbx.o: mail.h misc.h osdep.h dummy.h mh.o: mail.h misc.h osdep.h mh.h dummy.h mix.o: mail.h misc.h osdep.h dummy.h mx.o: mail.h misc.h osdep.h mx.h dummy.h misc.o: mail.h misc.h osdep.h mmdf.o: mail.h misc.h osdep.h pseudo.h dummy.h mtx.o: mail.h misc.h osdep.h dummy.h netmsg.o: mail.h misc.h osdep.h netmsg.h news.o: mail.h misc.h osdep.h newsrc.o: mail.h misc.h osdep.h newsrc.h nntp.o: mail.h misc.h osdep.h netmsg.h smtp.h nntp.h rfc822.h phile.o: mail.h misc.h osdep.h rfc822.h dummy.h pseudo.o: pseudo.h pop3.o: mail.h misc.h osdep.h pop3.h rfc822.h smanager.o: mail.h misc.h osdep.h smtp.o: mail.h misc.h osdep.h smtp.h rfc822.h rfc822.o: mail.h misc.h osdep.h rfc822.h tenex.o: mail.h misc.h osdep.h dummy.h unix.o: mail.h misc.h osdep.h unix.h pseudo.h dummy.h utf8.o: mail.h misc.h osdep.h utf8.h utf8aux.o: mail.h misc.h osdep.h utf8.h # OS-dependent osdep.o:mail.h misc.h env.h fs.h ftl.h nl.h tcp.h \ osdep.h env_ami.h tcp_ami.h \ osdep.c env_ami.c fs_ami.c ftl_ami.c nl_ami.c tcp_ami.c \ auths.c gethstid.c \ gr_waitp.c \ auth_log.c auth_md5.c auth_pla.c \ pmatch.c scandir.c \ tz_bsd.c \ write.c \ strerror.c strpbrk.c strstr.c strtok.c strtoul.c \ OSCFLAGS $(CC) $(CFLAGS) `cat OSCFLAGS` -c osdep.c osdep.c: osdepbas.c osdepckp.c osdeplog.c osdepssl.c $(RM) osdep.c || true cat osdepbas.c osdepckp.c osdeplog.c osdepssl.c > osdep.c # Once-only environment setup once: @echo Once-only environment setup... ./drivers $(EXTRADRIVERS) $(DEFAULTDRIVERS) dummy ./mkauths $(EXTRAAUTHENTICATORS) $(DEFAULTAUTHENTICATORS) echo $(CC) > CCTYPE echo $(CFLAGS) -DCHUNKSIZE=$(CHUNKSIZE) > CFLAGS echo -DCREATEPROTO=$(CREATEPROTO) -DEMPTYPROTO=$(EMPTYPROTO) \ -DMD5ENABLE=\"$(MD5PWD)\" -DMAILSPOOL=\"$(MAILSPOOL)\" \ -DACTIVEFILE=\"$(ACTIVEFILE)\" -DNEWSSPOOL=\"$(NEWSSPOOL)\" \ -DANONYMOUSHOME=\"$(MAILSPOOL)/anonymous\" > OSCFLAGS echo $(BASELDFLAGS) $(EXTRALDFLAGS) > LDFLAGS $(LN) os_$(OS).h osdep.h $(LN) os_$(OS).c osdepbas.c $(LN) log_$(LOGINPW).c osdeplog.c $(LN) ssl_none.c osdepssl.c # Password checkers ckpstd: # Port standard $(LN) ckp_$(CHECKPW).c osdepckp.c # A monument to a hack of long ago and far away... love: @echo not war? alpine-2.10+dfsg/imap/src/osdep/amiga/pseudo.c0000600000175000017500000000236611512502124022713 0ustar paulproteuspaulproteus/* ======================================================================== * Copyright 1988-2006 University of Washington * * Licensed under the Apache License, Version 2.0 (the "License"); * you may not use this file except in compliance with the License. * You may obtain a copy of the License at * * http://www.apache.org/licenses/LICENSE-2.0 * * * ======================================================================== */ /* * Program: Pseudo Header Strings * * Author: Mark Crispin * Networks and Distributed Computing * Computing & Communications * University of Washington * Administration Building, AG-44 * Seattle, WA 98195 * Internet: MRC@CAC.Washington.EDU * * Date: 26 September 1996 * Last Edited: 30 August 2006 */ /* Local sites may wish to alter this text */ char *pseudo_from = "MAILER-DAEMON"; char *pseudo_name = "Mail System Internal Data"; char *pseudo_subject = "DON'T DELETE THIS MESSAGE -- FOLDER INTERNAL DATA"; char *pseudo_msg = "This text is part of the internal format of your mail folder, and is not\na real message. It is created automatically by the mail system software.\nIf deleted, important folder data will be lost, and it will be re-created\nwith the data reset to initial values." ; alpine-2.10+dfsg/imap/src/osdep/amiga/mbx.c0000600000175000017500000017366511512502124022215 0ustar paulproteuspaulproteus/* ======================================================================== * Copyright 1988-2007 University of Washington * * Licensed under the Apache License, Version 2.0 (the "License"); * you may not use this file except in compliance with the License. * You may obtain a copy of the License at * * http://www.apache.org/licenses/LICENSE-2.0 * * * ======================================================================== */ /* * Program: MBX mail routines * * Author: Mark Crispin * Networks and Distributed Computing * Computing & Communications * University of Washington * Administration Building, AG-44 * Seattle, WA 98195 * Internet: MRC@CAC.Washington.EDU * * Date: 3 October 1995 * Last Edited: 11 October 2007 */ /* FILE TIME SEMANTICS * * The atime is the last read time of the file. * The mtime is the last flags update time of the file. * The ctime is the last write time of the file. */ #include #include #include extern int errno; /* just in case */ #include "mail.h" #include "osdep.h" #include #include #include #include "misc.h" #include "dummy.h" #include "fdstring.h" /* Build parameters */ #define HDRSIZE 2048 /* Kludge to make Cygwin happy */ #ifndef O_BINARY #define O_BINARY 0 #endif /* MBX I/O stream local data */ typedef struct mbx_local { unsigned int flagcheck: 1; /* if ping should sweep for flags */ unsigned int expok: 1; /* if expunging OK in ping */ unsigned int expunged : 1; /* if one or more expunged messages */ int fd; /* file descriptor for I/O */ int ld; /* lock file descriptor */ int ffuserflag; /* first free user flag */ off_t filesize; /* file size parsed */ time_t filetime; /* last file time */ time_t lastsnarf; /* last snarf time */ unsigned long lastpid; /* PID of last writer */ unsigned char *buf; /* temporary buffer */ unsigned long buflen; /* current size of temporary buffer */ char lock[MAILTMPLEN]; /* buffer to write lock name */ } MBXLOCAL; /* Convenient access to local data */ #define LOCAL ((MBXLOCAL *) stream->local) /* Function prototypes */ DRIVER *mbx_valid (char *name); int mbx_isvalid (MAILSTREAM **stream,char *name,char *tmp,int *ld,char *lock, long flags); void *mbx_parameters (long function,void *value); void mbx_scan (MAILSTREAM *stream,char *ref,char *pat,char *contents); void mbx_list (MAILSTREAM *stream,char *ref,char *pat); void mbx_lsub (MAILSTREAM *stream,char *ref,char *pat); long mbx_create (MAILSTREAM *stream,char *mailbox); long mbx_delete (MAILSTREAM *stream,char *mailbox); long mbx_rename (MAILSTREAM *stream,char *old,char *newname); long mbx_status (MAILSTREAM *stream,char *mbx,long flags); MAILSTREAM *mbx_open (MAILSTREAM *stream); void mbx_close (MAILSTREAM *stream,long options); void mbx_abort (MAILSTREAM *stream); void mbx_flags (MAILSTREAM *stream,char *sequence,long flags); char *mbx_header (MAILSTREAM *stream,unsigned long msgno,unsigned long *length, long flags); long mbx_text (MAILSTREAM *stream,unsigned long msgno,STRING *bs,long flags); void mbx_flag (MAILSTREAM *stream,char *sequence,char *flag,long flags); void mbx_flagmsg (MAILSTREAM *stream,MESSAGECACHE *elt); long mbx_ping (MAILSTREAM *stream); void mbx_check (MAILSTREAM *stream); long mbx_expunge (MAILSTREAM *stream,char *sequence,long options); void mbx_snarf (MAILSTREAM *stream); long mbx_copy (MAILSTREAM *stream,char *sequence,char *mailbox,long options); long mbx_append (MAILSTREAM *stream,char *mailbox,append_t af,void *data); char *mbx_file (char *dst,char *name); long mbx_parse (MAILSTREAM *stream); MESSAGECACHE *mbx_elt (MAILSTREAM *stream,unsigned long msgno,long expok); unsigned long mbx_read_flags (MAILSTREAM *stream,MESSAGECACHE *elt); void mbx_update_header (MAILSTREAM *stream); void mbx_update_status (MAILSTREAM *stream,unsigned long msgno,long flags); unsigned long mbx_hdrpos (MAILSTREAM *stream,unsigned long msgno, unsigned long *size,char **hdr); unsigned long mbx_rewrite (MAILSTREAM *stream,unsigned long *reclaimed, long flags); long mbx_flaglock (MAILSTREAM *stream); /* MBX mail routines */ /* Driver dispatch used by MAIL */ DRIVER mbxdriver = { "mbx", /* driver name */ DR_LOCAL|DR_MAIL|DR_CRLF|DR_LOCKING, /* driver flags */ (DRIVER *) NIL, /* next driver */ mbx_valid, /* mailbox is valid for us */ mbx_parameters, /* manipulate parameters */ mbx_scan, /* scan mailboxes */ mbx_list, /* list mailboxes */ mbx_lsub, /* list subscribed mailboxes */ NIL, /* subscribe to mailbox */ NIL, /* unsubscribe from mailbox */ mbx_create, /* create mailbox */ mbx_delete, /* delete mailbox */ mbx_rename, /* rename mailbox */ mbx_status, /* status of mailbox */ mbx_open, /* open mailbox */ mbx_close, /* close mailbox */ mbx_flags, /* fetch message "fast" attributes */ mbx_flags, /* fetch message flags */ NIL, /* fetch overview */ NIL, /* fetch message envelopes */ mbx_header, /* fetch message header */ mbx_text, /* fetch message body */ NIL, /* fetch partial message text */ NIL, /* unique identifier */ NIL, /* message number */ mbx_flag, /* modify flags */ mbx_flagmsg, /* per-message modify flags */ NIL, /* search for message based on criteria */ NIL, /* sort messages */ NIL, /* thread messages */ mbx_ping, /* ping mailbox to see if still alive */ mbx_check, /* check for new messages */ mbx_expunge, /* expunge deleted messages */ mbx_copy, /* copy messages to another mailbox */ mbx_append, /* append string message to mailbox */ NIL /* garbage collect stream */ }; /* prototype stream */ MAILSTREAM mbxproto = {&mbxdriver}; /* MBX mail validate mailbox * Accepts: mailbox name * Returns: our driver if name is valid, NIL otherwise */ DRIVER *mbx_valid (char *name) { char tmp[MAILTMPLEN]; int fd = mbx_isvalid (NIL,name,tmp,NIL,NIL,NIL); if (fd < 0) return NIL; close (fd); /* don't need the fd now */ return &mbxdriver; } /* MBX mail test for valid mailbox * Accepts: returned stream with valid mailbox keywords * mailbox name * scratch buffer * returned lock fd * returned lock name * RW flags or NIL for readonly * Returns: file descriptor if valid, NIL otherwise */ #define MBXISVALIDNOUID 0x1 /* RW, don't do UID action */ #define MBXISVALIDUID 0x2 /* RW, do UID action */ int mbx_isvalid (MAILSTREAM **stream,char *name,char *tmp,int *ld,char *lock, long flags) { int fd,upd; int ret = -1; unsigned long i; long j,k; off_t pos; char c,*s,*t,hdr[HDRSIZE]; struct stat sbuf; time_t tp[2]; int error = EINVAL; /* assume invalid argument */ if (ld) *ld = -1; /* initially no lock */ if ((s = mbx_file (tmp,name)) && !stat (s,&sbuf) && ((fd = open (tmp,(flags ? O_RDWR : O_RDONLY)|O_BINARY,NIL)) >= 0)) { error = -1; /* bogus format */ /* I love cretinous C compilers -- don't you? */ if (read (fd,hdr,HDRSIZE) == HDRSIZE) if ((hdr[0] == '*') && (hdr[1] == 'm') && (hdr[2] == 'b') && (hdr[3] == 'x') && (hdr[4] == '*') && (hdr[5] == '\015') && (hdr[6] == '\012') && isxdigit (hdr[7]) && isxdigit (hdr[8])) if (isxdigit (hdr[9]) && isxdigit (hdr[10]) && isxdigit (hdr[11]) && isxdigit (hdr[12]) && isxdigit (hdr[13]) && isxdigit (hdr[14]) && isxdigit (c = hdr[15]) && isxdigit (hdr[16])) if (isxdigit (hdr[17]) && isxdigit (hdr[18]) && isxdigit (hdr[19]) && isxdigit (hdr[20]) && isxdigit (hdr[21]) && isxdigit (hdr[22]) && (hdr[23] == '\015') && (hdr[24] == '\012')) { ret = fd; /* mbx format */ if (stream) { /* lock if making mini-stream */ if (flock (fd,LOCK_SH) || (flags && ((*ld = lockfd (fd,lock,LOCK_EX)) < 0))) ret = -1; /* reread data now that locked */ else if (lseek (fd,0,L_SET) || (read (fd,hdr,HDRSIZE) != HDRSIZE)) ret = -1; else { *stream = (MAILSTREAM *) memset (fs_get (sizeof (MAILSTREAM)), 0,sizeof (MAILSTREAM)); hdr[15] = '\0'; /* tie off UIDVALIDITY */ (*stream)->uid_validity = strtoul (hdr+7,NIL,16); hdr[15] = c; /* now get UIDLAST */ (*stream)->uid_last = strtoul (hdr+15,NIL,16); /* parse user flags */ for (i = 0, s = hdr + 25; (i < NUSERFLAGS) && (t = strchr (s,'\015')) && (t - s); i++, s = t + 2) { *t = '\0'; /* tie off flag */ if (strlen (s) <= MAXUSERFLAG) (*stream)->user_flags[i] = cpystr (s); } /* make sure have true UIDLAST */ if (flags & MBXISVALIDUID) { for (upd = NIL,pos = 2048, k = 0; pos < sbuf.st_size; pos += (j + k)) { /* read header for this message */ lseek (fd,pos,L_SET); if ((j = read (fd,hdr,64)) >= 0) { hdr[j] = '\0'; if ((s = strchr (hdr,'\015')) && (s[1] == '\012')) { *s = '\0'; k = s + 2 - hdr; if ((s = strchr (hdr,',')) && (j = strtol (s+1,&s,10)) && (*s == ';') && (s = strchr (s+1,'-'))) { /* get UID if there is any */ i = strtoul (++s,&t,16); if (!*t && (t == (s + 8)) && (i <= (*stream)->uid_last)) { if (!i) { lseek (fd,pos + s - hdr,L_SET); sprintf (hdr,"%08lx",++(*stream)->uid_last); write (fd,hdr,8); upd = T; } continue; } } } ret = -1; /* error, give up */ *stream = mail_close (*stream); pos = sbuf.st_size + 1; j = k = 0; } } if (upd) { /* need to update hdr with new UIDLAST? */ lseek (fd,15,L_SET); sprintf (hdr,"%08lx",(*stream)->uid_last); write (fd,hdr,8); } } } } } if (ret != fd) close (fd); /* close the file */ else lseek (fd,0,L_SET); /* else rewind to start */ /* \Marked status? */ if (sbuf.st_ctime > sbuf.st_atime) { tp[0] = sbuf.st_atime; /* preserve atime and mtime */ tp[1] = sbuf.st_mtime; utime (tmp,tp); /* set the times */ } } /* in case INBOX but not mbx format */ else if (((error = errno) == ENOENT) && !compare_cstring (name,"INBOX")) error = -1; if ((ret < 0) && ld && (*ld >= 0)) { unlockfd (*ld,lock); *ld = -1; } errno = error; /* return as last error */ return ret; /* return what we should */ } /* MBX manipulate driver parameters * Accepts: function code * function-dependent value * Returns: function-dependent return value */ void *mbx_parameters (long function,void *value) { void *ret = NIL; switch ((int) function) { case GET_INBOXPATH: if (value) ret = mbx_file ((char *) value,"INBOX"); break; case SET_ONETIMEEXPUNGEATPING: if (value) ((MBXLOCAL *) ((MAILSTREAM *) value)->local)->expok = T; case GET_ONETIMEEXPUNGEATPING: if (value) ret = (void *) (((MBXLOCAL *) ((MAILSTREAM *) value)->local)->expok ? VOIDT : NIL); break; } return ret; } /* MBX mail scan mailboxes * Accepts: mail stream * reference * pattern to search * string to scan */ void mbx_scan (MAILSTREAM *stream,char *ref,char *pat,char *contents) { if (stream) dummy_scan (NIL,ref,pat,contents); } /* MBX mail list mailboxes * Accepts: mail stream * reference * pattern to search */ void mbx_list (MAILSTREAM *stream,char *ref,char *pat) { if (stream) dummy_list (NIL,ref,pat); } /* MBX mail list subscribed mailboxes * Accepts: mail stream * reference * pattern to search */ void mbx_lsub (MAILSTREAM *stream,char *ref,char *pat) { if (stream) dummy_lsub (NIL,ref,pat); } /* MBX mail create mailbox * Accepts: MAIL stream * mailbox name to create * Returns: T on success, NIL on failure */ long mbx_create (MAILSTREAM *stream,char *mailbox) { char *s,*t,mbx[MAILTMPLEN],tmp[HDRSIZE]; long ret = NIL; int i,fd; if (!(s = mbx_file (mbx,mailbox))) { sprintf (mbx,"Can't create %.80s: invalid name",mailbox); MM_LOG (mbx,ERROR); } /* create underlying file */ else if (dummy_create_path (stream,s,get_dir_protection (mailbox))) { /* done if made directory */ if ((s = strrchr (s,'/')) && !s[1]) return T; if ((fd = open (mbx,O_WRONLY|O_BINARY,NIL)) < 0) { sprintf (tmp,"Can't reopen mailbox node %.80s: %s",mbx,strerror (errno)); MM_LOG (tmp,ERROR); unlink (mbx); /* delete the file */ } else { memset (tmp,'\0',HDRSIZE);/* initialize header */ sprintf (s = tmp,"*mbx*\015\012%08lx00000000\015\012", (unsigned long) time (0)); for (i = 0; i < NUSERFLAGS; ++i) { t = (stream && stream->user_flags[i]) ? stream->user_flags[i] : ((t = default_user_flag (i)) ? t : ""); sprintf (s += strlen (s),"%s\015\012",t); } if (write (fd,tmp,HDRSIZE) != HDRSIZE) { sprintf (tmp,"Can't initialize mailbox node %.80s: %s", mbx,strerror (errno)); MM_LOG (tmp,ERROR); unlink (mbx); /* delete the file */ } else ret = T; /* success */ close (fd); /* close file */ } } /* set proper protections */ return ret ? set_mbx_protections (mailbox,mbx) : NIL; } /* MBX mail delete mailbox * Accepts: MAIL stream * mailbox name to delete * Returns: T on success, NIL on failure */ long mbx_delete (MAILSTREAM *stream,char *mailbox) { return mbx_rename (stream,mailbox,NIL); } /* MBX mail rename mailbox * Accepts: MAIL stream * old mailbox name * new mailbox name (or NIL for delete) * Returns: T on success, NIL on failure */ long mbx_rename (MAILSTREAM *stream,char *old,char *newname) { long ret = LONGT; char c,*s,tmp[MAILTMPLEN],file[MAILTMPLEN],lock[MAILTMPLEN]; int fd,ld; struct stat sbuf; if (!mbx_file (file,old) || (newname && (!((s = mailboxfile (tmp,newname)) && *s) || ((s = strrchr (tmp,'/')) && !s[1])))) { sprintf (tmp,newname ? "Can't rename mailbox %.80s to %.80s: invalid name" : "Can't delete mailbox %.80s: invalid name", old,newname); MM_LOG (tmp,ERROR); return NIL; } else if ((fd = open (file,O_RDWR|O_BINARY,NIL)) < 0) { sprintf (tmp,"Can't open mailbox %.80s: %s",old,strerror (errno)); MM_LOG (tmp,ERROR); return NIL; } /* get parse/append permission */ if ((ld = lockfd (fd,lock,LOCK_EX)) < 0) { MM_LOG ("Unable to lock rename mailbox",ERROR); return NIL; } /* lock out other users */ if (flock (fd,LOCK_EX|LOCK_NB)) { close (fd); /* couldn't lock, give up on it then */ sprintf (tmp,"Mailbox %.80s is in use by another process",old); MM_LOG (tmp,ERROR); unlockfd (ld,lock); /* release exclusive parse/append permission */ return NIL; } if (newname) { /* want rename? */ /* found superior to destination name? */ if (s = strrchr (tmp,'/')) { c = *++s; /* remember first character of inferior */ *s = '\0'; /* tie off to get just superior */ /* superior name doesn't exist, create it */ if ((stat (tmp,&sbuf) || ((sbuf.st_mode & S_IFMT) != S_IFDIR)) && !dummy_create_path (stream,tmp,get_dir_protection (newname))) ret = NIL; else *s = c; /* restore full name */ } /* rename the file */ if (ret && rename (file,tmp)) { sprintf (tmp,"Can't rename mailbox %.80s to %.80s: %s",old,newname, strerror (errno)); MM_LOG (tmp,ERROR); ret = NIL; /* set failure */ } } else if (unlink (file)) { sprintf (tmp,"Can't delete mailbox %.80s: %s",old,strerror (errno)); MM_LOG (tmp,ERROR); ret = NIL; /* set failure */ } flock (fd,LOCK_UN); /* release lock on the file */ unlockfd (ld,lock); /* release exclusive parse/append permission */ close (fd); /* close the file */ /* recreate file if renamed INBOX */ if (ret && !compare_cstring (old,"INBOX")) mbx_create (NIL,"INBOX"); return ret; /* return success */ } /* MBX Mail status * Accepts: mail stream * mailbox name * status flags * Returns: T on success, NIL on failure */ long mbx_status (MAILSTREAM *stream,char *mbx,long flags) { MAILSTATUS status; unsigned long i; MAILSTREAM *tstream = NIL; MAILSTREAM *systream = NIL; /* make temporary stream (unless this mbx) */ if (!stream && !(stream = tstream = mail_open (NIL,mbx,OP_READONLY|OP_SILENT))) return NIL; status.flags = flags; /* return status values */ status.messages = stream->nmsgs; status.recent = stream->recent; if (flags & SA_UNSEEN) /* must search to get unseen messages */ for (i = 1,status.unseen = 0; i <= stream->nmsgs; i++) if (!mail_elt (stream,i)->seen) status.unseen++; status.uidnext = stream->uid_last + 1; status.uidvalidity = stream->uid_validity; /* calculate post-snarf results */ if (!status.recent && stream->inbox && (systream = mail_open (NIL,sysinbox (),OP_READONLY|OP_SILENT))) { status.messages += systream->nmsgs; status.recent += systream->recent; if (flags & SA_UNSEEN) /* must search to get unseen messages */ for (i = 1; i <= systream->nmsgs; i++) if (!mail_elt (systream,i)->seen) status.unseen++; /* kludge but probably good enough */ status.uidnext += systream->nmsgs; } MM_STATUS(stream,mbx,&status);/* pass status to main program */ if (tstream) mail_close (tstream); if (systream) mail_close (systream); return T; /* success */ } /* MBX mail open * Accepts: stream to open * Returns: stream on success, NIL on failure */ MAILSTREAM *mbx_open (MAILSTREAM *stream) { int fd,ld; short silent; char tmp[MAILTMPLEN]; blocknotify_t bn = (blocknotify_t) mail_parameters (NIL,GET_BLOCKNOTIFY,NIL); /* return prototype for OP_PROTOTYPE call */ if (!stream) return user_flags (&mbxproto); if (stream->local) fatal ("mbx recycle stream"); /* canonicalize the mailbox name */ if (!mbx_file (tmp,stream->mailbox)) { sprintf (tmp,"Can't open - invalid name: %.80s",stream->mailbox); MM_LOG (tmp,ERROR); } if (stream->rdonly || (fd = open (tmp,O_RDWR|O_BINARY,NIL)) < 0) { if ((fd = open (tmp,O_RDONLY|O_BINARY,NIL)) < 0) { sprintf (tmp,"Can't open mailbox: %s",strerror (errno)); MM_LOG (tmp,ERROR); return NIL; } else if (!stream->rdonly) { /* got it, but readonly */ MM_LOG ("Can't get write access to mailbox, access is readonly",WARN); stream->rdonly = T; } } stream->local = memset (fs_get (sizeof (MBXLOCAL)),NIL,sizeof (MBXLOCAL)); LOCAL->fd = fd; /* bind the file */ LOCAL->ld = -1; /* no flaglock */ LOCAL->buf = (char *) fs_get (CHUNKSIZE); LOCAL->buflen = CHUNKSIZE - 1; /* note if an INBOX or not */ stream->inbox = !compare_cstring (stream->mailbox,"INBOX"); fs_give ((void **) &stream->mailbox); stream->mailbox = cpystr (tmp); /* get parse/append permission */ if ((ld = lockfd (LOCAL->fd,tmp,LOCK_EX)) < 0) { MM_LOG ("Unable to lock open mailbox",ERROR); return NIL; } (*bn) (BLOCK_FILELOCK,NIL); flock (LOCAL->fd,LOCK_SH); /* lock the file */ (*bn) (BLOCK_NONE,NIL); unlockfd (ld,tmp); /* release shared parse permission */ LOCAL->filesize = HDRSIZE; /* initialize parsed file size */ /* time not set up yet */ LOCAL->lastsnarf = LOCAL->filetime = 0; LOCAL->expok = LOCAL->flagcheck = NIL; stream->sequence++; /* bump sequence number */ /* parse mailbox */ stream->nmsgs = stream->recent = 0; silent = stream->silent; /* defer events */ stream->silent = T; if (mbx_ping (stream) && !stream->nmsgs) MM_LOG ("Mailbox is empty",(long) NIL); stream->silent = silent; /* now notify upper level */ mail_exists (stream,stream->nmsgs); mail_recent (stream,stream->recent); if (!LOCAL) return NIL; /* failure if stream died */ stream->perm_seen = stream->perm_deleted = stream->perm_flagged = stream->perm_answered = stream->perm_draft = stream->rdonly ? NIL : T; stream->perm_user_flags = stream->rdonly ? NIL : 0xffffffff; stream->kwd_create = (stream->user_flags[NUSERFLAGS-1] || stream->rdonly) ? NIL : T; /* can we create new user flags? */ return stream; /* return stream to caller */ } /* MBX mail close * Accepts: MAIL stream * close options */ void mbx_close (MAILSTREAM *stream,long options) { if (stream && LOCAL) { /* only if a file is open */ int silent = stream->silent; stream->silent = T; /* note this stream is dying */ /* do an expunge if requested */ if (options & CL_EXPUNGE) mbx_expunge (stream,NIL,NIL); else { /* otherwise do a checkpoint to purge */ LOCAL->expok = T; /* possible expunged messages */ mbx_ping (stream); } stream->silent = silent; /* restore previous status */ mbx_abort (stream); } } /* MBX mail abort stream * Accepts: MAIL stream */ void mbx_abort (MAILSTREAM *stream) { if (stream && LOCAL) { /* only if a file is open */ flock (LOCAL->fd,LOCK_UN); /* unlock local file */ close (LOCAL->fd); /* close the local file */ /* free local text buffer */ if (LOCAL->buf) fs_give ((void **) &LOCAL->buf); /* nuke the local data */ fs_give ((void **) &stream->local); stream->dtb = NIL; /* log out the DTB */ } } /* MBX mail fetch flags * Accepts: MAIL stream * sequence * option flags * Sniffs at file to see if some other process changed the flags */ void mbx_flags (MAILSTREAM *stream,char *sequence,long flags) { MESSAGECACHE *elt; unsigned long i; if (mbx_ping (stream) && /* ping mailbox, get new status for messages */ ((flags & FT_UID) ? mail_uid_sequence (stream,sequence) : mail_sequence (stream,sequence))) for (i = 1; i <= stream->nmsgs; i++) if ((elt = mail_elt (stream,i))->sequence && !elt->valid) mbx_elt (stream,i,NIL); } /* MBX mail fetch message header * Accepts: MAIL stream * message # to fetch * pointer to returned header text length * option flags * Returns: message header in RFC822 format */ char *mbx_header (MAILSTREAM *stream,unsigned long msgno,unsigned long *length, long flags) { unsigned long i; char *s; *length = 0; /* default to empty */ if (flags & FT_UID) return "";/* UID call "impossible" */ /* get header position, possibly header */ i = mbx_hdrpos (stream,msgno,length,&s); if (!s) { /* mbx_hdrpos() returned header? */ lseek (LOCAL->fd,i,L_SET); /* no, get to header position */ /* is buffer big enough? */ if (*length > LOCAL->buflen) { fs_give ((void **) &LOCAL->buf); LOCAL->buf = (char *) fs_get ((LOCAL->buflen = *length) + 1); } /* slurp the data */ read (LOCAL->fd,s = LOCAL->buf,*length); } s[*length] = '\0'; /* tie off string */ return s; } /* MBX mail fetch message text (body only) * Accepts: MAIL stream * message # to fetch * pointer to returned header text length * option flags * Returns: T on success, NIL on failure */ long mbx_text (MAILSTREAM *stream,unsigned long msgno,STRING *bs,long flags) { FDDATA d; unsigned long i,j; MESSAGECACHE *elt; /* UID call "impossible" */ if (flags & FT_UID) return NIL; /* get message status */ elt = mbx_elt (stream,msgno,NIL); /* if message not seen */ if (!(flags & FT_PEEK) && !elt->seen && mbx_flaglock (stream)) { elt->seen = T; /* mark message as seen */ /* recalculate status */ mbx_update_status (stream,msgno,NIL); MM_FLAGS (stream,msgno); /* update flags */ mbx_flag (stream,NIL,NIL,NIL); } if (!LOCAL) return NIL; /* mbx_flaglock() could have aborted */ /* find header position */ i = mbx_hdrpos (stream,msgno,&j,NIL); d.fd = LOCAL->fd; /* set up file descriptor */ d.pos = i + j; d.chunk = LOCAL->buf; /* initial buffer chunk */ d.chunksize = CHUNKSIZE; INIT (bs,fd_string,&d,elt->rfc822_size - j); return LONGT; /* success */ } /* MBX mail modify flags * Accepts: MAIL stream * sequence * flag(s) * option flags * Unlocks flag lock */ void mbx_flag (MAILSTREAM *stream,char *sequence,char *flag,long flags) { time_t tp[2]; struct stat sbuf; unsigned long oldpid = LOCAL->lastpid; /* make sure the update takes */ if (!stream->rdonly && LOCAL && (LOCAL->fd >= 0) && (LOCAL->ld >= 0)) { fsync (LOCAL->fd); fstat (LOCAL->fd,&sbuf); /* get current write time */ tp[1] = LOCAL->filetime = sbuf.st_mtime; /* we are the last flag updater */ LOCAL->lastpid = (unsigned long) getpid (); /* update header if needed */ if (((LOCAL->ffuserflag < NUSERFLAGS) && stream->user_flags[LOCAL->ffuserflag]) || (oldpid != LOCAL->lastpid)) mbx_update_header (stream); tp[0] = time (0); /* make sure read comes after all that */ utime (stream->mailbox,tp); } if (LOCAL->ld >= 0) { /* unlock now */ unlockfd (LOCAL->ld,LOCAL->lock); LOCAL->ld = -1; } } /* MBX mail per-message modify flags * Accepts: MAIL stream * message cache element */ void mbx_flagmsg (MAILSTREAM *stream,MESSAGECACHE *elt) { if (mbx_flaglock (stream)) mbx_update_status (stream,elt->msgno,NIL); } /* MBX mail ping mailbox * Accepts: MAIL stream * Returns: T if stream still alive, NIL if not */ long mbx_ping (MAILSTREAM *stream) { unsigned long i,pos; long ret = NIL; int ld; char lock[MAILTMPLEN]; MESSAGECACHE *elt; struct stat sbuf; if (stream && LOCAL) { /* only if stream already open */ int snarf = stream->inbox && !stream->rdonly; ret = LONGT; /* assume OK */ fstat (LOCAL->fd,&sbuf); /* get current file poop */ /* allow expunge if permitted at ping */ if (mail_parameters (NIL,GET_EXPUNGEATPING,NIL)) LOCAL->expok = T; /* if external modification */ if (LOCAL->filetime && (LOCAL->filetime < sbuf.st_mtime)) LOCAL->flagcheck = T; /* upgrade to flag checking */ /* new mail or flagcheck handling needed? */ if (((sbuf.st_size - LOCAL->filesize) || LOCAL->flagcheck || !stream->nmsgs || snarf) && ((ld = lockfd (LOCAL->fd,lock,LOCK_EX)) >= 0)) { /* reparse header if not flagchecking */ if (!LOCAL->flagcheck) ret = mbx_parse (stream); /* sweep mailbox for changed message status */ else if (ret = mbx_parse (stream)) { unsigned long recent = 0; LOCAL->filetime = sbuf.st_mtime; for (i = 1; i <= stream->nmsgs; ) if (elt = mbx_elt (stream,i,LOCAL->expok)) { if (elt->recent) ++recent; ++i; } mail_recent (stream,recent); LOCAL->flagcheck = NIL; /* got all the updates */ } /* always reparse header at least */ if (ret && snarf) { /* snarf new messages if still OK */ mbx_snarf (stream); /* parse snarfed messages */ ret = mbx_parse (stream); } unlockfd (ld,lock); /* release shared parse/append permission */ } if (ret) { /* must still be alive */ if (!LOCAL->expunged) /* look for holes if none known yet */ for (i = 1, pos = HDRSIZE; !LOCAL->expunged && (i <= stream->nmsgs); i++, pos += elt->private.special.text.size + elt->rfc822_size) if ((elt = mail_elt (stream,i))->private.special.offset != pos) LOCAL->expunged = T;/* found a hole */ /* burp any holes */ if (LOCAL->expunged && !stream->rdonly) { if (mbx_rewrite (stream,&i,NIL)) fatal ("expunge on check"); if (i) { /* any space reclaimed? */ LOCAL->expunged = NIL;/* no more pending expunge */ sprintf (LOCAL->buf,"Reclaimed %lu bytes of expunged space",i); MM_LOG (LOCAL->buf,(long) NIL); } } LOCAL->expok = NIL; /* no more expok */ } } return ret; /* return result of the parse */ } /* MBX mail check mailbox (reparses status too) * Accepts: MAIL stream */ void mbx_check (MAILSTREAM *stream) { if (LOCAL) LOCAL->expok = T; /* mark that a check is desired */ if (mbx_ping (stream)) MM_LOG ("Check completed",(long) NIL); } /* MBX mail expunge mailbox * Accepts: MAIL stream * sequence to expunge if non-NIL * expunge options * Returns: T if success, NIL if failure */ long mbx_expunge (MAILSTREAM *stream,char *sequence,long options) { long ret; unsigned long nexp,reclaimed; if (ret = sequence ? ((options & EX_UID) ? mail_uid_sequence (stream,sequence) : mail_sequence (stream,sequence)) : LONGT) { if (!mbx_ping (stream)); /* do nothing if stream dead */ else if (stream->rdonly) /* won't do on readonly files! */ MM_LOG ("Expunge ignored on readonly mailbox",WARN); /* if expunged any messages */ else if (nexp = mbx_rewrite (stream,&reclaimed,sequence ? -1 : 1)) { sprintf (LOCAL->buf,"Expunged %lu messages",nexp); MM_LOG (LOCAL->buf,(long) NIL); } else if (reclaimed) { /* or if any prior expunged space reclaimed */ sprintf (LOCAL->buf,"Reclaimed %lu bytes of expunged space",reclaimed); MM_LOG (LOCAL->buf,(long) NIL); } else MM_LOG ("No messages deleted, so no update needed",(long) NIL); } return ret; } /* MBX mail snarf messages from system inbox * Accepts: MAIL stream, already locked */ void mbx_snarf (MAILSTREAM *stream) { unsigned long i = 0; unsigned long j,r,hdrlen,txtlen; struct stat sbuf; char *hdr,*txt,tmp[MAILTMPLEN]; MESSAGECACHE *elt; MAILSTREAM *sysibx = NIL; /* give up if can't get exclusive permission */ if ((time (0) >= (LOCAL->lastsnarf + (long) mail_parameters (NIL,GET_SNARFINTERVAL,NIL))) && strcmp (sysinbox (),stream->mailbox)) { MM_CRITICAL (stream); /* go critical */ /* sizes match and anything in sysinbox? */ if (!stat (sysinbox (),&sbuf) && sbuf.st_size && !fstat (LOCAL->fd,&sbuf) && (sbuf.st_size == LOCAL->filesize) && (sysibx = mail_open (sysibx,sysinbox (),OP_SILENT)) && (!sysibx->rdonly) && (r = sysibx->nmsgs)) { /* yes, go to end of file in our mailbox */ lseek (LOCAL->fd,sbuf.st_size,L_SET); /* for each message in sysibx mailbox */ while (r && (++i <= sysibx->nmsgs)) { /* snarf message from system INBOX */ hdr = cpystr (mail_fetchheader_full (sysibx,i,NIL,&hdrlen,NIL)); txt = mail_fetchtext_full (sysibx,i,&txtlen,FT_PEEK); /* if have a message */ if (j = hdrlen + txtlen) { /* build header line */ mail_date (LOCAL->buf,elt = mail_elt (sysibx,i)); sprintf (LOCAL->buf + strlen (LOCAL->buf), ",%lu;00000000%04x-00000000\015\012",j,(unsigned) ((fSEEN * elt->seen) + (fDELETED * elt->deleted) + (fFLAGGED * elt->flagged) + (fANSWERED * elt->answered) + (fDRAFT * elt->draft))); /* copy message */ if ((write (LOCAL->fd,LOCAL->buf,strlen (LOCAL->buf)) < 0) || (write (LOCAL->fd,hdr,hdrlen) < 0) || (write (LOCAL->fd,txt,txtlen) < 0)) r = 0; } fs_give ((void **) &hdr); } /* make sure all the updates take */ if (fsync (LOCAL->fd)) r = 0; if (r) { /* delete all the messages we copied */ if (r == 1) strcpy (tmp,"1"); else sprintf (tmp,"1:%lu",r); mail_setflag (sysibx,tmp,"\\Deleted"); mail_expunge (sysibx); /* now expunge all those messages */ } else { sprintf (LOCAL->buf,"Can't copy new mail: %s",strerror (errno)); MM_LOG (LOCAL->buf,WARN); ftruncate (LOCAL->fd,sbuf.st_size); } fstat (LOCAL->fd,&sbuf); /* yes, get current file size */ LOCAL->filetime = sbuf.st_mtime; } if (sysibx) mail_close (sysibx); MM_NOCRITICAL (stream); /* release critical */ LOCAL->lastsnarf = time (0);/* note time of last snarf */ } } /* MBX mail copy message(s) * Accepts: MAIL stream * sequence * destination mailbox * copy options * Returns: T if success, NIL if failed */ long mbx_copy (MAILSTREAM *stream,char *sequence,char *mailbox,long options) { struct stat sbuf; time_t tp[2]; MESSAGECACHE *elt; unsigned long i,j,k,m; long ret = LONGT; int fd,ld; char *s,*t,file[MAILTMPLEN],lock[MAILTMPLEN]; mailproxycopy_t pc = (mailproxycopy_t) mail_parameters (stream,GET_MAILPROXYCOPY,NIL); copyuid_t cu = (copyuid_t) mail_parameters (NIL,GET_COPYUID,NIL); SEARCHSET *source = cu ? mail_newsearchset () : NIL; SEARCHSET *dest = cu ? mail_newsearchset () : NIL; MAILSTREAM *dstream = NIL; if (!((options & CP_UID) ? mail_uid_sequence (stream,sequence) : mail_sequence (stream,sequence))) return NIL; /* make sure valid mailbox */ if ((fd = mbx_isvalid (&dstream,mailbox,file,&ld,lock, cu ? MBXISVALIDUID : MBXISVALIDNOUID)) < 0) switch (errno) { case ENOENT: /* no such file? */ MM_NOTIFY (stream,"[TRYCREATE] Must create mailbox before copy",NIL); return NIL; case EACCES: /* file protected */ sprintf (LOCAL->buf,"Can't access destination: %.80s",mailbox); MM_LOG (LOCAL->buf,ERROR); return NIL; case EINVAL: if (pc) return (*pc) (stream,sequence,mailbox,options); sprintf (LOCAL->buf,"Invalid MBX-format mailbox name: %.80s",mailbox); MM_LOG (LOCAL->buf,ERROR); return NIL; default: if (pc) return (*pc) (stream,sequence,mailbox,options); sprintf (LOCAL->buf,"Not a MBX-format mailbox: %.80s",mailbox); MM_LOG (LOCAL->buf,ERROR); return NIL; } MM_CRITICAL (stream); /* go critical */ fstat (fd,&sbuf); /* get current file size */ lseek (fd,sbuf.st_size,L_SET);/* move to end of file */ /* for each requested message */ for (i = 1; ret && (i <= stream->nmsgs); i++) if ((elt = mail_elt (stream,i))->sequence) { lseek (LOCAL->fd,elt->private.special.offset + elt->private.special.text.size,L_SET); mail_date(LOCAL->buf,elt);/* build target header */ /* get target keyword mask */ for (j = elt->user_flags, k = 0; j; ) if (s = stream->user_flags[find_rightmost_bit (&j)]) for (m = 0; (m < NUSERFLAGS) && (t = dstream->user_flags[m]); m++) if (!compare_cstring (s,t) && (k |= 1 << m)) break; sprintf (LOCAL->buf+strlen(LOCAL->buf),",%lu;%08lx%04x-%08lx\015\012", elt->rfc822_size,k,(unsigned) ((fSEEN * elt->seen) + (fDELETED * elt->deleted) + (fFLAGGED * elt->flagged) + (fANSWERED * elt->answered) + (fDRAFT * elt->draft)),cu ? ++dstream->uid_last : 0); /* write target header */ if (ret = (write (fd,LOCAL->buf,strlen (LOCAL->buf)) > 0)) { for (k = elt->rfc822_size; ret && (j = min (k,LOCAL->buflen)); k -= j){ read (LOCAL->fd,LOCAL->buf,j); ret = write (fd,LOCAL->buf,j) >= 0; } if (cu) { /* need to pass back new UID? */ mail_append_set (source,mail_uid (stream,i)); mail_append_set (dest,dstream->uid_last); } } } /* make sure all the updates take */ if (!(ret && (ret = !fsync (fd)))) { sprintf (LOCAL->buf,"Unable to write message: %s",strerror (errno)); MM_LOG (LOCAL->buf,ERROR); ftruncate (fd,sbuf.st_size); } if (cu && ret) { /* return sets if doing COPYUID */ (*cu) (stream,mailbox,dstream->uid_validity,source,dest); lseek (fd,15,L_SET); /* update UIDLAST */ sprintf (LOCAL->buf,"%08lx",dstream->uid_last); write (fd,LOCAL->buf,8); } else { /* flush any sets we may have built */ mail_free_searchset (&source); mail_free_searchset (&dest); } if (ret) tp[0] = time (0) - 1;/* set atime to now-1 if successful copy */ /* else preserve \Marked status */ else tp[0] = (sbuf.st_ctime > sbuf.st_atime) ? sbuf.st_atime : time(0); tp[1] = sbuf.st_mtime; /* preserve mtime */ utime (file,tp); /* set the times */ close (fd); /* close the file */ MM_NOCRITICAL (stream); /* release critical */ unlockfd (ld,lock); /* release exclusive parse/append permission */ /* delete all requested messages */ if (ret && (options & CP_MOVE) && mbx_flaglock (stream)) { for (i = 1; i <= stream->nmsgs; i++) if (mail_elt (stream,i)->sequence) { /* mark message deleted */ mbx_elt (stream,i,NIL)->deleted = T; /* recalculate status */ mbx_update_status (stream,i,NIL); } /* update flags */ mbx_flag (stream,NIL,NIL,NIL); } if (dstream != stream) mail_close (dstream); return ret; } /* MBX mail append message from stringstruct * Accepts: MAIL stream * destination mailbox * append callback * data for callback * Returns: T if append successful, else NIL */ long mbx_append (MAILSTREAM *stream,char *mailbox,append_t af,void *data) { struct stat sbuf; int fd,ld; char *flags,*date,tmp[MAILTMPLEN],file[MAILTMPLEN],lock[MAILTMPLEN]; time_t tp[2]; FILE *df; MESSAGECACHE elt; long f; unsigned long i,uf; STRING *message; long ret = NIL; MAILSTREAM *dstream = NIL; appenduid_t au = (appenduid_t) mail_parameters (NIL,GET_APPENDUID,NIL); SEARCHSET *dst = au ? mail_newsearchset () : NIL; /* make sure valid mailbox */ if ((fd = mbx_isvalid (&dstream,mailbox,file,&ld,lock, au ? MBXISVALIDUID : MBXISVALIDNOUID)) < 0) switch (errno) { case ENOENT: /* no such file? */ if (compare_cstring (mailbox,"INBOX")) { MM_NOTIFY (stream,"[TRYCREATE] Must create mailbox before append",NIL); return NIL; } /* can create INBOX here */ mbx_create (dstream = stream ? stream : user_flags (&mbxproto),"INBOX"); if ((fd = mbx_isvalid (&dstream,mailbox,file,&ld,lock, au ? MBXISVALIDUID : MBXISVALIDNOUID)) >= 0) break; case EACCES: /* file protected */ sprintf (tmp,"Can't access destination: %.80s",mailbox); MM_LOG (tmp,ERROR); return NIL; case EINVAL: sprintf (tmp,"Invalid MBX-format mailbox name: %.80s",mailbox); MM_LOG (tmp,ERROR); return NIL; default: sprintf (tmp,"Not a MBX-format mailbox: %.80s",mailbox); MM_LOG (tmp,ERROR); return NIL; } /* get first message */ if (!MM_APPEND (af) (dstream,data,&flags,&date,&message)) close (fd); else if (!(df = fdopen (fd,"r+b"))) { MM_LOG ("Unable to reopen append mailbox",ERROR); close (fd); } else { MM_CRITICAL (dstream); /* go critical */ fstat (fd,&sbuf); /* get current file size */ fseek (df,sbuf.st_size,SEEK_SET); errno = 0; for (ret = LONGT; ret && message; ) { if (!SIZE (message)) { /* guard against zero-length */ MM_LOG ("Append of zero-length message",ERROR); ret = NIL; break; } f = mail_parse_flags (dstream,flags,&uf); if (date) { /* parse date if given */ if (!mail_parse_date (&elt,date)) { sprintf (tmp,"Bad date in append: %.80s",date); MM_LOG (tmp,ERROR); ret = NIL; /* mark failure */ break; } mail_date (tmp,&elt); /* write preseved date */ } else internal_date (tmp); /* get current date in IMAP format */ /* write header */ if (fprintf (df,"%s,%lu;%08lx%04lx-%08lx\015\012",tmp,i = SIZE (message), uf,(unsigned long) f,au ? ++dstream->uid_last : 0) < 0) ret = NIL; else { /* write message */ size_t j; if (!message->cursize) SETPOS (message,GETPOS (message)); while (i && (j = fwrite (message->curpos,1,message->cursize,df))) { i -= j; SETPOS (message,GETPOS (message) + j); } /* get next message */ if (i || !MM_APPEND (af) (dstream,data,&flags,&date,&message)) ret = NIL; else if (au) mail_append_set (dst,dstream->uid_last); } } /* if error... */ if (!ret || (fflush (df) == EOF)) { /* revert file */ ftruncate (fd,sbuf.st_size); close (fd); /* make sure fclose() doesn't corrupt us */ if (errno) { sprintf (tmp,"Message append failed: %s",strerror (errno)); MM_LOG (tmp,ERROR); } ret = NIL; } if (au && ret) { /* return sets if doing APPENDUID */ (*au) (mailbox,dstream->uid_validity,dst); fseek (df,15,SEEK_SET); /* update UIDLAST */ fprintf (df,"%08lx",dstream->uid_last); } else mail_free_searchset (&dst); /* set atime to now-1 if successful copy */ if (ret) tp[0] = time (0) - 1; /* else preserve \Marked status */ else tp[0] = (sbuf.st_ctime > sbuf.st_atime) ? sbuf.st_atime : time(0); tp[1] = sbuf.st_mtime; /* preserve mtime */ utime (file,tp); /* set the times */ fclose (df); /* close the file */ MM_NOCRITICAL (dstream); /* release critical */ } unlockfd (ld,lock); /* release exclusive parse/append permission */ if (dstream != stream) mail_close (dstream); return ret; } /* Internal routines */ /* MBX mail generate file string * Accepts: temporary buffer to write into * mailbox name string * Returns: local file string or NIL if failure */ char *mbx_file (char *dst,char *name) { char *s = mailboxfile (dst,name); return (s && !*s) ? mailboxfile (dst,"~/INBOX") : s; } /* MBX mail parse mailbox * Accepts: MAIL stream * Returns: T if parse OK * NIL if failure, stream aborted */ long mbx_parse (MAILSTREAM *stream) { struct stat sbuf; MESSAGECACHE *elt = NIL; unsigned char c,*s,*t,*x; char tmp[MAILTMPLEN]; unsigned long i,j,k,m; off_t curpos = LOCAL->filesize; unsigned long nmsgs = stream->nmsgs; unsigned long recent = stream->recent; unsigned long lastuid = 0; short dirty = NIL; short added = NIL; short silent = stream->silent; short uidwarn = T; fstat (LOCAL->fd,&sbuf); /* get status */ if (sbuf.st_size < curpos) { /* sanity check */ sprintf (tmp,"Mailbox shrank from %lu to %lu!", (unsigned long) curpos,(unsigned long) sbuf.st_size); MM_LOG (tmp,ERROR); mbx_abort (stream); return NIL; } lseek (LOCAL->fd,0,L_SET); /* rewind file */ /* read internal header */ read (LOCAL->fd,LOCAL->buf,HDRSIZE); LOCAL->buf[HDRSIZE] = '\0'; /* tie off header */ c = LOCAL->buf[15]; /* save first character of last UID */ LOCAL->buf[15] = '\0'; /* parse UID validity */ stream->uid_validity = strtoul (LOCAL->buf + 7,NIL,16); LOCAL->buf[15] = c; /* restore first character of last UID */ /* parse last UID */ i = strtoul (LOCAL->buf + 15,NIL,16); stream->uid_last = stream->rdonly ? max (i,stream->uid_last) : i; /* parse user flags */ for (i = 0, s = LOCAL->buf + 25; (i < NUSERFLAGS) && (t = strchr (s,'\015')) && (t - s); i++, s = t + 2) { *t = '\0'; /* tie off flag */ if (!stream->user_flags[i] && (strlen (s) <= MAXUSERFLAG)) stream->user_flags[i] = cpystr (s); } LOCAL->ffuserflag = (int) i; /* first free user flag */ /* get current last flag updater PID */ i = (isxdigit (LOCAL->buf[HDRSIZE-10]) && isxdigit (LOCAL->buf[HDRSIZE-9]) && isxdigit (LOCAL->buf[HDRSIZE-8]) && isxdigit (LOCAL->buf[HDRSIZE-7]) && isxdigit (LOCAL->buf[HDRSIZE-6]) && isxdigit (LOCAL->buf[HDRSIZE-5]) && isxdigit (LOCAL->buf[HDRSIZE-4]) && isxdigit (LOCAL->buf[HDRSIZE-3]) && (LOCAL->buf[HDRSIZE-2] == '\015') && (LOCAL->buf[HDRSIZE-1] == '\012'))? strtoul (LOCAL->buf + HDRSIZE - 8,NIL,16) : 0; /* set flagcheck if lastpid changed */ if (LOCAL->lastpid && (LOCAL->lastpid != i)) LOCAL->flagcheck = T; LOCAL->lastpid = i; /* set as last PID */ stream->silent = T; /* don't pass up exists events yet */ while (sbuf.st_size - curpos){/* while there is stuff to parse */ /* get to that position in the file */ lseek (LOCAL->fd,curpos,L_SET); if ((i = read (LOCAL->fd,LOCAL->buf,64)) <= 0) { sprintf (tmp,"Unable to read internal header at %lu, size = %lu: %s", (unsigned long) curpos,(unsigned long) sbuf.st_size, i ? strerror (errno) : "no data read"); MM_LOG (tmp,ERROR); mbx_abort (stream); return NIL; } LOCAL->buf[i] = '\0'; /* tie off buffer just in case */ if (!((s = strchr (LOCAL->buf,'\015')) && (s[1] == '\012'))) { sprintf (tmp,"Unable to find CRLF at %lu in %lu bytes, text: %.80s", (unsigned long) curpos,i,(char *) LOCAL->buf); MM_LOG (tmp,ERROR); mbx_abort (stream); return NIL; } *s = '\0'; /* tie off header line */ i = (s + 2) - LOCAL->buf; /* note start of text offset */ if (!((s = strchr (LOCAL->buf,',')) && (t = strchr (s+1,';')))) { sprintf (tmp,"Unable to parse internal header at %lu: %.80s", (unsigned long) curpos,(char *) LOCAL->buf); MM_LOG (tmp,ERROR); mbx_abort (stream); return NIL; } if (!(isxdigit (t[1]) && isxdigit (t[2]) && isxdigit (t[3]) && isxdigit (t[4]) && isxdigit (t[5]) && isxdigit (t[6]) && isxdigit (t[7]) && isxdigit (t[8]) && isxdigit (t[9]) && isxdigit (t[10]) && isxdigit (t[11]) && isxdigit (t[12]))) { sprintf (tmp,"Unable to parse message flags at %lu: %.80s", (unsigned long) curpos,(char *) LOCAL->buf); MM_LOG (tmp,ERROR); mbx_abort (stream); return NIL; } if ((t[13] != '-') || t[22] || !(isxdigit (t[14]) && isxdigit (t[15]) && isxdigit (t[16]) && isxdigit (t[17]) && isxdigit (t[18]) && isxdigit (t[19]) && isxdigit (t[20]) && isxdigit (t[21]))) { sprintf (tmp,"Unable to parse message UID at %lu: %.80s", (unsigned long) curpos,(char *) LOCAL->buf); MM_LOG (tmp,ERROR); mbx_abort (stream); return NIL; } *s++ = '\0'; *t++ = '\0'; /* break up fields */ /* get message size */ if (!(j = strtoul (s,(char **) &x,10)) && (!(x && *x))) { sprintf (tmp,"Unable to parse message size at %lu: %.80s,%.80s;%.80s", (unsigned long) curpos,(char *) LOCAL->buf,(char *) s, (char *) t); MM_LOG (tmp,ERROR); mbx_abort (stream); return NIL; } /* make sure didn't run off end of file */ if (((off_t) (curpos + i + j)) > sbuf.st_size) { sprintf (tmp,"Last message (at %lu) runs past end of file (%lu > %lu)", (unsigned long) curpos,(unsigned long) (curpos + i + j), (unsigned long) sbuf.st_size); MM_LOG (tmp,ERROR); mbx_abort (stream); return NIL; } /* parse UID */ if ((m = strtoul (t+13,NIL,16)) && ((m <= lastuid) || (m > stream->uid_last))) { if (uidwarn) { sprintf (tmp,"Invalid UID %08lx in message %lu, rebuilding UIDs", m,nmsgs+1); MM_LOG (tmp,WARN); uidwarn = NIL; /* restart UID validity */ stream->uid_validity = time (0); } m = 0; /* lose this UID */ dirty = T; /* mark dirty, set new lastuid */ stream->uid_last = lastuid; } t[12] = '\0'; /* parse system flags */ if ((k = strtoul (t+8,NIL,16)) & fEXPUNGED) { if (m) lastuid = m; /* expunge message, update last UID seen */ else { /* no UID assigned? */ lastuid = ++stream->uid_last; dirty = T; } } else { /* not expunged, swell the cache */ added = T; /* note that a new message was added */ mail_exists (stream,++nmsgs); /* instantiate an elt for this message */ (elt = mail_elt (stream,nmsgs))->valid = T; /* parse the date */ if (!mail_parse_date (elt,LOCAL->buf)) { sprintf (tmp,"Unable to parse message date at %lu: %.80s", (unsigned long) curpos,(char *) LOCAL->buf); MM_LOG (tmp,ERROR); mbx_abort (stream); return NIL; } /* note file offset of header */ elt->private.special.offset = curpos; /* and internal header size */ elt->private.special.text.size = i; /* header size not known yet */ elt->private.msg.header.text.size = 0; elt->rfc822_size = j; /* note message size */ /* calculate system flags */ if (k & fSEEN) elt->seen = T; if (k & fDELETED) elt->deleted = T; if (k & fFLAGGED) elt->flagged = T; if (k & fANSWERED) elt->answered = T; if (k & fDRAFT) elt->draft = T; t[8] = '\0'; /* get user flags value */ elt->user_flags = strtoul (t,NIL,16); /* UID already assigned? */ if (!(elt->private.uid = m) || !(k & fOLD)) { elt->recent = T; /* no, mark as recent */ ++recent; /* count up a new recent message */ dirty = T; /* and must rewrite header */ /* assign new UID */ if (!elt->private.uid) elt->private.uid = ++stream->uid_last; mbx_update_status (stream,elt->msgno,NIL); } /* update last parsed UID */ lastuid = elt->private.uid; } curpos += i + j; /* update position */ } if (dirty && !stream->rdonly){/* update header */ mbx_update_header (stream); fsync (LOCAL->fd); /* make sure all the UID updates take */ } /* update parsed file size and time */ LOCAL->filesize = sbuf.st_size; fstat (LOCAL->fd,&sbuf); /* get status again to ensure time is right */ LOCAL->filetime = sbuf.st_mtime; if (added && !stream->rdonly){/* make sure atime updated */ time_t tp[2]; tp[0] = time (0); tp[1] = LOCAL->filetime; utime (stream->mailbox,tp); } stream->silent = silent; /* can pass up events now */ mail_exists (stream,nmsgs); /* notify upper level of new mailbox size */ mail_recent (stream,recent); /* and of change in recent messages */ return LONGT; /* return the winnage */ } /* MBX get cache element with status updating from file * Accepts: MAIL stream * message number * expunge OK flag * Returns: cache element */ MESSAGECACHE *mbx_elt (MAILSTREAM *stream,unsigned long msgno,long expok) { MESSAGECACHE *elt = mail_elt (stream,msgno); struct { /* old flags */ unsigned int seen : 1; unsigned int deleted : 1; unsigned int flagged : 1; unsigned int answered : 1; unsigned int draft : 1; unsigned long user_flags; } old; old.seen = elt->seen; old.deleted = elt->deleted; old.flagged = elt->flagged; old.answered = elt->answered; old.draft = elt->draft; old.user_flags = elt->user_flags; /* get new flags */ if (mbx_read_flags (stream,elt) && expok) { mail_expunged (stream,elt->msgno); return NIL; /* return this message was expunged */ } if ((old.seen != elt->seen) || (old.deleted != elt->deleted) || (old.flagged != elt->flagged) || (old.answered != elt->answered) || (old.draft != elt->draft) || (old.user_flags != elt->user_flags)) MM_FLAGS (stream,msgno); /* let top level know */ return elt; } /* MBX read flags from file * Accepts: MAIL stream * cache element * Returns: non-NIL if message expunged */ unsigned long mbx_read_flags (MAILSTREAM *stream,MESSAGECACHE *elt) { unsigned long i; struct stat sbuf; fstat (LOCAL->fd,&sbuf); /* get status */ /* make sure file size is good */ if (sbuf.st_size < LOCAL->filesize) { sprintf (LOCAL->buf,"Mailbox shrank from %lu to %lu in flag read!", (unsigned long) LOCAL->filesize,(unsigned long) sbuf.st_size); fatal (LOCAL->buf); } /* set the seek pointer */ lseek (LOCAL->fd,(off_t) elt->private.special.offset + elt->private.special.text.size - 24,L_SET); /* read the new flags */ if (read (LOCAL->fd,LOCAL->buf,14) < 0) { sprintf (LOCAL->buf,"Unable to read new status: %s",strerror (errno)); fatal (LOCAL->buf); } if ((LOCAL->buf[0] != ';') || (LOCAL->buf[13] != '-')) { LOCAL->buf[14] = '\0'; /* tie off buffer for error message */ sprintf (LOCAL->buf+50,"Invalid flags for message %lu (%lu %lu): %s", elt->msgno,elt->private.special.offset, elt->private.special.text.size,(char *) LOCAL->buf); fatal (LOCAL->buf+50); } LOCAL->buf[13] = '\0'; /* tie off buffer */ /* calculate system flags */ i = strtoul (LOCAL->buf+9,NIL,16); elt->seen = i & fSEEN ? T : NIL; elt->deleted = i & fDELETED ? T : NIL; elt->flagged = i & fFLAGGED ? T : NIL; elt->answered = i & fANSWERED ? T : NIL; elt->draft = i & fDRAFT ? T : NIL; LOCAL->expunged |= i & fEXPUNGED ? T : NIL; LOCAL->buf[9] = '\0'; /* tie off flags */ /* get user flags value */ elt->user_flags = strtoul (LOCAL->buf+1,NIL,16); elt->valid = T; /* have valid flags now */ return i & fEXPUNGED; } /* MBX update header * Accepts: MAIL stream */ #ifndef CYGKLUDGEOFFSET #define CYGKLUDGEOFFSET 0 #endif void mbx_update_header (MAILSTREAM *stream) { int i; char *s = LOCAL->buf; memset (s,'\0',HDRSIZE); /* initialize header */ sprintf (s,"*mbx*\015\012%08lx%08lx\015\012", stream->uid_validity,stream->uid_last); for (i = 0; (i < NUSERFLAGS) && stream->user_flags[i]; ++i) sprintf (s += strlen (s),"%s\015\012",stream->user_flags[i]); LOCAL->ffuserflag = i; /* first free user flag */ /* can we create more user flags? */ stream->kwd_create = (i < NUSERFLAGS) ? T : NIL; /* write reserved lines */ while (i++ < NUSERFLAGS) strcat (s,"\015\012"); sprintf (LOCAL->buf + HDRSIZE - 10,"%08lx\015\012",LOCAL->lastpid); while (T) { /* rewind file */ lseek (LOCAL->fd,CYGKLUDGEOFFSET,L_SET); /* write new header */ if (write (LOCAL->fd,LOCAL->buf + CYGKLUDGEOFFSET, HDRSIZE - CYGKLUDGEOFFSET) > 0) break; MM_NOTIFY (stream,strerror (errno),WARN); MM_DISKERROR (stream,errno,T); } } /* MBX update status string * Accepts: MAIL stream * message number * flags */ void mbx_update_status (MAILSTREAM *stream,unsigned long msgno,long flags) { struct stat sbuf; MESSAGECACHE *elt = mail_elt (stream,msgno); /* readonly */ if (stream->rdonly || !elt->valid) mbx_read_flags (stream,elt); else { /* readwrite */ fstat (LOCAL->fd,&sbuf); /* get status */ /* make sure file size is good */ if (sbuf.st_size < LOCAL->filesize) { sprintf (LOCAL->buf,"Mailbox shrank from %lu to %lu in flag update!", (unsigned long) LOCAL->filesize,(unsigned long) sbuf.st_size); fatal (LOCAL->buf); } /* set the seek pointer */ lseek (LOCAL->fd,(off_t) elt->private.special.offset + elt->private.special.text.size - 24,L_SET); /* read the new flags */ if (read (LOCAL->fd,LOCAL->buf,14) < 0) { sprintf (LOCAL->buf,"Unable to read old status: %s",strerror (errno)); fatal (LOCAL->buf); } if ((LOCAL->buf[0] != ';') || (LOCAL->buf[13] != '-')) { LOCAL->buf[14] = '\0'; /* tie off buffer for error message */ sprintf (LOCAL->buf+50,"Invalid flags for message %lu (%lu %lu): %s", elt->msgno,elt->private.special.offset, elt->private.special.text.size,(char *) LOCAL->buf); fatal (LOCAL->buf+50); } /* print new flag string */ sprintf (LOCAL->buf,"%08lx%04x-%08lx",elt->user_flags,(unsigned) (((elt->deleted && flags) ? fEXPUNGED : (strtoul (LOCAL->buf+9,NIL,16)) & fEXPUNGED) + (fSEEN * elt->seen) + (fDELETED * elt->deleted) + (fFLAGGED * elt->flagged) + (fANSWERED * elt->answered) + (fDRAFT * elt->draft) + fOLD),elt->private.uid); while (T) { /* get to that place in the file */ lseek (LOCAL->fd,(off_t) elt->private.special.offset + elt->private.special.text.size - 23,L_SET); /* write new flags and UID */ if (write (LOCAL->fd,LOCAL->buf,21) > 0) break; MM_NOTIFY (stream,strerror (errno),WARN); MM_DISKERROR (stream,errno,T); } } } /* MBX locate header for a message * Accepts: MAIL stream * message number * pointer to returned header size * pointer to possible returned header * Returns: position of header in file */ #define HDRBUFLEN 16384 /* good enough for most headers */ #define SLOP 4 /* CR LF CR LF */ unsigned long mbx_hdrpos (MAILSTREAM *stream,unsigned long msgno, unsigned long *size,char **hdr) { unsigned long siz,done; long i; unsigned char *s,*t,*te; MESSAGECACHE *elt = mail_elt (stream,msgno); unsigned long ret = elt->private.special.offset + elt->private.special.text.size; if (hdr) *hdr = NIL; /* assume no header returned */ /* is header size known? */ if (*size = elt->private.msg.header.text.size) return ret; /* paranoia check */ if (LOCAL->buflen < (HDRBUFLEN + SLOP)) fatal ("LOCAL->buf smaller than HDRBUFLEN"); lseek (LOCAL->fd,ret,L_SET); /* get to header position */ /* read HDRBUFLEN chunks with 4 byte slop */ for (done = siz = 0, s = LOCAL->buf; (i = min ((long) (elt->rfc822_size - done),(long) HDRBUFLEN)) && (read (LOCAL->fd,s,i) == i); done += i, siz += (t - LOCAL->buf) - SLOP, s = LOCAL->buf + SLOP) { te = (t = s + i) - 12; /* calculate end of fast scan */ /* fast scan for CR */ for (s = LOCAL->buf; s < te;) if (((*s++ == '\015') || (*s++ == '\015') || (*s++ == '\015') || (*s++ == '\015') || (*s++ == '\015') || (*s++ == '\015') || (*s++ == '\015') || (*s++ == '\015') || (*s++ == '\015') || (*s++ == '\015') || (*s++ == '\015') || (*s++ == '\015')) && (*s == '\012') && (*++s == '\015') && (*++s == '\012')) { *size = elt->private.msg.header.text.size = siz + (++s - LOCAL->buf); if (hdr) *hdr = LOCAL->buf; return ret; } for (te = t - 3; (s < te);) /* final character-at-a-time scan */ if ((*s++ == '\015') && (*s == '\012') && (*++s == '\015') && (*++s == '\012')) { *size = elt->private.msg.header.text.size = siz + (++s - LOCAL->buf); if (hdr) *hdr = LOCAL->buf; return ret; } if (i <= SLOP) break; /* end of data */ /* slide over last 4 bytes */ memmove (LOCAL->buf,t - SLOP,SLOP); hdr = NIL; /* can't return header this way */ } /* not found: header consumes entire message */ elt->private.msg.header.text.size = *size = elt->rfc822_size; if (hdr) *hdr = LOCAL->buf; /* possibly return header too */ return ret; } /* MBX mail rewrite mailbox * Accepts: MAIL stream * pointer to return reclaimed size * flags (0 = no expunge, 1 = expunge deleted, -1 = expunge sequence) * Returns: number of expunged messages */ unsigned long mbx_rewrite (MAILSTREAM *stream,unsigned long *reclaimed, long flags) { time_t tp[2]; struct stat sbuf; off_t pos,ppos; int ld; unsigned long i,j,k,m,delta; unsigned long n = *reclaimed = 0; unsigned long recent = 0; char lock[MAILTMPLEN]; MESSAGECACHE *elt; blocknotify_t bn = (blocknotify_t) mail_parameters (NIL,GET_BLOCKNOTIFY,NIL); /* The cretins who designed flock() created a window of vulnerability in * upgrading locks from shared to exclusive or downgrading from exclusive * to shared. Rather than maintain the lock at shared status at a minimum, * flock() actually *releases* the former lock. Obviously they never talked * to any database guys. Fortunately, we have the parse/append permission * lock. If we require this lock before going exclusive on the mailbox, * another process can not sneak in and steal the exclusive mailbox lock on * us, because it will block on trying to get parse/append permission first. */ /* get parse/append permission */ if ((ld = lockfd (LOCAL->fd,lock,LOCK_EX)) < 0) { MM_LOG ("Unable to lock mailbox for rewrite",ERROR); return 0; } fstat (LOCAL->fd,&sbuf); /* get current write time */ if (LOCAL->filetime && !LOCAL->flagcheck && (LOCAL->filetime < sbuf.st_mtime)) LOCAL->flagcheck = T; if (!mbx_parse (stream)) { /* make sure see any newly-arrived messages */ unlockfd (ld,lock); /* failed?? */ return 0; } if (LOCAL->flagcheck) { /* sweep flags if need flagcheck */ LOCAL->filetime = sbuf.st_mtime; for (i = 1; i <= stream->nmsgs; ++i) mbx_elt (stream,i,NIL); LOCAL->flagcheck = NIL; } /* get exclusive access */ if (!flock (LOCAL->fd,LOCK_EX|LOCK_NB)) { MM_CRITICAL (stream); /* go critical */ for (i = 1,delta = 0,pos = ppos = HDRSIZE; i <= stream->nmsgs; ) { /* note if message not at predicted location */ if (m = (elt = mbx_elt (stream,i,NIL))->private.special.offset - ppos) { ppos = elt->private.special.offset; *reclaimed += m; /* note reclaimed message space */ delta += m; /* and as expunge delta */ } /* number of bytes to smash or preserve */ ppos += (k = elt->private.special.text.size + elt->rfc822_size); /* if need to expunge this message*/ if (flags && elt->deleted && ((flags > 0) || elt->sequence)) { delta += k; /* number of bytes to delete */ mail_expunged(stream,i);/* notify upper levels */ n++; /* count up one more expunged message */ } else { /* preserved message */ i++; /* count this message */ if (elt->recent) ++recent; if (delta) { /* moved, note first byte to preserve */ j = elt->private.special.offset; do { /* read from source position */ m = min (k,LOCAL->buflen); lseek (LOCAL->fd,j,L_SET); read (LOCAL->fd,LOCAL->buf,m); pos = j - delta; /* write to destination position */ while (T) { lseek (LOCAL->fd,pos,L_SET); if (write (LOCAL->fd,LOCAL->buf,m) > 0) break; MM_NOTIFY (stream,strerror (errno),WARN); MM_DISKERROR (stream,errno,T); } pos += m; /* new position */ j += m; /* next chunk, perhaps */ } while (k -= m); /* until done */ /* note the new address of this text */ elt->private.special.offset -= delta; } /* preserved but no deleted messages yet */ else pos = elt->private.special.offset + k; } } /* deltaed file size match position? */ if (m = (LOCAL->filesize -= delta) - pos) { *reclaimed += m; /* probably an fEXPUNGED msg */ LOCAL->filesize = pos; /* set correct size */ } /* truncate file after last message */ ftruncate (LOCAL->fd,LOCAL->filesize); fsync (LOCAL->fd); /* force disk update */ MM_NOCRITICAL (stream); /* release critical */ (*bn) (BLOCK_FILELOCK,NIL); flock (LOCAL->fd,LOCK_SH); /* allow sharers again */ (*bn) (BLOCK_NONE,NIL); } else { /* can't get exclusive */ (*bn) (BLOCK_FILELOCK,NIL); flock (LOCAL->fd,LOCK_SH); /* recover previous shared mailbox lock */ (*bn) (BLOCK_NONE,NIL); /* do hide-expunge when shared */ if (flags) for (i = 1; i <= stream->nmsgs; ) { if (elt = mbx_elt (stream,i,T)) { /* make the message invisible */ if (elt->deleted && ((flags > 0) || elt->sequence)) { mbx_update_status (stream,elt->msgno,LONGT); /* notify upper levels */ mail_expunged (stream,i); n++; /* count up one more expunged message */ } else { i++; /* preserved message */ if (elt->recent) ++recent; } } else n++; /* count up one more expunged message */ } fsync (LOCAL->fd); /* force disk update */ } fstat (LOCAL->fd,&sbuf); /* get new write time */ tp[1] = LOCAL->filetime = sbuf.st_mtime; tp[0] = time (0); /* reset atime to now */ utime (stream->mailbox,tp); unlockfd (ld,lock); /* release exclusive parse/append permission */ /* notify upper level of new mailbox size */ mail_exists (stream,stream->nmsgs); mail_recent (stream,recent); return n; /* return number of expunged messages */ } /* MBX mail lock for flag updating * Accepts: stream * Returns: T if successful, NIL if failure */ long mbx_flaglock (MAILSTREAM *stream) { struct stat sbuf; unsigned long i; int ld; char lock[MAILTMPLEN]; /* no-op if readonly or already locked */ if (!stream->rdonly && LOCAL && (LOCAL->fd >= 0) && (LOCAL->ld < 0)) { /* lock now */ if ((ld = lockfd (LOCAL->fd,lock,LOCK_EX)) < 0) return NIL; if (!LOCAL->flagcheck) { /* don't do this if flagcheck already needed */ if (LOCAL->filetime) { /* know previous time? */ fstat (LOCAL->fd,&sbuf);/* get current write time */ if (LOCAL->filetime < sbuf.st_mtime) LOCAL->flagcheck = T; LOCAL->filetime = 0; /* don't do this test for any other messages */ } if (!mbx_parse (stream)) {/* parse mailbox */ unlockfd (ld,lock); /* shouldn't happen */ return NIL; } if (LOCAL->flagcheck) /* invalidate cache if flagcheck */ for (i = 1; i <= stream->nmsgs; ++i) mail_elt (stream,i)->valid = NIL; } LOCAL->ld = ld; /* copy to stream for subsequent calls */ memcpy (LOCAL->lock,lock,MAILTMPLEN); } return LONGT; } alpine-2.10+dfsg/imap/src/osdep/amiga/unix.h0000600000175000017500000002121611512502124022377 0ustar paulproteuspaulproteus/* ======================================================================== * Copyright 1988-2006 University of Washington * * Licensed under the Apache License, Version 2.0 (the "License"); * you may not use this file except in compliance with the License. * You may obtain a copy of the License at * * http://www.apache.org/licenses/LICENSE-2.0 * * * ======================================================================== */ /* * Program: UNIX mail routines, Amiga version * * Author: Mark Crispin * Networks and Distributed Computing * Computing & Communications * University of Washington * Administration Building, AG-44 * Seattle, WA 98195 * Internet: MRC@CAC.Washington.EDU * * Date: 20 December 1989 * Last Edited: 30 August 2006 */ /* DEDICATION * * This file is dedicated to my dog, Unix, also known as Yun-chan and * Unix J. Terwilliker Jehosophat Aloysius Monstrosity Animal Beast. Unix * passed away at the age of 11 1/2 on September 14, 1996, 12:18 PM PDT, after * a two-month bout with cirrhosis of the liver. * * He was a dear friend, and I miss him terribly. * * Lift a leg, Yunie. Luv ya forever!!!! */ /* Validate line * Accepts: pointer to candidate string to validate as a From header * return pointer to end of date/time field * return pointer to offset from t of time (hours of ``mmm dd hh:mm'') * return pointer to offset from t of time zone (if non-zero) * Returns: t,ti,zn set if valid From string, else ti is NIL */ #define VALID(s,x,ti,zn) { \ int remote = 0; \ ti = 0; \ if ((*s == 'F') && (s[1] == 'r') && (s[2] == 'o') && (s[3] == 'm') && \ (s[4] == ' ')) { \ for (x = s + 5; *x && *x != '\012'; x++); \ if (*x) { \ if (x[-1] == '\015') --x; \ if (x - s >= 41) { \ for (zn = -1; x[zn] != ' '; zn--); \ if ((x[zn-1] == 'm') && (x[zn-2] == 'o') && (x[zn-3] == 'r') && \ (x[zn-4] == 'f') && (x[zn-5] == ' ') && (x[zn-6] == 'e') && \ (x[zn-7] == 't') && (x[zn-8] == 'o') && (x[zn-9] == 'm') && \ (x[zn-10] == 'e') && (x[zn-11] == 'r') && (x[zn-12] == ' '))\ { \ while (x[zn-13] == ' ') zn--; \ x += zn - 12; \ remote = 1; \ } \ } \ if (x - s >= 27) { \ if (x[-5] == ' ') { \ if (x[-8] == ':') zn = 0,ti = -5; \ else if (x[-9] == ' ') ti = zn = -9; \ else if ((x[-11] == ' ') && ((x[-10]=='+') || (x[-10]=='-'))) \ ti = zn = -11; \ } \ else if (x[-4] == ' ') { \ if (x[-9] == ' ') zn = -4,ti = -9; \ else if ( (x[-13] == ' ') && (x[-16] == ' ') \ && (x[-20] ==' ') && \ ( ((x[-22] == ' ') && (x[-23] == ',')) || \ ((x[-23] == ' ') && (x[-24] == ',')) ) ) { \ char weekday[4]={0,}, month[4]={0,}, time[11]={0,}; \ char tzone[4]={0,}; \ char realtime[80]; \ int day,year,start=-26; \ if (x[-23] == ' ') x--; \ sscanf(&x[start],"%3c, %d %s %d %s %s", \ weekday,&day,month,&year,time,tzone); \ sprintf(realtime,"%s %s %2d %s %d %s", \ weekday,month,day,time, \ ( (year < 100) ? year+1900 : year),tzone); \ if (remote) \ strcat(realtime," remote from "); \ else \ strcat(realtime,"\n"); \ strncpy(&x[start],realtime,strlen(realtime)); \ zn = -2; \ ti = -7; \ } \ } \ else if (x[-6] == ' ') { \ if ((x[-11] == ' ') && ((x[-5] == '+') || (x[-5] == '-'))) \ zn = -6,ti = -11; \ } \ else if (x[-9] == ' ') { \ if ( ( (x[-12] == ' ') && (x[-16] == ' ') && \ ( ((x[-18] == ' ') && (x[-19] == ',') ) || \ ((x[-19] == ' ') && (x[-20] == ',')) ) \ || \ ((x[-14] == ' ') && (x[-18] == ' ') && \ ( ((x[-20] == ' ') && (x[-21] == ',') ) || \ ((x[-21] == ' ') && (x[-22] == ',')) ) ) ) ) { \ char weekday[4]={0,}, month[4]={0,},time[11]={0,}; \ int day,year,start=-24; \ char realtime[80]; \ if (x[-12] == ' ') x++; \ if (x[-19] == ' ') x++; \ sscanf(&x[start],"%3c, %d %3c %d %s",weekday, \ &day,month,&year,time); \ sprintf(realtime,"%s %s %2d %s %d",weekday,month,day,time,\ ( (year < 100) ? year+1900 : year)); \ if (remote) \ strcat(realtime," remote from "); \ else \ strcat(realtime,"\n"); \ strncpy(&x[start],realtime,strlen(realtime)); \ ti=-5; \ zn=0; \ } \ } \ if (ti && !((x[ti - 3] == ':') && \ (x[ti -= ((x[ti - 6] == ':') ? 9 : 6)] == ' ') && \ (x[ti - 3] == ' ') && (x[ti - 7] == ' ') && \ (x[ti - 11] == ' '))) ti = 0; \ } \ } \ } \ } /* You are not expected to understand this macro, but read the next page if * you are not faint of heart. * * Known formats to the VALID macro are: * From user Wed Dec 2 05:53 1992 * BSD From user Wed Dec 2 05:53:22 1992 * SysV From user Wed Dec 2 05:53 PST 1992 * rn From user Wed Dec 2 05:53:22 PST 1992 * From user Wed Dec 2 05:53 -0700 1992 * emacs From user Wed Dec 2 05:53:22 -0700 1992 * From user Wed Dec 2 05:53 1992 PST * From user Wed Dec 2 05:53:22 1992 PST * From user Wed Dec 2 05:53 1992 -0700 * Solaris From user Wed Dec 2 05:53:22 1992 -0700 * * Amiga From user Wed, 6 Dec 92 05:53:22 who did this !!! * CHANGED in place to * From user Wed Dec 2 05:53:22 1992 * * Plus all of the above with `` remote from xxx'' after it. Thank you very * much, smail and Solaris, for making my life considerably more complicated. */ /* * What? You want to understand the VALID macro anyway? Alright, since you * insist. Actually, it isn't really all that difficult, provided that you * take it step by step. * * Line 1 Initializes the return ti value to failure (0); * Lines 2-3 Validates that the 1st-5th characters are ``From ''. * Lines 4-6 Validates that there is an end of line and points x at it. * Lines 7-14 First checks to see if the line is at least 41 characters long. * If so, it scans backwards to find the rightmost space. From * that point, it scans backwards to see if the string matches * `` remote from''. If so, it sets x to point to the space at * the start of the string. * Line 15 Makes sure that there are at least 27 characters in the line. * Lines 16-21 Checks if the date/time ends with the year (there is a space * five characters back). If there is a colon three characters * further back, there is no timezone field, so zn is set to 0 * and ti is set in front of the year. Otherwise, there must * either to be a space four characters back for a three-letter * timezone, or a space six characters back followed by a + or - * for a numeric timezone; in either case, zn and ti become the * offset of the space immediately before it. * Lines 22-24 Are the failure case for line 14. If there is a space four * characters back, it is a three-letter timezone; there must be a * space for the year nine characters back. zn is the zone * offset; ti is the offset of the space. * Lines 25-28 Are the failure case for line 20. If there is a space six * characters back, it is a numeric timezone; there must be a * space eleven characters back and a + or - five characters back. * zn is the zone offset; ti is the offset of the space. * Line 29-32 If ti is valid, make sure that the string before ti is of the * form www mmm dd hh:mm or www mmm dd hh:mm:ss, otherwise * invalidate ti. There must be a colon three characters back * and a space six or nine characters back (depending upon * whether or not the character six characters back is a colon). * There must be a space three characters further back (in front * of the day), one seven characters back (in front of the month), * and one eleven characters back (in front of the day of week). * ti is set to be the offset of the space before the time. * * Why a macro? It gets invoked a *lot* in a tight loop. On some of the * newer pipelined machines it is faster being open-coded than it would be if * subroutines are called. * * Why does it scan backwards from the end of the line, instead of doing the * much easier forward scan? There is no deterministic way to parse the * ``user'' field, because it may contain unquoted spaces! Yes, I tested it to * see if unquoted spaces were possible. They are, and I've encountered enough * evil mail to be totally unwilling to trust that ``it will never happen''. */ /* Build parameters */ #define KODRETRY 15 /* kiss-of-death retry in seconds */ #define LOCKTIMEOUT 5 /* lock timeout in minutes */ #define CHUNK 16384 /* read-in chunk size */ alpine-2.10+dfsg/imap/src/osdep/amiga/os_ami.c0000600000175000017500000000403411512502124022655 0ustar paulproteuspaulproteus/* ======================================================================== * Copyright 1988-2006 University of Washington * * Licensed under the Apache License, Version 2.0 (the "License"); * you may not use this file except in compliance with the License. * You may obtain a copy of the License at * * http://www.apache.org/licenses/LICENSE-2.0 * * * ======================================================================== */ /* * Program: Operating-system dependent routines -- Amiga version * * Author: Mark Crispin * Networks and Distributed Computing * Computing & Communications * University of Washington * Administration Building, AG-44 * Seattle, WA 98195 * Internet: MRC@CAC.Washington.EDU * * Date: 11 May 1989 * Last Edited: 30 August 2006 */ #define PINE /* to get full DIR description in */ #include "tcp_ami.h" /* must be before osdep includes tcp.h */ #include "mail.h" #include "osdep.h" #include #include #include #include #include #include #include #include #include extern int errno; /* just in case */ #include #include "misc.h" extern int sys_nerr; extern char *sys_errlist[]; #define DIR_SIZE(d) d->d_reclen /* for scandir.c */ #include "fs_ami.c" #include "ftl_ami.c" #include "nl_ami.c" #include "env_ami.c" #include "tcp_ami.c" #include "log_std.c" #include "gr_waitp.c" #include "tz_bsd.c" #include "scandir.c" #include "gethstid.c" #undef utime /* Amiga has its own wierd utime() with an incompatible struct utimbuf that * does not match with the traditional time_t [2]. */ /* Portable utime() that takes it args like real Unix systems * Accepts: file path * traditional utime() argument * Returns: utime() results */ int portable_utime (char *file,time_t timep[2]) { struct utimbuf times; times.actime = timep[0]; /* copy the portable values */ times.modtime = timep[1]; return utime (file,×); /* now call Amiga's routine */ } alpine-2.10+dfsg/imap/src/osdep/amiga/pseudo.h0000600000175000017500000000150611512502124022713 0ustar paulproteuspaulproteus/* ======================================================================== * Copyright 1988-2006 University of Washington * * Licensed under the Apache License, Version 2.0 (the "License"); * you may not use this file except in compliance with the License. * You may obtain a copy of the License at * * http://www.apache.org/licenses/LICENSE-2.0 * * * ======================================================================== */ /* * Program: Pseudo Header Strings * * Author: Mark Crispin * Networks and Distributed Computing * Computing & Communications * University of Washington * Administration Building, AG-44 * Seattle, WA 98195 * Internet: MRC@CAC.Washington.EDU * * Date: 26 September 1996 * Last Edited: 30 August 2006 */ extern char *pseudo_from,*pseudo_name,*pseudo_subject,*pseudo_msg; alpine-2.10+dfsg/imap/src/osdep/amiga/os_ami.h0000600000175000017500000000264311512502124022666 0ustar paulproteuspaulproteus/* ======================================================================== * Copyright 1988-2006 University of Washington * * Licensed under the Apache License, Version 2.0 (the "License"); * you may not use this file except in compliance with the License. * You may obtain a copy of the License at * * http://www.apache.org/licenses/LICENSE-2.0 * * * ======================================================================== */ /* * Program: Operating-system dependent routines -- Amiga version * * Author: Mark Crispin * Networks and Distributed Computing * Computing & Communications * University of Washington * Administration Building, AG-44 * Seattle, WA 98195 * Internet: MRC@CAC.Washington.EDU * * Date: 11 May 1989 * Last Edited: 15 September 2006 */ #include #include #include #include #include #include #include /* Different names, equivalent things in BSD and SysV */ #define direct dirent #define utime portable_utime int portable_utime (char *file,time_t timep[2]); #include "env_ami.h" #include "fs.h" #include "ftl.h" #include "nl.h" #include "tcp.h" long gethostid (void); typedef int (*select_t) (struct direct *name); typedef int (*compar_t) (void *d1,void *d2); int scandir (char *dirname,struct direct ***namelist,select_t select, compar_t compar); int alphasort (void *d1,void *d2); alpine-2.10+dfsg/imap/src/osdep/amiga/ckp_std.c0000600000175000017500000000223711512502124023040 0ustar paulproteuspaulproteus/* ======================================================================== * Copyright 1988-2006 University of Washington * * Licensed under the Apache License, Version 2.0 (the "License"); * you may not use this file except in compliance with the License. * You may obtain a copy of the License at * * http://www.apache.org/licenses/LICENSE-2.0 * * * ======================================================================== */ /* * Program: Standard check password * * Author: Mark Crispin * Networks and Distributed Computing * Computing & Communications * University of Washington * Administration Building, AG-44 * Seattle, WA 98195 * Internet: MRC@CAC.Washington.EDU * * Date: 1 August 1988 * Last Edited: 30 August 2006 */ /* Check password * Accepts: login passwd struct * password string * argument count * argument vector * Returns: passwd struct if password validated, NIL otherwise */ struct passwd *checkpw (struct passwd *pw,char *pass,int argc,char *argv[]) { return (pw->pw_passwd && pw->pw_passwd[0] && pw->pw_passwd[1] && !strcmp (pw->pw_passwd,(char *) crypt (pass,pw->pw_passwd))) ? pw : NIL; } alpine-2.10+dfsg/imap/src/osdep/amiga/mix.c0000600000175000017500000027102011512502124022204 0ustar paulproteuspaulproteus/* ======================================================================== * Copyright 1988-2008 University of Washington * * Licensed under the Apache License, Version 2.0 (the "License"); * you may not use this file except in compliance with the License. * You may obtain a copy of the License at * * http://www.apache.org/licenses/LICENSE-2.0 * * * ======================================================================== */ /* * Program: MIX mail routines * * Author(s): Mark Crispin * UW Technology * University of Washington * Seattle, WA 98195 * Internet: MRC@Washington.EDU * * Date: 1 March 2006 * Last Edited: 7 May 2008 */ #include #include #include extern int errno; /* just in case */ #include "mail.h" #include "osdep.h" #include #include #include #include "misc.h" #include "dummy.h" #include "fdstring.h" /* MIX definitions */ #define MEGABYTE (1024*1024) #define MIXDATAROLL MEGABYTE /* size at which we roll to a new file */ /* MIX files */ #define MIXNAME ".mix" /* prefix for all MIX file names */ #define MIXMETA "meta" /* suffix for metadata */ #define MIXINDEX "index" /* suffix for index */ #define MIXSTATUS "status" /* suffix for status */ #define MIXSORTCACHE "sortcache"/* suffix for sortcache */ #define METAMAX (MEGABYTE-1) /* maximum metadata file size (sanity check) */ /* MIX file formats */ /* sequence format (all but msg files) */ #define SEQFMT "S%08lx\015\012" /* metadata file format */ #define MTAFMT "V%08lx\015\012L%08lx\015\012N%08lx\015\012" /* index file record format */ #define IXRFMT ":%08lx:%04d%02d%02d%02d%02d%02d%c%02d%02d:%08lx:%08lx:%08lx:%08lx:%08lx:\015\012" /* status file record format */ #define STRFMT ":%08lx:%08lx:%04x:%08lx:\015\012" /* message file header format */ #define MSRFMT "%s%08lx:%04d%02d%02d%02d%02d%02d%c%02d%02d:%08lx:\015\012" #define MSGTOK ":msg:" #define MSGTSZ (sizeof(MSGTOK)-1) /* sortcache file record format */ #define SCRFMT ":%08lx:%08lx:%08lx:%08lx:%08lx:%c%08lx:%08lx:%08lx:\015\012" /* MIX I/O stream local data */ typedef struct mix_local { unsigned long curmsg; /* current message file number */ unsigned long newmsg; /* current new message file number */ time_t lastsnarf; /* last snarf time */ int msgfd; /* file description of current msg file */ int mfd; /* file descriptor of open metadata */ unsigned long metaseq; /* metadata sequence */ char *index; /* mailbox index name */ unsigned long indexseq; /* index sequence */ char *status; /* mailbox status name */ unsigned long statusseq; /* status sequence */ char *sortcache; /* mailbox sortcache name */ unsigned long sortcacheseq; /* sortcache sequence */ unsigned char *buf; /* temporary buffer */ unsigned long buflen; /* current size of temporary buffer */ unsigned int expok : 1; /* non-zero if expunge reports OK */ unsigned int internal : 1; /* internally opened, do not validate */ } MIXLOCAL; #define MIXBURP struct mix_burp MIXBURP { unsigned long fileno; /* message file number */ char *name; /* message file name */ SEARCHSET *tail; /* tail of ranges */ SEARCHSET set; /* set of retained ranges */ MIXBURP *next; /* next file to burp */ }; /* Convenient access to local data */ #define LOCAL ((MIXLOCAL *) stream->local) /* Function prototypes */ DRIVER *mix_valid (char *name); long mix_isvalid (char *name,char *meta); void *mix_parameters (long function,void *value); long mix_dirfmttest (char *name); void mix_scan (MAILSTREAM *stream,char *ref,char *pat,char *contents); long mix_scan_contents (char *name,char *contents,unsigned long csiz, unsigned long fsiz); void mix_list (MAILSTREAM *stream,char *ref,char *pat); void mix_lsub (MAILSTREAM *stream,char *ref,char *pat); long mix_subscribe (MAILSTREAM *stream,char *mailbox); long mix_unsubscribe (MAILSTREAM *stream,char *mailbox); long mix_create (MAILSTREAM *stream,char *mailbox); long mix_delete (MAILSTREAM *stream,char *mailbox); long mix_rename (MAILSTREAM *stream,char *old,char *newname); int mix_rselect (struct direct *name); MAILSTREAM *mix_open (MAILSTREAM *stream); void mix_close (MAILSTREAM *stream,long options); void mix_abort (MAILSTREAM *stream); char *mix_header (MAILSTREAM *stream,unsigned long msgno,unsigned long *length, long flags); long mix_text (MAILSTREAM *stream,unsigned long msgno,STRING *bs,long flags); void mix_flag (MAILSTREAM *stream,char *sequence,char *flag,long flags); unsigned long *mix_sort (MAILSTREAM *stream,char *charset,SEARCHPGM *spg, SORTPGM *pgm,long flags); THREADNODE *mix_thread (MAILSTREAM *stream,char *type,char *charset, SEARCHPGM *spg,long flags); long mix_ping (MAILSTREAM *stream); void mix_check (MAILSTREAM *stream); long mix_expunge (MAILSTREAM *stream,char *sequence,long options); int mix_select (struct direct *name); int mix_msgfsort (const void *d1,const void *d2); long mix_addset (SEARCHSET **set,unsigned long start,unsigned long size); long mix_burp (MAILSTREAM *stream,MIXBURP *burp,unsigned long *reclaimed); long mix_burp_check (SEARCHSET *set,size_t size,char *file); long mix_copy (MAILSTREAM *stream,char *sequence,char *mailbox, long options); long mix_append (MAILSTREAM *stream,char *mailbox,append_t af,void *data); long mix_append_msg (MAILSTREAM *stream,FILE *f,char *flags,MESSAGECACHE *delt, STRING *msg,SEARCHSET *set,unsigned long seq); FILE *mix_parse (MAILSTREAM *stream,FILE **idxf,long iflags,long sflags); char *mix_meta_slurp (MAILSTREAM *stream,unsigned long *seq); long mix_meta_update (MAILSTREAM *stream); long mix_index_update (MAILSTREAM *stream,FILE *idxf,long flag); long mix_status_update (MAILSTREAM *stream,FILE *statf,long flag); FILE *mix_data_open (MAILSTREAM *stream,int *fd,long *size, unsigned long newsize); FILE *mix_sortcache_open (MAILSTREAM *stream); long mix_sortcache_update (MAILSTREAM *stream,FILE **sortcache); char *mix_read_record (FILE *f,char *buf,unsigned long buflen,char *type); unsigned long mix_read_sequence (FILE *f); char *mix_dir (char *dst,char *name); char *mix_file (char *dst,char *dir,char *name); char *mix_file_data (char *dst,char *dir,unsigned long data); unsigned long mix_modseq (unsigned long oldseq); /* MIX mail routines */ /* Driver dispatch used by MAIL */ DRIVER mixdriver = { "mix", /* driver name */ /* driver flags */ DR_MAIL|DR_LOCAL|DR_NOFAST|DR_CRLF|DR_LOCKING|DR_DIRFMT|DR_MODSEQ, (DRIVER *) NIL, /* next driver */ mix_valid, /* mailbox is valid for us */ mix_parameters, /* manipulate parameters */ mix_scan, /* scan mailboxes */ mix_list, /* find mailboxes */ mix_lsub, /* find subscribed mailboxes */ mix_subscribe, /* subscribe to mailbox */ mix_unsubscribe, /* unsubscribe from mailbox */ mix_create, /* create mailbox */ mix_delete, /* delete mailbox */ mix_rename, /* rename mailbox */ mail_status_default, /* status of mailbox */ mix_open, /* open mailbox */ mix_close, /* close mailbox */ NIL, /* fetch message "fast" attributes */ NIL, /* fetch message flags */ NIL, /* fetch overview */ NIL, /* fetch message envelopes */ mix_header, /* fetch message header only */ mix_text, /* fetch message body only */ NIL, /* fetch partial message test */ NIL, /* unique identifier */ NIL, /* message number */ mix_flag, /* modify flags */ NIL, /* per-message modify flags */ NIL, /* search for message based on criteria */ mix_sort, /* sort messages */ mix_thread, /* thread messages */ mix_ping, /* ping mailbox to see if still alive */ mix_check, /* check for new messages */ mix_expunge, /* expunge deleted messages */ mix_copy, /* copy messages to another mailbox */ mix_append, /* append string message to mailbox */ NIL /* garbage collect stream */ }; /* prototype stream */ MAILSTREAM mixproto = {&mixdriver}; /* MIX mail validate mailbox * Accepts: mailbox name * Returns: our driver if name is valid, NIL otherwise */ DRIVER *mix_valid (char *name) { char tmp[MAILTMPLEN]; return mix_isvalid (name,tmp) ? &mixdriver : NIL; } /* MIX mail test for valid mailbox * Accepts: mailbox name * buffer to return meta name * Returns: T if valid, NIL otherwise, metadata name written in both cases */ long mix_isvalid (char *name,char *meta) { char dir[MAILTMPLEN]; struct stat sbuf; /* validate name as directory */ if (!(errno = ((strlen (name) > NETMAXMBX) ? ENAMETOOLONG : NIL)) && *mix_dir (dir,name) && mix_file (meta,dir,MIXMETA) && !stat (dir,&sbuf) && ((sbuf.st_mode & S_IFMT) == S_IFDIR)) { /* name is directory; is it mix? */ if (!stat (meta,&sbuf) && ((sbuf.st_mode & S_IFMT) == S_IFREG)) return LONGT; else errno = NIL; /* directory but not mix */ } return NIL; } /* MIX manipulate driver parameters * Accepts: function code * function-dependent value * Returns: function-dependent return value */ void *mix_parameters (long function,void *value) { void *ret = NIL; switch ((int) function) { case GET_INBOXPATH: if (value) ret = mailboxfile ((char *) value,"~/INBOX"); break; case GET_DIRFMTTEST: ret = (void *) mix_dirfmttest; break; case GET_SCANCONTENTS: ret = (void *) mix_scan_contents; break; case SET_ONETIMEEXPUNGEATPING: if (value) ((MIXLOCAL *) ((MAILSTREAM *) value)->local)->expok = T; case GET_ONETIMEEXPUNGEATPING: if (value) ret = (void *) (((MIXLOCAL *) ((MAILSTREAM *) value)->local)->expok ? VOIDT : NIL); break; } return ret; } /* MIX test for directory format internal node * Accepts: candidate node name * Returns: T if internal name, NIL otherwise */ long mix_dirfmttest (char *name) { /* belongs to MIX if starts with .mix */ return strncmp (name,MIXNAME,sizeof (MIXNAME) - 1) ? NIL : LONGT; } /* MIX mail scan mailboxes * Accepts: mail stream * reference * pattern to search * string to scan */ void mix_scan (MAILSTREAM *stream,char *ref,char *pat,char *contents) { if (stream) dummy_scan (NIL,ref,pat,contents); } /* MIX scan mailbox for contents * Accepts: mailbox name * desired contents * contents size * file size (ignored) * Returns: NIL if contents not found, T if found */ long mix_scan_contents (char *name,char *contents,unsigned long csiz, unsigned long fsiz) { long i,nfiles; void *a; char *s; long ret = NIL; size_t namelen = strlen (name); struct stat sbuf; struct direct **names = NIL; if ((nfiles = scandir (name,&names,mix_select,mix_msgfsort)) > 0) for (i = 0; i < nfiles; ++i) { if (!ret) { sprintf (s = (char *) fs_get (namelen + strlen (names[i]->d_name) + 2), "%s/%s",name,names[i]->d_name); if (!stat (s,&sbuf) && (csiz <= sbuf.st_size)) ret = dummy_scan_contents (s,contents,csiz,sbuf.st_size); fs_give ((void **) &s); } fs_give ((void **) &names[i]); } /* free directory list */ if (a = (void *) names) fs_give ((void **) &a); return ret; } /* MIX list mailboxes * Accepts: mail stream * reference * pattern to search */ void mix_list (MAILSTREAM *stream,char *ref,char *pat) { if (stream) dummy_list (NIL,ref,pat); } /* MIX list subscribed mailboxes * Accepts: mail stream * reference * pattern to search */ void mix_lsub (MAILSTREAM *stream,char *ref,char *pat) { if (stream) dummy_lsub (NIL,ref,pat); } /* MIX mail subscribe to mailbox * Accepts: mail stream * mailbox to add to subscription list * Returns: T on success, NIL on failure */ long mix_subscribe (MAILSTREAM *stream,char *mailbox) { return sm_subscribe (mailbox); } /* MIX mail unsubscribe to mailbox * Accepts: mail stream * mailbox to delete from subscription list * Returns: T on success, NIL on failure */ long mix_unsubscribe (MAILSTREAM *stream,char *mailbox) { return sm_unsubscribe (mailbox); } /* MIX mail create mailbox * Accepts: mail stream * mailbox name to create * Returns: T on success, NIL on failure */ long mix_create (MAILSTREAM *stream,char *mailbox) { DRIVER *test; FILE *f; int c,i; char *t,tmp[MAILTMPLEN],file[MAILTMPLEN]; char *s = strrchr (mailbox,'/'); unsigned long now = time (NIL); long ret = NIL; /* always create \NoSelect if trailing / */ if (s && !s[1]) return dummy_create (stream,mailbox); /* validate name */ if (mix_dirfmttest (s ? s + 1 : mailbox)) sprintf(tmp,"Can't create mailbox %.80s: invalid MIX-format name",mailbox); /* must not already exist */ else if ((test = mail_valid (NIL,mailbox,NIL)) && strcmp (test->name,"dummy")) sprintf (tmp,"Can't create mailbox %.80s: mailbox already exists",mailbox); /* create directory and metadata */ else if (!dummy_create_path (stream, mix_file (file,mix_dir (tmp,mailbox),MIXMETA), get_dir_protection (mailbox))) sprintf (tmp,"Can't create mailbox %.80s: %.80s",mailbox,strerror (errno)); else if (!(f = fopen (file,"w"))) sprintf (tmp,"Can't re-open metadata %.80s: %.80s",mailbox, strerror (errno)); else { /* success, write initial metadata */ fprintf (f,SEQFMT,now); fprintf (f,MTAFMT,now,0,now); for (i = 0, c = 'K'; (i < NUSERFLAGS) && (t = (stream && stream->user_flags[i]) ? stream->user_flags[i] : default_user_flag (i)) && *t; ++i) { putc (c,f); /* write another keyword */ fputs (t,f); c = ' '; /* delimiter is now space */ } fclose (f); set_mbx_protections (mailbox,file); /* point to suffix */ s = file + strlen (file) - (sizeof (MIXMETA) - 1); strcpy (s,MIXINDEX); /* create index */ if (!dummy_create_path (stream,file,get_dir_protection (mailbox))) sprintf (tmp,"Can't create mix mailbox index: %.80s",strerror (errno)); else { set_mbx_protections (mailbox,file); strcpy (s,MIXSTATUS); /* create status */ if (!dummy_create_path (stream,file,get_dir_protection (mailbox))) sprintf (tmp,"Can't create mix mailbox status: %.80s", strerror (errno)); else { set_mbx_protections (mailbox,file); sprintf (s,"%08lx",now);/* message file */ if (!dummy_create_path (stream,file,get_dir_protection (mailbox))) sprintf (tmp,"Can't create mix mailbox data: %.80s", strerror (errno)); else { set_mbx_protections (mailbox,file); ret = LONGT; /* declare success at this point */ } } } } if (!ret) MM_LOG (tmp,ERROR); /* some error */ return ret; } /* MIX mail delete mailbox * mailbox name to delete * Returns: T on success, NIL on failure */ long mix_delete (MAILSTREAM *stream,char *mailbox) { DIR *dirp; struct direct *d; int fd = -1; char *s,tmp[MAILTMPLEN]; if (!mix_isvalid (mailbox,tmp)) sprintf (tmp,"Can't delete mailbox %.80s: no such mailbox",mailbox); else if (((fd = open (tmp,O_RDWR,NIL)) < 0) || flock (fd,LOCK_EX|LOCK_NB)) sprintf (tmp,"Can't lock mailbox for delete: %.80s",mailbox); /* delete metadata */ else if (unlink (tmp)) sprintf (tmp,"Can't delete mailbox %.80s index: %80s", mailbox,strerror (errno)); else { close (fd); /* close descriptor on deleted metadata */ /* get directory name */ *(s = strrchr (tmp,'/')) = '\0'; if (dirp = opendir (tmp)) { /* open directory */ *s++ = '/'; /* restore delimiter */ /* massacre messages */ while (d = readdir (dirp)) if (mix_dirfmttest (d->d_name)) { strcpy (s,d->d_name); /* make path */ unlink (tmp); /* sayonara */ } closedir (dirp); /* flush directory */ *(s = strrchr (tmp,'/')) = '\0'; if (rmdir (tmp)) { /* try to remove the directory */ sprintf (tmp,"Can't delete name %.80s: %.80s", mailbox,strerror (errno)); MM_LOG (tmp,WARN); } } return T; /* always success */ } if (fd >= 0) close (fd); /* close any descriptor on metadata */ MM_LOG (tmp,ERROR); /* something failed */ return NIL; } /* MIX mail rename mailbox * Accepts: MIX mail stream * old mailbox name * new mailbox name * Returns: T on success, NIL on failure */ long mix_rename (MAILSTREAM *stream,char *old,char *newname) { char c,*s,tmp[MAILTMPLEN],tmp1[MAILTMPLEN]; struct stat sbuf; int fd = -1; if (!mix_isvalid (old,tmp)) sprintf (tmp,"Can't rename mailbox %.80s: no such mailbox",old); else if (((fd = open (tmp,O_RDWR,NIL)) < 0) || flock (fd,LOCK_EX|LOCK_NB)) sprintf (tmp,"Can't lock mailbox for rename: %.80s",old); else if (mix_dirfmttest ((s = strrchr (newname,'/')) ? s + 1 : newname)) sprintf (tmp,"Can't rename to mailbox %.80s: invalid MIX-format name", newname); /* new mailbox name must not be valid */ else if (mix_isvalid (newname,tmp)) sprintf (tmp,"Can't rename to mailbox %.80s: destination already exists", newname); else { mix_dir (tmp,old); /* build old directory name */ mix_dir (tmp1,newname); /* and new directory name */ /* easy if not INBOX */ if (compare_cstring (old,"INBOX")) { /* found superior to destination name? */ if (s = strrchr (tmp1,'/')) { c = *++s; /* remember first character of inferior */ *s = '\0'; /* tie off to get just superior */ /* name doesn't exist, create it */ if ((stat (tmp1,&sbuf) || ((sbuf.st_mode & S_IFMT) != S_IFDIR)) && !dummy_create_path (stream,tmp1,get_dir_protection (newname))) return NIL; *s = c; /* restore full name */ } if (!rename (tmp,tmp1)) { close (fd); /* close descriptor on metadata */ return LONGT; } } /* RFC 3501 requires this */ else if (dummy_create_path (stream,strcat (tmp1,"/"), get_dir_protection (newname))) { void *a; int i,n,lasterror; char *src,*dst; struct direct **names = NIL; size_t srcl = strlen (tmp); size_t dstl = strlen (tmp1); /* rename each mix file to new directory */ for (i = lasterror = 0,n = scandir (tmp,&names,mix_rselect,alphasort); i < n; ++i) { size_t len = strlen (names[i]->d_name); sprintf (src = (char *) fs_get (srcl + len + 2),"%s/%s", tmp,names[i]->d_name); sprintf (dst = (char *) fs_get (dstl + len + 1),"%s%s", tmp1,names[i]->d_name); if (rename (src,dst)) lasterror = errno; fs_give ((void **) &src); fs_give ((void **) &dst); fs_give ((void **) &names[i]); } /* free directory list */ if (a = (void *) names) fs_give ((void **) &a); if (lasterror) errno = lasterror; else { close (fd); /* close descriptor on metadata */ return mix_create (NIL,"INBOX"); } } sprintf (tmp,"Can't rename mailbox %.80s to %.80s: %.80s", old,newname,strerror (errno)); } if (fd >= 0) close (fd); /* close any descriptor on metadata */ MM_LOG (tmp,ERROR); /* something failed */ return NIL; } /* MIX test for mix name * Accepts: candidate directory name * Returns: T if mix file name, NIL otherwise */ int mix_rselect (struct direct *name) { return mix_dirfmttest (name->d_name); } /* MIX mail open * Accepts: stream to open * Returns: stream on success, NIL on failure */ MAILSTREAM *mix_open (MAILSTREAM *stream) { short silent; /* return prototype for OP_PROTOTYPE call */ if (!stream) return user_flags (&mixproto); if (stream->local) fatal ("mix recycle stream"); stream->local = memset (fs_get (sizeof (MIXLOCAL)),0,sizeof (MIXLOCAL)); /* note if an INBOX or not */ stream->inbox = !compare_cstring (stream->mailbox,"INBOX"); /* make temporary buffer */ LOCAL->buf = (char *) fs_get (CHUNKSIZE); LOCAL->buflen = CHUNKSIZE - 1; /* set stream->mailbox to be directory name */ mix_dir (LOCAL->buf,stream->mailbox); fs_give ((void **) &stream->mailbox); stream->mailbox = cpystr (LOCAL->buf); LOCAL->msgfd = -1; /* currently no file open */ if (!(((!stream->rdonly && /* open metadata file */ ((LOCAL->mfd = open (mix_file (LOCAL->buf,stream->mailbox,MIXMETA), O_RDWR,NIL)) >= 0)) || ((stream->rdonly = T) && ((LOCAL->mfd = open (mix_file (LOCAL->buf,stream->mailbox,MIXMETA), O_RDONLY,NIL)) >= 0))) && !flock (LOCAL->mfd,LOCK_SH))) { MM_LOG ("Error opening mix metadata file",ERROR); mix_abort (stream); stream = NIL; /* open fails */ } else { /* metadata open, complete open */ LOCAL->index = cpystr (mix_file (LOCAL->buf,stream->mailbox,MIXINDEX)); LOCAL->status = cpystr (mix_file (LOCAL->buf,stream->mailbox,MIXSTATUS)); LOCAL->sortcache = cpystr (mix_file (LOCAL->buf,stream->mailbox, MIXSORTCACHE)); stream->sequence++; /* bump sequence number */ /* parse mailbox */ stream->nmsgs = stream->recent = 0; if (silent = stream->silent) LOCAL->internal = T; stream->silent = T; if (mix_ping (stream)) { /* do initial ping */ /* try burping in case we are exclusive */ if (!stream->rdonly) mix_expunge (stream,"",NIL); if (!(stream->nmsgs || stream->silent)) MM_LOG ("Mailbox is empty",(long) NIL); stream->silent = silent; /* now notify upper level */ mail_exists (stream,stream->nmsgs); stream->perm_seen = stream->perm_deleted = stream->perm_flagged = stream->perm_answered = stream->perm_draft = stream->rdonly ? NIL : T; stream->perm_user_flags = stream->rdonly ? NIL : 0xffffffff; stream->kwd_create = /* can we create new user flags? */ (stream->user_flags[NUSERFLAGS-1] || stream->rdonly) ? NIL : T; } else { /* got murdelyzed in ping */ mix_abort (stream); stream = NIL; } } return stream; /* return stream to caller */ } /* MIX mail close * Accepts: MAIL stream * close options */ void mix_close (MAILSTREAM *stream,long options) { if (LOCAL) { /* only if a file is open */ int silent = stream->silent; stream->silent = T; /* note this stream is dying */ /* burp-only or expunge */ mix_expunge (stream,(options & CL_EXPUNGE) ? NIL : "",NIL); mix_abort (stream); stream->silent = silent; /* reset silent state */ } } /* MIX mail abort stream * Accepts: MAIL stream */ void mix_abort (MAILSTREAM *stream) { if (LOCAL) { /* only if a file is open */ /* close current message file if open */ if (LOCAL->msgfd >= 0) close (LOCAL->msgfd); /* close current metadata file if open */ if (LOCAL->mfd >= 0) close (LOCAL->mfd); if (LOCAL->index) fs_give ((void **) &LOCAL->index); if (LOCAL->status) fs_give ((void **) &LOCAL->status); if (LOCAL->sortcache) fs_give ((void **) &LOCAL->sortcache); /* free local scratch buffer */ if (LOCAL->buf) fs_give ((void **) &LOCAL->buf); /* nuke the local data */ fs_give ((void **) &stream->local); stream->dtb = NIL; /* log out the DTB */ } } /* MIX mail fetch message header * Accepts: MAIL stream * message # to fetch * pointer to returned header text length * option flags * Returns: message header in RFC822 format */ char *mix_header (MAILSTREAM *stream,unsigned long msgno,unsigned long *length, long flags) { unsigned long i,j,k; int fd; char *s,tmp[MAILTMPLEN]; MESSAGECACHE *elt; if (length) *length = 0; /* default return */ if (flags & FT_UID) return "";/* UID call "impossible" */ elt = mail_elt (stream,msgno);/* get elt */ /* is message in current message file? */ if ((LOCAL->msgfd < 0) || (elt->private.spare.data != LOCAL->curmsg)) { if (LOCAL->msgfd >= 0) close (LOCAL->msgfd); if ((LOCAL->msgfd = open (mix_file_data (LOCAL->buf,stream->mailbox, elt->private.spare.data), O_RDONLY,NIL)) < 0) return ""; /* got file */ LOCAL->curmsg = elt->private.spare.data; } lseek (LOCAL->msgfd,elt->private.special.offset,L_SET); /* size of special data and header */ j = elt->private.msg.header.offset + elt->private.msg.header.text.size; if (j > LOCAL->buflen) { /* is buffer big enough? */ /* no, make one that is */ fs_give ((void **) &LOCAL->buf); LOCAL->buf = (char *) fs_get ((LOCAL->buflen = j) + 1); } /* Maybe someday validate internaldate too */ /* slurp special data + header, validate */ if ((read (LOCAL->msgfd,LOCAL->buf,j) == j) && !strncmp (LOCAL->buf,MSGTOK,MSGTSZ) && (elt->private.uid == strtoul ((char *) LOCAL->buf + MSGTSZ,&s,16)) && (*s++ == ':') && (s = strchr (s,':')) && (k = strtoul (s+1,&s,16)) && (*s++ == ':') && (s < (char *) (LOCAL->buf + elt->private.msg.header.offset))) { /* won, set offset and size of message */ i = elt->private.msg.header.offset; *length = elt->private.msg.header.text.size; if (k != elt->rfc822_size) { sprintf (tmp,"Inconsistency in mix message size, uid=%lx (%lu != %lu)", elt->private.uid,elt->rfc822_size,k); MM_LOG (tmp,WARN); } } else { /* document the problem */ LOCAL->buf[100] = '\0'; /* tie off buffer at no more than 100 octets */ /* or at newline, whichever is first */ if (s = strpbrk (LOCAL->buf,"\015\012")) *s = '\0'; sprintf (tmp,"Error reading mix message header, uid=%lx, s=%.0lx, h=%s", elt->private.uid,elt->rfc822_size,LOCAL->buf); MM_LOG (tmp,ERROR); *length = i = j = 0; /* default to empty */ } LOCAL->buf[j] = '\0'; /* tie off buffer at the end */ return (char *) LOCAL->buf + i; } /* MIX mail fetch message text (body only) * Accepts: MAIL stream * message # to fetch * pointer to returned stringstruct * option flags * Returns: T on success, NIL on failure */ long mix_text (MAILSTREAM *stream,unsigned long msgno,STRING *bs,long flags) { unsigned long i; FDDATA d; MESSAGECACHE *elt; /* UID call "impossible" */ if (flags & FT_UID) return NIL; elt = mail_elt (stream,msgno); /* is message in current message file? */ if ((LOCAL->msgfd < 0) || (elt->private.spare.data != LOCAL->curmsg)) { if (LOCAL->msgfd >= 0) close (LOCAL->msgfd); if ((LOCAL->msgfd = open (mix_file_data (LOCAL->buf,stream->mailbox, elt->private.spare.data), O_RDONLY,NIL)) < 0) return NIL; /* got file */ LOCAL->curmsg = elt->private.spare.data; } /* doing non-peek fetch? */ if (!(flags & FT_PEEK) && !elt->seen) { FILE *idxf; /* yes, process metadata/index/status */ FILE *statf = mix_parse (stream,&idxf,NIL,LONGT); elt->seen = T; /* mark as seen */ MM_FLAGS (stream,elt->msgno); /* update status file if possible */ if (statf && !stream->rdonly) { elt->private.mod = LOCAL->statusseq = mix_modseq (LOCAL->statusseq); mix_status_update (stream,statf,NIL); } if (idxf) fclose (idxf); /* release index and status file */ if (statf) fclose (statf); } d.fd = LOCAL->msgfd; /* set up file descriptor */ /* offset of message text */ d.pos = elt->private.special.offset + elt->private.msg.header.offset + elt->private.msg.header.text.size; d.chunk = LOCAL->buf; /* initial buffer chunk */ d.chunksize = CHUNKSIZE; /* chunk size */ INIT (bs,fd_string,&d,elt->rfc822_size - elt->private.msg.header.text.size); return T; } /* MIX mail modify flags * Accepts: MAIL stream * sequence * flag(s) * option flags */ void mix_flag (MAILSTREAM *stream,char *sequence,char *flag,long flags) { MESSAGECACHE *elt; unsigned long i,uf,ffkey; long f; short nf; FILE *idxf; FILE *statf = mix_parse (stream,&idxf,NIL,LONGT); unsigned long seq = mix_modseq (LOCAL->statusseq); /* find first free key */ for (ffkey = 0; (ffkey < NUSERFLAGS) && stream->user_flags[ffkey]; ++ffkey); /* parse sequence and flags */ if (((flags & ST_UID) ? mail_uid_sequence (stream,sequence) : mail_sequence (stream,sequence)) && ((f = mail_parse_flags (stream,flag,&uf)) || uf)) { /* alter flags */ for (i = 1,nf = (flags & ST_SET) ? T : NIL; i <= stream->nmsgs; i++) if ((elt = mail_elt (stream,i))->sequence) { struct { /* old flags */ unsigned int seen : 1; unsigned int deleted : 1; unsigned int flagged : 1; unsigned int answered : 1; unsigned int draft : 1; unsigned long user_flags; } old; old.seen = elt->seen; old.deleted = elt->deleted; old.flagged = elt->flagged; old.answered = elt->answered; old.draft = elt->draft; old.user_flags = elt->user_flags; if (f&fSEEN) elt->seen = nf; if (f&fDELETED) elt->deleted = nf; if (f&fFLAGGED) elt->flagged = nf; if (f&fANSWERED) elt->answered = nf; if (f&fDRAFT) elt->draft = nf; /* user flags */ if (flags & ST_SET) elt->user_flags |= uf; else elt->user_flags &= ~uf; if ((old.seen != elt->seen) || (old.deleted != elt->deleted) || (old.flagged != elt->flagged) || (old.answered != elt->answered) || (old.draft != elt->draft) || (old.user_flags != elt->user_flags)) { if (!stream->rdonly) elt->private.mod = LOCAL->statusseq = seq; MM_FLAGS (stream,elt->msgno); } } /* update status file after change */ if (statf && (seq == LOCAL->statusseq)) mix_status_update (stream,statf,NIL); /* update metadata if created a keyword */ if ((ffkey < NUSERFLAGS) && stream->user_flags[ffkey] && !mix_meta_update (stream)) MM_LOG ("Error updating mix metadata after keyword creation",ERROR); } if (statf) fclose (statf); /* release status file if still open */ if (idxf) fclose (idxf); /* release index file */ } /* MIX mail sort messages * Accepts: mail stream * character set * search program * sort program * option flags * Returns: vector of sorted message sequences or NIL if error */ unsigned long *mix_sort (MAILSTREAM *stream,char *charset,SEARCHPGM *spg, SORTPGM *pgm,long flags) { unsigned long *ret; FILE *sortcache = mix_sortcache_open (stream); ret = mail_sort_msgs (stream,charset,spg,pgm,flags); mix_sortcache_update (stream,&sortcache); return ret; } /* MIX mail thread messages * Accepts: mail stream * thread type * character set * search program * option flags * Returns: thread node tree or NIL if error */ THREADNODE *mix_thread (MAILSTREAM *stream,char *type,char *charset, SEARCHPGM *spg,long flags) { THREADNODE *ret; FILE *sortcache = mix_sortcache_open (stream); ret = mail_thread_msgs (stream,type,charset,spg,flags,mail_sort_msgs); mix_sortcache_update (stream,&sortcache); return ret; } /* MIX mail ping mailbox * Accepts: MAIL stream * Returns: T if stream alive, else NIL */ static int snarfing = 0; /* lock against recursive snarfing */ long mix_ping (MAILSTREAM *stream) { FILE *idxf,*statf; struct stat sbuf; STRING msg; MESSAGECACHE *elt; int mfd,ifd,sfd; unsigned long i,msglen; char *message,date[MAILTMPLEN],flags[MAILTMPLEN]; MAILSTREAM *sysibx = NIL; long ret = NIL; long snarfok = LONGT; /* time to snarf? */ if (stream->inbox && !stream->rdonly && !snarfing && (time (0) >= (LOCAL->lastsnarf + (time_t) mail_parameters (NIL,GET_SNARFINTERVAL,NIL)))) { appenduid_t au = (appenduid_t) mail_parameters (NIL,GET_APPENDUID,NIL); copyuid_t cu = (copyuid_t) mail_parameters (NIL,GET_COPYUID,NIL); MM_CRITICAL (stream); /* go critical */ snarfing = T; /* don't recursively snarf */ /* disable APPENDUID/COPYUID callbacks */ mail_parameters (NIL,SET_APPENDUID,NIL); mail_parameters (NIL,SET_COPYUID,NIL); /* sizes match and anything in sysinbox? */ if (!stat (sysinbox (),&sbuf) && ((sbuf.st_mode & S_IFMT) == S_IFREG) && sbuf.st_size && (sysibx = mail_open (sysibx,sysinbox (),OP_SILENT)) && !sysibx->rdonly && sysibx->nmsgs) { /* for each message in sysibx mailbox */ for (i = 1; snarfok && (i <= sysibx->nmsgs); ++i) if (!(elt = mail_elt (sysibx,i))->deleted && (message = mail_fetch_message (sysibx,i,&msglen,FT_PEEK)) && msglen) { mail_date (date,elt); /* make internal date string */ /* make flag string */ flags[0] = flags[1] = '\0'; if (elt->seen) strcat (flags," \\Seen"); if (elt->flagged) strcat (flags," \\Flagged"); if (elt->answered) strcat (flags," \\Answered"); if (elt->draft) strcat (flags," \\Draft"); flags[0] = '('; strcat (flags,")"); INIT (&msg,mail_string,message,msglen); if (snarfok = mail_append_full (stream,"INBOX",flags,date,&msg)) { char sequence[15]; sprintf (sequence,"%lu",i); mail_flag (sysibx,sequence,"\\Deleted",ST_SET); } } /* now expunge all those messages */ if (snarfok) mail_expunge (sysibx); else { sprintf (LOCAL->buf,"Can't copy new mail at message: %lu",i - 1); MM_LOG (LOCAL->buf,WARN); } } if (sysibx) mail_close (sysibx); /* reenable APPENDUID/COPYUID */ mail_parameters (NIL,SET_APPENDUID,(void *) au); mail_parameters (NIL,SET_COPYUID,(void *) cu); snarfing = NIL; /* no longer snarfing */ MM_NOCRITICAL (stream); /* release critical */ LOCAL->lastsnarf = time (0);/* note time of last snarf */ } /* expunging OK if global flag set */ if (mail_parameters (NIL,GET_EXPUNGEATPING,NIL)) LOCAL->expok = T; /* process metadata/index/status */ if (statf = mix_parse (stream,&idxf,LONGT, (LOCAL->internal ? NIL : LONGT))) { fclose (statf); /* just close the status file */ ret = LONGT; /* declare success */ } if (idxf) fclose (idxf); /* release index file */ LOCAL->expok = NIL; /* expunge no longer OK */ if (!ret) mix_abort (stream); /* murdelyze stream if ping fails */ return ret; } /* MIX mail checkpoint mailbox (burp only) * Accepts: MAIL stream */ void mix_check (MAILSTREAM *stream) { if (stream->rdonly) /* won't do on readonly files! */ MM_LOG ("Checkpoint ignored on readonly mailbox",NIL); /* do burp-only expunge action */ if (mix_expunge (stream,"",NIL)) MM_LOG ("Check completed",(long) NIL); } /* MIX mail expunge mailbox * Accepts: MAIL stream * sequence to expunge if non-NIL, empty string for burp only * expunge options * Returns: T on success, NIL if failure */ long mix_expunge (MAILSTREAM *stream,char *sequence,long options) { FILE *idxf = NIL; FILE *statf = NIL; MESSAGECACHE *elt; int ifd,sfd; long ret; unsigned long i; unsigned long nexp = 0; unsigned long reclaimed = 0; int burponly = (sequence && !*sequence); LOCAL->expok = T; /* expunge during ping is OK */ if (!(ret = burponly || !sequence || ((options & EX_UID) ? mail_uid_sequence (stream,sequence) : mail_sequence (stream,sequence))) || stream->rdonly); /* read index and open status exclusive */ else if (statf = mix_parse (stream,&idxf,LONGT, LOCAL->internal ? NIL : LONGT)) { /* expunge unless just burping */ if (!burponly) for (i = 1; i <= stream->nmsgs;) { elt = mail_elt (stream,i);/* need to expunge this message? */ if (sequence ? elt->sequence : elt->deleted) { ++nexp; /* yes, make it so */ mail_expunged (stream,i); } else ++i; /* otherwise advance to next message */ } /* burp if can get exclusive access */ if (!flock (LOCAL->mfd,LOCK_EX|LOCK_NB)) { void *a; struct direct **names = NIL; long nfiles = scandir (stream->mailbox,&names,mix_select,mix_msgfsort); if (nfiles > 0) { /* if have message files */ MIXBURP *burp,*cur; /* initialize burp list */ for (i = 0, burp = cur = NIL; i < nfiles; ++i) { MIXBURP *nxt = (MIXBURP *) memset (fs_get (sizeof (MIXBURP)),0, sizeof (MIXBURP)); /* another file found */ if (cur) cur = cur->next = nxt; else cur = burp = nxt; cur->name = names[i]->d_name; cur->fileno = strtoul (cur->name + sizeof (MIXNAME) - 1,NIL,16); cur->tail = &cur->set; fs_give ((void **) &names[i]); } /* now load ranges */ for (i = 1, cur = burp; ret && (i <= stream->nmsgs); i++) { /* is this message in current set? */ elt = mail_elt (stream,i); if (cur && (elt->private.spare.data != cur->fileno)) { /* restart if necessary */ if (elt->private.spare.data < cur->fileno) cur = burp; /* hunt for appropriate mailbox */ while (cur && (elt->private.spare.data > cur->fileno)) cur = cur->next; /* ought to have found it now... */ if (cur && (elt->private.spare.data != cur->fileno)) cur = NIL; } /* if found, add to set */ if (cur) ret = mix_addset (&cur->tail,elt->private.special.offset, elt->private.msg.header.offset + elt->rfc822_size); else { /* uh-oh */ sprintf (LOCAL->buf,"Can't locate mix message file %.08lx", elt->private.spare.data); MM_LOG (LOCAL->buf,ERROR); ret = NIL; } } if (ret) /* if no errors, burp all files */ for (cur = burp; ret && cur; cur = cur->next) { /* if non-empty, burp it */ if (cur->set.last) ret = mix_burp (stream,cur,&reclaimed); /* empty, delete it unless new msg file */ else if (mix_file_data (LOCAL->buf,stream->mailbox,cur->fileno) && ((cur->fileno == LOCAL->newmsg) ? truncate (LOCAL->buf,0) : unlink (LOCAL->buf))) { sprintf (LOCAL->buf, "Can't delete empty message file %.80s: %.80s", cur->name,strerror (errno)); MM_LOG (LOCAL->buf,WARN); } } } else MM_LOG ("No mix message files found during expunge",WARN); /* free directory list */ if (a = (void *) names) fs_give ((void **) &a); } /* either way, re-acquire shared lock */ if (flock (LOCAL->mfd,LOCK_SH|LOCK_NB)) fatal ("Unable to re-acquire metadata shared lock!"); /* Do this step even if ret is NIL (meaning some burp problem)! */ if (nexp || reclaimed) { /* rewrite index and status if changed */ LOCAL->indexseq = mix_modseq (LOCAL->indexseq); if (mix_index_update (stream,idxf,NIL)) { LOCAL->statusseq = mix_modseq (LOCAL->statusseq); /* set failure if update fails */ ret = mix_status_update (stream,statf,NIL); } } } if (statf) fclose (statf); /* close status if still open */ if (idxf) fclose (idxf); /* close index if still open */ LOCAL->expok = NIL; /* cancel expok */ if (ret) { /* only if success */ char *s = NIL; if (nexp) sprintf (s = LOCAL->buf,"Expunged %lu messages",nexp); else if (reclaimed) sprintf (s=LOCAL->buf,"Reclaimed %lu bytes of expunged space",reclaimed); else if (!burponly) s = stream->rdonly ? "Expunge ignored on readonly mailbox" : "No messages deleted, so no update needed"; if (s) MM_LOG (s,(long) NIL); } return ret; } /* MIX test for message file name * Accepts: candidate directory name * Returns: T if message file name, NIL otherwise * * ".mix" with no suffix was used by experimental versions */ int mix_select (struct direct *name) { char c,*s; /* make sure name has prefix */ if (mix_dirfmttest (name->d_name)) { for (c = *(s = name->d_name + sizeof (MIXNAME) - 1); c && isxdigit (c); c = *s++); if (!c) return T; /* all-hex or no suffix */ } return NIL; /* not suffix or non-hex */ } /* MIX msg file name comparision * Accepts: first candidate directory entry * second candidate directory entry * Returns: -1 if d1 < d2, 0 if d1 == d2, 1 d1 > d2 */ int mix_msgfsort (const void *d1,const void *d2) { char *n1 = (*(struct direct **) d1)->d_name + sizeof (MIXNAME) - 1; char *n2 = (*(struct direct **) d2)->d_name + sizeof (MIXNAME) - 1; return compare_ulong (*n1 ? strtoul (n1,NIL,16) : 0, *n2 ? strtoul (n2,NIL,16) : 0); } /* MIX add a range to a set * Accepts: pointer to set to add * start of set * size of set * Returns: T if success, set updated, NIL otherwise */ long mix_addset (SEARCHSET **set,unsigned long start,unsigned long size) { SEARCHSET *s = *set; if (start < s->last) { /* sanity check */ char tmp[MAILTMPLEN]; sprintf (tmp,"Backwards-running mix index %lu < %lu",start,s->last); MM_LOG (tmp,ERROR); return NIL; } /* range initially empty? */ if (!s->last) s->first = start; else if (start > s->last) /* no, start new range if can't append */ (*set = s = s->next = mail_newsearchset ())->first = start; s->last = start + size; /* end of current range */ return LONGT; } /* MIX burp message file * Accepts: MAIL stream * current burp block for this message * Returns: T if successful, NIL if failed */ static char *staterr = "Error in stat of mix message file %.80s: %.80s"; static char *truncerr = "Error truncating mix message file %.80s: %.80s"; long mix_burp (MAILSTREAM *stream,MIXBURP *burp,unsigned long *reclaimed) { MESSAGECACHE *elt; SEARCHSET *set; struct stat sbuf; off_t rpos,wpos; size_t size,wsize,wpending,written; int fd; FILE *f; void *s; unsigned long i; long ret = NIL; /* build file name */ mix_file_data (LOCAL->buf,stream->mailbox,burp->fileno); /* need to burp at start or multiple ranges? */ if (!burp->set.first && !burp->set.next) { /* easy case, single range at start of file */ if (stat (LOCAL->buf,&sbuf)) { sprintf (LOCAL->buf,staterr,burp->name,strerror (errno)); MM_LOG (LOCAL->buf,ERROR); } /* is this range sane? */ else if (mix_burp_check (&burp->set,sbuf.st_size,LOCAL->buf)) { /* if matches range then no burp needed! */ if (burp->set.last == sbuf.st_size) ret = LONGT; /* just need to remove cruft at end */ else if (ret = !truncate (LOCAL->buf,burp->set.last)) *reclaimed += sbuf.st_size - burp->set.last; else { sprintf (LOCAL->buf,truncerr,burp->name,strerror (errno)); MM_LOG (LOCAL->buf,ERROR); } } } /* have to do more work, get the file */ else if (((fd = open (LOCAL->buf,O_RDWR,NIL)) < 0) || !(f = fdopen (fd,"r+b"))) { sprintf (LOCAL->buf,"Error opening mix message file %.80s: %.80s", burp->name,strerror (errno)); MM_LOG (LOCAL->buf,ERROR); if (fd >= 0) close (fd); /* in case fdopen() failure */ } else if (fstat (fd,&sbuf)) { /* get file size */ sprintf (LOCAL->buf,staterr,burp->name,strerror (errno)); MM_LOG (LOCAL->buf,ERROR); fclose (f); } /* only if sane */ else if (mix_burp_check (&burp->set,sbuf.st_size,LOCAL->buf)) { /* make sure each range starts with token */ for (set = &burp->set; set; set = set->next) if (fseek (f,set->first,SEEK_SET) || (fread (LOCAL->buf,1,MSGTSZ,f) != MSGTSZ) || strncmp (LOCAL->buf,MSGTOK,MSGTSZ)) { sprintf (LOCAL->buf,"Bad message token in mix message file at %lu", set->first); MM_LOG (LOCAL->buf,ERROR); fclose (f); return NIL; /* burp fails for this file */ } /* burp out each old message */ for (set = &burp->set, wpos = 0; set; set = set->next) { /* move down this range */ for (rpos = set->first, size = set->last - set->first; size; size -= wsize) { if (rpos != wpos) { /* data to skip at start? */ /* no, slide this buffer down */ wsize = min (size,LOCAL->buflen); /* failure is not an option here */ while (fseek (f,rpos,SEEK_SET) || (fread (LOCAL->buf,1,wsize,f) != wsize)) { MM_NOTIFY (stream,strerror (errno),WARN); MM_DISKERROR (stream,errno,T); } /* nor here */ while (fseek (f,wpos,SEEK_SET)) { MM_NOTIFY (stream,strerror (errno),WARN); MM_DISKERROR (stream,errno,T); } /* and especially not here */ for (s = LOCAL->buf, wpending = wsize; wpending; wpending -= written) if (!(written = fwrite (LOCAL->buf,1,wpending,f))) { MM_NOTIFY (stream,strerror (errno),WARN); MM_DISKERROR (stream,errno,T); } } else wsize = size; /* nothing to skip, say we wrote it all */ rpos += wsize; wpos += wsize; } } while (fflush (f)) { /* failure also not an option here... */ MM_NOTIFY (stream,strerror (errno),WARN); MM_DISKERROR (stream,errno,T); } if (ftruncate (fd,wpos)) { /* flush cruft at end of file */ sprintf (LOCAL->buf,truncerr,burp->name,strerror (errno)); MM_LOG (LOCAL->buf,WARN); } else *reclaimed += rpos - wpos; ret = !fclose (f); /* close file */ /* slide down message positions in index */ for (i = 1,rpos = 0; i <= stream->nmsgs; ++i) if ((elt = mail_elt (stream,i))->private.spare.data == burp->fileno) { elt->private.special.offset = rpos; rpos += elt->private.msg.header.offset + elt->rfc822_size; } /* debugging */ if (rpos != wpos) fatal ("burp size consistency check!"); } return ret; } /* MIX burp sanity check to make sure not burping off end of file * Accepts: burp set * file size * file name * Returns: T if sane, NIL if insane */ long mix_burp_check (SEARCHSET *set,size_t size,char *file) { do if (set->last > size) { /* sanity check */ char tmp[MAILTMPLEN]; sprintf (tmp,"Unexpected short mix message file %.80s %lu < %lu", file,size,set->last); MM_LOG (tmp,ERROR); return NIL; /* don't burp this file at all */ } while (set = set->next); return LONGT; } /* MIX mail copy message(s) * Accepts: MAIL stream * sequence * destination mailbox * copy options * Returns: T if copy successful, else NIL */ long mix_copy (MAILSTREAM *stream,char *sequence,char *mailbox,long options) { FDDATA d; STRING st; char tmp[2*MAILTMPLEN]; long ret = mix_isvalid (mailbox,LOCAL->buf); mailproxycopy_t pc = (mailproxycopy_t) mail_parameters (stream,GET_MAILPROXYCOPY,NIL); MAILSTREAM *astream = NIL; FILE *idxf = NIL; FILE *msgf = NIL; FILE *statf = NIL; if (!ret) switch (errno) { /* make sure valid mailbox */ case NIL: /* no error in stat() */ if (pc) return (*pc) (stream,sequence,mailbox,options); sprintf (tmp,"Not a MIX-format mailbox: %.80s",mailbox); MM_LOG (tmp,ERROR); break; default: /* some stat() error */ MM_NOTIFY (stream,"[TRYCREATE] Must create mailbox before copy",NIL); break; } /* get sequence to copy */ else if (!(ret = ((options & CP_UID) ? mail_uid_sequence (stream,sequence) : mail_sequence (stream,sequence)))); /* acquire stream to append */ else if (ret = ((astream = mail_open (NIL,mailbox,OP_SILENT)) && !astream->rdonly && (((MIXLOCAL *) astream->local)->expok = T) && (statf = mix_parse (astream,&idxf,LONGT,NIL))) ? LONGT : NIL) { int fd; unsigned long i; MESSAGECACHE *elt; unsigned long newsize,hdrsize,size; MIXLOCAL *local = (MIXLOCAL *) astream->local; unsigned long seq = mix_modseq (local->metaseq); /* make sure new modseq fits */ if (local->indexseq > seq) seq = local->indexseq + 1; if (local->statusseq > seq) seq = local->statusseq + 1; /* calculate size of per-message header */ sprintf (local->buf,MSRFMT,MSGTOK,0,0,0,0,0,0,0,'+',0,0,0); hdrsize = strlen (local->buf); MM_CRITICAL (stream); /* go critical */ astream->silent = T; /* no events here */ /* calculate size that will be added */ for (i = 1, newsize = 0; i <= stream->nmsgs; ++i) if ((elt = mail_elt (stream,i))->sequence) newsize += hdrsize + elt->rfc822_size; /* open data file */ if (msgf = mix_data_open (astream,&fd,&size,newsize)) { char *t; unsigned long j,uid,uidv; copyuid_t cu = (copyuid_t) mail_parameters (NIL,GET_COPYUID,NIL); SEARCHSET *source = cu ? mail_newsearchset () : NIL; SEARCHSET *dest = cu ? mail_newsearchset () : NIL; for (i = 1,uid = uidv = 0; ret && (i <= stream->nmsgs); ++i) if (((elt = mail_elt (stream,i))->sequence) && elt->rfc822_size) { /* is message in current message file? */ if ((LOCAL->msgfd < 0) || (elt->private.spare.data != LOCAL->curmsg)) { if (LOCAL->msgfd >= 0) close (LOCAL->msgfd); if ((LOCAL->msgfd = open (mix_file_data (LOCAL->buf, stream->mailbox, elt->private.spare.data), O_RDONLY,NIL)) >= 0) LOCAL->curmsg = elt->private.spare.data; } if (LOCAL->msgfd < 0) ret = NIL; else { /* got file */ d.fd = LOCAL->msgfd;/* set up file descriptor */ /* start of message */ d.pos = elt->private.special.offset + elt->private.msg.header.offset; d.chunk = LOCAL->buf; d.chunksize = CHUNKSIZE; INIT (&st,fd_string,&d,elt->rfc822_size); /* init flag string */ tmp[0] = tmp[1] = '\0'; if (j = elt->user_flags) do if ((t = stream->user_flags[find_rightmost_bit (&j)]) && *t) strcat (strcat (tmp," "),t); while (j); if (elt->seen) strcat (tmp," \\Seen"); if (elt->deleted) strcat (tmp," \\Deleted"); if (elt->flagged) strcat (tmp," \\Flagged"); if (elt->answered) strcat (tmp," \\Answered"); if (elt->draft) strcat (tmp," \\Draft"); tmp[0] = '('; /* wrap list */ strcat (tmp,")"); /* if append OK, add to source set */ if ((ret = mix_append_msg (astream,msgf,tmp,elt,&st,dest, seq)) && source) mail_append_set (source,mail_uid (stream,i)); } } /* finish write if success */ if (ret && (ret = !fflush (msgf))) { fclose (msgf); /* all good, close the msg file now */ /* write new metadata, index, and status */ local->metaseq = local->indexseq = local->statusseq = seq; if (ret = (mix_meta_update (astream) && mix_index_update (astream,idxf,LONGT))) { /* success, delete if doing a move */ if (options & CP_MOVE) for (i = 1; i <= stream->nmsgs; i++) if ((elt = mail_elt (stream,i))->sequence) { elt->deleted = T; if (!stream->rdonly) elt->private.mod = LOCAL->statusseq = seq; MM_FLAGS (stream,elt->msgno); } /* done with status file now */ mix_status_update (astream,statf,LONGT); /* return sets if doing COPYUID */ if (cu) (*cu) (stream,mailbox,astream->uid_validity,source,dest); source = dest = NIL; /* don't free these sets now */ } } else { /* error */ if (errno) { /* output error message if system call error */ sprintf (tmp,"Message copy failed: %.80s",strerror (errno)); MM_LOG (tmp,ERROR); } ftruncate (fd,size); /* revert file */ close (fd); /* make sure that fclose doesn't corrupt us */ fclose (msgf); /* free the stdio resources */ } /* flush any sets remaining */ mail_free_searchset (&source); mail_free_searchset (&dest); } else { /* message file open failed */ sprintf (tmp,"Error opening copy message file: %.80s", strerror (errno)); MM_LOG (tmp,ERROR); ret = NIL; } MM_NOCRITICAL (stream); } else MM_LOG ("Can't open copy mailbox",ERROR); if (statf) fclose (statf); /* close status if still open */ if (idxf) fclose (idxf); /* close index if still open */ /* finished with append stream */ if (astream) mail_close (astream); return ret; /* return state */ } /* MIX mail append message from stringstruct * Accepts: MAIL stream * destination mailbox * append callback * data for callback * Returns: T if append successful, else NIL */ long mix_append (MAILSTREAM *stream,char *mailbox,append_t af,void *data) { STRING *message; char *flags,*date,tmp[MAILTMPLEN]; /* N.B.: can't use LOCAL->buf for tmp */ long ret = mix_isvalid (mailbox,tmp); /* default stream to prototype */ if (!stream) stream = user_flags (&mixproto); if (!ret) switch (errno) { /* if not valid mailbox */ case ENOENT: /* no such file? */ if (ret = compare_cstring (mailbox,"INBOX") ? NIL : mix_create (NIL,"INBOX")) break; MM_NOTIFY (stream,"[TRYCREATE] Must create mailbox before append",NIL); break; default: sprintf (tmp,"Not a MIX-format mailbox: %.80s",mailbox); MM_LOG (tmp,ERROR); break; } /* get first message */ if (ret && MM_APPEND (af) (stream,data,&flags,&date,&message)) { MAILSTREAM *astream; FILE *idxf = NIL; FILE *msgf = NIL; FILE *statf = NIL; if (ret = ((astream = mail_open (NIL,mailbox,OP_SILENT)) && !astream->rdonly && (((MIXLOCAL *) astream->local)->expok = T) && (statf = mix_parse (astream,&idxf,LONGT,NIL))) ? LONGT : NIL) { int fd; unsigned long size,hdrsize; MESSAGECACHE elt; MIXLOCAL *local = (MIXLOCAL *) astream->local; unsigned long seq = mix_modseq (local->metaseq); /* make sure new modseq fits */ if (local->indexseq > seq) seq = local->indexseq + 1; if (local->statusseq > seq) seq = local->statusseq + 1; /* calculate size of per-message header */ sprintf (local->buf,MSRFMT,MSGTOK,0,0,0,0,0,0,0,'+',0,0,0); hdrsize = strlen (local->buf); MM_CRITICAL (astream); /* go critical */ astream->silent = T; /* no events here */ /* open data file */ if (msgf = mix_data_open (astream,&fd,&size,hdrsize + SIZE (message))) { appenduid_t au = (appenduid_t) mail_parameters (NIL,GET_APPENDUID,NIL); SEARCHSET *dst = au ? mail_newsearchset () : NIL; while (ret && message) {/* while good to go and have messages */ errno = NIL; /* in case one of these causes failure */ /* guard against zero-length */ if (!(ret = SIZE (message))) MM_LOG ("Append of zero-length message",ERROR); else if (date && !(ret = mail_parse_date (&elt,date))) { sprintf (tmp,"Bad date in append: %.80s",date); MM_LOG (tmp,ERROR); } else { if (!date) { /* if date not specified, use now */ internal_date (tmp); mail_parse_date (&elt,tmp); } ret = mix_append_msg (astream,msgf,flags,&elt,message,dst,seq) && MM_APPEND (af) (stream,data,&flags,&date,&message); } } /* finish write if success */ if (ret && (ret = !fflush (msgf))) { fclose (msgf); /* all good, close the msg file now */ /* write new metadata, index, and status */ local->metaseq = local->indexseq = local->statusseq = seq; if ((ret = (mix_meta_update (astream) && mix_index_update (astream,idxf,LONGT) && mix_status_update (astream,statf,LONGT))) && au) { (*au) (mailbox,astream->uid_validity,dst); dst = NIL; /* don't free this set now */ } } else { /* failure */ if (errno) { /* output error message if system call error */ sprintf (tmp,"Message append failed: %.80s",strerror (errno)); MM_LOG (tmp,ERROR); } ftruncate (fd,size); /* revert all writes to file*/ close (fd); /* make sure that fclose doesn't corrupt us */ fclose (msgf); /* free the stdio resources */ } /* flush any set remaining */ mail_free_searchset (&dst); } else { /* message file open failed */ sprintf (tmp,"Error opening append message file: %.80s", strerror (errno)); MM_LOG (tmp,ERROR); ret = NIL; } MM_NOCRITICAL (astream); /* release critical */ } else MM_LOG ("Can't open append mailbox",ERROR); if (statf) fclose (statf); /* close status if still open */ if (idxf) fclose (idxf); /* close index if still open */ if (astream) mail_close (astream); } return ret; } /* MIX mail append single message * Accepts: MAIL stream * flags for new message if non-NIL * elt with source date if non-NIL * stringstruct of message text * searchset to place UID * modseq of message * Returns: T if success, NIL if failure */ long mix_append_msg (MAILSTREAM *stream,FILE *f,char *flags,MESSAGECACHE *delt, STRING *msg,SEARCHSET *set,unsigned long seq) { MESSAGECACHE *elt; int c,cs; unsigned long i,j,k,uf,hoff; long sf; stream->kwd_create = NIL; /* don't copy unknown keywords */ sf = mail_parse_flags (stream,flags,&uf); /* swell the cache */ mail_exists (stream,++stream->nmsgs); /* assign new UID from metadata */ (elt = mail_elt (stream,stream->nmsgs))->private.uid = ++stream->uid_last; elt->private.mod = seq; /* set requested modseq in status */ elt->rfc822_size = SIZE (msg);/* copy message size and date to index */ elt->year = delt->year; elt->month = delt->month; elt->day = delt->day; elt->hours = delt->hours; elt->minutes = delt->minutes; elt->seconds = delt->seconds; elt->zoccident = delt->zoccident; elt->zhours = delt->zhours; elt->zminutes = delt->zminutes; /* * Do NOT set elt->valid here! mix_status_update() uses it to determine * whether a message should be marked as old. */ if (sf&fSEEN) elt->seen = T; /* copy flags to status */ if (sf&fDELETED) elt->deleted = T; if (sf&fFLAGGED) elt->flagged = T; if (sf&fANSWERED) elt->answered = T; if (sf&fDRAFT) elt->draft = T; elt->user_flags |= uf; /* message is in new message file */ elt->private.spare.data = LOCAL->newmsg; /* offset to message internal header */ elt->private.special.offset = ftell (f); /* build header for message */ fprintf (f,MSRFMT,MSGTOK,elt->private.uid, elt->year + BASEYEAR,elt->month,elt->day, elt->hours,elt->minutes,elt->seconds, elt->zoccident ? '-' : '+',elt->zhours,elt->zminutes, elt->rfc822_size); /* offset to header from internal header */ elt->private.msg.header.offset = ftell (f) - elt->private.special.offset; for (cs = 0; SIZE (msg); ) { /* copy message */ if (elt->private.msg.header.text.size) { if (msg->cursize) /* blat entire chunk if have it */ for (j = msg->cursize; j; j -= k) if (!(k = fwrite (msg->curpos,1,j,f))) return NIL; SETPOS (msg,GETPOS (msg) + msg->cursize); } else { /* still searching for delimiter */ c = 0xff & SNX (msg); /* get source character */ if (putc (c,f) == EOF) return NIL; switch (cs) { /* decide what to do based on state */ case 0: /* previous char ordinary */ if (c == '\015') cs = 1;/* advance if CR */ break; case 1: /* previous CR, advance if LF */ cs = (c == '\012') ? 2 : 0; break; case 2: /* previous CRLF, advance if CR */ cs = (c == '\015') ? 3 : 0; break; case 3: /* previous CRLFCR, done if LF */ if (c == '\012') elt->private.msg.header.text.size = elt->rfc822_size - SIZE (msg); cs = 0; /* reset mechanism */ break; } } } /* if no delimiter, header is entire msg */ if (!elt->private.msg.header.text.size) elt->private.msg.header.text.size = elt->rfc822_size; /* add this message to set */ mail_append_set (set,elt->private.uid); return LONGT; /* success */ } /* MIX mail read metadata, index, and status * Accepts: MAIL stream * returned index file * index file flags (non-NIL if want to add/remove messages) * status file flags (non-NIL if want to update elt->valid and old) * Returns: open status file, or NIL if failure * * Note that this routine can return an open index file even if it fails! */ static char *shortmsg = "message %lu (UID=%.08lx) truncated by %lu byte(s) (%lu < %lu)"; FILE *mix_parse (MAILSTREAM *stream,FILE **idxf,long iflags,long sflags) { int fd; unsigned long i; char *s,*t; struct stat sbuf; FILE *statf = NIL; short metarepairneeded = 0; short indexrepairneeded = 0; short silent = stream->silent; *idxf = NIL; /* in case error */ /* readonly means no updates */ if (stream->rdonly) iflags = sflags = NIL; /* open index file */ if ((fd = open (LOCAL->index,iflags ? O_RDWR : O_RDONLY,NIL)) < 0) MM_LOG ("Error opening mix index file",ERROR); /* acquire exclusive access and FILE */ else if (!flock (fd,iflags ? LOCK_EX : LOCK_SH) && !(*idxf = fdopen (fd,iflags ? "r+b" : "rb"))) { MM_LOG ("Error obtaining stream on mix index file",ERROR); flock (fd,LOCK_UN); /* relinquish lock */ close (fd); } /* slurp metadata */ else if (s = mix_meta_slurp (stream,&i)) { unsigned long j = 0; /* non-zero if UIDVALIDITY/UIDLAST changed */ if (i != LOCAL->metaseq) { /* metadata changed? */ char *t,*k; LOCAL->metaseq = i; /* note new metadata sequence */ while (s && *s) { /* parse entire metadata file */ /* locate end of line */ if (s = strstr (t = s,"\015\012")) { *s = '\0'; /* tie off line */ s += 2; /* skip past CRLF */ switch (*t++) { /* parse line */ case 'V': /* UIDVALIDITY */ if (!isxdigit (*t) || !(i = strtoul (t,&t,16))) { MM_LOG ("Error in mix metadata file UIDVALIDITY record",ERROR); return NIL; /* give up */ } if (i != stream->uid_validity) j = stream->uid_validity = i; break; case 'L': /* new UIDLAST */ if (!isxdigit (*t)) { MM_LOG ("Error in mix metadata file UIDLAST record",ERROR); return NIL; /* give up */ } if ((i = strtoul (t,&t,16)) != stream->uid_last) j = stream->uid_last = i; break; case 'N': /* new message file */ if (!isxdigit (*t)) { MM_LOG ("Error in mix metadata file new msg record",ERROR); return NIL; /* give up */ } if ((i = strtoul (t,&t,16)) != stream->uid_last) LOCAL->newmsg = i; break; case 'K': /* new keyword list */ for (i = 0; t && *t && (i < NUSERFLAGS); ++i) { if (t = strchr (k = t,' ')) *t++ = '\0'; /* make sure keyword non-empty */ if (*k && (strlen (k) <= MAXUSERFLAG)) { /* in case value changes (shouldn't happen) */ if (stream->user_flags[i] && strcmp (stream->user_flags[i],k)){ char tmp[MAILTMPLEN]; sprintf (tmp,"flag rename old=%.80s new=%.80s", stream->user_flags[i],k); MM_LOG (tmp,WARN); fs_give ((void **) &stream->user_flags[i]); } if (!stream->user_flags[i]) stream->user_flags[i] = cpystr (k); } else break; /* empty keyword */ } if ((i < NUSERFLAGS) && stream->user_flags[i]) { MM_LOG ("Error in mix metadata file keyword record",ERROR); return NIL; /* give up */ } else if (i == NUSERFLAGS) stream->kwd_create = NIL; break; } } if (t && *t) { /* junk in line */ MM_LOG ("Error in mix metadata record",ERROR); return NIL; /* give up */ } } } /* get sequence */ if (!(i = mix_read_sequence (*idxf)) || (i < LOCAL->indexseq)) { MM_LOG ("Error in mix index file sequence record",ERROR); return NIL; /* give up */ } /* sequence changed from last time? */ else if (j || (i > LOCAL->indexseq)) { unsigned long uid,nmsgs,curfile,curfilesize,curpos; char *t,*msg,tmp[MAILTMPLEN]; /* start with no messages */ curfile = curfilesize = curpos = nmsgs = 0; /* update sequence iff expunging OK */ if (LOCAL->expok) LOCAL->indexseq = i; /* get first elt */ while ((s = mix_read_record (*idxf,LOCAL->buf,LOCAL->buflen,"index")) && *s) switch (*s) { case ':': /* message record */ if (!(isxdigit (*++s) && (uid = strtoul (s,&t,16)))) msg = "UID"; else if (!((*t++ == ':') && isdigit (*t) && isdigit (t[1]) && isdigit (t[2]) && isdigit (t[3]) && isdigit (t[4]) && isdigit (t[5]) && isdigit (t[6]) && isdigit (t[7]) && isdigit (t[8]) && isdigit (t[9]) && isdigit (t[10]) && isdigit (t[11]) && isdigit (t[12]) && isdigit (t[13]) && ((t[14] == '+') || (t[14] == '-')) && isdigit (t[15]) && isdigit (t[16]) && isdigit (t[17]) && isdigit (t[18]))) msg = "internaldate"; else if ((*(s = t+19) != ':') || !isxdigit (*++s)) msg = "size"; else { unsigned int y = (((*t - '0') * 1000) + ((t[1] - '0') * 100) + ((t[2] - '0') * 10) + t[3] - '0') - BASEYEAR; unsigned int m = ((t[4] - '0') * 10) + t[5] - '0'; unsigned int d = ((t[6] - '0') * 10) + t[7] - '0'; unsigned int hh = ((t[8] - '0') * 10) + t[9] - '0'; unsigned int mm = ((t[10] - '0') * 10) + t[11] - '0'; unsigned int ss = ((t[12] - '0') * 10) + t[13] - '0'; unsigned int z = (t[14] == '-') ? 1 : 0; unsigned int zh = ((t[15] - '0') * 10) + t[16] - '0'; unsigned int zm = ((t[17] - '0') * 10) + t[18] - '0'; unsigned long size = strtoul (s,&s,16); if ((*s++ == ':') && isxdigit (*s)) { unsigned long file = strtoul (s,&s,16); if ((*s++ == ':') && isxdigit (*s)) { unsigned long pos = strtoul (s,&s,16); if ((*s++ == ':') && isxdigit (*s)) { unsigned long hpos = strtoul (s,&s,16); if ((*s++ == ':') && isxdigit (*s)) { unsigned long hsiz = strtoul (s,&s,16); if (uid > stream->uid_last) { sprintf (tmp,"mix index invalid UID (%08lx < %08lx)", uid,stream->uid_last); if (stream->rdonly) { MM_LOG (tmp,ERROR); return NIL; } strcat (tmp,", repaired"); MM_LOG (tmp,WARN); stream->uid_last = uid; metarepairneeded = T; } /* ignore expansion values */ if (*s++ == ':') { MESSAGECACHE *elt; ++nmsgs; /* this is another mesage */ /* within current known range of messages? */ while (nmsgs <= stream->nmsgs) { /* yes, get corresponding elt */ elt = mail_elt (stream,nmsgs); /* existing message with matching data? */ if (uid == elt->private.uid) { /* beware of Dracula's resurrection */ if (elt->private.ghost) { sprintf (tmp,"mix index data unexpunged UID: %lx", uid); MM_LOG (tmp,ERROR); return NIL; } /* also of static data changing */ if ((size != elt->rfc822_size) || (file != elt->private.spare.data) || (pos != elt->private.special.offset) || (hpos != elt->private.msg.header.offset) || (hsiz != elt->private.msg.header.text.size) || (y != elt->year) || (m != elt->month) || (d != elt->day) || (hh != elt->hours) || (mm != elt->minutes) || (ss != elt->seconds) || (z != elt->zoccident) || (zh != elt->zhours) || (zm != elt->zminutes)) { sprintf (tmp,"mix index data mismatch: %lx",uid); MM_LOG (tmp,ERROR); return NIL; } break; } /* existing msg with lower UID is expunged */ else if (uid > elt->private.uid) { if (LOCAL->expok) mail_expunged (stream,nmsgs); else {/* message expunged, but not yet for us */ ++nmsgs; elt->private.ghost = T; } } else { /* unexpected message record */ sprintf (tmp,"mix index UID mismatch (%lx < %lx)", uid,elt->private.uid); MM_LOG (tmp,ERROR); return NIL; } } /* time to create a new message? */ if (nmsgs > stream->nmsgs) { /* defer announcing until later */ stream->silent = T; mail_exists (stream,nmsgs); stream->silent = silent; (elt = mail_elt (stream,nmsgs))->recent = T; elt->private.uid = uid; elt->rfc822_size = size; elt->private.spare.data = file; elt->private.special.offset = pos; elt->private.msg.header.offset = hpos; elt->private.msg.header.text.size = hsiz; elt->year = y; elt->month = m; elt->day = d; elt->hours = hh; elt->minutes = mm; elt->seconds = ss; elt->zoccident = z; elt->zhours = zh; elt->zminutes = zm; /* message in same file? */ if (curfile == file) { if (pos < curpos) { MESSAGECACHE *plt = mail_elt (stream,elt->msgno-1); /* uh-oh, calculate delta? */ i = curpos - pos; sprintf (tmp,shortmsg,plt->msgno,plt->private.uid, i,pos,curpos); /* possible to fix? */ if (!stream->rdonly && LOCAL->expok && (i < plt->rfc822_size)) { plt->rfc822_size -= i; if (plt->rfc822_size < plt->private.msg.header.text.size) plt->private.msg.header.text.size = plt->rfc822_size; strcat (tmp,", repaired"); indexrepairneeded = T; } MM_LOG (tmp,WARN); } } else { /* new file, restart */ if (stat (mix_file_data (LOCAL->buf,stream->mailbox, curfile = file),&sbuf)) { sprintf (tmp,"Missing mix data file: %.500s", LOCAL->buf); MM_LOG (tmp,ERROR); return NIL; } curfile = file; curfilesize = sbuf.st_size; } /* position of message in file */ curpos = pos + elt->private.msg.header.offset + elt->rfc822_size; /* short file? */ if (curfilesize < curpos) { /* uh-oh, calculate delta? */ i = curpos - curfilesize; sprintf (tmp,shortmsg,elt->msgno,elt->private.uid, i,curfilesize,curpos); /* possible to fix? */ if (!stream->rdonly && LOCAL->expok && (i < elt->rfc822_size)) { elt->rfc822_size -= i; if (elt->rfc822_size < elt->private.msg.header.text.size) elt->private.msg.header.text.size = elt->rfc822_size; strcat (tmp,", repaired"); indexrepairneeded = T; } MM_LOG (tmp,WARN); } } break; } else msg = "expansion"; } else msg = "header size"; } else msg = "header position"; } else msg = "message position"; } else msg = "file#"; } sprintf (tmp,"Error in %s in mix index file: %.500s",msg,s); MM_LOG (tmp,ERROR); return NIL; default: sprintf (tmp,"Unknown record in mix index file: %.500s",s); MM_LOG (tmp,ERROR); return NIL; } if (!s) return NIL; /* barfage from mix_read_record() */ /* expunge trailing messages not in index */ if (LOCAL->expok) while (nmsgs < stream->nmsgs) mail_expunged (stream,stream->nmsgs); } /* repair metadata and index if needed */ if ((metarepairneeded ? mix_meta_update (stream) : T) && (indexrepairneeded ? mix_index_update (stream,*idxf,NIL) : T)) { MESSAGECACHE *elt; int fd; unsigned long uid,uf,sf,mod; char *s; int updatep = NIL; /* open status file */ if ((fd = open (LOCAL->status, stream->rdonly ? O_RDONLY : O_RDWR,NIL)) < 0) MM_LOG ("Error opening mix status file",ERROR); /* acquire exclusive access and FILE */ else if (!flock (fd,stream->rdonly ? LOCK_SH : LOCK_EX) && !(statf = fdopen (fd,stream->rdonly ? "rb" : "r+b"))) { MM_LOG ("Error obtaining stream on mix status file",ERROR); flock (fd,LOCK_UN); /* relinquish lock */ close (fd); } /* get sequence */ else if (!(i = mix_read_sequence (statf)) || ((i < LOCAL->statusseq) && stream->nmsgs && (i != 1))) { sprintf (LOCAL->buf, "Error in mix status sequence record, i=%lx, seq=%lx", i,LOCAL->statusseq); MM_LOG (LOCAL->buf,ERROR); } /* sequence changed from last time? */ else if (i != LOCAL->statusseq) { /* update sequence, get first elt */ if (i > LOCAL->statusseq) LOCAL->statusseq = i; if (stream->nmsgs) { elt = mail_elt (stream,i = 1); /* read message records */ while ((t = s = mix_read_record (statf,LOCAL->buf,LOCAL->buflen, "status")) && *s && (*s++ == ':') && isxdigit (*s)) { uid = strtoul (s,&s,16); if ((*s++ == ':') && isxdigit (*s)) { uf = strtoul (s,&s,16); if ((*s++ == ':') && isxdigit (*s)) { sf = strtoul (s,&s,16); if ((*s++ == ':') && isxdigit (*s)) { mod = strtoul (s,&s,16); /* ignore expansion values */ if (*s++ == ':') { /* need to move ahead to next elt? */ while ((uid > elt->private.uid) && (i < stream->nmsgs)) elt = mail_elt (stream,++i); /* update elt if altered */ if ((uid == elt->private.uid) && (!elt->valid || (mod != elt->private.mod))) { elt->user_flags = uf; elt->private.mod = mod; elt->seen = (sf & fSEEN) ? T : NIL; elt->deleted = (sf & fDELETED) ? T : NIL; elt->flagged = (sf & fFLAGGED) ? T : NIL; elt->answered = (sf & fANSWERED) ? T : NIL; elt->draft = (sf & fDRAFT) ? T : NIL; /* announce if altered existing message */ if (elt->valid) MM_FLAGS (stream,elt->msgno); /* first time, is old message? */ else if (sf & fOLD) { /* yes, clear recent and set valid */ elt->recent = NIL; elt->valid = T; } /* recent, allowed to update its status? */ else if (sflags) { /* yes, set valid and check in status */ elt->valid = T; elt->private.mod = mix_modseq (elt->private.mod); updatep = T; } /* leave valid unset and recent if sflags not set */ } continue; /* everything looks good */ } } } } break; /* error somewhere */ } if (t && *t) { /* non-null means bogus record */ char msg[MAILTMPLEN]; sprintf (msg,"Error in mix status file message record%s: %.80s", stream->rdonly ? "" : ", fixing",t); MM_LOG (msg,WARN); /* update it if not readonly */ if (!stream->rdonly) updatep = T; } if (updatep) { /* need to update? */ LOCAL->statusseq = mix_modseq (LOCAL->statusseq); mix_status_update (stream,statf,LONGT); } } } } } if (statf) { /* still happy? */ unsigned long j; stream->silent = silent; /* now notify upper level */ mail_exists (stream,stream->nmsgs); for (i = 1, j = 0; i <= stream->nmsgs; ++i) if (mail_elt (stream,i)->recent) ++j; mail_recent (stream,j); } return statf; } /* MIX metadata file routines */ /* MIX read metadata * Accepts: MAIL stream * return pointer for modseq * Returns: pointer to metadata after modseq or NIL if failure */ char *mix_meta_slurp (MAILSTREAM *stream,unsigned long *seq) { struct stat sbuf; char *s; char *ret = NIL; if (fstat (LOCAL->mfd,&sbuf)) MM_LOG ("Error obtaining size of mix metatdata file",ERROR); if (sbuf.st_size > LOCAL->buflen) { /* should be just a few dozen bytes */ if (sbuf.st_size > METAMAX) fatal ("absurd mix metadata file size"); fs_give ((void **) &LOCAL->buf); LOCAL->buf = (char *) fs_get ((LOCAL->buflen = sbuf.st_size) + 1); } /* read current metadata file */ LOCAL->buf[sbuf.st_size] = '\0'; if (lseek (LOCAL->mfd,0,L_SET) || (read (LOCAL->mfd,s = LOCAL->buf,sbuf.st_size) != sbuf.st_size)) MM_LOG ("Error reading mix metadata file",ERROR); else if ((*s != 'S') || !isxdigit (s[1]) || ((*seq = strtoul (s+1,&s,16)) < LOCAL->metaseq) || (*s++ != '\015') || (*s++ != '\012')) MM_LOG ("Error in mix metadata file sequence record",ERROR); else ret = s; return ret; } /* MIX update metadata * Accepts: MAIL stream * Returns: T on success, NIL if error * * Index MUST be locked!! */ long mix_meta_update (MAILSTREAM *stream) { long ret; /* do nothing if stream readonly */ if (stream->rdonly) ret = LONGT; else { unsigned char c,*s,*ss,*t; unsigned long i; /* The worst-case metadata is limited to: * 4 * (1 + 8 + 2) + (NUSERFLAGS * (MAXUSERFLAG + 1)) * which comes out to 1994 octets. This is much smaller than the normal * CHUNKSIZE definition of 64K, and CHUNKSIZE is the smallest size of * LOCAL->buf. * * If more stuff gets added to the metadata, or if you change the value * of NUSERFLAGS, MAXUSERFLAG or CHUNKSIZE, be sure to recalculate the * above assertation. */ sprintf (LOCAL->buf,SEQFMT,LOCAL->metaseq = mix_modseq (LOCAL->metaseq)); sprintf (LOCAL->buf + strlen (LOCAL->buf),MTAFMT, stream->uid_validity,stream->uid_last,LOCAL->newmsg); for (i = 0, c = 'K', s = ss = LOCAL->buf + strlen (LOCAL->buf); (i < NUSERFLAGS) && (t = stream->user_flags[i]); ++i) { if (!*t) fatal ("impossible empty keyword"); *s++ = c; /* write delimiter */ while (*t) *s++ = *t++; /* write keyword */ c = ' '; /* delimiter is now space */ } if (s != ss) { /* tie off keywords line */ *s++ = '\015'; *s++ = '\012'; } /* calculate length of metadata */ if ((i = s - LOCAL->buf) > LOCAL->buflen) fatal ("impossible buffer overflow"); lseek (LOCAL->mfd,0,L_SET); /* rewind file */ /* write new metadata */ ret = (write (LOCAL->mfd,LOCAL->buf,i) == i) ? LONGT : NIL; ftruncate (LOCAL->mfd,i); /* and tie off at that point */ } return ret; } /* MIX index file routines */ /* MIX update index * Accepts: MAIL stream * open FILE * expansion check flag * Returns: T on success, NIL if error */ long mix_index_update (MAILSTREAM *stream,FILE *idxf,long flag) { unsigned long i; long ret = LONGT; if (!stream->rdonly) { /* do nothing if stream readonly */ if (flag) { /* need to do expansion check? */ char tmp[MAILTMPLEN]; size_t size; struct stat sbuf; /* calculate file size we need */ for (i = 1, size = 0; i <= stream->nmsgs; ++i) if (!mail_elt (stream,i)->private.ghost) ++size; if (size) { /* Winston Smith's first dairy entry */ sprintf (tmp,IXRFMT,0,14,4,4,13,0,0,'+',0,0,0,0,0,0,0); size *= strlen (tmp); } /* calculate file size we need */ sprintf (tmp,SEQFMT,LOCAL->indexseq); size += strlen (tmp); /* get current file size */ if (fstat (fileno (idxf),&sbuf)) { MM_LOG ("Error getting size of mix index file",ERROR); ret = NIL; } /* need to write additional space? */ else if (sbuf.st_size < size) { void *buf = fs_get (size -= sbuf.st_size); memset (buf,0,size); if (fseek (idxf,0,SEEK_END) || (fwrite (buf,1,size,idxf) != size) || fflush (idxf)) { fseek (idxf,sbuf.st_size,SEEK_SET); ftruncate (fileno (idxf),sbuf.st_size); MM_LOG ("Error extending mix index file",ERROR); ret = NIL; } fs_give ((void **) &buf); } } if (ret) { /* if still good to go */ rewind (idxf); /* let's start at the very beginning */ /* write modseq first */ fprintf (idxf,SEQFMT,LOCAL->indexseq); /* then write all messages */ for (i = 1; ret && (i <= stream->nmsgs); i++) { MESSAGECACHE *elt = mail_elt (stream,i); if (!elt->private.ghost)/* only write living messages */ fprintf (idxf,IXRFMT,elt->private.uid, elt->year + BASEYEAR,elt->month,elt->day, elt->hours,elt->minutes,elt->seconds, elt->zoccident ? '-' : '+',elt->zhours,elt->zminutes, elt->rfc822_size,elt->private.spare.data, elt->private.special.offset, elt->private.msg.header.offset, elt->private.msg.header.text.size); if (ferror (idxf)) { MM_LOG ("Error updating mix index file",ERROR); ret = NIL; } } if (fflush (idxf)) { MM_LOG ("Error flushing mix index file",ERROR); ret = NIL; } if (ret) ftruncate (fileno (idxf),ftell (idxf)); } } return ret; } /* MIX status file routines */ /* MIX update status * Accepts: MAIL stream * pointer to open FILE * expansion check flag * Returns: T on success, NIL if error */ long mix_status_update (MAILSTREAM *stream,FILE *statf,long flag) { unsigned long i; char tmp[MAILTMPLEN]; long ret = LONGT; if (!stream->rdonly) { /* do nothing if stream readonly */ if (flag) { /* need to do expansion check? */ char tmp[MAILTMPLEN]; size_t size; struct stat sbuf; /* calculate file size we need */ for (i = 1, size = 0; i <= stream->nmsgs; ++i) if (!mail_elt (stream,i)->private.ghost) ++size; if (size) { /* number of living messages */ sprintf (tmp,STRFMT,0,0,0,0); size *= strlen (tmp); } sprintf (tmp,SEQFMT,LOCAL->statusseq); size += strlen (tmp); /* get current file size */ if (fstat (fileno (statf),&sbuf)) { MM_LOG ("Error getting size of mix status file",ERROR); ret = NIL; } /* need to write additional space? */ else if (sbuf.st_size < size) { void *buf = fs_get (size -= sbuf.st_size); memset (buf,0,size); if (fseek (statf,0,SEEK_END) || (fwrite (buf,1,size,statf) != size) || fflush (statf)) { fseek (statf,sbuf.st_size,SEEK_SET); ftruncate (fileno (statf),sbuf.st_size); MM_LOG ("Error extending mix status file",ERROR); ret = NIL; } fs_give ((void **) &buf); } } if (ret) { /* if still good to go */ rewind (statf); /* let's start at the very beginning */ /* write sequence */ fprintf (statf,SEQFMT,LOCAL->statusseq); /* write message status records */ for (i = 1; ret && (i <= stream->nmsgs); ++i) { MESSAGECACHE *elt = mail_elt (stream,i); /* make sure all messages have a modseq */ if (!elt->private.mod) elt->private.mod = LOCAL->statusseq; if (!elt->private.ghost)/* only write living messages */ fprintf (statf,STRFMT,elt->private.uid,elt->user_flags, (fSEEN * elt->seen) + (fDELETED * elt->deleted) + (fFLAGGED * elt->flagged) + (fANSWERED * elt->answered) + (fDRAFT * elt->draft) + (elt->valid ? fOLD : NIL), elt->private.mod); if (ferror (statf)) { sprintf (tmp,"Error updating mix status file: %.80s", strerror (errno)); MM_LOG (tmp,ERROR); ret = NIL; } } if (ret && fflush (statf)) { MM_LOG ("Error flushing mix status file",ERROR); ret = NIL; } if (ret) ftruncate (fileno (statf),ftell (statf)); } } return ret; } /* MIX data file routines */ /* MIX open data file * Accepts: MAIL stream * pointer to returned fd if success * pointer to returned size if success * size of new data to be added * Returns: open FILE, or NIL if failure * * The curend test assumes that the last message of the mailbox is the furthest * point that the current data file extends, and thus that is all that needs to * be tested for short file prevention. */ FILE *mix_data_open (MAILSTREAM *stream,int *fd,long *size, unsigned long newsize) { FILE *msgf = NIL; struct stat sbuf; MESSAGECACHE *elt = stream->nmsgs ? mail_elt (stream,stream->nmsgs) : NIL; unsigned long curend = (elt && (elt->private.spare.data == LOCAL->newmsg)) ? elt->private.special.offset + elt->private.msg.header.offset + elt->rfc822_size : 0; /* allow create if curend 0 */ if ((*fd = open (mix_file_data (LOCAL->buf,stream->mailbox,LOCAL->newmsg), O_RDWR | (curend ? NIL : O_CREAT),NIL)) >= 0) { fstat (*fd,&sbuf); /* get current file size */ /* can we use this file? */ if ((curend <= sbuf.st_size) && (!sbuf.st_size || ((sbuf.st_size + newsize) <= MIXDATAROLL))) *size = sbuf.st_size; /* yes, return current size */ else { /* short file or becoming too long */ if (curend > sbuf.st_size) { char tmp[MAILTMPLEN]; sprintf (tmp,"short mix message file %.08lx (%ld > %ld), rolling", LOCAL->newmsg,curend,sbuf.st_size); MM_LOG (tmp,WARN); /* shouldn't happen */ } close (*fd); /* roll to a new file */ while ((*fd = open (mix_file_data (LOCAL->buf,stream->mailbox, LOCAL->newmsg = mix_modseq (LOCAL->newmsg)), O_RDWR | O_CREAT | O_EXCL,sbuf.st_mode)) < 0); *size = 0; /* brand new file */ fchmod (*fd,sbuf.st_mode);/* with same mode as previous file */ } } if (*fd >= 0) { /* have a data file? */ /* yes, get stdio and set position */ if (msgf = fdopen (*fd,"r+b")) fseek (msgf,*size,SEEK_SET); else close (*fd); /* fdopen() failed? */ } return msgf; /* return results */ } /* MIX open sortcache * Accepts: MAIL stream * Returns: open FILE, or NIL if failure or could only get readonly sortcache */ FILE *mix_sortcache_open (MAILSTREAM *stream) { int fd,refwd; unsigned long i,uid,sentdate,fromlen,tolen,cclen,subjlen,msgidlen,reflen; char *s,*t,*msg,tmp[MAILTMPLEN]; MESSAGECACHE *elt; SORTCACHE *sc; STRINGLIST *sl; struct stat sbuf; int rdonly = NIL; FILE *srtcf = NIL; mailcache_t mc = (mailcache_t) mail_parameters (NIL,GET_CACHE,NIL); fstat (LOCAL->mfd,&sbuf); if (!stream->nmsgs); /* do nothing if mailbox empty */ /* open sortcache file */ else if (((fd = open (LOCAL->sortcache,O_RDWR|O_CREAT,sbuf.st_mode)) < 0) && !(rdonly = ((fd = open (LOCAL->sortcache,O_RDONLY,NIL)) >= 0))) MM_LOG ("Error opening mix sortcache file",WARN); /* acquire lock and FILE */ else if (!flock (fd,rdonly ? LOCK_SH : LOCK_EX) && !(srtcf = fdopen (fd,rdonly ? "rb" : "r+b"))) { MM_LOG ("Error obtaining stream on mix sortcache file",WARN); flock (fd,LOCK_UN); /* relinquish lock */ close (fd); } else if (!(i = mix_read_sequence (srtcf)) || (i < LOCAL->sortcacheseq)) MM_LOG ("Error in mix sortcache file sequence record",WARN); /* sequence changed from last time? */ else if (i > LOCAL->sortcacheseq) { LOCAL->sortcacheseq = i; /* update sequence */ while ((s = t = mix_read_record (srtcf,LOCAL->buf,LOCAL->buflen, "sortcache")) && *s && (msg = "uid") && (*s++ == ':') && isxdigit (*s)) { uid = strtoul (s,&s,16); if ((*s++ == ':') && isxdigit (*s)) { sentdate = strtoul (s,&s,16); if ((*s++ == ':') && isxdigit (*s)) { fromlen = strtoul (s,&s,16); if ((*s++ == ':') && isxdigit (*s)) { tolen = strtoul (s,&s,16); if ((*s++ == ':') && isxdigit (*s)) { cclen = strtoul (s,&s,16); if ((*s++ == ':') && ((*s == 'R') || (*s == ' ')) && isxdigit (s[1])) { refwd = (*s++ == 'R') ? T : NIL; subjlen = strtoul (s,&s,16); if ((*s++ == ':') && isxdigit (*s)) { msgidlen = strtoul (s,&s,16); if ((*s++ == ':') && isxdigit (*s)) { reflen = strtoul (s,&s,16); /* ignore expansion values */ if (*s++ == ':') { if (i = mail_msgno (stream,uid)) { sc = (SORTCACHE *) (*mc) (stream,i,CH_SORTCACHE); sc->size = (elt = mail_elt (stream,i))->rfc822_size; sc->date = sentdate; sc->arrival = elt->day ? mail_longdate (elt) : 1; if (refwd) sc->refwd = T; if (fromlen) { if (sc->from) fseek (srtcf,fromlen + 2,SEEK_CUR); else if ((getc (srtcf) != 'F') || (fread (sc->from = (char *) fs_get(fromlen), 1,fromlen-1,srtcf) != (fromlen-1))|| (sc->from[fromlen-1] = '\0') || (getc (srtcf) != '\015') || (getc (srtcf) != '\012')) { msg = "from data"; break; } } if (tolen) { if (sc->to) fseek (srtcf,tolen + 2,SEEK_CUR); else if ((getc (srtcf) != 'T') || (fread (sc->to = (char *) fs_get (tolen), 1,tolen-1,srtcf) != (tolen - 1)) || (sc->to[tolen-1] = '\0') || (getc (srtcf) != '\015') || (getc (srtcf) != '\012')) { msg = "to data"; break; } } if (cclen) { if (sc->cc) fseek (srtcf,cclen + 2,SEEK_CUR); else if ((getc (srtcf) != 'C') || (fread (sc->cc = (char *) fs_get (cclen), 1,cclen-1,srtcf) != (cclen - 1)) || (sc->cc[cclen-1] = '\0') || (getc (srtcf) != '\015') || (getc (srtcf) != '\012')) { msg = "cc data"; break; } } if (subjlen) { if (sc->subject) fseek (srtcf,subjlen + 2,SEEK_CUR); else if ((getc (srtcf) != 'S') || (fread (sc->subject = (char *) fs_get (subjlen),1, subjlen-1,srtcf) != (subjlen-1))|| (sc->subject[subjlen-1] = '\0') || (getc (srtcf) != '\015') || (getc (srtcf) != '\012')) { msg = "subject data"; break; } } if (msgidlen) { if (sc->message_id) fseek (srtcf,msgidlen + 2,SEEK_CUR); else if ((getc (srtcf) != 'M') || (fread (sc->message_id = (char *) fs_get (msgidlen),1, msgidlen-1,srtcf) != (msgidlen-1))|| (sc->message_id[msgidlen-1] = '\0') || (getc (srtcf) != '\015') || (getc (srtcf) != '\012')) { msg = "message-id data"; break; } } if (reflen) { if (sc->references) fseek(srtcf,reflen + 2,SEEK_CUR); /* make sure it fits */ else { if (reflen >= LOCAL->buflen) { fs_give ((void **) &LOCAL->buf); LOCAL->buf = (char *) fs_get ((LOCAL->buflen = reflen) + 1); } if ((getc (srtcf) != 'R') || (fread (LOCAL->buf,1,reflen-1,srtcf) != (reflen - 1)) || (LOCAL->buf[reflen-1] = '\0') || (getc (srtcf) != '\015') || (getc (srtcf) != '\012')) { msg = "references data"; break; } for (s = LOCAL->buf,sl = NIL, sc->references = mail_newstringlist (); s && *s; s += i + 1) { if ((i = strtoul (s,&s,16)) && (*s++ == ':') && (s[i] == ':')) { if (sl) sl = sl->next = mail_newstringlist(); else sl = sc->references; s[i] = '\0'; sl->text.data = cpystr (s); sl->text.size = i; } else s = NIL; } if (!s || *s || (s != ((char *) LOCAL->buf + reflen - 1))) { msg = "references length consistency check"; break; } } } } /* UID not found, ignore this message */ else fseek (srtcf,((fromlen ? fromlen + 2 : 0) + (tolen ? tolen + 2 : 0) + (cclen ? cclen + 2 : 0) + (subjlen ? subjlen + 2 : 0) + (msgidlen ? msgidlen + 2 : 0) + (reflen ? reflen + 2 : 0)), SEEK_CUR); continue; } else msg = "expansion"; } else msg = "references"; } else msg = "message-id"; } else msg = "subject"; } else msg = "cc"; } else msg = "to"; } else msg = "from"; } else msg = "sentdate"; break; /* error somewhere */ } if (!t || *t) { /* error detected? */ if (t) { /* non-null means bogus record */ sprintf (tmp,"Error in %s in mix sortcache record: %.500s",msg,t); MM_LOG (tmp,WARN); } fclose (srtcf); /* either way, must punt */ srtcf = NIL; } } if (rdonly && srtcf) { /* can't update if readonly */ unlink (LOCAL->sortcache); /* try deleting it */ fclose (srtcf); /* so close it and return as if error */ srtcf = NIL; } else fchmod (fd,sbuf.st_mode); return srtcf; } /* MIX update and close sortcache * Accepts: MAIL stream * pointer to open FILE (if FILE is NIL, do nothing) * Returns: T on success, NIL on error */ long mix_sortcache_update (MAILSTREAM *stream,FILE **sortcache) { FILE *f = *sortcache; long ret = LONGT; if (f) { /* ignore if no file */ unsigned long i,j; mailcache_t mc = (mailcache_t) mail_parameters (NIL,GET_CACHE,NIL); for (i = 1; (i <= stream->nmsgs) && !((SORTCACHE *) (*mc) (stream,i,CH_SORTCACHE))->dirty; ++i); if (i <= stream->nmsgs) { /* only update if some entry is dirty */ rewind (f); /* let's start at the very beginning */ /* write sequence */ fprintf (f,SEQFMT,LOCAL->sortcacheseq = mix_modseq(LOCAL->sortcacheseq)); for (i = 1; ret && (i <= stream->nmsgs); ++i) { MESSAGECACHE *elt = mail_elt (stream,i); SORTCACHE *s = (SORTCACHE *) (*mc) (stream,i,CH_SORTCACHE); STRINGLIST *sl; s->dirty = NIL; /* no longer dirty */ if (sl = s->references) /* count length of references */ for (j = 1; sl && sl->text.data; sl = sl->next) j += 10 + sl->text.size; else j = 0; /* no references yet */ fprintf (f,SCRFMT,elt->private.uid,s->date, s->from ? strlen (s->from) + 1 : 0, s->to ? strlen (s->to) + 1 : 0,s->cc ? strlen (s->cc) + 1 : 0, s->refwd ? 'R' : ' ',s->subject ? strlen (s->subject) + 1: 0, s->message_id ? strlen (s->message_id) + 1 : 0,j); if (s->from) fprintf (f,"F%s\015\012",s->from); if (s->to) fprintf (f,"T%s\015\012",s->to); if (s->cc) fprintf (f,"C%s\015\012",s->cc); if (s->subject) fprintf (f,"S%s\015\012",s->subject); if (s->message_id) fprintf (f,"M%s\015\012",s->message_id); if (j) { /* any references to write? */ fputc ('R',f); /* yes, do so */ for (sl = s->references; sl && sl->text.data; sl = sl->next) fprintf (f,"%08lx:%s:",sl->text.size,sl->text.data); fputs ("\015\012",f); } if (ferror (f)) { MM_LOG ("Error updating mix sortcache file",WARN); ret = NIL; } } if (ret && fflush (f)) { MM_LOG ("Error flushing mix sortcache file",WARN); ret = NIL; } if (ret) ftruncate (fileno (f),ftell (f)); } if (fclose (f)) { MM_LOG ("Error closing mix sortcache file",WARN); ret = NIL; } } return ret; } /* MIX generic file routines */ /* MIX read record * Accepts: open FILE * buffer * buffer length * record type * Returns: buffer if success, else NIL (zero-length buffer means EOF) */ char *mix_read_record (FILE *f,char *buf,unsigned long buflen,char *type) { char *s,tmp[MAILTMPLEN]; /* ensure string tied off */ buf[buflen-2] = buf[buflen-1] = '\0'; while (fgets (buf,buflen-1,f)) { if (s = strchr (buf,'\012')) { if ((s != buf) && (s[-1] == '\015')) --s; *s = '\0'; /* tie off buffer */ if (s != buf) return buf; /* return if non-empty buffer */ sprintf (tmp,"Empty mix %s record",type); MM_LOG (tmp,WARN); } else if (buf[buflen-2]) { /* overlong record is bad news */ sprintf (tmp,"Oversize mix %s record: %.512s",type,buf); MM_LOG (tmp,ERROR); return NIL; } else { sprintf (tmp,"Truncated mix %s record: %.512s",type,buf); MM_LOG (tmp,WARN); return buf; /* pass to caller anyway */ } } buf[0] = '\0'; /* return empty buffer on EOF */ return buf; } /* MIX read sequence record * Accepts: open FILE * Returns: sequence value, or NIL if failure */ unsigned long mix_read_sequence (FILE *f) { unsigned long ret; char *s,tmp[MAILTMPLEN]; if (!mix_read_record (f,tmp,MAILTMPLEN-1,"sequence")) return NIL; switch (tmp[0]) { /* examine record */ case '\0': /* end of file */ ret = 1; /* start a new sequence regime */ break; case 'S': /* sequence record */ if (isxdigit (tmp[1])) { /* must be followed by hex value */ ret = strtoul (tmp+1,&s,16); if (!*s) break; /* and nothing more */ } /* drop into default case */ default: /* anything else is an error */ return NIL; /* return error */ } return ret; } /* MIX internal routines */ /* MIX mail build directory name * Accepts: destination string * source * Returns: destination or empty string if error */ char *mix_dir (char *dst,char *name) { char *s; /* empty string if mailboxfile fails */ if (!mailboxfile (dst,name)) *dst = '\0'; /* driver-selected INBOX */ else if (!*dst) mailboxfile (dst,"~/INBOX"); /* tie off unnecessary trailing / */ else if ((s = strrchr (dst,'/')) && !s[1]) *s = '\0'; return dst; } /* MIX mail build file name * Accepts: destination string * directory name * file name * Returns: destination */ char *mix_file (char *dst,char *dir,char *name) { sprintf (dst,"%.500s/%.80s%.80s",dir,MIXNAME,name); return dst; } /* MIX mail build file name from data file number * Accepts: destination string * directory name * data file number * Returns: destination */ char *mix_file_data (char *dst,char *dir,unsigned long data) { char tmp[MAILTMPLEN]; if (data) sprintf (tmp,"%08lx",data); else tmp[0] = '\0'; /* compatibility with experimental version */ return mix_file (dst,dir,tmp); } /* MIX mail get new modseq * Accepts: old modseq * Returns: new modseq value */ unsigned long mix_modseq (unsigned long oldseq) { /* normally time now */ unsigned long ret = (unsigned long) time (NIL); /* ensure that modseq doesn't go backwards */ if (ret <= oldseq) ret = oldseq + 1; return ret; } alpine-2.10+dfsg/imap/src/osdep/amiga/gethstid.c0000600000175000017500000000171711512502124023226 0ustar paulproteuspaulproteus/* ======================================================================== * Copyright 1988-2006 University of Washington * * Licensed under the Apache License, Version 2.0 (the "License"); * you may not use this file except in compliance with the License. * You may obtain a copy of the License at * * http://www.apache.org/licenses/LICENSE-2.0 * * * ======================================================================== */ /* * Program: Get host ID emulator * * Author: Mark Crispin * Networks and Distributed Computing * Computing & Communications * University of Washington * Administration Building, AG-44 * Seattle, WA 98195 * Internet: MRC@CAC.Washington.EDU * * Date: 3 May 1995 * Last Edited: 30 August 2006 */ /* Emulator for BSD gethostid() call * Returns: unique identifier for this machine */ long gethostid (void) { /* No gethostid() here, so just fake it and hope things turn out okay. */ return 0xdeadface; } alpine-2.10+dfsg/imap/src/osdep/amiga/mx.c0000600000175000017500000011607011512502124022036 0ustar paulproteuspaulproteus/* ======================================================================== * Copyright 1988-2008 University of Washington * * Licensed under the Apache License, Version 2.0 (the "License"); * you may not use this file except in compliance with the License. * You may obtain a copy of the License at * * http://www.apache.org/licenses/LICENSE-2.0 * * * ======================================================================== */ /* * Program: MX mail routines * * Author(s): Mark Crispin * Networks and Distributed Computing * Computing & Communications * University of Washington * Administration Building, AG-44 * Seattle, WA 98195 * Internet: MRC@CAC.Washington.EDU * * Date: 3 May 1996 * Last Edited: 6 January 2008 */ #include #include #include extern int errno; /* just in case */ #include "mail.h" #include "osdep.h" #include #include #include #include "misc.h" #include "dummy.h" #include "fdstring.h" /* Index file */ #define MXINDEXNAME "/.mxindex" #define MXINDEX(d,s) strcat (mx_file (d,s),MXINDEXNAME) /* MX I/O stream local data */ typedef struct mx_local { int fd; /* file descriptor of open index */ unsigned char *buf; /* temporary buffer */ unsigned long buflen; /* current size of temporary buffer */ unsigned long cachedtexts; /* total size of all cached texts */ time_t scantime; /* last time directory scanned */ } MXLOCAL; /* Convenient access to local data */ #define LOCAL ((MXLOCAL *) stream->local) /* Function prototypes */ DRIVER *mx_valid (char *name); int mx_isvalid (char *name,char *tmp); int mx_namevalid (char *name); void *mx_parameters (long function,void *value); long mx_dirfmttest (char *name); void mx_scan (MAILSTREAM *stream,char *ref,char *pat,char *contents); long mx_scan_contents (char *name,char *contents,unsigned long csiz, unsigned long fsiz); void mx_list (MAILSTREAM *stream,char *ref,char *pat); void mx_lsub (MAILSTREAM *stream,char *ref,char *pat); long mx_subscribe (MAILSTREAM *stream,char *mailbox); long mx_unsubscribe (MAILSTREAM *stream,char *mailbox); long mx_create (MAILSTREAM *stream,char *mailbox); long mx_delete (MAILSTREAM *stream,char *mailbox); long mx_rename (MAILSTREAM *stream,char *old,char *newname); int mx_rename_work (char *src,size_t srcl,char *dst,size_t dstl,char *name); MAILSTREAM *mx_open (MAILSTREAM *stream); void mx_close (MAILSTREAM *stream,long options); void mx_fast (MAILSTREAM *stream,char *sequence,long flags); char *mx_fast_work (MAILSTREAM *stream,MESSAGECACHE *elt); char *mx_header (MAILSTREAM *stream,unsigned long msgno,unsigned long *length, long flags); long mx_text (MAILSTREAM *stream,unsigned long msgno,STRING *bs,long flags); void mx_flag (MAILSTREAM *stream,char *sequence,char *flag,long flags); void mx_flagmsg (MAILSTREAM *stream,MESSAGECACHE *elt); long mx_ping (MAILSTREAM *stream); void mx_check (MAILSTREAM *stream); long mx_expunge (MAILSTREAM *stream,char *sequence,long options); long mx_copy (MAILSTREAM *stream,char *sequence,char *mailbox, long options); long mx_append (MAILSTREAM *stream,char *mailbox,append_t af,void *data); long mx_append_msg (MAILSTREAM *stream,char *flags,MESSAGECACHE *elt, STRING *st,SEARCHSET *set); int mx_select (struct direct *name); int mx_numsort (const void *d1,const void *d2); char *mx_file (char *dst,char *name); long mx_lockindex (MAILSTREAM *stream); void mx_unlockindex (MAILSTREAM *stream); void mx_setdate (char *file,MESSAGECACHE *elt); /* MX mail routines */ /* Driver dispatch used by MAIL */ DRIVER mxdriver = { "mx", /* driver name */ /* driver flags */ DR_MAIL|DR_LOCAL|DR_NOFAST|DR_CRLF|DR_LOCKING|DR_DIRFMT, (DRIVER *) NIL, /* next driver */ mx_valid, /* mailbox is valid for us */ mx_parameters, /* manipulate parameters */ mx_scan, /* scan mailboxes */ mx_list, /* find mailboxes */ mx_lsub, /* find subscribed mailboxes */ mx_subscribe, /* subscribe to mailbox */ mx_unsubscribe, /* unsubscribe from mailbox */ mx_create, /* create mailbox */ mx_delete, /* delete mailbox */ mx_rename, /* rename mailbox */ mail_status_default, /* status of mailbox */ mx_open, /* open mailbox */ mx_close, /* close mailbox */ mx_fast, /* fetch message "fast" attributes */ NIL, /* fetch message flags */ NIL, /* fetch overview */ NIL, /* fetch message envelopes */ mx_header, /* fetch message header only */ mx_text, /* fetch message body only */ NIL, /* fetch partial message test */ NIL, /* unique identifier */ NIL, /* message number */ mx_flag, /* modify flags */ mx_flagmsg, /* per-message modify flags */ NIL, /* search for message based on criteria */ NIL, /* sort messages */ NIL, /* thread messages */ mx_ping, /* ping mailbox to see if still alive */ mx_check, /* check for new messages */ mx_expunge, /* expunge deleted messages */ mx_copy, /* copy messages to another mailbox */ mx_append, /* append string message to mailbox */ NIL /* garbage collect stream */ }; /* prototype stream */ MAILSTREAM mxproto = {&mxdriver}; /* MX mail validate mailbox * Accepts: mailbox name * Returns: our driver if name is valid, NIL otherwise */ DRIVER *mx_valid (char *name) { char tmp[MAILTMPLEN]; return mx_isvalid (name,tmp) ? &mxdriver : NIL; } /* MX mail test for valid mailbox * Accepts: mailbox name * temporary buffer to use * Returns: T if valid, NIL otherwise with errno holding dir stat error */ int mx_isvalid (char *name,char *tmp) { struct stat sbuf; errno = NIL; /* zap error */ if ((strlen (name) <= NETMAXMBX) && *mx_file (tmp,name) && !stat (tmp,&sbuf) && ((sbuf.st_mode & S_IFMT) == S_IFDIR)) { /* name is directory; is it mx? */ if (!stat (MXINDEX (tmp,name),&sbuf) && ((sbuf.st_mode & S_IFMT) == S_IFREG)) return T; errno = NIL; /* directory but not mx */ } else if (!compare_cstring (name,"INBOX")) errno = NIL; return NIL; } /* MX mail test for valid mailbox * Accepts: mailbox name * Returns: T if valid, NIL otherwise */ int mx_namevalid (char *name) { char *s = (*name == '/') ? name + 1 : name; while (s && *s) { /* make sure valid name */ if (isdigit (*s)) s++; /* digit, check this node further... */ else if (*s == '/') break; /* all digit node, barf */ /* non-digit, skip to next node or return */ else if (!((s = strchr (s+1,'/')) && *++s)) return T; } return NIL; /* all numeric or empty node */ } /* MX manipulate driver parameters * Accepts: function code * function-dependent value * Returns: function-dependent return value */ void *mx_parameters (long function,void *value) { void *ret = NIL; switch ((int) function) { case GET_INBOXPATH: if (value) ret = mailboxfile ((char *) value,"~/INBOX"); break; case GET_DIRFMTTEST: ret = (void *) mx_dirfmttest; break; case GET_SCANCONTENTS: ret = (void *) mx_scan_contents; break; } return ret; } /* MX test for directory format internal node * Accepts: candidate node name * Returns: T if internal name, NIL otherwise */ long mx_dirfmttest (char *name) { int c; /* success if index name or all-numberic */ if (strcmp (name,MXINDEXNAME+1)) while (c = *name++) if (!isdigit (c)) return NIL; return LONGT; } /* MX scan mailboxes * Accepts: mail stream * reference * pattern to search * string to scan */ void mx_scan (MAILSTREAM *stream,char *ref,char *pat,char *contents) { if (stream) dummy_scan (NIL,ref,pat,contents); } /* MX scan mailbox for contents * Accepts: mailbox name * desired contents * contents size * file size (ignored) * Returns: NIL if contents not found, T if found */ long mx_scan_contents (char *name,char *contents,unsigned long csiz, unsigned long fsiz) { long i,nfiles; void *a; char *s; long ret = NIL; size_t namelen = strlen (name); struct stat sbuf; struct direct **names = NIL; if ((nfiles = scandir (name,&names,mx_select,mx_numsort)) > 0) for (i = 0; i < nfiles; ++i) { if (!ret) { sprintf (s = (char *) fs_get (namelen + strlen (names[i]->d_name) + 2), "%s/%s",name,names[i]->d_name); if (!stat (s,&sbuf) && (csiz <= sbuf.st_size)) ret = dummy_scan_contents (s,contents,csiz,sbuf.st_size); fs_give ((void **) &s); } fs_give ((void **) &names[i]); } /* free directory list */ if (a = (void *) names) fs_give ((void **) &a); return ret; } /* MX list mailboxes * Accepts: mail stream * reference * pattern to search */ void mx_list (MAILSTREAM *stream,char *ref,char *pat) { if (stream) dummy_list (NIL,ref,pat); } /* MX list subscribed mailboxes * Accepts: mail stream * reference * pattern to search */ void mx_lsub (MAILSTREAM *stream,char *ref,char *pat) { if (stream) dummy_lsub (NIL,ref,pat); } /* MX mail subscribe to mailbox * Accepts: mail stream * mailbox to add to subscription list * Returns: T on success, NIL on failure */ long mx_subscribe (MAILSTREAM *stream,char *mailbox) { return sm_subscribe (mailbox); } /* MX mail unsubscribe to mailbox * Accepts: mail stream * mailbox to delete from subscription list * Returns: T on success, NIL on failure */ long mx_unsubscribe (MAILSTREAM *stream,char *mailbox) { return sm_unsubscribe (mailbox); } /* MX mail create mailbox * Accepts: mail stream * mailbox name to create * Returns: T on success, NIL on failure */ long mx_create (MAILSTREAM *stream,char *mailbox) { DRIVER *test; int fd; char *s,tmp[MAILTMPLEN]; int mask = umask (0); long ret = NIL; if (!mx_namevalid (mailbox)) /* validate name */ sprintf (tmp,"Can't create mailbox %.80s: invalid MX-format name",mailbox); /* must not already exist */ else if ((test = mail_valid (NIL,mailbox,NIL)) && strcmp (test->name,"dummy")) sprintf (tmp,"Can't create mailbox %.80s: mailbox already exists",mailbox); /* create directory */ else if (!dummy_create_path (stream,MXINDEX (tmp,mailbox), get_dir_protection (mailbox))) sprintf (tmp,"Can't create mailbox %.80s: %s",mailbox,strerror (errno)); else { /* success */ /* set index protection */ set_mbx_protections (mailbox,tmp); /* tie off directory name */ *(s = strrchr (tmp,'/') + 1) = '\0'; /* set directory protection */ set_mbx_protections (mailbox,tmp); ret = LONGT; } umask (mask); /* restore mask */ if (!ret) MM_LOG (tmp,ERROR); /* some error */ return ret; } /* MX mail delete mailbox * mailbox name to delete * Returns: T on success, NIL on failure */ long mx_delete (MAILSTREAM *stream,char *mailbox) { DIR *dirp; struct direct *d; char *s; char tmp[MAILTMPLEN]; if (!mx_isvalid (mailbox,tmp)) sprintf (tmp,"Can't delete mailbox %.80s: no such mailbox",mailbox); /* delete index */ else if (unlink (MXINDEX (tmp,mailbox))) sprintf (tmp,"Can't delete mailbox %.80s index: %s", mailbox,strerror (errno)); else { /* get directory name */ *(s = strrchr (tmp,'/')) = '\0'; if (dirp = opendir (tmp)) { /* open directory */ *s++ = '/'; /* restore delimiter */ /* massacre messages */ while (d = readdir (dirp)) if (mx_select (d)) { strcpy (s,d->d_name); /* make path */ unlink (tmp); /* sayonara */ } closedir (dirp); /* flush directory */ *(s = strrchr (tmp,'/')) = '\0'; if (rmdir (tmp)) { /* try to remove the directory */ sprintf (tmp,"Can't delete name %.80s: %s",mailbox,strerror (errno)); MM_LOG (tmp,WARN); } } return T; /* always success */ } MM_LOG (tmp,ERROR); /* something failed */ return NIL; } /* MX mail rename mailbox * Accepts: MX mail stream * old mailbox name * new mailbox name * Returns: T on success, NIL on failure */ long mx_rename (MAILSTREAM *stream,char *old,char *newname) { char c,*s,tmp[MAILTMPLEN],tmp1[MAILTMPLEN]; struct stat sbuf; if (!mx_isvalid (old,tmp)) sprintf (tmp,"Can't rename mailbox %.80s: no such mailbox",old); else if (!mx_namevalid (newname)) sprintf (tmp,"Can't rename to mailbox %.80s: invalid MX-format name", newname); /* new mailbox name must not be valid */ else if (mx_isvalid (newname,tmp)) sprintf (tmp,"Can't rename to mailbox %.80s: destination already exists", newname); else { mx_file (tmp,old); /* build old directory name */ mx_file (tmp1,newname); /* and new directory name */ /* easy if not INBOX */ if (compare_cstring (old,"INBOX")) { /* found superior to destination name? */ if (s = strrchr (mx_file (tmp1,newname),'/')) { c = *++s; /* remember first character of inferior */ *s = '\0'; /* tie off to get just superior */ /* name doesn't exist, create it */ if ((stat (tmp1,&sbuf) || ((sbuf.st_mode & S_IFMT) != S_IFDIR)) && !dummy_create_path (stream,tmp1,get_dir_protection (newname))) return NIL; *s = c; /* restore full name */ } if (!rename (tmp,tmp1)) return LONGT; } /* RFC 3501 requires this */ else if (dummy_create_path (stream,strcat (tmp1,"/"), get_dir_protection (newname))) { void *a; int i,n,lasterror; struct direct **names = NIL; size_t srcl = strlen (tmp); size_t dstl = strlen (tmp1); /* rename each mx file to new directory */ for (i = lasterror = 0,n = scandir (tmp,&names,mx_select,mx_numsort); i < n; ++i) { if (mx_rename_work (tmp,srcl,tmp1,dstl,names[i]->d_name)) lasterror = errno; fs_give ((void **) &names[i]); } /* free directory list */ if (a = (void *) names) fs_give ((void **) &a); if (lasterror || mx_rename_work (tmp,srcl,tmp1,dstl,MXINDEXNAME+1)) errno = lasterror; else return mx_create (NIL,"INBOX"); } sprintf (tmp,"Can't rename mailbox %.80s to %.80s: %s", old,newname,strerror (errno)); } MM_LOG (tmp,ERROR); /* something failed */ return NIL; } /* MX rename worker routine * Accepts: source directory name * source directory name length * destination directory name * destination directory name length * name of node to move * Returns: zero if success, non-zero if error */ int mx_rename_work (char *src,size_t srcl,char *dst,size_t dstl,char *name) { int ret; size_t len = strlen (name); char *s = (char *) fs_get (srcl + len + 2); char *d = (char *) fs_get (dstl + len + 1); sprintf (s,"%s/%s",src,name); sprintf (d,"%s%s",dst,name); ret = rename (s,d); fs_give ((void **) &s); fs_give ((void **) &d); return ret; } /* MX mail open * Accepts: stream to open * Returns: stream on success, NIL on failure */ MAILSTREAM *mx_open (MAILSTREAM *stream) { char tmp[MAILTMPLEN]; /* return prototype for OP_PROTOTYPE call */ if (!stream) return user_flags (&mxproto); if (stream->local) fatal ("mx recycle stream"); stream->local = fs_get (sizeof (MXLOCAL)); /* note if an INBOX or not */ stream->inbox = !compare_cstring (stream->mailbox,"INBOX"); mx_file (tmp,stream->mailbox);/* get directory name */ /* canonicalize mailbox name */ fs_give ((void **) &stream->mailbox); stream->mailbox = cpystr (tmp); /* make temporary buffer */ LOCAL->buf = (char *) fs_get (CHUNKSIZE); LOCAL->buflen = CHUNKSIZE - 1; LOCAL->scantime = 0; /* not scanned yet */ LOCAL->fd = -1; /* no index yet */ LOCAL->cachedtexts = 0; /* no cached texts */ stream->sequence++; /* bump sequence number */ /* parse mailbox */ stream->nmsgs = stream->recent = 0; if (mx_ping (stream) && !(stream->nmsgs || stream->silent)) MM_LOG ("Mailbox is empty",(long) NIL); stream->perm_seen = stream->perm_deleted = stream->perm_flagged = stream->perm_answered = stream->perm_draft = stream->rdonly ? NIL : T; stream->perm_user_flags = stream->rdonly ? NIL : 0xffffffff; stream->kwd_create = (stream->user_flags[NUSERFLAGS-1] || stream->rdonly) ? NIL : T; /* can we create new user flags? */ return stream; /* return stream to caller */ } /* MX mail close * Accepts: MAIL stream * close options */ void mx_close (MAILSTREAM *stream,long options) { if (LOCAL) { /* only if a file is open */ int silent = stream->silent; stream->silent = T; /* note this stream is dying */ if (options & CL_EXPUNGE) mx_expunge (stream,NIL,NIL); /* free local scratch buffer */ if (LOCAL->buf) fs_give ((void **) &LOCAL->buf); /* nuke the local data */ fs_give ((void **) &stream->local); stream->dtb = NIL; /* log out the DTB */ stream->silent = silent; /* reset silent state */ } } /* MX mail fetch fast information * Accepts: MAIL stream * sequence * option flags */ void mx_fast (MAILSTREAM *stream,char *sequence,long flags) { unsigned long i; MESSAGECACHE *elt; if (stream && LOCAL && ((flags & FT_UID) ? mail_uid_sequence (stream,sequence) : mail_sequence (stream,sequence))) for (i = 1; i <= stream->nmsgs; i++) if ((elt = mail_elt (stream,i))->sequence) mx_fast_work (stream,elt); } /* MX mail fetch fast information * Accepts: MAIL stream * message cache element * Returns: name of message file */ char *mx_fast_work (MAILSTREAM *stream,MESSAGECACHE *elt) { struct stat sbuf; struct tm *tm; /* build message file name */ sprintf (LOCAL->buf,"%s/%lu",stream->mailbox,elt->private.uid); /* have size yet? */ if (!elt->rfc822_size && !stat (LOCAL->buf,&sbuf)) { /* make plausible IMAPish date string */ tm = gmtime (&sbuf.st_mtime); elt->day = tm->tm_mday; elt->month = tm->tm_mon + 1; elt->year = tm->tm_year + 1900 - BASEYEAR; elt->hours = tm->tm_hour; elt->minutes = tm->tm_min; elt->seconds = tm->tm_sec; elt->zhours = 0; elt->zminutes = 0; elt->zoccident = 0; elt->rfc822_size = sbuf.st_size; } return (char *) LOCAL->buf; /* return file name */ } /* MX mail fetch message header * Accepts: MAIL stream * message # to fetch * pointer to returned header text length * option flags * Returns: message header in RFC822 format */ char *mx_header (MAILSTREAM *stream,unsigned long msgno,unsigned long *length, long flags) { unsigned long i; int fd; MESSAGECACHE *elt; *length = 0; /* default to empty */ if (flags & FT_UID) return "";/* UID call "impossible" */ elt = mail_elt (stream,msgno);/* get elt */ if (!elt->private.msg.header.text.data) { /* purge cache if too big */ if (LOCAL->cachedtexts > max (stream->nmsgs * 4096,2097152)) { mail_gc (stream,GC_TEXTS);/* just can't keep that much */ LOCAL->cachedtexts = 0; } if ((fd = open (mx_fast_work (stream,elt),O_RDONLY,NIL)) < 0) return ""; /* is buffer big enough? */ if (elt->rfc822_size > LOCAL->buflen) { fs_give ((void **) &LOCAL->buf); LOCAL->buf = (char *) fs_get ((LOCAL->buflen = elt->rfc822_size) + 1); } /* slurp message */ read (fd,LOCAL->buf,elt->rfc822_size); /* tie off file */ LOCAL->buf[elt->rfc822_size] = '\0'; close (fd); /* flush message file */ /* find end of header */ if (elt->rfc822_size < 4) i = 0; else for (i = 4; (i < elt->rfc822_size) && !((LOCAL->buf[i - 4] == '\015') && (LOCAL->buf[i - 3] == '\012') && (LOCAL->buf[i - 2] == '\015') && (LOCAL->buf[i - 1] == '\012')); i++); /* copy header */ cpytxt (&elt->private.msg.header.text,LOCAL->buf,i); cpytxt (&elt->private.msg.text.text,LOCAL->buf+i,elt->rfc822_size - i); /* add to cached size */ LOCAL->cachedtexts += elt->rfc822_size; } *length = elt->private.msg.header.text.size; return (char *) elt->private.msg.header.text.data; } /* MX mail fetch message text (body only) * Accepts: MAIL stream * message # to fetch * pointer to returned stringstruct * option flags * Returns: T on success, NIL on failure */ long mx_text (MAILSTREAM *stream,unsigned long msgno,STRING *bs,long flags) { unsigned long i; MESSAGECACHE *elt; /* UID call "impossible" */ if (flags & FT_UID) return NIL; elt = mail_elt (stream,msgno); /* snarf message if don't have it yet */ if (!elt->private.msg.text.text.data) { mx_header (stream,msgno,&i,flags); if (!elt->private.msg.text.text.data) return NIL; } /* mark as seen */ if (!(flags & FT_PEEK) && mx_lockindex (stream)) { elt->seen = T; mx_unlockindex (stream); MM_FLAGS (stream,msgno); } INIT (bs,mail_string,elt->private.msg.text.text.data, elt->private.msg.text.text.size); return T; } /* MX mail modify flags * Accepts: MAIL stream * sequence * flag(s) * option flags */ void mx_flag (MAILSTREAM *stream,char *sequence,char *flag,long flags) { mx_unlockindex (stream); /* finished with index */ } /* MX per-message modify flags * Accepts: MAIL stream * message cache element */ void mx_flagmsg (MAILSTREAM *stream,MESSAGECACHE *elt) { mx_lockindex (stream); /* lock index if not already locked */ } /* MX mail ping mailbox * Accepts: MAIL stream * Returns: T if stream alive, else NIL */ long mx_ping (MAILSTREAM *stream) { MAILSTREAM *sysibx = NIL; MESSAGECACHE *elt,*selt; struct stat sbuf; char *s,tmp[MAILTMPLEN]; int fd; unsigned long i,j,r,old; long nmsgs = stream->nmsgs; long recent = stream->recent; int silent = stream->silent; if (stat (stream->mailbox,&sbuf)) return NIL; stream->silent = T; /* don't pass up exists events yet */ if (sbuf.st_ctime != LOCAL->scantime) { struct direct **names = NIL; long nfiles = scandir (stream->mailbox,&names,mx_select,mx_numsort); if (nfiles < 0) nfiles = 0; /* in case error */ old = stream->uid_last; /* note scanned now */ LOCAL->scantime = sbuf.st_ctime; /* scan directory */ for (i = 0; i < nfiles; ++i) { /* if newly seen, add to list */ if ((j = atoi (names[i]->d_name)) > old) { /* swell the cache */ mail_exists (stream,++nmsgs); stream->uid_last = (elt = mail_elt (stream,nmsgs))->private.uid = j; elt->valid = T; /* note valid flags */ if (old) { /* other than the first pass? */ elt->recent = T; /* yup, mark as recent */ recent++; /* bump recent count */ } } fs_give ((void **) &names[i]); } /* free directory */ if (s = (void *) names) fs_give ((void **) &s); } stream->nmsgs = nmsgs; /* don't upset mail_uid() */ /* if INBOX, snarf from system INBOX */ if (mx_lockindex (stream) && stream->inbox && !strcmp (sysinbox (),stream->mailbox)) { old = stream->uid_last; MM_CRITICAL (stream); /* go critical */ /* see if anything in system inbox */ if (!stat (sysinbox (),&sbuf) && sbuf.st_size && (sysibx = mail_open (sysibx,sysinbox (),OP_SILENT)) && !sysibx->rdonly && (r = sysibx->nmsgs)) { for (i = 1; i <= r; ++i) {/* for each message in sysinbox mailbox */ /* build file name we will use */ sprintf (LOCAL->buf,"%s/%lu",stream->mailbox,++old); /* snarf message from Berkeley mailbox */ selt = mail_elt (sysibx,i); if (((fd = open (LOCAL->buf,O_WRONLY|O_CREAT|O_EXCL, (long) mail_parameters (NIL,GET_MBXPROTECTION,NIL))) >= 0) && (s = mail_fetchheader_full (sysibx,i,NIL,&j,FT_PEEK)) && (write (fd,s,j) == j) && (s = mail_fetchtext_full (sysibx,i,&j,FT_PEEK)) && (write (fd,s,j) == j) && !fsync (fd) && !close (fd)) { /* swell the cache */ mail_exists (stream,++nmsgs); stream->uid_last = /* create new elt, note its file number */ (elt = mail_elt (stream,nmsgs))->private.uid = old; recent++; /* bump recent count */ /* set up initial flags and date */ elt->valid = elt->recent = T; elt->seen = selt->seen; elt->deleted = selt->deleted; elt->flagged = selt->flagged; elt->answered = selt->answered; elt->draft = selt->draft; elt->day = selt->day;elt->month = selt->month;elt->year = selt->year; elt->hours = selt->hours;elt->minutes = selt->minutes; elt->seconds = selt->seconds; elt->zhours = selt->zhours; elt->zminutes = selt->zminutes; elt->zoccident = selt->zoccident; mx_setdate (LOCAL->buf,elt); sprintf (tmp,"%lu",i);/* delete it from the sysinbox */ mail_flag (sysibx,tmp,"\\Deleted",ST_SET); } else { /* failed to snarf */ if (fd) { /* did it ever get opened? */ close (fd); /* close descriptor */ unlink (LOCAL->buf);/* flush this file */ } sprintf (tmp,"Message copy to MX mailbox failed: %.80s", s,strerror (errno)); MM_LOG (tmp,ERROR); r = 0; /* stop the snarf in its tracks */ } } /* update scan time */ if (!stat (stream->mailbox,&sbuf)) LOCAL->scantime = sbuf.st_ctime; mail_expunge (sysibx); /* now expunge all those messages */ } if (sysibx) mail_close (sysibx); MM_NOCRITICAL (stream); /* release critical */ } mx_unlockindex (stream); /* done with index */ stream->silent = silent; /* can pass up events now */ mail_exists (stream,nmsgs); /* notify upper level of mailbox size */ mail_recent (stream,recent); return T; /* return that we are alive */ } /* MX mail check mailbox * Accepts: MAIL stream */ void mx_check (MAILSTREAM *stream) { if (mx_ping (stream)) MM_LOG ("Check completed",(long) NIL); } /* MX mail expunge mailbox * Accepts: MAIL stream * sequence to expunge if non-NIL * expunge options * Returns: T, always */ long mx_expunge (MAILSTREAM *stream,char *sequence,long options) { long ret; MESSAGECACHE *elt; unsigned long i = 1; unsigned long n = 0; unsigned long recent = stream->recent; if (ret = (sequence ? ((options & EX_UID) ? mail_uid_sequence (stream,sequence) : mail_sequence (stream,sequence)) : LONGT) && mx_lockindex (stream)) { /* lock the index */ MM_CRITICAL (stream); /* go critical */ while (i <= stream->nmsgs) {/* for each message */ elt = mail_elt (stream,i);/* if deleted, need to trash it */ if (elt->deleted && (sequence ? elt->sequence : T)) { sprintf (LOCAL->buf,"%s/%lu",stream->mailbox,elt->private.uid); if (unlink (LOCAL->buf)) {/* try to delete the message */ sprintf (LOCAL->buf,"Expunge of message %lu failed, aborted: %s",i, strerror (errno)); MM_LOG (LOCAL->buf,(long) NIL); break; } /* note uncached */ LOCAL->cachedtexts -= ((elt->private.msg.header.text.data ? elt->private.msg.header.text.size : 0) + (elt->private.msg.text.text.data ? elt->private.msg.text.text.size : 0)); mail_gc_msg (&elt->private.msg,GC_ENV | GC_TEXTS); if(elt->recent)--recent;/* if recent, note one less recent message */ mail_expunged(stream,i);/* notify upper levels */ n++; /* count up one more expunged message */ } else i++; /* otherwise try next message */ } if (n) { /* output the news if any expunged */ sprintf (LOCAL->buf,"Expunged %lu messages",n); MM_LOG (LOCAL->buf,(long) NIL); } else MM_LOG ("No messages deleted, so no update needed",(long) NIL); MM_NOCRITICAL (stream); /* release critical */ mx_unlockindex (stream); /* finished with index */ /* notify upper level of new mailbox size */ mail_exists (stream,stream->nmsgs); mail_recent (stream,recent); } return ret; } /* MX mail copy message(s) * Accepts: MAIL stream * sequence * destination mailbox * copy options * Returns: T if copy successful, else NIL */ long mx_copy (MAILSTREAM *stream,char *sequence,char *mailbox,long options) { FDDATA d; STRING st; MESSAGECACHE *elt; MAILSTREAM *astream; struct stat sbuf; int fd; unsigned long i,j,uid,uidv; char *t,tmp[MAILTMPLEN]; long ret; mailproxycopy_t pc = (mailproxycopy_t) mail_parameters (stream,GET_MAILPROXYCOPY,NIL); /* make sure valid mailbox */ if (!mx_valid (mailbox)) switch (errno) { case NIL: /* no error in stat() */ if (pc) return (*pc) (stream,sequence,mailbox,options); sprintf (LOCAL->buf,"Not a MX-format mailbox: %.80s",mailbox); MM_LOG (LOCAL->buf,ERROR); return NIL; default: /* some stat() error */ MM_NOTIFY (stream,"[TRYCREATE] Must create mailbox before copy",NIL); return NIL; } /* copy the messages */ if (!(ret = ((options & CP_UID) ? mail_uid_sequence (stream,sequence) : mail_sequence (stream,sequence)))); /* acquire stream to append to */ else if (!(astream = mail_open (NIL,mailbox,OP_SILENT))) { MM_LOG ("Can't open copy mailbox",ERROR); ret = NIL; } else { MM_CRITICAL (stream); /* go critical */ if (!(ret = mx_lockindex (astream))) MM_LOG ("Message copy failed: unable to lock index",ERROR); else { copyuid_t cu = (copyuid_t) mail_parameters (NIL,GET_COPYUID,NIL); SEARCHSET *source = cu ? mail_newsearchset () : NIL; SEARCHSET *dest = cu ? mail_newsearchset () : NIL; for (i = 1,uid = uidv = 0; ret && (i <= stream->nmsgs); i++) if ((elt = mail_elt (stream,i))->sequence) { if (ret = ((fd = open (mx_fast_work (stream,elt),O_RDONLY,NIL)) >= 0)) { fstat (fd,&sbuf); /* get size of message */ d.fd = fd; /* set up file descriptor */ d.pos = 0; /* start of file */ d.chunk = LOCAL->buf; d.chunksize = CHUNKSIZE; INIT (&st,fd_string,&d,sbuf.st_size); /* init flag string */ tmp[0] = tmp[1] = '\0'; if (j = elt->user_flags) do if (t = stream->user_flags[find_rightmost_bit (&j)]) strcat (strcat (tmp," "),t); while (j); if (elt->seen) strcat (tmp," \\Seen"); if (elt->deleted) strcat (tmp," \\Deleted"); if (elt->flagged) strcat (tmp," \\Flagged"); if (elt->answered) strcat (tmp," \\Answered"); if (elt->draft) strcat (tmp," \\Draft"); tmp[0] = '('; /* open list */ strcat (tmp,")"); /* close list */ if (ret = mx_append_msg (astream,tmp,elt,&st,dest)) { /* add to source set if needed */ if (source) mail_append_set (source,mail_uid (stream,i)); /* delete if doing a move */ if (options & CP_MOVE) elt->deleted = T; } } } /* return sets if doing COPYUID */ if (cu && ret) (*cu) (stream,mailbox,astream->uid_validity,source,dest); else { /* flush any sets we may have built */ mail_free_searchset (&source); mail_free_searchset (&dest); } mx_unlockindex (astream); /* unlock index */ } MM_NOCRITICAL (stream); mail_close (astream); /* finished with append stream */ } return ret; /* return success */ } /* MX mail append message from stringstruct * Accepts: MAIL stream * destination mailbox * append callback * data for callback * Returns: T if append successful, else NIL */ long mx_append (MAILSTREAM *stream,char *mailbox,append_t af,void *data) { MESSAGECACHE elt; MAILSTREAM *astream; char *flags,*date,tmp[MAILTMPLEN]; STRING *message; long ret = LONGT; /* default stream to prototype */ if (!stream) stream = user_flags (&mxproto); /* N.B.: can't use LOCAL->buf for tmp */ /* make sure valid mailbox */ if (!mx_isvalid (mailbox,tmp)) switch (errno) { case ENOENT: /* no such file? */ if (!compare_cstring (mailbox,"INBOX")) mx_create (NIL,"INBOX"); else { MM_NOTIFY (stream,"[TRYCREATE] Must create mailbox before append",NIL); return NIL; } /* falls through */ case 0: /* merely empty file? */ break; case EINVAL: sprintf (tmp,"Invalid MX-format mailbox name: %.80s",mailbox); MM_LOG (tmp,ERROR); return NIL; default: sprintf (tmp,"Not a MX-format mailbox: %.80s",mailbox); MM_LOG (tmp,ERROR); return NIL; } /* get first message */ if (!MM_APPEND (af) (stream,data,&flags,&date,&message)) return NIL; if (!(astream = mail_open (NIL,mailbox,OP_SILENT))) { MM_LOG ("Can't open append mailbox",ERROR); return NIL; } MM_CRITICAL (astream); /* go critical */ /* lock the index */ if (!(ret = mx_lockindex (astream))) MM_LOG ("Message append failed: unable to lock index",ERROR); else { appenduid_t au = (appenduid_t) mail_parameters (NIL,GET_APPENDUID,NIL); SEARCHSET *dst = au ? mail_newsearchset () : NIL; do { /* guard against zero-length */ if (!(ret = SIZE (message))) MM_LOG ("Append of zero-length message",ERROR); else if (date && !(ret = mail_parse_date (&elt,date))) { sprintf (tmp,"Bad date in append: %.80s",date); MM_LOG (tmp,ERROR); } else ret = mx_append_msg (astream,flags,date ? &elt : NIL,message,dst)&& MM_APPEND (af) (stream,data,&flags,&date,&message); } while (ret && message); /* return sets if doing APPENDUID */ if (au && ret) (*au) (mailbox,astream->uid_validity,dst); else mail_free_searchset (&dst); mx_unlockindex (astream); /* unlock index */ } MM_NOCRITICAL (astream); /* release critical */ mail_close (astream); return ret; } /* MX mail append single message * Accepts: MAIL stream * flags for new message if non-NIL * elt with source date if non-NIL * stringstruct of message text * searchset to place UID * Returns: T if success, NIL if failure */ long mx_append_msg (MAILSTREAM *stream,char *flags,MESSAGECACHE *elt, STRING *st,SEARCHSET *set) { char tmp[MAILTMPLEN]; int fd; unsigned long uf; long f = mail_parse_flags (stream,flags,&uf); /* make message file name */ sprintf (tmp,"%s/%lu",stream->mailbox,++stream->uid_last); if ((fd = open (tmp,O_WRONLY|O_CREAT|O_EXCL, (long) mail_parameters (NIL,GET_MBXPROTECTION,NIL))) < 0) { sprintf (tmp,"Can't create append message: %s",strerror (errno)); MM_LOG (tmp,ERROR); return NIL; } while (SIZE (st)) { /* copy the file */ if (st->cursize && (write (fd,st->curpos,st->cursize) < 0)) { unlink (tmp); /* delete file */ close (fd); /* close the file */ sprintf (tmp,"Message append failed: %s",strerror (errno)); MM_LOG (tmp,ERROR); return NIL; } SETPOS (st,GETPOS (st) + st->cursize); } close (fd); /* close the file */ if (elt) mx_setdate (tmp,elt);/* set file date */ /* swell the cache */ mail_exists (stream,++stream->nmsgs); /* copy flags */ mail_append_set (set,(elt = mail_elt (stream,stream->nmsgs))->private.uid = stream->uid_last); if (f&fSEEN) elt->seen = T; if (f&fDELETED) elt->deleted = T; if (f&fFLAGGED) elt->flagged = T; if (f&fANSWERED) elt->answered = T; if (f&fDRAFT) elt->draft = T; elt->user_flags |= uf; return LONGT; } /* Internal routines */ /* MX file name selection test * Accepts: candidate directory entry * Returns: T to use file name, NIL to skip it */ int mx_select (struct direct *name) { char c; char *s = name->d_name; while (c = *s++) if (!isdigit (c)) return NIL; return T; } /* MX file name comparision * Accepts: first candidate directory entry * second candidate directory entry * Returns: negative if d1 < d2, 0 if d1 == d2, postive if d1 > d2 */ int mx_numsort (const void *d1,const void *d2) { return atoi ((*(struct direct **) d1)->d_name) - atoi ((*(struct direct **) d2)->d_name); } /* MX mail build file name * Accepts: destination string * source * Returns: destination */ char *mx_file (char *dst,char *name) { char *s; /* empty string if mailboxfile fails */ if (!mailboxfile (dst,name)) *dst = '\0'; /* driver-selected INBOX */ else if (!*dst) mailboxfile (dst,"~/INBOX"); /* tie off unnecessary trailing / */ else if ((s = strrchr (dst,'/')) && !s[1]) *s = '\0'; return dst; } /* MX read and lock index * Accepts: MAIL stream * Returns: T if success, NIL if failure */ long mx_lockindex (MAILSTREAM *stream) { unsigned long uf,sf,uid; int k = 0; unsigned long msgno = 1; struct stat sbuf; char *s,*t,*idx,tmp[2*MAILTMPLEN]; MESSAGECACHE *elt; blocknotify_t bn = (blocknotify_t) mail_parameters (NIL,GET_BLOCKNOTIFY,NIL); if ((LOCAL->fd < 0) && /* get index file, no-op if already have it */ (LOCAL->fd = open (strcat (strcpy (tmp,stream->mailbox),MXINDEXNAME), O_RDWR|O_CREAT, (long) mail_parameters (NIL,GET_MBXPROTECTION,NIL))) >= 0) { (*bn) (BLOCK_FILELOCK,NIL); flock (LOCAL->fd,LOCK_EX); /* get exclusive lock */ (*bn) (BLOCK_NONE,NIL); fstat (LOCAL->fd,&sbuf); /* get size of index */ /* slurp index */ read (LOCAL->fd,s = idx = (char *) fs_get (sbuf.st_size + 1),sbuf.st_size); idx[sbuf.st_size] = '\0'; /* tie off index */ /* parse index */ if (sbuf.st_size) while (s && *s) switch (*s) { case 'V': /* UID validity record */ stream->uid_validity = strtoul (s+1,&s,16); break; case 'L': /* UID last record */ stream->uid_last = strtoul (s+1,&s,16); break; case 'K': /* keyword */ /* find end of keyword */ if (s = strchr (t = ++s,'\n')) { *s++ = '\0'; /* tie off keyword */ /* copy keyword */ if ((k < NUSERFLAGS) && !stream->user_flags[k] && (strlen (t) <= MAXUSERFLAG)) stream->user_flags[k] = cpystr (t); k++; /* one more keyword */ } break; case 'M': /* message status record */ uid = strtoul (s+1,&s,16);/* get UID for this message */ if (*s == ';') { /* get user flags */ uf = strtoul (s+1,&s,16); if (*s == '.') { /* get system flags */ sf = strtoul (s+1,&s,16); while ((msgno <= stream->nmsgs) && (mail_uid (stream,msgno) < uid)) msgno++; /* find message number for this UID */ if ((msgno <= stream->nmsgs) && (mail_uid (stream,msgno) == uid)) { (elt = mail_elt (stream,msgno))->valid = T; elt->user_flags=uf; /* set user and system flags in elt */ if (sf & fSEEN) elt->seen = T; if (sf & fDELETED) elt->deleted = T; if (sf & fFLAGGED) elt->flagged = T; if (sf & fANSWERED) elt->answered = T; if (sf & fDRAFT) elt->draft = T; } break; } } default: /* bad news */ sprintf (tmp,"Error in index: %.80s",s); MM_LOG (tmp,ERROR); *s = NIL; /* ignore remainder of index */ } else { /* new index */ stream->uid_validity = time (0); user_flags (stream); /* init stream with default user flags */ } fs_give ((void **) &idx); /* flush index */ } return (LOCAL->fd >= 0) ? T : NIL; } /* MX write and unlock index * Accepts: MAIL stream */ #define MXIXBUFLEN 2048 void mx_unlockindex (MAILSTREAM *stream) { unsigned long i,j; off_t size = 0; char *s,tmp[MXIXBUFLEN + 64]; MESSAGECACHE *elt; if (LOCAL->fd >= 0) { lseek (LOCAL->fd,0,L_SET); /* rewind file */ /* write header */ sprintf (s = tmp,"V%08lxL%08lx",stream->uid_validity,stream->uid_last); for (i = 0; (i < NUSERFLAGS) && stream->user_flags[i]; ++i) sprintf (s += strlen (s),"K%s\n",stream->user_flags[i]); /* write messages */ for (i = 1; i <= stream->nmsgs; i++) { /* filled buffer? */ if (((s += strlen (s)) - tmp) > MXIXBUFLEN) { write (LOCAL->fd,tmp,j = s - tmp); size += j; *(s = tmp) = '\0'; /* dump out and restart buffer */ } elt = mail_elt (stream,i); sprintf(s,"M%08lx;%08lx.%04x",elt->private.uid,elt->user_flags,(unsigned) ((fSEEN * elt->seen) + (fDELETED * elt->deleted) + (fFLAGGED * elt->flagged) + (fANSWERED * elt->answered) + (fDRAFT * elt->draft))); } /* write tail end of buffer */ if ((s += strlen (s)) != tmp) { write (LOCAL->fd,tmp,j = s - tmp); size += j; } ftruncate (LOCAL->fd,size); flock (LOCAL->fd,LOCK_UN); /* unlock the index */ close (LOCAL->fd); /* finished with file */ LOCAL->fd = -1; /* no index now */ } } /* Set date for message * Accepts: file name * elt containing date */ void mx_setdate (char *file,MESSAGECACHE *elt) { time_t tp[2]; tp[0] = time (0); /* atime is now */ tp[1] = mail_longdate (elt); /* modification time */ utime (file,tp); /* set the times */ } alpine-2.10+dfsg/imap/src/osdep/amiga/news.c0000600000175000017500000005343211512502124022370 0ustar paulproteuspaulproteus/* ======================================================================== * Copyright 1988-2007 University of Washington * * Licensed under the Apache License, Version 2.0 (the "License"); * you may not use this file except in compliance with the License. * You may obtain a copy of the License at * * http://www.apache.org/licenses/LICENSE-2.0 * * * ======================================================================== */ /* * Program: News routines * * Author: Mark Crispin * Networks and Distributed Computing * Computing & Communications * University of Washington * Administration Building, AG-44 * Seattle, WA 98195 * Internet: MRC@CAC.Washington.EDU * * Date: 4 September 1991 * Last Edited: 30 January 2007 */ #include #include #include extern int errno; /* just in case */ #include "mail.h" #include "osdep.h" #include #include #include "misc.h" #include "newsrc.h" #include "fdstring.h" /* news_load_message() flags */ #define NLM_HEADER 0x1 /* load message text */ #define NLM_TEXT 0x2 /* load message text */ /* NEWS I/O stream local data */ typedef struct news_local { unsigned int dirty : 1; /* disk copy of .newsrc needs updating */ char *dir; /* spool directory name */ char *name; /* local mailbox name */ unsigned char buf[CHUNKSIZE]; /* scratch buffer */ unsigned long cachedtexts; /* total size of all cached texts */ } NEWSLOCAL; /* Convenient access to local data */ #define LOCAL ((NEWSLOCAL *) stream->local) /* Function prototypes */ DRIVER *news_valid (char *name); DRIVER *news_isvalid (char *name,char *mbx); void *news_parameters (long function,void *value); void news_scan (MAILSTREAM *stream,char *ref,char *pat,char *contents); void news_list (MAILSTREAM *stream,char *ref,char *pat); void news_lsub (MAILSTREAM *stream,char *ref,char *pat); long news_canonicalize (char *ref,char *pat,char *pattern); long news_subscribe (MAILSTREAM *stream,char *mailbox); long news_unsubscribe (MAILSTREAM *stream,char *mailbox); long news_create (MAILSTREAM *stream,char *mailbox); long news_delete (MAILSTREAM *stream,char *mailbox); long news_rename (MAILSTREAM *stream,char *old,char *newname); MAILSTREAM *news_open (MAILSTREAM *stream); int news_select (struct direct *name); int news_numsort (const void *d1,const void *d2); void news_close (MAILSTREAM *stream,long options); void news_fast (MAILSTREAM *stream,char *sequence,long flags); void news_flags (MAILSTREAM *stream,char *sequence,long flags); void news_load_message (MAILSTREAM *stream,unsigned long msgno,long flags); char *news_header (MAILSTREAM *stream,unsigned long msgno, unsigned long *length,long flags); long news_text (MAILSTREAM *stream,unsigned long msgno,STRING *bs,long flags); void news_flagmsg (MAILSTREAM *stream,MESSAGECACHE *elt); long news_ping (MAILSTREAM *stream); void news_check (MAILSTREAM *stream); long news_expunge (MAILSTREAM *stream,char *sequence,long options); long news_copy (MAILSTREAM *stream,char *sequence,char *mailbox,long options); long news_append (MAILSTREAM *stream,char *mailbox,append_t af,void *data); /* News routines */ /* Driver dispatch used by MAIL */ DRIVER newsdriver = { "news", /* driver name */ /* driver flags */ DR_NEWS|DR_READONLY|DR_NOFAST|DR_NAMESPACE|DR_NONEWMAIL|DR_DIRFMT, (DRIVER *) NIL, /* next driver */ news_valid, /* mailbox is valid for us */ news_parameters, /* manipulate parameters */ news_scan, /* scan mailboxes */ news_list, /* find mailboxes */ news_lsub, /* find subscribed mailboxes */ news_subscribe, /* subscribe to mailbox */ news_unsubscribe, /* unsubscribe from mailbox */ news_create, /* create mailbox */ news_delete, /* delete mailbox */ news_rename, /* rename mailbox */ mail_status_default, /* status of mailbox */ news_open, /* open mailbox */ news_close, /* close mailbox */ news_fast, /* fetch message "fast" attributes */ news_flags, /* fetch message flags */ NIL, /* fetch overview */ NIL, /* fetch message envelopes */ news_header, /* fetch message header */ news_text, /* fetch message body */ NIL, /* fetch partial message text */ NIL, /* unique identifier */ NIL, /* message number */ NIL, /* modify flags */ news_flagmsg, /* per-message modify flags */ NIL, /* search for message based on criteria */ NIL, /* sort messages */ NIL, /* thread messages */ news_ping, /* ping mailbox to see if still alive */ news_check, /* check for new messages */ news_expunge, /* expunge deleted messages */ news_copy, /* copy messages to another mailbox */ news_append, /* append string message to mailbox */ NIL /* garbage collect stream */ }; /* prototype stream */ MAILSTREAM newsproto = {&newsdriver}; /* News validate mailbox * Accepts: mailbox name * Returns: our driver if name is valid, NIL otherwise */ DRIVER *news_valid (char *name) { int fd; char *s,*t,*u; struct stat sbuf; if ((name[0] == '#') && (name[1] == 'n') && (name[2] == 'e') && (name[3] == 'w') && (name[4] == 's') && (name[5] == '.') && !strchr (name,'/') && !stat ((char *) mail_parameters (NIL,GET_NEWSSPOOL,NIL),&sbuf) && ((fd = open ((char *) mail_parameters (NIL,GET_NEWSACTIVE,NIL),O_RDONLY, NIL)) >= 0)) { fstat (fd,&sbuf); /* get size of active file */ /* slurp in active file */ read (fd,t = s = (char *) fs_get (sbuf.st_size+1),sbuf.st_size); s[sbuf.st_size] = '\0'; /* tie off file */ close (fd); /* flush file */ while (*t && (u = strchr (t,' '))) { *u++ = '\0'; /* tie off at end of name */ if (!strcmp (name+6,t)) { fs_give ((void **) &s); /* flush data */ return &newsdriver; } t = 1 + strchr (u,'\n'); /* next line */ } fs_give ((void **) &s); /* flush data */ } return NIL; /* return status */ } /* News manipulate driver parameters * Accepts: function code * function-dependent value * Returns: function-dependent return value */ void *news_parameters (long function,void *value) { return (function == GET_NEWSRC) ? env_parameters (function,value) : NIL; } /* News scan mailboxes * Accepts: mail stream * reference * pattern to search * string to scan */ void news_scan (MAILSTREAM *stream,char *ref,char *pat,char *contents) { char tmp[MAILTMPLEN]; if (news_canonicalize (ref,pat,tmp)) mm_log ("Scan not valid for news mailboxes",ERROR); } /* News find list of newsgroups * Accepts: mail stream * reference * pattern to search */ void news_list (MAILSTREAM *stream,char *ref,char *pat) { int fd; int i; char *s,*t,*u,*r,pattern[MAILTMPLEN],name[MAILTMPLEN]; struct stat sbuf; if (!pat || !*pat) { /* empty pattern? */ if (news_canonicalize (ref,"*",pattern)) { /* tie off name at root */ if (s = strchr (pattern,'.')) *++s = '\0'; else pattern[0] = '\0'; mm_list (stream,'.',pattern,LATT_NOSELECT); } } else if (news_canonicalize (ref,pat,pattern) && !stat ((char *) mail_parameters (NIL,GET_NEWSSPOOL,NIL),&sbuf) && ((fd = open ((char *) mail_parameters (NIL,GET_NEWSACTIVE,NIL), O_RDONLY,NIL)) >= 0)) { fstat (fd,&sbuf); /* get file size and read data */ read (fd,s = (char *) fs_get (sbuf.st_size + 1),sbuf.st_size); close (fd); /* close file */ s[sbuf.st_size] = '\0'; /* tie off string */ strcpy (name,"#news."); /* write initial prefix */ i = strlen (pattern); /* length of pattern */ if (pattern[--i] != '%') i = 0; if (t = strtok_r (s,"\n",&r)) do if (u = strchr (t,' ')) { *u = '\0'; /* tie off at end of name */ strcpy (name + 6,t); /* make full form of name */ if (pmatch_full (name,pattern,'.')) mm_list (stream,'.',name,NIL); else if (i && (u = strchr (name + i,'.'))) { *u = '\0'; /* tie off at delimiter, see if matches */ if (pmatch_full (name,pattern,'.')) mm_list (stream,'.',name,LATT_NOSELECT); } } while (t = strtok_r (NIL,"\n",&r)); fs_give ((void **) &s); } } /* News find list of subscribed newsgroups * Accepts: mail stream * reference * pattern to search */ void news_lsub (MAILSTREAM *stream,char *ref,char *pat) { char pattern[MAILTMPLEN]; /* return data from newsrc */ if (news_canonicalize (ref,pat,pattern)) newsrc_lsub (stream,pattern); } /* News canonicalize newsgroup name * Accepts: reference * pattern * returned single pattern * Returns: T on success, NIL on failure */ long news_canonicalize (char *ref,char *pat,char *pattern) { unsigned long i; char *s; if (ref && *ref) { /* have a reference */ strcpy (pattern,ref); /* copy reference to pattern */ /* # overrides mailbox field in reference */ if (*pat == '#') strcpy (pattern,pat); /* pattern starts, reference ends, with . */ else if ((*pat == '.') && (pattern[strlen (pattern) - 1] == '.')) strcat (pattern,pat + 1); /* append, omitting one of the period */ else strcat (pattern,pat); /* anything else is just appended */ } else strcpy (pattern,pat); /* just have basic name */ if ((pattern[0] == '#') && (pattern[1] == 'n') && (pattern[2] == 'e') && (pattern[3] == 'w') && (pattern[4] == 's') && (pattern[5] == '.') && !strchr (pattern,'/')) { /* count wildcards */ for (i = 0, s = pattern; *s; *s++) if ((*s == '*') || (*s == '%')) ++i; /* success if not too many */ if (i <= MAXWILDCARDS) return LONGT; MM_LOG ("Excessive wildcards in LIST/LSUB",ERROR); } return NIL; } /* News subscribe to mailbox * Accepts: mail stream * mailbox to add to subscription list * Returns: T on success, NIL on failure */ long news_subscribe (MAILSTREAM *stream,char *mailbox) { return news_valid (mailbox) ? newsrc_update (stream,mailbox+6,':') : NIL; } /* NEWS unsubscribe to mailbox * Accepts: mail stream * mailbox to delete from subscription list * Returns: T on success, NIL on failure */ long news_unsubscribe (MAILSTREAM *stream,char *mailbox) { return news_valid (mailbox) ? newsrc_update (stream,mailbox+6,'!') : NIL; } /* News create mailbox * Accepts: mail stream * mailbox name to create * Returns: T on success, NIL on failure */ long news_create (MAILSTREAM *stream,char *mailbox) { return NIL; /* never valid for News */ } /* News delete mailbox * mailbox name to delete * Returns: T on success, NIL on failure */ long news_delete (MAILSTREAM *stream,char *mailbox) { return NIL; /* never valid for News */ } /* News rename mailbox * Accepts: mail stream * old mailbox name * new mailbox name * Returns: T on success, NIL on failure */ long news_rename (MAILSTREAM *stream,char *old,char *newname) { return NIL; /* never valid for News */ } /* News open * Accepts: stream to open * Returns: stream on success, NIL on failure */ MAILSTREAM *news_open (MAILSTREAM *stream) { long i,nmsgs; char *s,tmp[MAILTMPLEN]; struct direct **names = NIL; /* return prototype for OP_PROTOTYPE call */ if (!stream) return &newsproto; if (stream->local) fatal ("news recycle stream"); /* build directory name */ sprintf (s = tmp,"%s/%s",(char *) mail_parameters (NIL,GET_NEWSSPOOL,NIL), stream->mailbox + 6); while (s = strchr (s,'.')) *s = '/'; /* scan directory */ if ((nmsgs = scandir (tmp,&names,news_select,news_numsort)) >= 0) { mail_exists (stream,nmsgs); /* notify upper level that messages exist */ stream->local = fs_get (sizeof (NEWSLOCAL)); LOCAL->dirty = NIL; /* no update to .newsrc needed yet */ LOCAL->dir = cpystr (tmp); /* copy directory name for later */ LOCAL->name = cpystr (stream->mailbox + 6); for (i = 0; i < nmsgs; ++i) { stream->uid_last = mail_elt (stream,i+1)->private.uid = atoi (names[i]->d_name); fs_give ((void **) &names[i]); } s = (void *) names; /* stupid language */ fs_give ((void **) &s); /* free directory */ LOCAL->cachedtexts = 0; /* no cached texts */ stream->sequence++; /* bump sequence number */ stream->rdonly = stream->perm_deleted = T; /* UIDs are always valid */ stream->uid_validity = 0xbeefface; /* read .newsrc entries */ mail_recent (stream,newsrc_read (LOCAL->name,stream)); /* notify if empty newsgroup */ if (!(stream->nmsgs || stream->silent)) { sprintf (tmp,"Newsgroup %s is empty",LOCAL->name); mm_log (tmp,WARN); } } else mm_log ("Unable to scan newsgroup spool directory",ERROR); return LOCAL ? stream : NIL; /* if stream is alive, return to caller */ } /* News file name selection test * Accepts: candidate directory entry * Returns: T to use file name, NIL to skip it */ int news_select (struct direct *name) { char c; char *s = name->d_name; while (c = *s++) if (!isdigit (c)) return NIL; return T; } /* News file name comparision * Accepts: first candidate directory entry * second candidate directory entry * Returns: negative if d1 < d2, 0 if d1 == d2, postive if d1 > d2 */ int news_numsort (const void *d1,const void *d2) { return atoi ((*(struct direct **) d1)->d_name) - atoi ((*(struct direct **) d2)->d_name); } /* News close * Accepts: MAIL stream * option flags */ void news_close (MAILSTREAM *stream,long options) { if (LOCAL) { /* only if a file is open */ news_check (stream); /* dump final checkpoint */ if (LOCAL->dir) fs_give ((void **) &LOCAL->dir); if (LOCAL->name) fs_give ((void **) &LOCAL->name); /* nuke the local data */ fs_give ((void **) &stream->local); stream->dtb = NIL; /* log out the DTB */ } } /* News fetch fast information * Accepts: MAIL stream * sequence * option flags */ void news_fast (MAILSTREAM *stream,char *sequence,long flags) { MESSAGECACHE *elt; unsigned long i; /* set up metadata for all messages */ if (stream && LOCAL && ((flags & FT_UID) ? mail_uid_sequence (stream,sequence) : mail_sequence (stream,sequence))) for (i = 1; i <= stream->nmsgs; i++) if ((elt = mail_elt (stream,i))->sequence && !(elt->day && elt->rfc822_size)) news_load_message (stream,i,NIL); } /* News fetch flags * Accepts: MAIL stream * sequence * option flags */ void news_flags (MAILSTREAM *stream,char *sequence,long flags) { unsigned long i; if ((flags & FT_UID) ? /* validate all elts */ mail_uid_sequence (stream,sequence) : mail_sequence (stream,sequence)) for (i = 1; i <= stream->nmsgs; i++) mail_elt (stream,i)->valid = T; } /* News load message into cache * Accepts: MAIL stream * message # * option flags */ void news_load_message (MAILSTREAM *stream,unsigned long msgno,long flags) { unsigned long i,j,nlseen; int fd; unsigned char c,*t; struct stat sbuf; MESSAGECACHE *elt; FDDATA d; STRING bs; elt = mail_elt (stream,msgno);/* get elt */ /* build message file name */ sprintf (LOCAL->buf,"%s/%lu",LOCAL->dir,elt->private.uid); /* anything we need not currently cached? */ if ((!elt->day || !elt->rfc822_size || ((flags & NLM_HEADER) && !elt->private.msg.header.text.data) || ((flags & NLM_TEXT) && !elt->private.msg.text.text.data)) && ((fd = open (LOCAL->buf,O_RDONLY,NIL)) >= 0)) { fstat (fd,&sbuf); /* get file metadata */ d.fd = fd; /* set up file descriptor */ d.pos = 0; /* start of file */ d.chunk = LOCAL->buf; d.chunksize = CHUNKSIZE; INIT (&bs,fd_string,&d,sbuf.st_size); if (!elt->day) { /* set internaldate to file date */ struct tm *tm = gmtime (&sbuf.st_mtime); elt->day = tm->tm_mday; elt->month = tm->tm_mon + 1; elt->year = tm->tm_year + 1900 - BASEYEAR; elt->hours = tm->tm_hour; elt->minutes = tm->tm_min; elt->seconds = tm->tm_sec; elt->zhours = 0; elt->zminutes = 0; } if (!elt->rfc822_size) { /* know message size yet? */ for (i = 0, j = SIZE (&bs), nlseen = 0; j--; ) switch (SNX (&bs)) { case '\015': /* unlikely carriage return */ if (!j || (CHR (&bs) != '\012')) { i++; /* ugh, raw CR */ nlseen = NIL; break; } SNX (&bs); /* eat the line feed, drop in */ case '\012': /* line feed? */ i += 2; /* count a CRLF */ /* header size known yet? */ if (!elt->private.msg.header.text.size && nlseen) { /* note position in file */ elt->private.special.text.size = GETPOS (&bs); /* and CRLF-adjusted size */ elt->private.msg.header.text.size = i; } nlseen = T; /* note newline seen */ break; default: /* ordinary chararacter */ i++; nlseen = NIL; break; } SETPOS (&bs,0); /* restore old position */ elt->rfc822_size = i; /* note that we have size now */ /* header is entire message if no delimiter */ if (!elt->private.msg.header.text.size) elt->private.msg.header.text.size = elt->rfc822_size; /* text is remainder of message */ elt->private.msg.text.text.size = elt->rfc822_size - elt->private.msg.header.text.size; } /* need to load cache with message data? */ if (((flags & NLM_HEADER) && !elt->private.msg.header.text.data) || ((flags & NLM_TEXT) && !elt->private.msg.text.text.data)) { /* purge cache if too big */ if (LOCAL->cachedtexts > max (stream->nmsgs * 4096,2097152)) { /* just can't keep that much */ mail_gc (stream,GC_TEXTS); LOCAL->cachedtexts = 0; } if ((flags & NLM_HEADER) && !elt->private.msg.header.text.data) { t = elt->private.msg.header.text.data = (unsigned char *) fs_get (elt->private.msg.header.text.size + 1); LOCAL->cachedtexts += elt->private.msg.header.text.size; /* read in message header */ for (i = 0; i <= elt->private.msg.header.text.size; i++) switch (c = SNX (&bs)) { case '\015': /* unlikely carriage return */ *t++ = c; if ((CHR (&bs) == '\012')) *t++ = SNX (&bs); break; case '\012': /* line feed? */ *t++ = '\015'; default: *t++ = c; break; } *t = '\0'; /* tie off string */ } if ((flags & NLM_TEXT) && !elt->private.msg.text.text.data) { t = elt->private.msg.text.text.data = (unsigned char *) fs_get (elt->private.msg.text.text.size + 1); SETPOS (&bs,elt->private.msg.header.text.size); LOCAL->cachedtexts += elt->private.msg.text.text.size; /* read in message text */ for (i = 0; i <= elt->private.msg.text.text.size; i++) switch (c = SNX (&bs)) { case '\015': /* unlikely carriage return */ *t++ = c; if ((CHR (&bs) == '\012')) *t++ = SNX (&bs); break; case '\012': /* line feed? */ *t++ = '\015'; default: *t++ = c; break; } *t = '\0'; /* tie off string */ } } close (fd); /* flush message file */ } } /* News fetch message header * Accepts: MAIL stream * message # to fetch * pointer to returned header text length * option flags * Returns: message header in RFC822 format */ char *news_header (MAILSTREAM *stream,unsigned long msgno, unsigned long *length,long flags) { MESSAGECACHE *elt; *length = 0; /* default to empty */ if (flags & FT_UID) return "";/* UID call "impossible" */ elt = mail_elt (stream,msgno);/* get elt */ if (!elt->private.msg.header.text.data) news_load_message (stream,msgno,NLM_HEADER); *length = elt->private.msg.header.text.size; return (char *) elt->private.msg.header.text.data; } /* News fetch message text (body only) * Accepts: MAIL stream * message # to fetch * pointer to returned stringstruct * option flags * Returns: T on success, NIL on failure */ long news_text (MAILSTREAM *stream,unsigned long msgno,STRING *bs,long flags) { MESSAGECACHE *elt; /* UID call "impossible" */ if (flags & FT_UID) return NIL; elt = mail_elt (stream,msgno);/* get elt */ /* snarf message if don't have it yet */ if (!elt->private.msg.text.text.data) { news_load_message (stream,msgno,NLM_TEXT); if (!elt->private.msg.text.text.data) return NIL; } if (!(flags & FT_PEEK)) { /* mark as seen */ mail_elt (stream,msgno)->seen = T; mm_flags (stream,msgno); } INIT (bs,mail_string,elt->private.msg.text.text.data, elt->private.msg.text.text.size); return T; } /* News per-message modify flag * Accepts: MAIL stream * message cache element */ void news_flagmsg (MAILSTREAM *stream,MESSAGECACHE *elt) { if (!LOCAL->dirty) { /* only bother checking if not dirty yet */ if (elt->valid) { /* if done, see if deleted changed */ if (elt->sequence != elt->deleted) LOCAL->dirty = T; elt->sequence = T; /* leave the sequence set */ } /* note current setting of deleted flag */ else elt->sequence = elt->deleted; } } /* News ping mailbox * Accepts: MAIL stream * Returns: T if stream alive, else NIL */ long news_ping (MAILSTREAM *stream) { return T; /* always alive */ } /* News check mailbox * Accepts: MAIL stream */ void news_check (MAILSTREAM *stream) { /* never do if no updates */ if (LOCAL->dirty) newsrc_write (LOCAL->name,stream); LOCAL->dirty = NIL; } /* News expunge mailbox * Accepts: MAIL stream * sequence to expunge if non-NIL * expunge options * Returns: T if success, NIL if failure */ long news_expunge (MAILSTREAM *stream,char *sequence,long options) { if (!stream->silent) mm_log ("Expunge ignored on readonly mailbox",NIL); return LONGT; } /* News copy message(s) * Accepts: MAIL stream * sequence * destination mailbox * option flags * Returns: T if copy successful, else NIL */ long news_copy (MAILSTREAM *stream,char *sequence,char *mailbox,long options) { mailproxycopy_t pc = (mailproxycopy_t) mail_parameters (stream,GET_MAILPROXYCOPY,NIL); if (pc) return (*pc) (stream,sequence,mailbox,options); mm_log ("Copy not valid for News",ERROR); return NIL; } /* News append message from stringstruct * Accepts: MAIL stream * destination mailbox * append callback function * data for callback * Returns: T if append successful, else NIL */ long news_append (MAILSTREAM *stream,char *mailbox,append_t af,void *data) { mm_log ("Append not valid for news",ERROR); return NIL; } alpine-2.10+dfsg/imap/src/osdep/amiga/fs_ami.c0000600000175000017500000000353511512502124022651 0ustar paulproteuspaulproteus/* ======================================================================== * Copyright 1988-2006 University of Washington * * Licensed under the Apache License, Version 2.0 (the "License"); * you may not use this file except in compliance with the License. * You may obtain a copy of the License at * * http://www.apache.org/licenses/LICENSE-2.0 * * * ======================================================================== */ /* * Program: Free storage management routines * * Author: Mark Crispin * Networks and Distributed Computing * Computing & Communications * University of Washington * Administration Building, AG-44 * Seattle, WA 98195 * Internet: MRC@CAC.Washington.EDU * * Date: 1 August 1988 * Last Edited: 30 August 2006 */ /* Get a block of free storage * Accepts: size of desired block * Returns: free storage block */ void *fs_get (size_t size) { blocknotify_t bn = (blocknotify_t) mail_parameters (NIL,GET_BLOCKNOTIFY,NIL); void *data = (*bn) (BLOCK_SENSITIVE,NIL); void *block = malloc (size ? size : (size_t) 1); if (!block) fatal ("Out of memory"); (*bn) (BLOCK_NONSENSITIVE,data); return (block); } /* Resize a block of free storage * Accepts: ** pointer to current block * new size */ void fs_resize (void **block,size_t size) { blocknotify_t bn = (blocknotify_t) mail_parameters (NIL,GET_BLOCKNOTIFY,NIL); void *data = (*bn) (BLOCK_SENSITIVE,NIL); if (!(*block = realloc (*block,size ? size : (size_t) 1))) fatal ("Can't resize memory"); (*bn) (BLOCK_NONSENSITIVE,data); } /* Return a block of free storage * Accepts: ** pointer to free storage block */ void fs_give (void **block) { blocknotify_t bn = (blocknotify_t) mail_parameters (NIL,GET_BLOCKNOTIFY,NIL); void *data = (*bn) (BLOCK_SENSITIVE,NIL); free (*block); *block = NIL; (*bn) (BLOCK_NONSENSITIVE,data); } alpine-2.10+dfsg/imap/src/osdep/amiga/write.c0000600000175000017500000000336711512502124022550 0ustar paulproteuspaulproteus/* ======================================================================== * Copyright 1988-2006 University of Washington * * Licensed under the Apache License, Version 2.0 (the "License"); * you may not use this file except in compliance with the License. * You may obtain a copy of the License at * * http://www.apache.org/licenses/LICENSE-2.0 * * * ======================================================================== */ /* * Program: Write data, treating partial writes as an error * * Author: Mark Crispin * Networks and Distributed Computing * Computing & Communications * University of Washington * Administration Building, AG-44 * Seattle, WA 98195 * Internet: MRC@CAC.Washington.EDU * * Date: 26 May 1995 * Last Edited: 30 August 2006 */ /* The whole purpose of this unfortunate routine is to deal with DOS and * certain cretinous versions of UNIX which decided that the "bytes actually * written" return value from write() gave them license to use that for things * that are really errors, such as disk quota exceeded, maximum file size * exceeded, disk full, etc. * * BSD won't screw us this way on the local filesystem, but who knows what * some NFS-mounted filesystem will do. */ #undef write /* Write data to file * Accepts: file descriptor * I/O vector structure * number of vectors in structure * Returns: number of bytes written if successful, -1 if failure */ long maxposint = (long)((((unsigned long) 1) << ((sizeof(int) * 8) - 1)) - 1); long safe_write (int fd,char *buf,long nbytes) { long i,j; if (nbytes > 0) for (i = nbytes; i; i -= j,buf += j) { while (((j = write (fd,buf,(int) min (maxposint,i))) < 0) && (errno == EINTR)); if (j < 0) return j; } return nbytes; } alpine-2.10+dfsg/imap/src/osdep/amiga/drivers0000700000175000017500000000173511512502124022651 0ustar paulproteuspaulproteus#!/bin/sh # ======================================================================== # Copyright 1988-2006 University of Washington # # Licensed under the Apache License, Version 2.0 (the "License"); # you may not use this file except in compliance with the License. # You may obtain a copy of the License at # # http://www.apache.org/licenses/LICENSE-2.0 # # # ======================================================================== # Program: Driver Linkage Generator # # Author: Mark Crispin # Networks and Distributed Computing # Computing & Communications # University of Washington # Administration Building, AG-44 # Seattle, WA 98195 # Internet: MRC@CAC.Washington.EDU # # Date: 11 October 1989 # Last Edited: 30 August 2006 # Erase old driver linkage rm -f linkage.[ch] # Now define the new list for driver do echo "extern DRIVER "$driver"driver;" >> linkage.h echo " mail_link (&"$driver"driver); /* link in the $driver driver */" | cat >> linkage.c done alpine-2.10+dfsg/imap/src/osdep/amiga/ftl_ami.c0000600000175000017500000000167311512502124023027 0ustar paulproteuspaulproteus/* ======================================================================== * Copyright 1988-2006 University of Washington * * Licensed under the Apache License, Version 2.0 (the "License"); * you may not use this file except in compliance with the License. * You may obtain a copy of the License at * * http://www.apache.org/licenses/LICENSE-2.0 * * * ======================================================================== */ /* * Program: DOS/VMS/TOPS-20 crash management routines * * Author: Mark Crispin * Networks and Distributed Computing * Computing & Communications * University of Washington * Administration Building, AG-44 * Seattle, WA 98195 * Internet: MRC@CAC.Washington.EDU * * Date: 1 August 1988 * Last Edited: 30 August 2006 */ /* Report a fatal error * Accepts: string to output */ void fatal (char *string) { mm_fatal (string); /* pass up the string */ abort (); /* die horribly */ } alpine-2.10+dfsg/imap/src/osdep/amiga/env_ami.h0000600000175000017500000000556511512502124023043 0ustar paulproteuspaulproteus/* ======================================================================== * Copyright 1988-2006 University of Washington * * Licensed under the Apache License, Version 2.0 (the "License"); * you may not use this file except in compliance with the License. * You may obtain a copy of the License at * * http://www.apache.org/licenses/LICENSE-2.0 * * * ======================================================================== */ /* * Program: UNIX environment routines * * Author: Mark Crispin * Networks and Distributed Computing * Computing & Communications * University of Washington * Administration Building, AG-44 * Seattle, WA 98195 * Internet: MRC@CAC.Washington.EDU * * Date: 1 August 1988 * Last Edited: 30 August 2006 */ typedef struct dotlock_base { char lock[MAILTMPLEN]; int pipei; int pipeo; } DOTLOCK; /* Bits that can be set in restrictBox */ #define RESTRICTROOT 0x1 /* restricted box doesn't allow root */ #define RESTRICTOTHERUSER 0x2 /* restricted box doesn't allow other user */ /* Subscription definitions for UNIX */ #define SUBSCRIPTIONFILE(t) sprintf (t,"%s/.mailboxlist",myhomedir ()) #define SUBSCRIPTIONTEMP(t) sprintf (t,"%s/.mlbxlsttmp",myhomedir ()) /* dorc() options */ #define SYSCONFIG "/etc/c-client.cf" /* Special users */ #define ANONYMOUSUSER "nobody" /* anonymous user */ #define UNLOGGEDUSER "root" /* unlogged-in user */ #define ADMINGROUP "mailadm" /* mail administrator group */ /* Function prototypes */ #include "env.h" void rfc822_fixed_date (char *date); long env_init (char *user,char *home); char *myusername_full (unsigned long *flags); #define MU_LOGGEDIN 0 #define MU_NOTLOGGEDIN 1 #define MU_ANONYMOUS 2 #define myusername() \ myusername_full (NIL) char *sysinbox (); char *mailboxdir (char *dst,char *dir,char *name); long dotlock_lock (char *file,DOTLOCK *base,int fd); long dotlock_unlock (DOTLOCK *base); int lockname (char *lock,char *fname,int op,long *pid); int lockfd (int fd,char *lock,int op); int lock_work (char *lock,void *sbuf,int op,long *pid); long chk_notsymlink (char *name,void *sbuf); void unlockfd (int fd,char *lock); long set_mbx_protections (char *mailbox,char *path); long get_dir_protection (char *mailbox); MAILSTREAM *user_flags (MAILSTREAM *stream); char *default_user_flag (unsigned long i); void dorc (char *file,long flag); long path_create (MAILSTREAM *stream,char *mailbox); void grim_pid_reap_status (int pid,int killreq,void *status); #define grim_pid_reap(pid,killreq) \ grim_pid_reap_status (pid,killreq,NIL) long safe_write (int fd,char *buf,long nbytes); void *arm_signal (int sig,void *action); struct passwd *checkpw (struct passwd *pw,char *pass,int argc,char *argv[]); long loginpw (struct passwd *pw,int argc,char *argv[]); long pw_login (struct passwd *pw,char *auser,char *user,char *home,int argc, char *argv[]); void *mm_blocknotify (int reason,void *data); alpine-2.10+dfsg/imap/src/osdep/amiga/mkauths0000700000175000017500000000227011512502124022642 0ustar paulproteuspaulproteus#!/bin/sh # ======================================================================== # Copyright 1988-2006 University of Washington # # Licensed under the Apache License, Version 2.0 (the "License"); # you may not use this file except in compliance with the License. # You may obtain a copy of the License at # # http://www.apache.org/licenses/LICENSE-2.0 # # # ======================================================================== # Program: Authenticator Linkage Generator # # Author: Mark Crispin # Networks and Distributed Computing # Computing & Communications # University of Washington # Administration Building, AG-44 # Seattle, WA 98195 # Internet: MRC@CAC.Washington.EDU # # Date: 5 December 1995 # Last Edited: 30 August 2006 # Erase old authenticators list rm -f auths.c touch auths.c # Now define the new list for authenticator do if [ -f Makefile."$authenticator" ]; then make -f Makefile."$authenticator" `cat SPECIALS` fi echo "extern AUTHENTICATOR auth_"$authenticator";" >> linkage.h echo " auth_link (&auth_"$authenticator"); /* link in the $authenticator authenticator */" | cat >> linkage.c echo "#include \"auth_"$authenticator".c\"" >> auths.c done alpine-2.10+dfsg/imap/src/osdep/amiga/tz_bsd.c0000600000175000017500000000173511512502124022700 0ustar paulproteuspaulproteus/* ======================================================================== * Copyright 1988-2006 University of Washington * * Licensed under the Apache License, Version 2.0 (the "License"); * you may not use this file except in compliance with the License. * You may obtain a copy of the License at * * http://www.apache.org/licenses/LICENSE-2.0 * * * ======================================================================== */ /* * Program: BSD-style Time Zone String * * Author: Mark Crispin * Networks and Distributed Computing * Computing & Communications * University of Washington * Administration Building, AG-44 * Seattle, WA 98195 * Internet: MRC@CAC.Washington.EDU * * Date: 30 August 1994 * Last Edited: 30 August 2006 */ /* Append local timezone name * Accepts: destination string */ void rfc822_timezone (char *s,void *t) { /* append timezone from tm struct */ sprintf (s + strlen (s)," (%.50s)",((struct tm *) t)->tm_zone); } alpine-2.10+dfsg/imap/src/osdep/amiga/fdstring.c0000600000175000017500000000540711512502124023233 0ustar paulproteuspaulproteus/* ======================================================================== * Copyright 1988-2007 University of Washington * * Licensed under the Apache License, Version 2.0 (the "License"); * you may not use this file except in compliance with the License. * You may obtain a copy of the License at * * http://www.apache.org/licenses/LICENSE-2.0 * * * ======================================================================== */ /* * Program: File descriptor string routines * * Author: Mark Crispin * Networks and Distributed Computing * Computing & Communications * University of Washington * Administration Building, AG-44 * Seattle, WA 98195 * Internet: MRC@CAC.Washington.EDU * * Date: 15 April 1997 * Last Edited: 4 April 2007 */ #include "mail.h" #include "osdep.h" #include "misc.h" #include "fdstring.h" /* String driver for fd stringstructs */ static void fd_string_init (STRING *s,void *data,unsigned long size); static char fd_string_next (STRING *s); static void fd_string_setpos (STRING *s,unsigned long i); STRINGDRIVER fd_string = { fd_string_init, /* initialize string structure */ fd_string_next, /* get next byte in string structure */ fd_string_setpos /* set position in string structure */ }; /* Initialize string structure for fd stringstruct * Accepts: string structure * pointer to string * size of string */ static void fd_string_init (STRING *s,void *data,unsigned long size) { FDDATA *d = (FDDATA *) data; /* note fd */ s->data = (void *) (unsigned long) d->fd; s->data1 = d->pos; /* note file offset */ s->size = size; /* note size */ s->curpos = s->chunk = d->chunk; s->chunksize = (unsigned long) d->chunksize; s->offset = 0; /* initial position */ /* and size of data */ s->cursize = min (s->chunksize,size); /* move to that position in the file */ lseek (d->fd,d->pos,L_SET); read (d->fd,s->chunk,(size_t) s->cursize); } /* Get next character from fd stringstruct * Accepts: string structure * Returns: character, string structure chunk refreshed */ static char fd_string_next (STRING *s) { char c = *s->curpos++; /* get next byte */ SETPOS (s,GETPOS (s)); /* move to next chunk */ return c; /* return the byte */ } /* Set string pointer position for fd stringstruct * Accepts: string structure * new position */ static void fd_string_setpos (STRING *s,unsigned long i) { if (i > s->size) i = s->size; /* don't permit setting beyond EOF */ s->offset = i; /* set new offset */ s->curpos = s->chunk; /* reset position */ /* set size of data */ if (s->cursize = min (s->chunksize,SIZE (s))) { /* move to that position in the file */ lseek ((long) s->data,s->data1 + s->offset,L_SET); read ((long) s->data,s->curpos,(size_t) s->cursize); } } alpine-2.10+dfsg/imap/src/osdep/amiga/tcp_ami.h0000600000175000017500000000231011512502124023022 0ustar paulproteuspaulproteus/* ======================================================================== * Copyright 1988-2006 University of Washington * * Licensed under the Apache License, Version 2.0 (the "License"); * you may not use this file except in compliance with the License. * You may obtain a copy of the License at * * http://www.apache.org/licenses/LICENSE-2.0 * * * ======================================================================== */ /* * Program: UNIX TCP/IP routines * * Author: Mark Crispin * Networks and Distributed Computing * Computing & Communications * University of Washington * Administration Building, AG-44 * Seattle, WA 98195 * Internet: MRC@CAC.Washington.EDU * * Date: 1 August 1988 * Last Edited: 30 August 2006 */ /* TCP input buffer */ #define BUFLEN 8192 /* TCP I/O stream */ #define TCPSTREAM struct tcp_stream TCPSTREAM { char *host; /* host name */ unsigned long port; /* port number */ char *localhost; /* local host name */ char *remotehost; /* remote host name */ int tcpsi; /* input socket */ int tcpso; /* output socket */ int ictr; /* input counter */ char *iptr; /* input pointer */ char ibuf[BUFLEN]; /* input buffer */ }; alpine-2.10+dfsg/imap/src/osdep/amiga/pmatch.c0000600000175000017500000000542411512502124022666 0ustar paulproteuspaulproteus/* ======================================================================== * Copyright 1988-2006 University of Washington * * Licensed under the Apache License, Version 2.0 (the "License"); * you may not use this file except in compliance with the License. * You may obtain a copy of the License at * * http://www.apache.org/licenses/LICENSE-2.0 * * * ======================================================================== */ /* * Program: IMAP Wildcard Matching Routines (case-dependent) * * Author: Mark Crispin * Networks and Distributed Computing * Computing & Communications * University of Washington * Administration Building, AG-44 * Seattle, WA 98195 * Internet: MRC@CAC.Washington.EDU * * Date: 15 June 2000 * Last Edited: 30 August 2006 */ /* Wildcard pattern match * Accepts: base string * pattern string * delimiter character * Returns: T if pattern matches base, else NIL */ long pmatch_full (unsigned char *s,unsigned char *pat,unsigned char delim) { switch (*pat) { case '%': /* non-recursive */ /* % at end, OK if no inferiors */ if (!pat[1]) return (delim && strchr (s,delim)) ? NIL : T; /* scan remainder of string until delimiter */ do if (pmatch_full (s,pat+1,delim)) return T; while ((*s != delim) && *s++); break; case '*': /* match 0 or more characters */ if (!pat[1]) return T; /* * at end, unconditional match */ /* scan remainder of string */ do if (pmatch_full (s,pat+1,delim)) return T; while (*s++); break; case '\0': /* end of pattern */ return *s ? NIL : T; /* success if also end of base */ default: /* match this character */ return (*pat == *s) ? pmatch_full (s+1,pat+1,delim) : NIL; } return NIL; } /* Directory pattern match * Accepts: base string * pattern string * delimiter character * Returns: T if base is a matching directory of pattern, else NIL */ long dmatch (unsigned char *s,unsigned char *pat,unsigned char delim) { switch (*pat) { case '%': /* non-recursive */ if (!*s) return T; /* end of base means have a subset match */ if (!*++pat) return NIL; /* % at end, no inferiors permitted */ /* scan remainder of string until delimiter */ do if (dmatch (s,pat,delim)) return T; while ((*s != delim) && *s++); if (*s && !s[1]) return T; /* ends with delimiter, must be subset */ return dmatch (s,pat,delim);/* do new scan */ case '*': /* match 0 or more characters */ return T; /* unconditional match */ case '\0': /* end of pattern */ break; default: /* match this character */ if (*s) return (*pat == *s) ? dmatch (s+1,pat+1,delim) : NIL; /* end of base, return if at delimiter */ else if (*pat == delim) return T; break; } return NIL; } alpine-2.10+dfsg/imap/src/osdep/amiga/env_ami.c0000600000175000017500000012133511512502124023030 0ustar paulproteuspaulproteus/* ======================================================================== * Copyright 1988-2008 University of Washington * * Licensed under the Apache License, Version 2.0 (the "License"); * you may not use this file except in compliance with the License. * You may obtain a copy of the License at * * http://www.apache.org/licenses/LICENSE-2.0 * * * ======================================================================== */ /* * Program: Amiga environment routines * * Author: Mark Crispin * UW Technology * Seattle, WA 98195 * Internet: MRC@Washington.EDU * * Date: 1 August 1988 * Last Edited: 15 May 2008 */ #include #include #include /* c-client environment parameters */ static char *myUserName = NIL; /* user name */ static char *myHomeDir = NIL; /* home directory name */ static char *myMailboxDir = NIL;/* mailbox directory name */ static char *myLocalHost = NIL; /* local host name */ static char *myNewsrc = NIL; /* newsrc file name */ static char *mailsubdir = NIL; /* mail subdirectory name */ static char *sysInbox = NIL; /* system inbox name */ static char *newsActive = NIL; /* news active file */ static char *newsSpool = NIL; /* news spool */ /* anonymous home directory */ static char *anonymousHome = NIL; static char *ftpHome = NIL; /* ftp export home directory */ static char *publicHome = NIL; /* public home directory */ static char *sharedHome = NIL; /* shared home directory */ static short anonymous = NIL; /* is anonymous */ static short restrictBox = NIL; /* is a restricted box */ static short has_no_life = NIL; /* is a cretin with no life */ /* block environment init */ static short block_env_init = NIL; static short hideDotFiles = NIL;/* hide files whose names start with . */ /* advertise filesystem root */ static short advertisetheworld = NIL; /* disable automatic shared namespaces */ static short noautomaticsharedns = NIL; static short no822tztext = NIL; /* disable RFC [2]822 timezone text */ static short netfsstatbug = NIL;/* compensate for broken stat() on network * filesystems (AFS and old NFS). Don't do * this unless you really have to! */ /* 1 = disable plaintext, 2 = if not SSL */ static long disablePlaintext = NIL; static long list_max_level = 20;/* maximum level of list recursion */ /* default file protection */ static long mbx_protection = 0600; /* default directory protection */ static long dir_protection = 0700; /* default lock file protection */ static long lock_protection = MANDATORYLOCKPROT; /* default ftp file protection */ static long ftp_protection = 0644; static long ftp_dir_protection = 0755; /* default public file protection */ static long public_protection = 0666; static long public_dir_protection = 0777; /* default shared file protection */ static long shared_protection = 0660; static long shared_dir_protection = 0770; static long locktimeout = 5; /* default lock timeout */ /* default prototypes */ static MAILSTREAM *createProto = NIL; static MAILSTREAM *appendProto = NIL; /* default user flags */ static char *userFlags[NUSERFLAGS] = {NIL}; static NAMESPACE *nslist[3]; /* namespace list */ static int logtry = 3; /* number of server login tries */ /* block notification */ static blocknotify_t mailblocknotify = mm_blocknotify; /* Amiga namespaces */ /* personal mh namespace */ static NAMESPACE nsmhf = {"#mh/",'/',NIL,NIL}; static NAMESPACE nsmh = {"#mhinbox",NIL,NIL,&nsmhf}; /* home namespace */ static NAMESPACE nshome = {"",'/',NIL,&nsmh}; /* Amiga other user namespace */ static NAMESPACE nsamigaother = {"~",'/',NIL,NIL}; /* public (anonymous OK) namespace */ static NAMESPACE nspublic = {"#public/",'/',NIL,NIL}; /* netnews namespace */ static NAMESPACE nsnews = {"#news.",'.',NIL,&nspublic}; /* FTP export namespace */ static NAMESPACE nsftp = {"#ftp/",'/',NIL,&nsnews}; /* shared (no anonymous) namespace */ static NAMESPACE nsshared = {"#shared/",'/',NIL,&nsftp}; /* world namespace */ static NAMESPACE nsworld = {"/",'/',NIL,&nsshared}; #include "write.c" /* include safe writing routines */ #include "pmatch.c" /* include wildcard pattern matcher */ /* Get all authenticators */ #include "auths.c" /* Environment manipulate parameters * Accepts: function code * function-dependent value * Returns: function-dependent return value */ void *env_parameters (long function,void *value) { void *ret = NIL; switch ((int) function) { case GET_NAMESPACE: ret = (void *) nslist; break; case SET_USERNAME: if (myUserName) fs_give ((void **) &myUserName); myUserName = cpystr ((char *) value); case GET_USERNAME: ret = (void *) myUserName; break; case SET_HOMEDIR: if (myHomeDir) fs_give ((void **) &myHomeDir); myHomeDir = cpystr ((char *) value); case GET_HOMEDIR: ret = (void *) myHomeDir; break; case SET_LOCALHOST: if (myLocalHost) fs_give ((void **) &myLocalHost); myLocalHost = cpystr ((char *) value); case GET_LOCALHOST: ret = (void *) myLocalHost; break; case SET_NEWSRC: if (myNewsrc) fs_give ((void **) &myNewsrc); myNewsrc = cpystr ((char *) value); case GET_NEWSRC: ret = (void *) myNewsrc; break; case SET_NEWSACTIVE: if (newsActive) fs_give ((void **) &newsActive); newsActive = cpystr ((char *) value); case GET_NEWSACTIVE: ret = (void *) newsActive; break; case SET_NEWSSPOOL: if (newsSpool) fs_give ((void **) &newsSpool); newsSpool = cpystr ((char *) value); case GET_NEWSSPOOL: ret = (void *) newsSpool; break; case SET_ANONYMOUSHOME: if (anonymousHome) fs_give ((void **) &anonymousHome); anonymousHome = cpystr ((char *) value); case GET_ANONYMOUSHOME: if (!anonymousHome) anonymousHome = cpystr (ANONYMOUSHOME); ret = (void *) anonymousHome; break; case SET_FTPHOME: if (ftpHome) fs_give ((void **) &ftpHome); ftpHome = cpystr ((char *) value); case GET_FTPHOME: ret = (void *) ftpHome; break; case SET_PUBLICHOME: if (publicHome) fs_give ((void **) &publicHome); publicHome = cpystr ((char *) value); case GET_PUBLICHOME: ret = (void *) publicHome; break; case SET_SHAREDHOME: if (sharedHome) fs_give ((void **) &sharedHome); sharedHome = cpystr ((char *) value); case GET_SHAREDHOME: ret = (void *) sharedHome; break; case SET_SYSINBOX: if (sysInbox) fs_give ((void **) &sysInbox); sysInbox = cpystr ((char *) value); case GET_SYSINBOX: ret = (void *) sysInbox; break; case SET_LISTMAXLEVEL: list_max_level = (long) value; case GET_LISTMAXLEVEL: ret = (void *) list_max_level; break; case SET_MBXPROTECTION: mbx_protection = (long) value; case GET_MBXPROTECTION: ret = (void *) mbx_protection; break; case SET_DIRPROTECTION: dir_protection = (long) value; case GET_DIRPROTECTION: ret = (void *) dir_protection; break; case SET_LOCKPROTECTION: lock_protection = (long) value; case GET_LOCKPROTECTION: ret = (void *) lock_protection; break; case SET_FTPPROTECTION: ftp_protection = (long) value; case GET_FTPPROTECTION: ret = (void *) ftp_protection; break; case SET_PUBLICPROTECTION: public_protection = (long) value; case GET_PUBLICPROTECTION: ret = (void *) public_protection; break; case SET_SHAREDPROTECTION: shared_protection = (long) value; case GET_SHAREDPROTECTION: ret = (void *) shared_protection; break; case SET_FTPDIRPROTECTION: ftp_dir_protection = (long) value; case GET_FTPDIRPROTECTION: ret = (void *) ftp_dir_protection; break; case SET_PUBLICDIRPROTECTION: public_dir_protection = (long) value; case GET_PUBLICDIRPROTECTION: ret = (void *) public_dir_protection; break; case SET_SHAREDDIRPROTECTION: shared_dir_protection = (long) value; case GET_SHAREDDIRPROTECTION: ret = (void *) shared_dir_protection; break; case SET_LOCKTIMEOUT: locktimeout = (long) value; case GET_LOCKTIMEOUT: ret = (void *) locktimeout; break; case SET_HIDEDOTFILES: hideDotFiles = value ? T : NIL; case GET_HIDEDOTFILES: ret = (void *) (hideDotFiles ? VOIDT : NIL); break; case SET_DISABLEPLAINTEXT: disablePlaintext = (long) value; case GET_DISABLEPLAINTEXT: ret = (void *) disablePlaintext; break; case SET_ADVERTISETHEWORLD: advertisetheworld = value ? T : NIL; case GET_ADVERTISETHEWORLD: ret = (void *) (advertisetheworld ? VOIDT : NIL); break; case SET_DISABLEAUTOSHAREDNS: noautomaticsharedns = value ? T : NIL; case GET_DISABLEAUTOSHAREDNS: ret = (void *) (noautomaticsharedns ? VOIDT : NIL); break; case SET_DISABLE822TZTEXT: no822tztext = value ? T : NIL; case GET_DISABLE822TZTEXT: ret = (void *) (no822tztext ? VOIDT : NIL); break; case SET_USERHASNOLIFE: has_no_life = value ? T : NIL; case GET_USERHASNOLIFE: ret = (void *) (has_no_life ? VOIDT : NIL); break; case SET_NETFSSTATBUG: netfsstatbug = value ? T : NIL; case GET_NETFSSTATBUG: ret = (void *) (netfsstatbug ? VOIDT : NIL); break; case SET_BLOCKENVINIT: block_env_init = value ? T : NIL; case GET_BLOCKENVINIT: ret = (void *) (block_env_init ? VOIDT : NIL); break; case SET_BLOCKNOTIFY: mailblocknotify = (blocknotify_t) value; case GET_BLOCKNOTIFY: ret = (void *) mailblocknotify; break; } return ret; } /* Write current time * Accepts: destination string * optional format of day-of-week prefix * format of date and time * flag whether to append symbolic timezone */ static void do_date (char *date,char *prefix,char *fmt,int suffix) { time_t tn = time (0); struct tm *t = gmtime (&tn); int zone = t->tm_hour * 60 + t->tm_min; int julian = t->tm_yday; t = localtime (&tn); /* get local time now */ /* minus UTC minutes since midnight */ zone = t->tm_hour * 60 + t->tm_min - zone; /* julian can be one of: * 36x local time is December 31, UTC is January 1, offset -24 hours * 1 local time is 1 day ahead of UTC, offset +24 hours * 0 local time is same day as UTC, no offset * -1 local time is 1 day behind UTC, offset -24 hours * -36x local time is January 1, UTC is December 31, offset +24 hours */ if (julian = t->tm_yday -julian) zone += ((julian < 0) == (abs (julian) == 1)) ? -24*60 : 24*60; if (prefix) { /* want day of week? */ sprintf (date,prefix,days[t->tm_wday]); date += strlen (date); /* make next sprintf append */ } /* output the date */ sprintf (date,fmt,t->tm_mday,months[t->tm_mon],t->tm_year+1900, t->tm_hour,t->tm_min,t->tm_sec,zone/60,abs (zone) % 60); /* append timezone suffix if desired */ if (suffix) rfc822_timezone (date,(void *) t); } /* Write current time in RFC 822 format * Accepts: destination string */ void rfc822_date (char *date) { do_date (date,"%s, ","%d %s %d %02d:%02d:%02d %+03d%02d", no822tztext ? NIL : T); } /* Write current time in fixed-width RFC 822 format * Accepts: destination string */ void rfc822_fixed_date (char *date) { do_date (date,NIL,"%02d %s %4d %02d:%02d:%02d %+03d%02d",NIL); } /* Write current time in internal format * Accepts: destination string */ void internal_date (char *date) { do_date (date,NIL,"%02d-%s-%d %02d:%02d:%02d %+03d%02d",NIL); } /* Initialize server * Accepts: server name for syslog or NIL * /etc/services service name or NIL * alternate /etc/services service name or NIL * clock interrupt handler * kiss-of-death interrupt handler * hangup interrupt handler * termination interrupt handler */ void server_init (char *server,char *service,char *sslservice, void *clkint,void *kodint,void *hupint,void *trmint, void *staint) { int onceonly = server && service && sslservice; if (onceonly) { /* set server name in syslog */ int mask; openlog (myServerName = cpystr (server),LOG_PID,syslog_facility); fclose (stderr); /* possibly save a process ID */ switch (mask = umask (022)){/* check old umask */ case 0: /* definitely unreasonable */ case 022: /* don't need to change it */ break; default: /* already was a reasonable value */ umask (mask); /* so change it back */ } } arm_signal (SIGALRM,clkint); /* prepare for clock interrupt */ arm_signal (SIGUSR2,kodint); /* prepare for Kiss Of Death */ arm_signal (SIGHUP,hupint); /* prepare for hangup */ arm_signal (SIGPIPE,hupint); /* alternative hangup */ arm_signal (SIGTERM,trmint); /* prepare for termination */ /* status dump */ if (staint) arm_signal (SIGUSR1,staint); if (onceonly) { /* set up network and maybe SSL */ long port; struct servent *sv; /* Use SSL if SSL service, or if server starts with "s" and not service */ if (((port = tcp_serverport ()) >= 0)) { if ((sv = getservbyname (service,"tcp")) && (port == ntohs (sv->s_port))) syslog (LOG_DEBUG,"%s service init from %s",service,tcp_clientaddr ()); else if ((sv = getservbyname (sslservice,"tcp")) && (port == ntohs (sv->s_port))) { syslog (LOG_DEBUG,"%s SSL service init from %s",sslservice, tcp_clientaddr ()); ssl_server_init (server); } else { /* not service or SSL service port */ syslog (LOG_DEBUG,"port %ld service init from %s",port, tcp_clientaddr ()); if (*server == 's') ssl_server_init (server); } } } } /* Wait for stdin input * Accepts: timeout in seconds * Returns: T if have input on stdin, else NIL */ long server_input_wait (long seconds) { fd_set rfd,efd; struct timeval tmo; FD_ZERO (&rfd); FD_ZERO (&efd); FD_SET (0,&rfd); FD_SET (0,&efd); tmo.tv_sec = seconds; tmo.tv_usec = 0; return select (1,&rfd,0,&efd,&tmo) ? LONGT : NIL; } /* Return Amiga password entry for user name * Accepts: user name string * Returns: password entry * * Tries all-lowercase form of user name if given user name fails */ static struct passwd *pwuser (unsigned char *user) { unsigned char *s; struct passwd *pw = getpwnam (user); if (!pw) { /* failed, see if any uppercase characters */ for (s = user; *s && ((*s < 'A') || (*s > 'Z')); s++); if (*s) { /* yes, try all lowercase form */ pw = getpwnam (s = lcase (cpystr (user))); fs_give ((void **) &s); } } return pw; } /* Validate password for user name * Accepts: user name string * password string * argument count * argument vector * Returns: password entry if validated * * Tries password+1 if password fails and starts with space */ static struct passwd *valpwd (char *user,char *pwd,int argc,char *argv[]) { char *s; struct passwd *pw; struct passwd *ret = NIL; if (auth_md5.server) { /* using CRAM-MD5 authentication? */ if (s = auth_md5_pwd (user)) { if (!strcmp (s,pwd) || ((*pwd == ' ') && pwd[1] && !strcmp (s,pwd+1))) ret = pwuser (user); /* validated, get passwd entry for user */ memset (s,0,strlen (s)); /* erase sensitive information */ fs_give ((void **) &s); } } else if (pw = pwuser (user)) {/* can get user? */ s = cpystr (pw->pw_name); /* copy returned name in case we need it */ if (*pwd && !(ret = checkpw (pw,pwd,argc,argv)) && (*pwd == ' ') && pwd[1] && (ret = pwuser (s))) ret = checkpw (pw,pwd+1,argc,argv); fs_give ((void **) &s); /* don't need copy of name any more */ } return ret; } /* Server log in * Accepts: user name string * password string * authenticating user name string * argument count * argument vector * Returns: T if password validated, NIL otherwise */ long server_login (char *user,char *pwd,char *authuser,int argc,char *argv[]) { struct passwd *pw = NIL; int level = LOG_NOTICE; char *err = "failed"; /* cretins still haven't given up */ if ((strlen (user) >= NETMAXUSER) || (authuser && (strlen (authuser) >= NETMAXUSER))) { level = LOG_ALERT; /* escalate this alert */ err = "SYSTEM BREAK-IN ATTEMPT"; logtry = 0; /* render this session useless */ } else if (logtry-- <= 0) err = "excessive login failures"; else if (disablePlaintext) err = "disabled"; else if (!(authuser && *authuser)) pw = valpwd (user,pwd,argc,argv); else if (valpwd (authuser,pwd,argc,argv)) pw = pwuser (user); if (pw && pw_login (pw,authuser,pw->pw_name,NIL,argc,argv)) return T; syslog (level|LOG_AUTH,"Login %s user=%.64s auth=%.64s host=%.80s",err, user,(authuser && *authuser) ? authuser : user,tcp_clienthost ()); sleep (3); /* slow down possible cracker */ return NIL; } /* Authenticated server log in * Accepts: user name string * authenticating user name string * argument count * argument vector * Returns: T if password validated, NIL otherwise */ long authserver_login (char *user,char *authuser,int argc,char *argv[]) { return pw_login (pwuser (user),authuser,user,NIL,argc,argv); } /* Log in as anonymous daemon * Accepts: argument count * argument vector * Returns: T if successful, NIL if error */ long anonymous_login (int argc,char *argv[]) { /* log in Mr. A. N. Onymous */ return pw_login (getpwnam (ANONYMOUSUSER),NIL,NIL, (char *) mail_parameters (NIL,GET_ANONYMOUSHOME,NIL), argc,argv); } /* Finish log in and environment initialization * Accepts: passwd struct for loginpw() * optional authentication user name * user name (NIL for anonymous) * home directory (NIL to use directory from passwd struct) * argument count * argument vector * Returns: T if successful, NIL if error */ long pw_login (struct passwd *pw,char *auser,char *user,char *home,int argc, char *argv[]) { struct group *gr; char **t; long ret = NIL; if (pw && pw->pw_uid) { /* must have passwd struct for non-UID 0 */ /* make safe copies of user and home */ if (user) user = cpystr (pw->pw_name); home = cpystr (home ? home : pw->pw_dir); /* authorization ID .NE. authentication ID? */ if (user && auser && *auser && compare_cstring (auser,user)) { /* scan list of mail administrators */ if ((gr = getgrnam (ADMINGROUP)) && (t = gr->gr_mem)) while (*t && !ret) if (!compare_cstring (auser,*t++)) ret = pw_login (pw,NIL,user,home,argc,argv); syslog (LOG_NOTICE|LOG_AUTH,"%s %.80s override of user=%.80s host=%.80s", ret ? "Admin" : "Failed",auser,user,tcp_clienthost ()); } /* normal login */ else if (((pw->pw_uid == geteuid ()) || loginpw (pw,argc,argv)) && (ret = env_init (user,home))) chdir (myhomedir ()); fs_give ((void **) &home); /* clean up */ if (user) fs_give ((void **) &user); } return ret; /* return status */ } /* Initialize environment * Accepts: user name (NIL for anonymous) * home directory name * Returns: T, always */ long env_init (char *user,char *home) { extern MAILSTREAM CREATEPROTO; extern MAILSTREAM EMPTYPROTO; struct passwd *pw; struct stat sbuf; char tmp[MAILTMPLEN]; /* don't init if blocked */ if (block_env_init) return LONGT; if (myUserName) fatal ("env_init called twice!"); /* set up user name */ myUserName = cpystr (user ? user : ANONYMOUSUSER); if (user) { /* remember user name and home directory */ nslist[0] = &nshome; /* home namespace */ nslist[1] = &nsamigaother; nslist[2] = advertisetheworld ? &nsworld : &nsshared; } else { /* anonymous user */ nslist[0] = nslist[1] = NIL,nslist[2] = &nsftp; sprintf (tmp,"%s/INBOX", home = (char *) mail_parameters (NIL,GET_ANONYMOUSHOME,NIL)); sysInbox = cpystr (tmp); /* make system INBOX */ anonymous = T; /* flag as anonymous */ } myHomeDir = cpystr (home); /* set home directory */ if (!noautomaticsharedns) { /* #ftp namespace */ if (!ftpHome && (pw = getpwnam ("ftp"))) ftpHome = cpystr (pw->pw_dir); /* #public namespace */ if (!publicHome && (pw = getpwnam ("imappublic"))) publicHome = cpystr (pw->pw_dir); /* #shared namespace */ if (!anonymous && !sharedHome && (pw = getpwnam ("imapshared"))) sharedHome = cpystr (pw->pw_dir); } if (!myLocalHost) mylocalhost (); if (!myNewsrc) myNewsrc = cpystr(strcat (strcpy (tmp,myHomeDir),"/.newsrc")); if (!newsActive) newsActive = cpystr (ACTIVEFILE); if (!newsSpool) newsSpool = cpystr (NEWSSPOOL); /* force default prototype to be set */ if (!createProto) createProto = &CREATEPROTO; if (!appendProto) appendProto = &EMPTYPROTO; /* re-do open action to get flags */ (*createProto->dtb->open) (NIL); endpwent (); /* close pw database */ return T; } /* Return my user name * Accepts: pointer to optional flags * Returns: my user name */ char *myusername_full (unsigned long *flags) { struct passwd *pw; struct stat sbuf; char *s; unsigned long euid; char *ret = UNLOGGEDUSER; /* no user name yet and not root? */ if (!myUserName && (euid = geteuid ())) { /* yes, look up getlogin() user name or EUID */ if (((s = (char *) getlogin ()) && *s && (strlen (s) < NETMAXUSER) && (pw = getpwnam (s)) && (pw->pw_uid == euid)) || (pw = getpwuid (euid))) { if (block_env_init) { /* don't env_init if blocked */ if (flags) *flags = MU_LOGGEDIN; return pw->pw_name; } env_init (pw->pw_name, ((s = getenv ("HOME")) && *s && (strlen (s) < NETMAXMBX) && !stat (s,&sbuf) && ((sbuf.st_mode & S_IFMT) == S_IFDIR)) ? s : pw->pw_dir); } else fatal ("Unable to look up user name"); } if (myUserName) { /* logged in? */ if (flags) *flags = anonymous ? MU_ANONYMOUS : MU_LOGGEDIN; ret = myUserName; /* return user name */ } else if (flags) *flags = MU_NOTLOGGEDIN; return ret; } /* Return my local host name * Returns: my local host name */ char *mylocalhost () { char tmp[MAILTMPLEN]; struct hostent *host_name; if (!myLocalHost) myLocalHost = cpystr (gethostname (tmp,MAILTMPLEN-1) ? "random-pc" : tcp_canonical (tmp)); return myLocalHost; } /* Return my home directory name * Returns: my home directory name */ char *myhomedir () { if (!myHomeDir) myusername ();/* initialize if first time */ return myHomeDir ? myHomeDir : ""; } /* Return my home mailbox name * Returns: my home directory name */ static char *mymailboxdir () { char *home = myhomedir (); if (!myMailboxDir && home) { /* initialize if first time */ if (mailsubdir) { char tmp[MAILTMPLEN]; sprintf (tmp,"%s/%s",home,mailsubdir); myMailboxDir = cpystr (tmp);/* use pre-defined subdirectory of home */ } else myMailboxDir = cpystr (home); } return myMailboxDir ? myMailboxDir : ""; } /* Return system standard INBOX * Accepts: buffer string */ char *sysinbox () { char tmp[MAILTMPLEN]; if (!sysInbox) { /* initialize if first time */ sprintf (tmp,"%s/%s",MAILSPOOL,myusername ()); sysInbox = cpystr (tmp); /* system inbox is from mail spool */ } return sysInbox; } /* Return mailbox directory name * Accepts: destination buffer * directory prefix * name in directory * Returns: file name or NIL if error */ char *mailboxdir (char *dst,char *dir,char *name) { char tmp[MAILTMPLEN]; if (dir || name) { /* if either argument provided */ if (dir) { if (strlen (dir) > NETMAXMBX) return NIL; strcpy (tmp,dir); /* write directory prefix */ } else tmp[0] = '\0'; /* otherwise null string */ if (name) { if (strlen (name) > NETMAXMBX) return NIL; strcat (tmp,name); /* write name in directory */ } /* validate name, return its name */ if (!mailboxfile (dst,tmp)) return NIL; } /* no arguments, wants mailbox directory */ else strcpy (dst,mymailboxdir ()); return dst; /* return the name */ } /* Return mailbox file name * Accepts: destination buffer * mailbox name * Returns: file name or empty string for driver-selected INBOX or NIL if error */ char *mailboxfile (char *dst,char *name) { struct passwd *pw; char *s; if (!name || !*name || (*name == '{') || (strlen (name) > NETMAXMBX) || ((anonymous || restrictBox || (*name == '#')) && (strstr (name,"..") || strstr (name,"//") || strstr (name,"/~")))) dst = NIL; /* invalid name */ else switch (*name) { /* determine mailbox type based upon name */ case '#': /* namespace name */ /* #ftp/ namespace */ if (((name[1] == 'f') || (name[1] == 'F')) && ((name[2] == 't') || (name[2] == 'T')) && ((name[3] == 'p') || (name[3] == 'P')) && (name[4] == '/') && ftpHome) sprintf (dst,"%s/%s",ftpHome,name+5); /* #public/ and #shared/ namespaces */ else if ((((name[1] == 'p') || (name[1] == 'P')) && ((name[2] == 'u') || (name[2] == 'U')) && ((name[3] == 'b') || (name[3] == 'B')) && ((name[4] == 'l') || (name[4] == 'L')) && ((name[5] == 'i') || (name[5] == 'I')) && ((name[6] == 'c') || (name[6] == 'C')) && (name[7] == '/') && (s = publicHome)) || (!anonymous && ((name[1] == 's') || (name[1] == 'S')) && ((name[2] == 'h') || (name[2] == 'H')) && ((name[3] == 'a') || (name[3] == 'A')) && ((name[4] == 'r') || (name[4] == 'R')) && ((name[5] == 'e') || (name[5] == 'E')) && ((name[6] == 'd') || (name[6] == 'D')) && (name[7] == '/') && (s = sharedHome))) sprintf (dst,"%s/%s",s,compare_cstring (name,"INBOX") ? name : "INBOX"); else dst = NIL; /* unknown namespace */ break; case '/': /* root access */ if (anonymous) dst = NIL; /* anonymous forbidden to do this */ else if ((restrictBox & RESTRICTROOT) && strcmp (name,sysinbox ())) dst = NIL; /* restricted and not access to sysinbox */ else strcpy (dst,name); /* unrestricted, copy root name */ break; case '~': /* other user access */ /* bad syntax or anonymous can't win */ if (!*++name || anonymous) dst = NIL; /* ~/ equivalent to ordinary name */ else if (*name == '/') sprintf (dst,"%s/%s",mymailboxdir (),name+1); /* other user forbidden if restricted */ else if (restrictBox & RESTRICTOTHERUSER) dst = NIL; else { /* clear box other user */ /* copy user name */ for (s = dst; *name && (*name != '/'); *s++ = *name++); *s++ = '\0'; /* tie off user name, look up in passwd file */ if ((pw = getpwnam (dst)) && pw->pw_dir) { if (*name) name++; /* skip past the slash */ /* canonicalize case of INBOX */ if (!compare_cstring (name,"INBOX")) name = "INBOX"; /* remove trailing / from directory */ if ((s = strrchr (pw->pw_dir,'/')) && !s[1]) *s = '\0'; /* don't allow ~root/ if restricted root */ if ((restrictBox & RESTRICTROOT) && !*pw->pw_dir) dst = NIL; /* build final name w/ subdir if needed */ else if (mailsubdir) sprintf (dst,"%s/%s/%s",pw->pw_dir,mailsubdir,name); else sprintf (dst,"%s/%s",pw->pw_dir,name); } else dst = NIL; /* no such user */ } break; case 'I': case 'i': /* possible INBOX */ if (!compare_cstring (name+1,"NBOX")) { /* if anonymous, use INBOX in mailbox dir */ if (anonymous) sprintf (dst,"%s/INBOX",mymailboxdir ()); else *dst = '\0'; /* otherwise driver selects the name */ break; } /* drop into to ordinary name case */ default: /* ordinary name is easy */ sprintf (dst,"%s/%s",mymailboxdir (),name); break; } return dst; /* return final name */ } /* Dot-lock file locker * Accepts: file name to lock * destination buffer for lock file name * open file description on file name to lock * Returns: T if success, NIL if failure */ long dotlock_lock (char *file,DOTLOCK *base,int fd) { int i = locktimeout * 60; int j,mask,retry,pi[2],po[2]; char *s,tmp[MAILTMPLEN]; struct stat sb; /* flush absurd file name */ if (strlen (file) > 512) return NIL; /* build lock filename */ sprintf (base->lock,"%s.lock",file); /* assume no pipe */ base->pipei = base->pipeo = -1; do { /* make sure not symlink */ if (!(j = chk_notsymlink (base->lock,&sb))) return NIL; /* time out if file older than 5 minutes */ if ((j > 0) && ((time (0)) >= (sb.st_ctime + locktimeout * 60))) i = 0; /* try to create the lock */ if ((j = open (name,O_WRONLY|O_CREAT|O_EXCL,(int) lock_protection)) >= 0) { close (i); /* make the file, now close it */ chmod (base->lock,(int) lock_protection); return LONGT; } if (errno == EEXIST) { /* already locked? */ retry = -1; /* can try again */ if (!(i%15)) { /* time to notify? */ sprintf (tmp,"Mailbox %.80s is locked, will override in %d seconds...", file,i); mm_log (tmp,WARN); } sleep (1); /* wait 1 second before next try */ } else retry = i = 0; /* hard failure, no more retries */ } while (i--); /* until out of retries */ if (retry < 0) { /* still returning retry after locktimeout? */ if (!(j = chk_notsymlink (base->lock,&sb))) return NIL; if ((j > 0) && ((time (0)) < (sb.st_ctime + locktimeout * 60))) { sprintf (tmp,"Mailbox vulnerable - seizing %ld second old lock", (long) (time (0) - sb.st_ctime)); mm_log (tmp,WARN); } mask = umask (0); unlink (base->lock); /* try to remove the old file */ /* seize the lock */ if ((i = open (base->lock,O_WRONLY|O_CREAT,(int) lock_protection)) >= 0) { close (i); /* don't need descriptor any more */ sprintf (tmp,"Mailbox %.80s lock overridden",file); mm_log (tmp,NIL); chmod (base->lock,(int) lock_protection); umask (mask) /* restore old umask */ return LONGT; } umask (mask) /* restore old umask */ } if (fd >= 0) switch (errno) { case EACCES: /* protection failure? */ /* make command pipes */ if (!stat (LOCKPGM,&sb) && (pipe (pi) >= 0)) { /* if input pipes usable create output pipes */ if ((pi[0] < FD_SETSIZE) && (pi[1] < FD_SETSIZE) && (pipe (po) >= 0)) { /* make sure output pipes are usable */ if ((po[0] >= FD_SETSIZE) || (po[1] >= FD_SETSIZE)); /* all is good, make inferior process */ else if (!(j = fork ())) { if (!fork ()) { /* make grandchild so it's inherited by init */ long cf; /* don't change caller vars in case vfork() */ char *argv[4],arg[20]; /* prepare argument vector */ sprintf (arg,"%d",fd); argv[0] = LOCKPGM; argv[1] = arg; argv[2] = file; argv[3] = NIL; /* set parent's I/O to my O/I */ dup2 (pi[1],1); dup2 (pi[1],2); dup2 (po[0],0); /* close all unnecessary descriptors */ for (cf = max (20,max (max (pi[0],pi[1]),max(po[0],po[1]))); cf >= 3; --cf) if (cf != fd) close (cf); /* be our own process group */ setpgrp (0,getpid ()); /* now run it */ _exit (execv (argv[0],argv)); } _exit (1); /* child is done */ } else if (j > 0) { /* parent process */ fd_set rfd; struct timeval tmo; FD_ZERO (&rfd); FD_SET (pi[0],&rfd); tmo.tv_sec = locktimeout * 60; grim_pid_reap (j,NIL);/* reap child; grandchild now owned by init */ /* read response from locking program */ if (select (pi[0]+1,&rfd,0,0,&tmo) && (read (pi[0],tmp,1) == 1) && (tmp[0] == '+')) { /* success, record pipes */ base->pipei = pi[0]; base->pipeo = po[1]; /* close child's side of the pipes */ close (pi[1]); close (po[0]); return LONGT; } } close (po[0]); close (po[1]); } close (pi[0]); close (pi[1]); } /* find directory/file delimiter */ if (s = strrchr (base->lock,'/')) { *s = '\0'; /* tie off at directory */ sprintf(tmp, /* generate default message */ "Mailbox vulnerable - directory %.80s must have 1777 protection", base->lock); /* definitely not 1777 if can't stat */ mask = stat (base->lock,&sb) ? 0 : (sb.st_mode & 1777); *s = '/'; /* restore lock name */ if (mask != 1777) { /* default warning if not 1777 */ MM_LOG (tmp,WARN); break; } } default: sprintf (tmp,"Mailbox vulnerable - error creating %.80s: %s", base->lock,strerror (errno)); mm_log (tmp,WARN); /* this is probably not good */ break; } base->lock[0] = '\0'; /* don't use lock files */ return NIL; } /* Dot-lock file unlocker * Accepts: lock file name * Returns: T if success, NIL if failure */ long dotlock_unlock (DOTLOCK *base) { long ret = LONGT; if (base && base->lock[0]) { if (base->pipei >= 0) { /* if running through a pipe unlocker */ ret = (write (base->pipeo,"+",1) == 1); /* nuke the pipes */ close (base->pipei); close (base->pipeo); } else ret = !unlink (base->lock); } return ret; } /* Lock file name * Accepts: scratch buffer * file name * type of locking operation (LOCK_SH or LOCK_EX) * pointer to return PID of locker * Returns: file descriptor of lock or negative if error */ int lockname (char *lock,char *fname,int op,long *pid) { struct stat sbuf; *pid = 0; /* no locker PID */ return stat (fname,&sbuf) ? -1 : lock_work (lock,&sbuf,op,pid); } /* Lock file descriptor * Accepts: file descriptor * lock file name buffer * type of locking operation (LOCK_SH or LOCK_EX) * Returns: file descriptor of lock or negative if error */ int lockfd (int fd,char *lock,int op) { struct stat sbuf; return fstat (fd,&sbuf) ? -1 : lock_work (lock,&sbuf,op,NIL); } /* Lock file name worker * Accepts: lock file name * pointer to stat() buffer * type of locking operation (LOCK_SH or LOCK_EX) * pointer to return PID of locker * Returns: file descriptor of lock or negative if error */ int lock_work (char *lock,void *sb,int op,long *pid) { struct stat lsb,fsb; struct stat *sbuf = (struct stat *) sb; char tmp[MAILTMPLEN]; long i; int fd; int mask = umask (0); if (pid) *pid = 0; /* initialize return PID */ /* make temporary lock file name */ sprintf (lock,"%s/.%lx.%lx","/tmp", (unsigned long) sbuf->st_dev,(unsigned long) sbuf->st_ino); while (T) { /* until get a good lock */ do switch ((int) chk_notsymlink (lock,&lsb)) { case 1: /* exists just once */ if (((fd = open (lock,O_RDWR,lock_protection)) >= 0) || (errno != ENOENT) || (chk_notsymlink (lock,&lsb) >= 0)) break; case -1: /* name doesn't exist */ fd = open (lock,O_RDWR|O_CREAT|O_EXCL,lock_protection); break; default: /* multiple hard links */ mm_log ("hard link to lock name",ERROR); syslog (LOG_CRIT,"SECURITY PROBLEM: hard link to lock name: %.80s",lock); case 0: /* symlink (already did syslog) */ umask (mask); /* restore old mask */ return -1; /* fail: no lock file */ } while ((fd < 0) && (errno == EEXIST)); if (fd < 0) { /* failed to get file descriptor */ syslog (LOG_INFO,"Mailbox lock file %s open failure: %s",lock, strerror (errno)); if (stat ("/tmp",&lsb)) syslog (LOG_CRIT,"SYSTEM ERROR: no /tmp: %s",strerror (errno)); else if ((lsb.st_mode & 01777) != 01777) mm_log ("Can't lock for write: /tmp must have 1777 protection",WARN); umask (mask); /* restore old mask */ return -1; /* fail: can't open lock file */ } /* non-blocking form */ if (op & LOCK_NB) i = flock (fd,op); else { /* blocking form */ (*mailblocknotify) (BLOCK_FILELOCK,NIL); i = flock (fd,op); (*mailblocknotify) (BLOCK_NONE,NIL); } if (i) { /* failed, get other process' PID */ if (pid && !fstat (fd,&fsb) && (i = min (fsb.st_size,MAILTMPLEN-1)) && (read (fd,tmp,i) == i) && !(tmp[i] = 0) && ((i = atol (tmp)) > 0)) *pid = i; close (fd); /* failed, give up on lock */ umask (mask); /* restore old mask */ return -1; /* fail: can't lock */ } /* make sure this lock is good for us */ if (!lstat (lock,&lsb) && ((lsb.st_mode & S_IFMT) != S_IFLNK) && !fstat (fd,&fsb) && (lsb.st_dev == fsb.st_dev) && (lsb.st_ino == fsb.st_ino) && (fsb.st_nlink == 1)) break; close (fd); /* lock not right, drop fd and try again */ } /* make sure mode OK (don't use fchmod()) */ chmod (lock,(int) lock_protection); umask (mask); /* restore old mask */ return fd; /* success */ } /* Check to make sure not a symlink * Accepts: file name * stat buffer * Returns: -1 if doesn't exist, NIL if symlink, else number of hard links */ long chk_notsymlink (char *name,void *sb) { struct stat *sbuf = (struct stat *) sb; /* name exists? */ if (lstat (name,sbuf)) return -1; /* forbid symbolic link */ if ((sbuf->st_mode & S_IFMT) == S_IFLNK) { mm_log ("symbolic link on lock name",ERROR); syslog (LOG_CRIT,"SECURITY PROBLEM: symbolic link on lock name: %.80s", name); return NIL; } return (long) sbuf->st_nlink; /* return number of hard links */ } /* Unlock file descriptor * Accepts: file descriptor * lock file name from lockfd() */ void unlockfd (int fd,char *lock) { /* delete the file if no sharers */ if (!flock (fd,LOCK_EX|LOCK_NB)) unlink (lock); flock (fd,LOCK_UN); /* unlock it */ close (fd); /* close it */ } /* Set proper file protection for mailbox * Accepts: mailbox name * actual file path name * Returns: T, always */ long set_mbx_protections (char *mailbox,char *path) { struct stat sbuf; int mode = (int) mbx_protection; if (*mailbox == '#') { /* possible namespace? */ if (((mailbox[1] == 'f') || (mailbox[1] == 'F')) && ((mailbox[2] == 't') || (mailbox[2] == 'T')) && ((mailbox[3] == 'p') || (mailbox[3] == 'P')) && (mailbox[4] == '/')) mode = (int) ftp_protection; else if (((mailbox[1] == 'p') || (mailbox[1] == 'P')) && ((mailbox[2] == 'u') || (mailbox[2] == 'U')) && ((mailbox[3] == 'b') || (mailbox[3] == 'B')) && ((mailbox[4] == 'l') || (mailbox[4] == 'L')) && ((mailbox[5] == 'i') || (mailbox[5] == 'I')) && ((mailbox[6] == 'c') || (mailbox[6] == 'C')) && (mailbox[7] == '/')) mode = (int) public_protection; else if (((mailbox[1] == 's') || (mailbox[1] == 'S')) && ((mailbox[2] == 'h') || (mailbox[2] == 'H')) && ((mailbox[3] == 'a') || (mailbox[3] == 'A')) && ((mailbox[4] == 'r') || (mailbox[4] == 'R')) && ((mailbox[5] == 'e') || (mailbox[5] == 'E')) && ((mailbox[6] == 'd') || (mailbox[6] == 'D')) && (mailbox[7] == '/')) mode = (int) shared_protection; } /* if a directory */ if (!stat (path,&sbuf) && ((sbuf.st_mode & S_IFMT) == S_IFDIR)) { /* set owner search if allow read or write */ if (mode & 0600) mode |= 0100; if (mode & 060) mode |= 010;/* set group search if allow read or write */ if (mode & 06) mode |= 01; /* set world search if allow read or write */ /* preserve directory SGID bit */ if (sbuf.st_mode & S_ISGID) mode |= S_ISGID; } chmod (path,mode); /* set the new protection, ignore failure */ return LONGT; } /* Get proper directory protection * Accepts: mailbox name * Returns: directory mode, always */ long get_dir_protection (char *mailbox) { if (*mailbox == '#') { /* possible namespace? */ if (((mailbox[1] == 'f') || (mailbox[1] == 'F')) && ((mailbox[2] == 't') || (mailbox[2] == 'T')) && ((mailbox[3] == 'p') || (mailbox[3] == 'P')) && (mailbox[4] == '/')) return ftp_dir_protection; else if (((mailbox[1] == 'p') || (mailbox[1] == 'P')) && ((mailbox[2] == 'u') || (mailbox[2] == 'U')) && ((mailbox[3] == 'b') || (mailbox[3] == 'B')) && ((mailbox[4] == 'l') || (mailbox[4] == 'L')) && ((mailbox[5] == 'i') || (mailbox[5] == 'I')) && ((mailbox[6] == 'c') || (mailbox[6] == 'C')) && (mailbox[7] == '/')) return public_dir_protection; else if (((mailbox[1] == 's') || (mailbox[1] == 'S')) && ((mailbox[2] == 'h') || (mailbox[2] == 'H')) && ((mailbox[3] == 'a') || (mailbox[3] == 'A')) && ((mailbox[4] == 'r') || (mailbox[4] == 'R')) && ((mailbox[5] == 'e') || (mailbox[5] == 'E')) && ((mailbox[6] == 'd') || (mailbox[6] == 'D')) && (mailbox[7] == '/')) return shared_dir_protection; } return dir_protection; } /* Determine default prototype stream to user * Accepts: type (NIL for create, T for append) * Returns: default prototype stream */ MAILSTREAM *default_proto (long type) { myusername (); /* make sure initialized */ /* return default driver's prototype */ return type ? appendProto : createProto; } /* Set up user flags for stream * Accepts: MAIL stream * Returns: MAIL stream with user flags set up */ MAILSTREAM *user_flags (MAILSTREAM *stream) { int i; myusername (); /* make sure initialized */ for (i = 0; i < NUSERFLAGS && userFlags[i]; ++i) if (!stream->user_flags[i]) stream->user_flags[i] = cpystr (userFlags[i]); return stream; } /* Return nth user flag * Accepts: user flag number * Returns: flag */ char *default_user_flag (unsigned long i) { myusername (); /* make sure initialized */ return userFlags[i]; } /* Default block notify routine * Accepts: reason for calling * data * Returns: data */ void *mm_blocknotify (int reason,void *data) { void *ret = data; switch (reason) { case BLOCK_SENSITIVE: /* entering sensitive code */ ret = (void *) alarm (0); break; case BLOCK_NONSENSITIVE: /* exiting sensitive code */ if ((unsigned int) data) alarm ((unsigned int) data); break; default: /* ignore all other reasons */ break; } return ret; } alpine-2.10+dfsg/imap/src/osdep/amiga/unix.c0000600000175000017500000027174311512502124022406 0ustar paulproteuspaulproteus/* ======================================================================== * Copyright 1988-2008 University of Washington * * Licensed under the Apache License, Version 2.0 (the "License"); * you may not use this file except in compliance with the License. * You may obtain a copy of the License at * * http://www.apache.org/licenses/LICENSE-2.0 * * * ======================================================================== */ /* * Program: UNIX mail routines * * Author: Mark Crispin * UW Technology * University of Washington * Seattle, WA 98195 * Internet: MRC@Washington.EDU * * Date: 20 December 1989 * Last Edited: 27 March 2008 */ /* DEDICATION * * This file is dedicated to my dog, Unix, also known as Yun-chan and * Unix J. Terwilliker Jehosophat Aloysius Monstrosity Animal Beast. Unix * passed away at the age of 11 1/2 on September 14, 1996, 12:18 PM PDT, after * a two-month bout with cirrhosis of the liver. * * He was a dear friend, and I miss him terribly. * * Lift a leg, Yunie. Luv ya forever!!!! */ #include #include #include extern int errno; /* just in case */ #include #include "mail.h" #include "osdep.h" #include #include #include "unix.h" #include "pseudo.h" #include "fdstring.h" #include "misc.h" #include "dummy.h" /* UNIX I/O stream local data */ typedef struct unix_local { unsigned int dirty : 1; /* disk copy needs updating */ unsigned int ddirty : 1; /* double-dirty, ping becomes checkpoint */ unsigned int pseudo : 1; /* uses a pseudo message */ unsigned int appending : 1; /* don't mark new messages as old */ int fd; /* mailbox file descriptor */ int ld; /* lock file descriptor */ char *lname; /* lock file name */ off_t filesize; /* file size parsed */ time_t filetime; /* last file time */ time_t lastsnarf; /* last snarf time (for mbox driver) */ unsigned char *buf; /* temporary buffer */ unsigned long buflen; /* current size of temporary buffer */ unsigned long uid; /* current text uid */ SIZEDTEXT text; /* current text */ unsigned long textlen; /* current text length */ char *line; /* returned line */ char *linebuf; /* line readin buffer */ unsigned long linebuflen; /* current line readin buffer length */ } UNIXLOCAL; /* Convenient access to local data */ #define LOCAL ((UNIXLOCAL *) stream->local) /* UNIX protected file structure */ typedef struct unix_file { MAILSTREAM *stream; /* current stream */ off_t curpos; /* current file position */ off_t protect; /* protected position */ off_t filepos; /* current last written file position */ char *buf; /* overflow buffer */ size_t buflen; /* current overflow buffer length */ char *bufpos; /* current buffer position */ } UNIXFILE; /* Function prototypes */ DRIVER *unix_valid (char *name); long unix_isvalid_fd (int fd); void *unix_parameters (long function,void *value); void unix_scan (MAILSTREAM *stream,char *ref,char *pat,char *contents); void unix_list (MAILSTREAM *stream,char *ref,char *pat); void unix_lsub (MAILSTREAM *stream,char *ref,char *pat); long unix_create (MAILSTREAM *stream,char *mailbox); long unix_delete (MAILSTREAM *stream,char *mailbox); long unix_rename (MAILSTREAM *stream,char *old,char *newname); MAILSTREAM *unix_open (MAILSTREAM *stream); void unix_close (MAILSTREAM *stream,long options); char *unix_header (MAILSTREAM *stream,unsigned long msgno, unsigned long *length,long flags); long unix_text (MAILSTREAM *stream,unsigned long msgno,STRING *bs,long flags); char *unix_text_work (MAILSTREAM *stream,MESSAGECACHE *elt, unsigned long *length,long flags); void unix_flagmsg (MAILSTREAM *stream,MESSAGECACHE *elt); long unix_ping (MAILSTREAM *stream); void unix_check (MAILSTREAM *stream); long unix_expunge (MAILSTREAM *stream,char *sequence,long options); long unix_copy (MAILSTREAM *stream,char *sequence,char *mailbox,long options); long unix_append (MAILSTREAM *stream,char *mailbox,append_t af,void *data); int unix_collect_msg (MAILSTREAM *stream,FILE *sf,char *flags,char *date, STRING *msg); int unix_append_msgs (MAILSTREAM *stream,FILE *sf,FILE *df,SEARCHSET *set); void unix_abort (MAILSTREAM *stream); char *unix_file (char *dst,char *name); int unix_lock (char *file,int flags,int mode,DOTLOCK *lock,int op); void unix_unlock (int fd,MAILSTREAM *stream,DOTLOCK *lock); int unix_parse (MAILSTREAM *stream,DOTLOCK *lock,int op); char *unix_mbxline (MAILSTREAM *stream,STRING *bs,unsigned long *size); unsigned long unix_pseudo (MAILSTREAM *stream,char *hdr); unsigned long unix_xstatus (MAILSTREAM *stream,char *status,MESSAGECACHE *elt, unsigned long uid,long flag); long unix_rewrite (MAILSTREAM *stream,unsigned long *nexp,DOTLOCK *lock, long flags); long unix_extend (MAILSTREAM *stream,unsigned long size); void unix_write (UNIXFILE *f,char *s,unsigned long i); void unix_phys_write (UNIXFILE *f,char *buf,size_t size); /* mbox mail routines */ /* Function prototypes */ DRIVER *mbox_valid (char *name); long mbox_create (MAILSTREAM *stream,char *mailbox); long mbox_delete (MAILSTREAM *stream,char *mailbox); long mbox_rename (MAILSTREAM *stream,char *old,char *newname); long mbox_status (MAILSTREAM *stream,char *mbx,long flags); MAILSTREAM *mbox_open (MAILSTREAM *stream); long mbox_ping (MAILSTREAM *stream); void mbox_check (MAILSTREAM *stream); long mbox_expunge (MAILSTREAM *stream,char *sequence,long options); long mbox_append (MAILSTREAM *stream,char *mailbox,append_t af,void *data); /* UNIX mail routines */ /* Driver dispatch used by MAIL */ DRIVER unixdriver = { "unix", /* driver name */ /* driver flags */ DR_LOCAL|DR_MAIL|DR_LOCKING|DR_NONEWMAILRONLY|DR_XPOINT, (DRIVER *) NIL, /* next driver */ unix_valid, /* mailbox is valid for us */ unix_parameters, /* manipulate parameters */ unix_scan, /* scan mailboxes */ unix_list, /* list mailboxes */ unix_lsub, /* list subscribed mailboxes */ NIL, /* subscribe to mailbox */ NIL, /* unsubscribe from mailbox */ unix_create, /* create mailbox */ unix_delete, /* delete mailbox */ unix_rename, /* rename mailbox */ mail_status_default, /* status of mailbox */ unix_open, /* open mailbox */ unix_close, /* close mailbox */ NIL, /* fetch message "fast" attributes */ NIL, /* fetch message flags */ NIL, /* fetch overview */ NIL, /* fetch message envelopes */ unix_header, /* fetch message header */ unix_text, /* fetch message text */ NIL, /* fetch partial message text */ NIL, /* unique identifier */ NIL, /* message number */ NIL, /* modify flags */ unix_flagmsg, /* per-message modify flags */ NIL, /* search for message based on criteria */ NIL, /* sort messages */ NIL, /* thread messages */ unix_ping, /* ping mailbox to see if still alive */ unix_check, /* check for new messages */ unix_expunge, /* expunge deleted messages */ unix_copy, /* copy messages to another mailbox */ unix_append, /* append string message to mailbox */ NIL /* garbage collect stream */ }; /* prototype stream */ MAILSTREAM unixproto = {&unixdriver}; /* driver parameters */ static long unix_fromwidget = T; /* UNIX mail validate mailbox * Accepts: mailbox name * Returns: our driver if name is valid, NIL otherwise */ DRIVER *unix_valid (char *name) { int fd; DRIVER *ret = NIL; char *t,file[MAILTMPLEN]; struct stat sbuf; time_t tp[2]; errno = EINVAL; /* assume invalid argument */ /* must be non-empty file */ if ((t = dummy_file (file,name)) && !stat (t,&sbuf)) { if (!sbuf.st_size)errno = 0;/* empty file */ else if ((fd = open (file,O_RDONLY,NIL)) >= 0) { /* OK if mailbox format good */ if (unix_isvalid_fd (fd)) ret = &unixdriver; else errno = -1; /* invalid format */ close (fd); /* close the file */ /* \Marked status? */ if ((sbuf.st_ctime > sbuf.st_atime) || (sbuf.st_mtime > sbuf.st_atime)) { tp[0] = sbuf.st_atime; /* yes, preserve atime and mtime */ tp[1] = sbuf.st_mtime; utime (file,tp); /* set the times */ } } } return ret; /* return what we should */ } /* UNIX mail test for valid mailbox * Accepts: file descriptor * scratch buffer * Returns: T if valid, NIL otherwise */ long unix_isvalid_fd (int fd) { int zn; int ret = NIL; char tmp[MAILTMPLEN],*s,*t,c = '\n'; memset (tmp,'\0',MAILTMPLEN); if (read (fd,tmp,MAILTMPLEN-1) >= 0) { for (s = tmp; (*s == '\r') || (*s == '\n') || (*s == ' ') || (*s == '\t');) c = *s++; if (c == '\n') VALID (s,t,ret,zn); } return ret; /* return what we should */ } /* UNIX manipulate driver parameters * Accepts: function code * function-dependent value * Returns: function-dependent return value */ void *unix_parameters (long function,void *value) { void *ret = NIL; switch ((int) function) { case GET_INBOXPATH: if (value) ret = dummy_file ((char *) value,"INBOX"); break; case SET_FROMWIDGET: unix_fromwidget = (long) value; case GET_FROMWIDGET: ret = (void *) unix_fromwidget; break; } return ret; } /* UNIX mail scan mailboxes * Accepts: mail stream * reference * pattern to search * string to scan */ void unix_scan (MAILSTREAM *stream,char *ref,char *pat,char *contents) { if (stream) dummy_scan (NIL,ref,pat,contents); } /* UNIX mail list mailboxes * Accepts: mail stream * reference * pattern to search */ void unix_list (MAILSTREAM *stream,char *ref,char *pat) { if (stream) dummy_list (NIL,ref,pat); } /* UNIX mail list subscribed mailboxes * Accepts: mail stream * reference * pattern to search */ void unix_lsub (MAILSTREAM *stream,char *ref,char *pat) { if (stream) dummy_lsub (NIL,ref,pat); } /* UNIX mail create mailbox * Accepts: MAIL stream * mailbox name to create * Returns: T on success, NIL on failure */ long unix_create (MAILSTREAM *stream,char *mailbox) { char *s,mbx[MAILTMPLEN],tmp[MAILTMPLEN]; long ret = NIL; int i,fd; time_t ti = time (0); if (!(s = dummy_file (mbx,mailbox))) { sprintf (tmp,"Can't create %.80s: invalid name",mailbox); MM_LOG (tmp,ERROR); } /* create underlying file */ else if (dummy_create_path (stream,s,get_dir_protection (mailbox))) { /* done if dir-only or whiner */ if (((s = strrchr (s,'/')) && !s[1]) || mail_parameters (NIL,GET_USERHASNOLIFE,NIL)) ret = T; else if ((fd = open (mbx,O_WRONLY, (long) mail_parameters (NIL,GET_MBXPROTECTION,NIL))) < 0) { sprintf (tmp,"Can't reopen mailbox node %.80s: %s",mbx,strerror (errno)); MM_LOG (tmp,ERROR); unlink (mbx); /* delete the file */ } else { /* initialize header */ memset (tmp,'\0',MAILTMPLEN); sprintf (tmp,"From %s %sDate: ",pseudo_from,ctime (&ti)); rfc822_fixed_date (s = tmp + strlen (tmp)); /* write the pseudo-header */ sprintf (s += strlen (s), "\nFrom: %s <%s@%s>\nSubject: %s\nX-IMAP: %010lu 0000000000", pseudo_name,pseudo_from,mylocalhost (),pseudo_subject, (unsigned long) ti); for (i = 0; i < NUSERFLAGS; ++i) if (default_user_flag (i)) sprintf (s += strlen (s)," %s",default_user_flag (i)); sprintf (s += strlen (s),"\nStatus: RO\n\n%s\n\n",pseudo_msg); if (write (fd,tmp,strlen (tmp)) > 0) ret = T; else { sprintf (tmp,"Can't initialize mailbox node %.80s: %s",mbx, strerror (errno)); MM_LOG (tmp,ERROR); unlink (mbx); /* delete the file */ } close (fd); /* close file */ } } /* set proper protections */ return ret ? set_mbx_protections (mailbox,mbx) : NIL; } /* UNIX mail delete mailbox * Accepts: MAIL stream * mailbox name to delete * Returns: T on success, NIL on failure */ long unix_delete (MAILSTREAM *stream,char *mailbox) { return unix_rename (stream,mailbox,NIL); } /* UNIX mail rename mailbox * Accepts: MAIL stream * old mailbox name * new mailbox name (or NIL for delete) * Returns: T on success, NIL on failure */ long unix_rename (MAILSTREAM *stream,char *old,char *newname) { long ret = NIL; char c,*s = NIL; char tmp[MAILTMPLEN],file[MAILTMPLEN],lock[MAILTMPLEN]; DOTLOCK lockx; int fd,ld; long i; struct stat sbuf; MM_CRITICAL (stream); /* get the c-client lock */ if (!dummy_file (file,old) || (newname && (!((s = mailboxfile (tmp,newname)) && *s) || ((s = strrchr (tmp,'/')) && !s[1])))) sprintf (tmp,newname ? "Can't rename mailbox %.80s to %.80s: invalid name" : "Can't delete mailbox %.80s: invalid name", old,newname); /* lock out other c-clients */ else if ((ld = lockname (lock,file,LOCK_EX|LOCK_NB,&i)) < 0) sprintf (tmp,"Mailbox %.80s is in use by another process",old); else { if ((fd = unix_lock (file,O_RDWR, (long) mail_parameters (NIL,GET_MBXPROTECTION,NIL), &lockx,LOCK_EX)) < 0) sprintf (tmp,"Can't lock mailbox %.80s: %s",old,strerror (errno)); else { if (newname) { /* want rename? */ /* found superior to destination name? */ if (s = strrchr (s,'/')) { c = *++s; /* remember first character of inferior */ *s = '\0'; /* tie off to get just superior */ /* name doesn't exist, create it */ if ((stat (tmp,&sbuf) || ((sbuf.st_mode & S_IFMT) != S_IFDIR)) && !dummy_create_path (stream,tmp,get_dir_protection (newname))) { unix_unlock (fd,NIL,&lockx); unix_unlock (ld,NIL,NIL); unlink (lock); MM_NOCRITICAL (stream); return ret; /* return success or failure */ } *s = c; /* restore full name */ } if (rename (file,tmp)) sprintf (tmp,"Can't rename mailbox %.80s to %.80s: %s",old,newname, strerror (errno)); else ret = T; /* set success */ } else if (unlink (file)) sprintf (tmp,"Can't delete mailbox %.80s: %s",old,strerror (errno)); else ret = T; /* set success */ unix_unlock (fd,NIL,&lockx); } unix_unlock (ld,NIL,NIL); /* flush the lock */ unlink (lock); } MM_NOCRITICAL (stream); /* no longer critical */ if (!ret) MM_LOG (tmp,ERROR); /* log error */ return ret; /* return success or failure */ } /* UNIX mail open * Accepts: Stream to open * Returns: Stream on success, NIL on failure */ MAILSTREAM *unix_open (MAILSTREAM *stream) { long i; int fd; char tmp[MAILTMPLEN]; DOTLOCK lock; long retry; /* return prototype for OP_PROTOTYPE call */ if (!stream) return user_flags (&unixproto); retry = stream->silent ? 1 : KODRETRY; if (stream->local) fatal ("unix recycle stream"); stream->local = memset (fs_get (sizeof (UNIXLOCAL)),0,sizeof (UNIXLOCAL)); /* note if an INBOX or not */ stream->inbox = !compare_cstring (stream->mailbox,"INBOX"); /* canonicalize the stream mailbox name */ if (!dummy_file (tmp,stream->mailbox)) { sprintf (tmp,"Can't open - invalid name: %.80s",stream->mailbox); MM_LOG (tmp,ERROR); return NIL; } /* flush old name */ fs_give ((void **) &stream->mailbox); /* save canonical name */ stream->mailbox = cpystr (tmp); LOCAL->fd = LOCAL->ld = -1; /* no file or state locking yet */ LOCAL->buf = (char *) fs_get (CHUNKSIZE); LOCAL->buflen = CHUNKSIZE - 1; LOCAL->text.data = (unsigned char *) fs_get (CHUNKSIZE); LOCAL->text.size = CHUNKSIZE - 1; LOCAL->linebuf = (char *) fs_get (CHUNKSIZE); LOCAL->linebuflen = CHUNKSIZE - 1; stream->sequence++; /* bump sequence number */ /* make lock for read/write access */ if (!stream->rdonly) while (retry) { /* try to lock file */ if ((fd = lockname (tmp,stream->mailbox,LOCK_EX|LOCK_NB,&i)) < 0) { /* suppressing kiss-of-death? */ if (stream->nokod) retry = 0; /* no, first time through? */ else if (retry-- == KODRETRY) { /* learned other guy's PID and can signal? */ if (i && !kill ((int) i,SIGUSR2)) { sprintf (tmp,"Trying to get mailbox lock from process %ld",i); MM_LOG (tmp,WARN); } else retry = 0; /* give up */ } if (!stream->silent) { /* nothing if silent stream */ if (retry) sleep (1); /* wait a second before trying again */ else MM_LOG ("Mailbox is open by another process, access is readonly", WARN); } } else { /* got the lock, nobody else can alter state */ LOCAL->ld = fd; /* note lock's fd and name */ LOCAL->lname = cpystr (tmp); /* make sure mode OK (don't use fchmod()) */ chmod (LOCAL->lname,(long) mail_parameters (NIL,GET_LOCKPROTECTION,NIL)); if (stream->silent) i = 0;/* silent streams won't accept KOD */ else { /* note our PID in the lock */ sprintf (tmp,"%d",getpid ()); write (fd,tmp,(i = strlen (tmp))+1); } ftruncate (fd,i); /* make sure tied off */ fsync (fd); /* make sure it's available */ retry = 0; /* no more need to try */ } } /* parse mailbox */ stream->nmsgs = stream->recent = 0; /* will we be able to get write access? */ if ((LOCAL->ld >= 0) && access (stream->mailbox,W_OK) && (errno == EACCES)) { MM_LOG ("Can't get write access to mailbox, access is readonly",WARN); flock (LOCAL->ld,LOCK_UN); /* release the lock */ close (LOCAL->ld); /* close the lock file */ LOCAL->ld = -1; /* no more lock fd */ unlink (LOCAL->lname); /* delete it */ } /* reset UID validity */ stream->uid_validity = stream->uid_last = 0; if (stream->silent && !stream->rdonly && (LOCAL->ld < 0)) unix_abort (stream); /* abort if can't get RW silent stream */ /* parse mailbox */ else if (unix_parse (stream,&lock,LOCK_SH)) { unix_unlock (LOCAL->fd,stream,&lock); mail_unlock (stream); MM_NOCRITICAL (stream); /* done with critical */ } if (!LOCAL) return NIL; /* failure if stream died */ /* make sure upper level knows readonly */ stream->rdonly = (LOCAL->ld < 0); /* notify about empty mailbox */ if (!(stream->nmsgs || stream->silent)) MM_LOG ("Mailbox is empty",NIL); if (!stream->rdonly) { /* flags stick if readwrite */ stream->perm_seen = stream->perm_deleted = stream->perm_flagged = stream->perm_answered = stream->perm_draft = T; if (!stream->uid_nosticky) {/* users with lives get permanent keywords */ stream->perm_user_flags = 0xffffffff; /* and maybe can create them too! */ stream->kwd_create = stream->user_flags[NUSERFLAGS-1] ? NIL : T; } } return stream; /* return stream alive to caller */ } /* UNIX mail close * Accepts: MAIL stream * close options */ void unix_close (MAILSTREAM *stream,long options) { int silent = stream->silent; stream->silent = T; /* go silent */ /* expunge if requested */ if (options & CL_EXPUNGE) unix_expunge (stream,NIL,NIL); /* else dump final checkpoint */ else if (LOCAL->dirty) unix_check (stream); stream->silent = silent; /* restore old silence state */ unix_abort (stream); /* now punt the file and local data */ } /* UNIX mail fetch message header * Accepts: MAIL stream * message # to fetch * pointer to returned header text length * option flags * Returns: message header in RFC822 format */ /* lines to filter from header */ static STRINGLIST *unix_hlines = NIL; char *unix_header (MAILSTREAM *stream,unsigned long msgno, unsigned long *length,long flags) { MESSAGECACHE *elt; unsigned char *s,*t,*tl; *length = 0; /* default to empty */ if (flags & FT_UID) return "";/* UID call "impossible" */ elt = mail_elt (stream,msgno);/* get cache */ if (!unix_hlines) { /* once only code */ STRINGLIST *lines = unix_hlines = mail_newstringlist (); lines->text.size = strlen ((char *) (lines->text.data = (unsigned char *) "Status")); lines = lines->next = mail_newstringlist (); lines->text.size = strlen ((char *) (lines->text.data = (unsigned char *) "X-Status")); lines = lines->next = mail_newstringlist (); lines->text.size = strlen ((char *) (lines->text.data = (unsigned char *) "X-Keywords")); lines = lines->next = mail_newstringlist (); lines->text.size = strlen ((char *) (lines->text.data = (unsigned char *) "X-UID")); lines = lines->next = mail_newstringlist (); lines->text.size = strlen ((char *) (lines->text.data = (unsigned char *) "X-IMAP")); lines = lines->next = mail_newstringlist (); lines->text.size = strlen ((char *) (lines->text.data = (unsigned char *) "X-IMAPbase")); } /* go to header position */ lseek (LOCAL->fd,elt->private.special.offset + elt->private.msg.header.offset,L_SET); if (flags & FT_INTERNAL) { /* initial data OK? */ if (elt->private.msg.header.text.size > LOCAL->buflen) { fs_give ((void **) &LOCAL->buf); LOCAL->buf = (char *) fs_get ((LOCAL->buflen = elt->private.msg.header.text.size) + 1); } /* read message */ read (LOCAL->fd,LOCAL->buf,elt->private.msg.header.text.size); /* got text, tie off string */ LOCAL->buf[*length = elt->private.msg.header.text.size] = '\0'; /* squeeze out CRs (in case from PC) */ for (s = t = LOCAL->buf,tl = LOCAL->buf + *length; t < tl; t++) if (*t != '\r') *s++ = *t; *s = '\0'; *length = s - LOCAL->buf; /* adjust length */ } else { /* need to make a CRLF version */ read (LOCAL->fd,s = (char *) fs_get (elt->private.msg.header.text.size+1), elt->private.msg.header.text.size); /* tie off string, and convert to CRLF */ s[elt->private.msg.header.text.size] = '\0'; *length = strcrlfcpy (&LOCAL->buf,&LOCAL->buflen,s, elt->private.msg.header.text.size); fs_give ((void **) &s); /* free readin buffer */ /* squeeze out spurious CRs */ for (s = t = LOCAL->buf,tl = LOCAL->buf + *length; t < tl; t++) if ((*t != '\r') || (t[1] == '\n')) *s++ = *t; *s = '\0'; *length = s - LOCAL->buf; /* adjust length */ } *length = mail_filter (LOCAL->buf,*length,unix_hlines,FT_NOT); return (char *) LOCAL->buf; /* return processed copy */ } /* UNIX mail fetch message text * Accepts: MAIL stream * message # to fetch * pointer to returned stringstruct * option flags * Returns: T on success, NIL if failure */ long unix_text (MAILSTREAM *stream,unsigned long msgno,STRING *bs,long flags) { char *s; unsigned long i; MESSAGECACHE *elt; /* UID call "impossible" */ if (flags & FT_UID) return NIL; elt = mail_elt (stream,msgno);/* get cache element */ /* if message not seen */ if (!(flags & FT_PEEK) && !elt->seen) { /* mark message seen and dirty */ elt->seen = elt->private.dirty = LOCAL->dirty = T; MM_FLAGS (stream,msgno); } s = unix_text_work (stream,elt,&i,flags); INIT (bs,mail_string,s,i); /* set up stringstruct */ return T; /* success */ } /* UNIX mail fetch message text worker routine * Accepts: MAIL stream * message cache element * pointer to returned header text length * option flags */ char *unix_text_work (MAILSTREAM *stream,MESSAGECACHE *elt, unsigned long *length,long flags) { FDDATA d; STRING bs; unsigned char c,*s,*t,*tl,tmp[CHUNKSIZE]; /* go to text position */ lseek (LOCAL->fd,elt->private.special.offset + elt->private.msg.text.offset,L_SET); if (flags & FT_INTERNAL) { /* initial data OK? */ if (elt->private.msg.text.text.size > LOCAL->buflen) { fs_give ((void **) &LOCAL->buf); LOCAL->buf = (char *) fs_get ((LOCAL->buflen = elt->private.msg.text.text.size) + 1); } /* read message */ read (LOCAL->fd,LOCAL->buf,elt->private.msg.text.text.size); /* got text, tie off string */ LOCAL->buf[*length = elt->private.msg.text.text.size] = '\0'; /* squeeze out CRs (in case from PC) */ for (s = t = LOCAL->buf,tl = LOCAL->buf + *length; t < tl; t++) if (*t != '\r') *s++ = *t; *s = '\0'; *length = s - LOCAL->buf; /* adjust length */ return (char *) LOCAL->buf; } /* have it cached already? */ if (elt->private.uid != LOCAL->uid) { /* not cached, cache it now */ LOCAL->uid = elt->private.uid; /* is buffer big enough? */ if (elt->rfc822_size > LOCAL->text.size) { /* excessively conservative, but the right thing is too hard to do */ fs_give ((void **) &LOCAL->text.data); LOCAL->text.data = (unsigned char *) fs_get ((LOCAL->text.size = elt->rfc822_size) + 1); } d.fd = LOCAL->fd; /* yes, set up file descriptor */ d.pos = elt->private.special.offset + elt->private.msg.text.offset; d.chunk = tmp; /* initial buffer chunk */ d.chunksize = CHUNKSIZE; /* file chunk size */ INIT (&bs,fd_string,&d,elt->private.msg.text.text.size); for (s = (char *) LOCAL->text.data; SIZE (&bs);) switch (c = SNX (&bs)) { case '\r': /* carriage return seen */ break; case '\n': *s++ = '\r'; /* insert a CR */ default: *s++ = c; /* copy characters */ } *s = '\0'; /* tie off buffer */ /* calculate length of cached data */ LOCAL->textlen = s - LOCAL->text.data; } *length = LOCAL->textlen; /* return from cache */ return (char *) LOCAL->text.data; } /* UNIX per-message modify flag * Accepts: MAIL stream * message cache element */ void unix_flagmsg (MAILSTREAM *stream,MESSAGECACHE *elt) { /* only after finishing */ if (elt->valid) elt->private.dirty = LOCAL->dirty = T; } /* UNIX mail ping mailbox * Accepts: MAIL stream * Returns: T if stream alive, else NIL */ long unix_ping (MAILSTREAM *stream) { DOTLOCK lock; struct stat sbuf; long reparse; /* big no-op if not readwrite */ if (LOCAL && (LOCAL->ld >= 0) && !stream->lock) { if (stream->rdonly) { /* does he want to give up readwrite? */ /* checkpoint if we changed something */ if (LOCAL->dirty) unix_check (stream); flock (LOCAL->ld,LOCK_UN);/* release readwrite lock */ close (LOCAL->ld); /* close the readwrite lock file */ LOCAL->ld = -1; /* no more readwrite lock fd */ unlink (LOCAL->lname); /* delete the readwrite lock file */ } else { /* see if need to reparse */ if (!(reparse = (long) mail_parameters (NIL,GET_NETFSSTATBUG,NIL))) { /* get current mailbox size */ if (LOCAL->fd >= 0) fstat (LOCAL->fd,&sbuf); else if (stat (stream->mailbox,&sbuf)) { sprintf (LOCAL->buf,"Mailbox stat failed, aborted: %s", strerror (errno)); MM_LOG (LOCAL->buf,ERROR); unix_abort (stream); return NIL; } reparse = (sbuf.st_size != LOCAL->filesize); } /* parse if mailbox changed */ if ((LOCAL->ddirty || reparse) && unix_parse (stream,&lock,LOCK_EX)) { /* force checkpoint if double-dirty */ if (LOCAL->ddirty) unix_rewrite (stream,NIL,&lock,NIL); /* unlock mailbox */ else unix_unlock (LOCAL->fd,stream,&lock); mail_unlock (stream); /* and stream */ MM_NOCRITICAL (stream); /* done with critical */ } } } return LOCAL ? LONGT : NIL; /* return if still alive */ } /* UNIX mail check mailbox * Accepts: MAIL stream */ void unix_check (MAILSTREAM *stream) { DOTLOCK lock; /* parse and lock mailbox */ if (LOCAL && (LOCAL->ld >= 0) && !stream->lock && unix_parse (stream,&lock,LOCK_EX)) { /* any unsaved changes? */ if (LOCAL->dirty && unix_rewrite (stream,NIL,&lock,NIL)) { if (!stream->silent) MM_LOG ("Checkpoint completed",NIL); } /* no checkpoint needed, just unlock */ else unix_unlock (LOCAL->fd,stream,&lock); mail_unlock (stream); /* unlock the stream */ MM_NOCRITICAL (stream); /* done with critical */ } } /* UNIX mail expunge mailbox * Accepts: MAIL stream * sequence to expunge if non-NIL * expunge options * Returns: T, always */ long unix_expunge (MAILSTREAM *stream,char *sequence,long options) { long ret; unsigned long i; DOTLOCK lock; char *msg = NIL; /* parse and lock mailbox */ if (ret = (sequence ? ((options & EX_UID) ? mail_uid_sequence (stream,sequence) : mail_sequence (stream,sequence)) : LONGT) && LOCAL && (LOCAL->ld >= 0) && !stream->lock && unix_parse (stream,&lock,LOCK_EX)) { /* check expunged messages if not dirty */ for (i = 1; !LOCAL->dirty && (i <= stream->nmsgs); i++) { MESSAGECACHE *elt = mail_elt (stream,i); if (mail_elt (stream,i)->deleted) LOCAL->dirty = T; } if (!LOCAL->dirty) { /* not dirty and no expunged messages */ unix_unlock (LOCAL->fd,stream,&lock); msg = "No messages deleted, so no update needed"; } else if (unix_rewrite (stream,&i,&lock,sequence ? LONGT : NIL)) { if (i) sprintf (msg = LOCAL->buf,"Expunged %lu messages",i); else msg = "Mailbox checkpointed, but no messages expunged"; } /* rewrite failed */ else unix_unlock (LOCAL->fd,stream,&lock); mail_unlock (stream); /* unlock the stream */ MM_NOCRITICAL (stream); /* done with critical */ if (msg && !stream->silent) MM_LOG (msg,NIL); } else if (!stream->silent) MM_LOG("Expunge ignored on readonly mailbox",WARN); return ret; } /* UNIX mail copy message(s) * Accepts: MAIL stream * sequence * destination mailbox * copy options * Returns: T if copy successful, else NIL */ long unix_copy (MAILSTREAM *stream,char *sequence,char *mailbox,long options) { struct stat sbuf; int fd; char *s,file[MAILTMPLEN]; DOTLOCK lock; time_t tp[2]; unsigned long i,j; MESSAGECACHE *elt; long ret = T; mailproxycopy_t pc = (mailproxycopy_t) mail_parameters (stream,GET_MAILPROXYCOPY,NIL); copyuid_t cu = (copyuid_t) (mail_parameters (NIL,GET_USERHASNOLIFE,NIL) ? NIL : mail_parameters (NIL,GET_COPYUID,NIL)); SEARCHSET *source = cu ? mail_newsearchset () : NIL; SEARCHSET *dest = cu ? mail_newsearchset () : NIL; MAILSTREAM *tstream = NIL; DRIVER *d; for (d = (DRIVER *) mail_parameters (NIL,GET_DRIVERS,NIL); (d && strcmp (d->name,"mbox") && !(d->flags & DR_DISABLE)); d = d->next); /* see if mbox driver active */ if (!((options & CP_UID) ? mail_uid_sequence (stream,sequence) : mail_sequence (stream,sequence))) return NIL; /* make sure destination is valid */ if (!((d && mbox_valid (mailbox) && (mailbox = "mbox")) || unix_valid (mailbox) || !errno)) switch (errno) { case ENOENT: /* no such file? */ if (compare_cstring (mailbox,"INBOX")) { MM_NOTIFY (stream,"[TRYCREATE] Must create mailbox before copy",NIL); return NIL; } if (pc) return (*pc) (stream,sequence,mailbox,options); unix_create (NIL,"INBOX");/* create empty INBOX */ case EACCES: /* file protected */ sprintf (LOCAL->buf,"Can't access destination: %.80s",mailbox); MM_LOG (LOCAL->buf,ERROR); return NIL; case EINVAL: if (pc) return (*pc) (stream,sequence,mailbox,options); sprintf (LOCAL->buf,"Invalid UNIX-format mailbox name: %.80s",mailbox); MM_LOG (LOCAL->buf,ERROR); return NIL; default: if (pc) return (*pc) (stream,sequence,mailbox,options); sprintf (LOCAL->buf,"Not a UNIX-format mailbox: %.80s",mailbox); MM_LOG (LOCAL->buf,ERROR); return NIL; } /* try to open rewrite for UIDPLUS */ if ((tstream = mail_open_work (&unixdriver,NIL,mailbox, OP_SILENT|OP_NOKOD)) && tstream->rdonly) tstream = mail_close (tstream); if (cu && !tstream) { /* wanted a COPYUID? */ sprintf (LOCAL->buf,"Unable to write-open mailbox for COPYUID: %.80s", mailbox); MM_LOG (LOCAL->buf,WARN); cu = NIL; /* don't try to do COPYUID */ } LOCAL->buf[0] = '\0'; MM_CRITICAL (stream); /* go critical */ if ((fd = unix_lock (dummy_file (file,mailbox),O_WRONLY|O_APPEND, (long) mail_parameters (NIL,GET_MBXPROTECTION,NIL), &lock,LOCK_EX)) < 0) { MM_NOCRITICAL (stream); /* done with critical */ sprintf (LOCAL->buf,"Can't open destination mailbox: %s",strerror (errno)); MM_LOG (LOCAL->buf,ERROR);/* log the error */ return NIL; /* failed */ } fstat (fd,&sbuf); /* get current file size */ /* write all requested messages to mailbox */ for (i = 1; ret && (i <= stream->nmsgs); i++) if ((elt = mail_elt (stream,i))->sequence) { lseek (LOCAL->fd,elt->private.special.offset,L_SET); read (LOCAL->fd,LOCAL->buf,elt->private.special.text.size); if (write (fd,LOCAL->buf,elt->private.special.text.size) < 0) ret = NIL; else { /* internal header succeeded */ s = unix_header (stream,i,&j,FT_INTERNAL); /* header size, sans trailing newline */ if (j && (s[j - 2] == '\n')) j--; if (write (fd,s,j) < 0) ret = NIL; else { /* message header succeeded */ j = tstream ? /* write UIDPLUS data if have readwrite */ unix_xstatus (stream,LOCAL->buf,elt,++(tstream->uid_last),LONGT) : unix_xstatus (stream,LOCAL->buf,elt,NIL,NIL); if (write (fd,LOCAL->buf,j) < 0) ret = NIL; else { /* message status succeeded */ s = unix_text_work (stream,elt,&j,FT_INTERNAL); if ((write (fd,s,j) < 0) || (write (fd,"\n",1) < 0)) ret = NIL; else if (cu) { /* need to pass back new UID? */ mail_append_set (source,mail_uid (stream,i)); mail_append_set (dest,tstream->uid_last); } } } } } if (!ret || fsync (fd)) { /* force out the update */ sprintf (LOCAL->buf,"Message copy failed: %s",strerror (errno)); ftruncate (fd,sbuf.st_size); ret = NIL; } /* force UIDVALIDITY assignment now */ if (tstream && !tstream->uid_validity) tstream->uid_validity = time (0); /* return sets if doing COPYUID */ if (cu && ret) (*cu) (stream,mailbox,tstream->uid_validity,source,dest); else { /* flush any sets we may have built */ mail_free_searchset (&source); mail_free_searchset (&dest); } tp[1] = time (0); /* set mtime to now */ if (ret) tp[0] = tp[1] - 1; /* set atime to now-1 if successful copy */ else tp[0] = /* else preserve \Marked status */ ((sbuf.st_ctime > sbuf.st_atime) || (sbuf.st_mtime > sbuf.st_atime)) ? sbuf.st_atime : tp[1]; utime (file,tp); /* set the times */ unix_unlock (fd,NIL,&lock); /* unlock and close mailbox */ if (tstream) { /* update last UID if we can */ UNIXLOCAL *local = (UNIXLOCAL *) tstream->local; local->dirty = T; /* do a rewrite */ local->appending = T; /* but not at the cost of marking as old */ tstream = mail_close (tstream); } /* log the error */ if (!ret) MM_LOG (LOCAL->buf,ERROR); /* delete if requested message */ else if (options & CP_MOVE) for (i = 1; i <= stream->nmsgs; i++) if ((elt = mail_elt (stream,i))->sequence) elt->deleted = elt->private.dirty = LOCAL->dirty = T; MM_NOCRITICAL (stream); /* release critical */ return ret; } /* UNIX mail append message from stringstruct * Accepts: MAIL stream * destination mailbox * append callback * data for callback * Returns: T if append successful, else NIL */ #define BUFLEN 8*MAILTMPLEN long unix_append (MAILSTREAM *stream,char *mailbox,append_t af,void *data) { struct stat sbuf; int fd; unsigned long i; char *flags,*date,buf[BUFLEN],tmp[MAILTMPLEN],file[MAILTMPLEN]; time_t tp[2]; FILE *sf,*df; MESSAGECACHE elt; DOTLOCK lock; STRING *message; unsigned long uidlocation = 0; appenduid_t au = (appenduid_t) (mail_parameters (NIL,GET_USERHASNOLIFE,NIL) ? NIL : mail_parameters (NIL,GET_APPENDUID,NIL)); SEARCHSET *dst = au ? mail_newsearchset () : NIL; long ret = LONGT; MAILSTREAM *tstream = NIL; if (!stream) { /* stream specified? */ stream = &unixproto; /* no, default stream to prototype */ for (i = 0; i < NUSERFLAGS && stream->user_flags[i]; ++i) fs_give ((void **) &stream->user_flags[i]); } if (!unix_valid (mailbox)) switch (errno) { case ENOENT: /* no such file? */ if (compare_cstring (mailbox,"INBOX")) { MM_NOTIFY (stream,"[TRYCREATE] Must create mailbox before append",NIL); return NIL; } unix_create (NIL,"INBOX"); /* create empty INBOX */ case 0: /* merely empty file? */ tstream = stream; break; case EACCES: /* file protected */ sprintf (tmp,"Can't access destination: %.80s",mailbox); MM_LOG (tmp,ERROR); return NIL; case EINVAL: sprintf (tmp,"Invalid UNIX-format mailbox name: %.80s",mailbox); MM_LOG (tmp,ERROR); return NIL; default: sprintf (tmp,"Not a UNIX-format mailbox: %.80s",mailbox); MM_LOG (tmp,ERROR); return NIL; } /* get sniffing stream for keywords */ else if (!(tstream = mail_open (NIL,mailbox, OP_READONLY|OP_SILENT|OP_NOKOD|OP_SNIFF))) { sprintf (tmp,"Unable to examine mailbox for APPEND: %.80s",mailbox); MM_LOG (tmp,ERROR); return NIL; } /* get first message */ if (!MM_APPEND (af) (tstream,data,&flags,&date,&message)) return NIL; if (!(sf = tmpfile ())) { /* must have scratch file */ sprintf (tmp,".%lx.%lx",(unsigned long) time (0),(unsigned long)getpid ()); if (!stat (tmp,&sbuf) || !(sf = fopen (tmp,"wb+"))) { sprintf (tmp,"Unable to create scratch file: %.80s",strerror (errno)); MM_LOG (tmp,ERROR); return NIL; } unlink (tmp); } do { /* parse date */ if (!date) rfc822_date (date = tmp); if (!mail_parse_date (&elt,date)) { sprintf (tmp,"Bad date in append: %.80s",date); MM_LOG (tmp,ERROR); } else { /* user wants to suppress time zones? */ if (mail_parameters (NIL,GET_NOTIMEZONES,NIL)) { time_t when = mail_longdate (&elt); date = ctime (&when); /* use traditional date */ } /* use POSIX-style date */ else date = mail_cdate (tmp,&elt); if (!SIZE (message)) MM_LOG ("Append of zero-length message",ERROR); else if (!unix_collect_msg (tstream,sf,flags,date,message)) { sprintf (tmp,"Error writing scratch file: %.80s",strerror (errno)); MM_LOG (tmp,ERROR); } /* get next message */ else if (MM_APPEND (af) (tstream,data,&flags,&date,&message)) continue; } fclose (sf); /* punt scratch file */ return NIL; /* give up */ } while (message); /* until no more messages */ if (fflush (sf)) { sprintf (tmp,"Error finishing scratch file: %.80s",strerror (errno)); MM_LOG (tmp,ERROR); fclose (sf); /* punt scratch file */ return NIL; /* give up */ } i = ftell (sf); /* size of scratch file */ /* close sniffing stream */ if (tstream != stream) tstream = mail_close (tstream); MM_CRITICAL (stream); /* go critical */ /* try to open readwrite for UIDPLUS */ if ((tstream = mail_open_work (&unixdriver,NIL,mailbox, OP_SILENT|OP_NOKOD)) && tstream->rdonly) tstream = mail_close (tstream); if (au && !tstream) { /* wanted an APPENDUID? */ sprintf (tmp,"Unable to re-open mailbox for APPENDUID: %.80s",mailbox); MM_LOG (tmp,WARN); au = NIL; } if (((fd = unix_lock (dummy_file (file,mailbox),O_WRONLY|O_APPEND, (long) mail_parameters (NIL,GET_MBXPROTECTION,NIL), &lock,LOCK_EX)) < 0) || !(df = fdopen (fd,"ab"))) { MM_NOCRITICAL (stream); /* done with critical */ sprintf (tmp,"Can't open append mailbox: %s",strerror (errno)); MM_LOG (tmp,ERROR); return NIL; } fstat (fd,&sbuf); /* get current file size */ rewind (sf); tp[1] = time (0); /* set mtime to now */ /* write all messages */ if (!unix_append_msgs (tstream,sf,df,au ? dst : NIL) || (fflush (df) == EOF) || fsync (fd)) { sprintf (buf,"Message append failed: %s",strerror (errno)); MM_LOG (buf,ERROR); ftruncate (fd,sbuf.st_size); tp[0] = /* preserve \Marked status */ ((sbuf.st_ctime > sbuf.st_atime) || (sbuf.st_mtime > sbuf.st_atime)) ? sbuf.st_atime : tp[1]; ret = NIL; /* return error */ } else tp[0] = tp[1] - 1; /* set atime to now-1 if successful copy */ utime (file,tp); /* set the times */ fclose (sf); /* done with scratch file */ /* force UIDVALIDITY assignment now */ if (tstream && !tstream->uid_validity) tstream->uid_validity = time (0); /* return sets if doing APPENDUID */ if (au && ret) (*au) (mailbox,tstream->uid_validity,dst); else mail_free_searchset (&dst); unix_unlock (fd,NIL,&lock); /* unlock and close mailbox */ fclose (df); /* note that unix_unlock() released the fd */ if (tstream) { /* update last UID if we can */ UNIXLOCAL *local = (UNIXLOCAL *) tstream->local; local->dirty = T; /* do a rewrite */ local->appending = T; /* but not at the cost of marking as old */ tstream = mail_close (tstream); } MM_NOCRITICAL (stream); /* release critical */ return ret; } /* Collect and write single message to append scratch file * Accepts: MAIL stream * scratch file * flags * date * message stringstruct * Returns: NIL if write error, else T */ int unix_collect_msg (MAILSTREAM *stream,FILE *sf,char *flags,char *date, STRING *msg) { unsigned char *s,*t; unsigned long uf; long f = mail_parse_flags (stream,flags,&uf); /* write metadata, note date ends with NL */ if (fprintf (sf,"%ld %lu %s",f,SIZE (msg) + 1,date) < 0) return NIL; while (uf) /* write user flags */ if ((s = stream->user_flags[find_rightmost_bit (&uf)]) && (fprintf (sf," %s",s) < 0)) return NIL; if (putc ('\n',sf) == EOF) return NIL; while (SIZE (msg)) { /* copy text to scratch file */ for (s = (unsigned char *) msg->curpos, t = s + msg->cursize; s < t; ++s) if (!*s) *s = 0x80; /* disallow NUL */ /* write buffered text */ if (fwrite (msg->curpos,1,msg->cursize,sf) == msg->cursize) SETPOS (msg,GETPOS (msg) + msg->cursize); else return NIL; /* failed */ } /* write trailing newline and return */ return (putc ('\n',sf) == EOF) ? NIL : T; } /* Append messages from scratch file to mailbox * Accepts: MAIL stream * source file * destination file * uidset to update if non-NIL * Returns: T if success, NIL if failure */ int unix_append_msgs (MAILSTREAM *stream,FILE *sf,FILE *df,SEARCHSET *set) { int ti,zn,c; long f; unsigned long i,j; char *x,tmp[MAILTMPLEN]; int hdrp = T; /* get message metadata line */ while (fgets (tmp,MAILTMPLEN,sf)) { if (!(isdigit (tmp[0]) && strchr (tmp,'\n'))) return NIL; f = strtol (tmp,&x,10); /* get flags */ if (!((*x++ == ' ') && isdigit (*x))) return NIL; i = strtoul (x,&x,10); /* get message size */ if ((*x++ != ' ') || /* build initial header */ (fprintf (df,"From %s@%s %sStatus: ",myusername(),mylocalhost(),x)<0)|| (f&fSEEN && (putc ('R',df) == EOF)) || (fputs ("\nX-Status: ",df) == EOF) || (f&fDELETED && (putc ('D',df) == EOF)) || (f&fFLAGGED && (putc ('F',df) == EOF)) || (f&fANSWERED && (putc ('A',df) == EOF)) || (f&fDRAFT && (putc ('T',df) == EOF)) || (fputs ("\nX-Keywords:",df) == EOF)) return NIL; /* copy keywords */ while ((c = getc (sf)) != '\n') switch (c) { case EOF: return NIL; default: if (putc (c,df) == EOF) return NIL; } if ((putc ('\n',df) == EOF) || (set && (fprintf (df,"X-UID: %lu\n",++(stream->uid_last)) < 0))) return NIL; for (c = '\n'; i && fgets (tmp,MAILTMPLEN,sf); c = tmp[j-1]) { /* get read line length */ if (i < (j = strlen (tmp))) fatal ("unix_append_msgs overrun"); i -= j; /* number of bytes left */ /* squish out CRs (note also copies NUL) */ for (x = tmp; x = strchr (x,'\r'); --j) memmove (x,x+1,j-(x-tmp)); if (!j) continue; /* do nothing if line emptied */ /* start of line? */ if ((c == '\n')) switch (tmp[0]) { case 'F': /* possible "From " (case counts here) */ if ((j > 4) && (tmp[0] == 'F') && (tmp[1] == 'r') && (tmp[2] == 'o') && (tmp[3] == 'm') && (tmp[4] == ' ')) { if (!unix_fromwidget) { VALID (tmp,x,ti,zn);/* conditional, only write widget if */ if (!ti) break; /* it looks like a valid header */ } /* write the widget */ if (putc ('>',df) == EOF) return NIL; } break; case 'S': case 's': /* possible "Status:" */ if (hdrp && (j > 6) && ((tmp[1] == 't') || (tmp[1] == 'T')) && ((tmp[2] == 'a') || (tmp[2] == 'A')) && ((tmp[3] == 't') || (tmp[3] == 'T')) && ((tmp[4] == 'u') || (tmp[4] == 'U')) && ((tmp[5] == 's') || (tmp[5] == 'S')) && (tmp[6] == ':') && (fputs ("X-Original-",df) == EOF)) return NIL; break; case 'X': case 'x': /* possible X-??? header */ if (hdrp && (tmp[1] == '-') && /* possible X-UID: */ (((j > 5) && ((tmp[2] == 'U') || (tmp[2] == 'u')) && ((tmp[3] == 'I') || (tmp[3] == 'i')) && ((tmp[4] == 'D') || (tmp[4] == 'd')) && (tmp[5] == ':')) || /* possible X-IMAP: */ ((j > 6) && ((tmp[2] == 'I') || (tmp[2] == 'i')) && ((tmp[3] == 'M') || (tmp[3] == 'm')) && ((tmp[4] == 'A') || (tmp[4] == 'a')) && ((tmp[5] == 'P') || (tmp[5] == 'p')) && ((tmp[6] == ':') || /* or X-IMAPbase: */ ((j > 10) && ((tmp[6] == 'b') || (tmp[6] == 'B')) && ((tmp[7] == 'a') || (tmp[7] == 'A')) && ((tmp[8] == 's') || (tmp[8] == 'S')) && ((tmp[9] == 'e') || (tmp[9] == 'E')) && (tmp[10] == ':')))) || /* possible X-Status: */ ((j > 8) && ((tmp[2] == 'S') || (tmp[2] == 's')) && ((tmp[3] == 't') || (tmp[3] == 'T')) && ((tmp[4] == 'a') || (tmp[4] == 'A')) && ((tmp[5] == 't') || (tmp[5] == 'T')) && ((tmp[6] == 'u') || (tmp[6] == 'U')) && ((tmp[7] == 's') || (tmp[7] == 'S')) && (tmp[8] == ':')) || /* possible X-Keywords: */ ((j > 10) && ((tmp[2] == 'K') || (tmp[2] == 'k')) && ((tmp[3] == 'e') || (tmp[3] == 'E')) && ((tmp[4] == 'y') || (tmp[4] == 'Y')) && ((tmp[5] == 'w') || (tmp[5] == 'W')) && ((tmp[6] == 'o') || (tmp[6] == 'O')) && ((tmp[7] == 'r') || (tmp[7] == 'R')) && ((tmp[8] == 'd') || (tmp[8] == 'D')) && ((tmp[9] == 's') || (tmp[9] == 'S')) && (tmp[10] == ':'))) && (fputs ("X-Original-",df) == EOF)) return NIL; case '\n': /* blank line */ hdrp = NIL; break; default: /* nothing to do */ break; } /* just write the line */ if (fwrite (tmp,1,j,df) != j) return NIL; } if (i) return NIL; /* didn't read entire message */ /* update set */ if (stream) mail_append_set (set,stream->uid_last); } return T; } /* Internal routines */ /* UNIX mail abort stream * Accepts: MAIL stream */ void unix_abort (MAILSTREAM *stream) { if (LOCAL) { /* only if a file is open */ if (LOCAL->fd >= 0) close (LOCAL->fd); if (LOCAL->ld >= 0) { /* have a mailbox lock? */ flock (LOCAL->ld,LOCK_UN);/* yes, release the lock */ close (LOCAL->ld); /* close the lock file */ unlink (LOCAL->lname); /* and delete it */ } if (LOCAL->lname) fs_give ((void **) &LOCAL->lname); /* free local text buffers */ if (LOCAL->buf) fs_give ((void **) &LOCAL->buf); if (LOCAL->text.data) fs_give ((void **) &LOCAL->text.data); if (LOCAL->linebuf) fs_give ((void **) &LOCAL->linebuf); if (LOCAL->line) fs_give ((void **) &LOCAL->line); /* nuke the local data */ fs_give ((void **) &stream->local); stream->dtb = NIL; /* log out the DTB */ } } /* UNIX open and lock mailbox * Accepts: file name to open/lock * file open mode * destination buffer for lock file name * type of locking operation (LOCK_SH or LOCK_EX) */ int unix_lock (char *file,int flags,int mode,DOTLOCK *lock,int op) { int fd; blocknotify_t bn = (blocknotify_t) mail_parameters (NIL,GET_BLOCKNOTIFY,NIL); (*bn) (BLOCK_FILELOCK,NIL); /* try locking the easy way */ if (dotlock_lock (file,lock,-1)) { /* got dotlock file, easy open */ if ((fd = open (file,flags,mode)) >= 0) flock (fd,op); else dotlock_unlock (lock); /* open failed, free the dotlock */ } /* no dot lock file, open file now */ else if ((fd = open (file,flags,mode)) >= 0) { /* try paranoid way to make a dot lock file */ if (dotlock_lock (file,lock,fd)) { close (fd); /* get fresh fd in case of timing race */ if ((fd = open (file,flags,mode)) >= 0) flock (fd,op); /* open failed, free the dotlock */ else dotlock_unlock (lock); } else flock (fd,op); /* paranoid way failed, just flock() it */ } (*bn) (BLOCK_NONE,NIL); return fd; } /* UNIX unlock and close mailbox * Accepts: file descriptor * (optional) mailbox stream to check atime/mtime * (optional) lock file name */ void unix_unlock (int fd,MAILSTREAM *stream,DOTLOCK *lock) { if (stream) { /* need to muck with times? */ struct stat sbuf; time_t tp[2]; time_t now = time (0); fstat (fd,&sbuf); /* get file times */ if (LOCAL->ld >= 0) { /* yes, readwrite session? */ tp[0] = now; /* set atime to now */ /* set mtime to (now - 1) if necessary */ tp[1] = (now > sbuf.st_mtime) ? sbuf.st_mtime : now - 1; } else if (stream->recent) { /* readonly with recent messages */ if ((sbuf.st_atime >= sbuf.st_mtime) || (sbuf.st_atime >= sbuf.st_ctime)) /* keep past mtime, whack back atime */ tp[0] = (tp[1] = (sbuf.st_mtime < now) ? sbuf.st_mtime : now) - 1; else now = 0; /* no time change needed */ } /* readonly with no recent messages */ else if ((sbuf.st_atime < sbuf.st_mtime) || (sbuf.st_atime < sbuf.st_ctime)) { tp[0] = now; /* set atime to now */ /* set mtime to (now - 1) if necessary */ tp[1] = (now > sbuf.st_mtime) ? sbuf.st_mtime : now - 1; } else now = 0; /* no time change needed */ /* set the times, note change */ if (now && !utime (stream->mailbox,tp)) LOCAL->filetime = tp[1]; } flock (fd,LOCK_UN); /* release flock'ers */ if (!stream) close (fd); /* close the file if no stream */ dotlock_unlock (lock); /* flush the lock file if any */ } /* UNIX mail parse and lock mailbox * Accepts: MAIL stream * space to write lock file name * type of locking operation * Returns: T if parse OK, critical & mailbox is locked shared; NIL if failure */ int unix_parse (MAILSTREAM *stream,DOTLOCK *lock,int op) { int zn; unsigned long i,j,k,m; unsigned char c,*s,*t,*u,tmp[MAILTMPLEN],date[30]; int ti = 0,retain = T; unsigned long nmsgs = stream->nmsgs; unsigned long prevuid = nmsgs ? mail_elt (stream,nmsgs)->private.uid : 0; unsigned long recent = stream->recent; unsigned long oldnmsgs = stream->nmsgs; short silent = stream->silent; short pseudoseen = NIL; struct stat sbuf; STRING bs; FDDATA d; MESSAGECACHE *elt; mail_lock (stream); /* guard against recursion or pingers */ /* toss out previous descriptor */ if (LOCAL->fd >= 0) close (LOCAL->fd); MM_CRITICAL (stream); /* open and lock mailbox (shared OK) */ if ((LOCAL->fd = unix_lock (stream->mailbox,(LOCAL->ld >= 0) ? O_RDWR : O_RDONLY, (long)mail_parameters(NIL,GET_MBXPROTECTION,NIL), lock,op)) < 0) { sprintf (tmp,"Mailbox open failed, aborted: %s",strerror (errno)); MM_LOG (tmp,ERROR); unix_abort (stream); mail_unlock (stream); MM_NOCRITICAL (stream); /* done with critical */ return NIL; } fstat (LOCAL->fd,&sbuf); /* get status */ /* validate change in size */ if (sbuf.st_size < LOCAL->filesize) { sprintf (tmp,"Mailbox shrank from %lu to %lu bytes, aborted", (unsigned long) LOCAL->filesize,(unsigned long) sbuf.st_size); MM_LOG (tmp,ERROR); /* this is pretty bad */ unix_unlock (LOCAL->fd,stream,lock); unix_abort (stream); mail_unlock (stream); MM_NOCRITICAL (stream); /* done with critical */ return NIL; } /* new data? */ else if (i = sbuf.st_size - LOCAL->filesize) { d.fd = LOCAL->fd; /* yes, set up file descriptor */ d.pos = LOCAL->filesize; /* get to that position in the file */ d.chunk = LOCAL->buf; /* initial buffer chunk */ d.chunksize = CHUNKSIZE; /* file chunk size */ INIT (&bs,fd_string,&d,i); /* initialize stringstruct */ /* skip leading whitespace for broken MTAs */ while (((c = CHR (&bs)) == '\n') || (c == '\r') || (c == ' ') || (c == '\t')) SNX (&bs); if (SIZE (&bs)) { /* read new data */ /* remember internal header position */ j = LOCAL->filesize + GETPOS (&bs); s = unix_mbxline (stream,&bs,&i); t = NIL,zn = 0; if (i) VALID (s,t,ti,zn); /* see if valid From line */ if (!ti) { /* someone pulled the rug from under us */ sprintf (tmp,"Unexpected changes to mailbox (try restarting): %.20s", (char *) s); MM_LOG (tmp,ERROR); unix_unlock (LOCAL->fd,stream,lock); unix_abort (stream); mail_unlock (stream); /* done with critical */ MM_NOCRITICAL (stream); return NIL; } stream->silent = T; /* quell main program new message events */ do { /* found a message */ /* instantiate first new message */ mail_exists (stream,++nmsgs); (elt = mail_elt (stream,nmsgs))->valid = T; recent++; /* assume recent by default */ elt->recent = T; /* note position/size of internal header */ elt->private.special.offset = j; elt->private.msg.header.offset = elt->private.special.text.size = i; /* generate plausible IMAPish date string */ date[2] = date[6] = date[20] = '-'; date[11] = ' '; date[14] = date[17] = ':'; /* dd */ date[0] = t[ti - 2]; date[1] = t[ti - 1]; /* mmm */ date[3] = t[ti - 6]; date[4] = t[ti - 5]; date[5] = t[ti - 4]; /* hh */ date[12] = t[ti + 1]; date[13] = t[ti + 2]; /* mm */ date[15] = t[ti + 4]; date[16] = t[ti + 5]; if (t[ti += 6] == ':') {/* ss */ date[18] = t[++ti]; date[19] = t[++ti]; ti++; /* move to space */ } else date[18] = date[19] = '0'; /* yy -- advance over timezone if necessary */ if (zn == ti) ti += (((t[zn+1] == '+') || (t[zn+1] == '-')) ? 6 : 4); date[7] = t[ti + 1]; date[8] = t[ti + 2]; date[9] = t[ti + 3]; date[10] = t[ti + 4]; /* zzz */ t = zn ? (t + zn + 1) : (unsigned char *) "LCL"; date[21] = *t++; date[22] = *t++; date[23] = *t++; if ((date[21] != '+') && (date[21] != '-')) date[24] = '\0'; else { /* numeric time zone */ date[24] = *t++; date[25] = *t++; date[26] = '\0'; date[20] = ' '; } /* set internal date */ if (!mail_parse_date (elt,date)) { sprintf (tmp,"Unable to parse internal date: %s",(char *) date); MM_LOG (tmp,WARN); } do { /* look for message body */ s = t = unix_mbxline (stream,&bs,&i); if (i) switch (*s) { /* check header lines */ case 'X': /* possible X-???: line */ if (s[1] == '-') { /* must be immediately followed by hyphen */ /* X-Status: becomes Status: in S case */ if (s[2] == 'S' && s[3] == 't' && s[4] == 'a' && s[5] == 't' && s[6] == 'u' && s[7] == 's' && s[8] == ':') s += 2; /* possible X-Keywords */ else if (s[2] == 'K' && s[3] == 'e' && s[4] == 'y' && s[5] == 'w' && s[6] == 'o' && s[7] == 'r' && s[8] == 'd' && s[9] == 's' && s[10] == ':') { SIZEDTEXT uf; retain = NIL; /* don't retain continuation */ s += 11; /* flush leading whitespace */ while (*s && (*s != '\n') && ((*s != '\r') || (s[1] != '\n'))){ while (*s == ' ') s++; /* find end of keyword */ if (!(u = strpbrk (s," \n\r"))) u = s + strlen (s); /* got a keyword? */ if ((k = (u - s)) && (k <= MAXUSERFLAG)) { uf.data = (unsigned char *) s; uf.size = k; for (j = 0; (j < NUSERFLAGS) && stream->user_flags[j]; ++j) if (!compare_csizedtext (stream->user_flags[j],&uf)) { elt->user_flags |= ((long) 1) << j; break; } } s = u; /* advance to next keyword */ } break; } /* possible X-IMAP */ else if ((s[2] == 'I') && (s[3] == 'M') && (s[4] == 'A') && (s[5] == 'P') && ((m = (s[6] == ':')) || ((s[6] == 'b') && (s[7] == 'a') && (s[8] == 's') && (s[9] == 'e') && (s[10] == ':')))) { retain = NIL; /* don't retain continuation */ if ((nmsgs == 1) && !stream->uid_validity) { /* advance to data */ s += m ? 7 : 11; /* flush whitespace */ while (*s == ' ') s++; j = 0; /* slurp UID validity */ /* found a digit? */ while (isdigit (*s)) { j *= 10; /* yes, add it in */ j += *s++ - '0'; } /* flush whitespace */ while (*s == ' ') s++; /* must have valid UID validity and UID last */ if (j && isdigit (*s)) { /* pseudo-header seen if X-IMAP */ if (m) pseudoseen = LOCAL->pseudo = T; /* save UID validity */ stream->uid_validity = j; j = 0; /* slurp UID last */ while (isdigit (*s)) { j *= 10; /* yes, add it in */ j += *s++ - '0'; } /* save UID last */ stream->uid_last = j; /* process keywords */ for (j = 0; (*s != '\n') && ((*s != '\r')||(s[1] != '\n')); s = u,j++) { /* flush leading whitespace */ while (*s == ' ') s++; u = strpbrk (s," \n\r"); /* got a keyword? */ if ((j < NUSERFLAGS) && (k = (u - s)) && (k <= MAXUSERFLAG)) { if (stream->user_flags[j]) fs_give ((void **) &stream->user_flags[j]); stream->user_flags[j] = (char *) fs_get (k + 1); strncpy (stream->user_flags[j],s,k); stream->user_flags[j][k] = '\0'; } } } } break; } /* possible X-UID */ else if (s[2] == 'U' && s[3] == 'I' && s[4] == 'D' && s[5] == ':') { retain = NIL; /* don't retain continuation */ /* only believe if have a UID validity */ if (stream->uid_validity && ((nmsgs > 1) || !pseudoseen)) { s += 6; /* advance to UID value */ /* flush whitespace */ while (*s == ' ') s++; j = 0; /* found a digit? */ while (isdigit (*s)) { j *= 10; /* yes, add it in */ j += *s++ - '0'; } /* flush remainder of line */ while (*s != '\n') s++; /* make sure not duplicated */ if (elt->private.uid) sprintf (tmp,"Message %lu UID %lu already has UID %lu", pseudoseen ? elt->msgno - 1 : elt->msgno, j,elt->private.uid); /* make sure UID doesn't go backwards */ else if (j <= prevuid) sprintf (tmp,"Message %lu UID %lu less than %lu", pseudoseen ? elt->msgno - 1 : elt->msgno, j,prevuid + 1); #if 0 /* this is currently broken by UIDPLUS */ /* or skip by mailbox's recorded last */ else if (j > stream->uid_last) sprintf (tmp,"Message %lu UID %lu greater than last %lu", pseudoseen ? elt->msgno - 1 : elt->msgno, j,stream->uid_last); #endif else { /* normal UID case */ prevuid = elt->private.uid = j; #if 1 /* temporary kludge for UIDPLUS */ if (prevuid > stream->uid_last) { stream->uid_last = prevuid; LOCAL->ddirty = LOCAL->dirty = T; } #endif break; /* exit this cruft */ } MM_LOG (tmp,WARN); /* invalidate UID validity */ stream->uid_validity = 0; elt->private.uid = 0; } break; } } /* otherwise fall into S case */ case 'S': /* possible Status: line */ if (s[0] == 'S' && s[1] == 't' && s[2] == 'a' && s[3] == 't' && s[4] == 'u' && s[5] == 's' && s[6] == ':') { retain = NIL; /* don't retain continuation */ s += 6; /* advance to status flags */ do switch (*s++) {/* parse flags */ case 'R': /* message read */ elt->seen = T; break; case 'O': /* message old */ if (elt->recent) { elt->recent = NIL; recent--; /* it really wasn't recent */ } break; case 'D': /* message deleted */ elt->deleted = T; break; case 'F': /* message flagged */ elt->flagged = T; break; case 'A': /* message answered */ elt->answered = T; break; case 'T': /* message is a draft */ elt->draft = T; break; default: /* some other crap */ break; } while (*s && (*s != '\n') && ((*s != '\r') || (s[1] != '\n'))); break; /* all done */ } /* otherwise fall into default case */ default: /* ordinary header line */ if ((*s == 'S') || (*s == 's') || (((*s == 'X') || (*s == 'x')) && (s[1] == '-'))) { unsigned char *e,*v; /* must match what mail_filter() does */ for (u = s,v = tmp,e = u + min (i,MAILTMPLEN - 1); (u < e) && ((c = (*u ? *u : (*u = ' '))) != ':') && ((c > ' ') || ((c != ' ') && (c != '\t') && (c != '\r') && (c != '\n'))); *v++ = *u++); *v = '\0'; /* tie off */ /* matches internal header? */ if (!compare_cstring (tmp,"STATUS") || !compare_cstring (tmp,"X-STATUS") || !compare_cstring (tmp,"X-KEYWORDS") || !compare_cstring (tmp,"X-UID") || !compare_cstring (tmp,"X-IMAP") || !compare_cstring (tmp,"X-IMAPBASE")) { char err[MAILTMPLEN]; sprintf (err,"Discarding bogus %s header in message %lu", (char *) tmp,elt->msgno); MM_LOG (err,WARN); retain = NIL; /* don't retain continuation */ break; /* different case or something */ } } /* retain or non-continuation? */ if (retain || ((*s != ' ') && (*s != '\t'))) { retain = T; /* retaining continuation now */ /* line length in LF format newline */ for (j = k = 0; j < i; ++j) if (s[j] != '\r') ++k; /* "internal" header size */ elt->private.spare.data += k; /* message size */ elt->rfc822_size += k + 1; } else { char err[MAILTMPLEN]; sprintf (err,"Discarding bogus continuation in msg %lu: %.80s", elt->msgno,(char *) s); if (u = strpbrk (err,"\r\n")) *u = '\0'; MM_LOG (err,WARN); break; /* different case or something */ } break; } } while (i && (*t != '\n') && ((*t != '\r') || (t[1] != '\n'))); /* "internal" header sans trailing newline */ if (i) elt->private.spare.data--; /* assign a UID if none found */ if (((nmsgs > 1) || !pseudoseen) && !elt->private.uid) { prevuid = elt->private.uid = ++stream->uid_last; elt->private.dirty = T; LOCAL->ddirty = T; /* force update */ } else elt->private.dirty = elt->recent; /* note size of header, location of text */ elt->private.msg.header.text.size = (elt->private.msg.text.offset = (LOCAL->filesize + GETPOS (&bs)) - elt->private.special.offset) - elt->private.special.text.size; k = m = 0; /* no previous line size yet */ /* note current position */ j = LOCAL->filesize + GETPOS (&bs); if (i) do { /* look for next message */ s = unix_mbxline (stream,&bs,&i); if (i) { /* got new data? */ VALID (s,t,ti,zn); /* yes, parse line */ if (!ti) { /* not a header line, add it to message */ elt->rfc822_size += i; for (j = 0; j < i; ++j) switch (s[j]) { case '\r': /* squeeze out CRs */ elt->rfc822_size -= 1; break; case '\n': /* LF becomes CRLF */ elt->rfc822_size += 1; break; default: break; } if ((i == 1) && (*s == '\n')) { k = 2; m = 1; } else if ((i == 2) && (*s == '\r') && (s[1] == '\n')) k = m = 2; else k = m = 0; /* file does not end with newline! */ /* update current position */ j = LOCAL->filesize + GETPOS (&bs); } } } while (i && !ti); /* until found a header */ elt->private.msg.text.text.size = j - (elt->private.special.offset + elt->private.msg.text.offset); /* flush ending blank line */ elt->private.msg.text.text.size -= m; elt->rfc822_size -= k; /* until end of buffer */ } while (!stream->sniff && i); if (pseudoseen) { /* flush pseudo-message if present */ /* decrement recent count */ if (mail_elt (stream,1)->recent) recent--; /* and the exists count */ mail_exists (stream,nmsgs--); mail_expunged(stream,1);/* fake an expunge of that message */ } /* need to start a new UID validity? */ if (!stream->uid_validity) { stream->uid_validity = time (0); /* in case a whiner with no life */ if (mail_parameters (NIL,GET_USERHASNOLIFE,NIL)) stream->uid_nosticky = T; else if (nmsgs) { /* don't bother if empty file */ /* make dirty to restart UID epoch */ LOCAL->ddirty = LOCAL->dirty = T; /* need to rewrite msg 1 if not pseudo */ if (!LOCAL->pseudo) mail_elt (stream,1)->private.dirty = T; MM_LOG ("Assigning new unique identifiers to all messages",NIL); } } stream->nmsgs = oldnmsgs; /* whack it back down */ stream->silent = silent; /* restore old silent setting */ /* notify upper level of new mailbox sizes */ mail_exists (stream,nmsgs); mail_recent (stream,recent); /* mark dirty so O flags are set */ if (recent) LOCAL->dirty = T; } } /* no change, don't babble if never got time */ else if (LOCAL->filetime && LOCAL->filetime != sbuf.st_mtime) MM_LOG ("New mailbox modification time but apparently no changes",WARN); /* update parsed file size and time */ LOCAL->filesize = sbuf.st_size; LOCAL->filetime = sbuf.st_mtime; return T; /* return the winnage */ } /* UNIX read line from mailbox * Accepts: mail stream * stringstruct * pointer to line size * Returns: pointer to input line */ char *unix_mbxline (MAILSTREAM *stream,STRING *bs,unsigned long *size) { unsigned long i,j,k,m; char *s,*t,*te; char *ret = ""; /* flush old buffer */ if (LOCAL->line) fs_give ((void **) &LOCAL->line); /* if buffer needs refreshing */ if (!bs->cursize) SETPOS (bs,GETPOS (bs)); if (SIZE (bs)) { /* find newline */ /* end of fast scan */ te = (t = (s = bs->curpos) + bs->cursize) - 12; while (s < te) if ((*s++ == '\n') || (*s++ == '\n') || (*s++ == '\n') || (*s++ == '\n') || (*s++ == '\n') || (*s++ == '\n') || (*s++ == '\n') || (*s++ == '\n') || (*s++ == '\n') || (*s++ == '\n') || (*s++ == '\n') || (*s++ == '\n')) { --s; /* back up */ break; /* exit loop */ } /* final character-at-a-time scan */ while ((s < t) && (*s != '\n')) ++s; /* difficult case if line spans buffer */ if ((i = s - bs->curpos) == bs->cursize) { /* have space in line buffer? */ if (i > LOCAL->linebuflen) { fs_give ((void **) &LOCAL->linebuf); LOCAL->linebuf = (char *) fs_get (LOCAL->linebuflen = i); } /* remember what we have so far */ memcpy (LOCAL->linebuf,bs->curpos,i); /* load next buffer */ SETPOS (bs,k = GETPOS (bs) + i); /* end of fast scan */ te = (t = (s = bs->curpos) + bs->cursize) - 12; /* fast scan in overlap buffer */ while (s < te) if ((*s++ == '\n') || (*s++ == '\n') || (*s++ == '\n') || (*s++ == '\n') || (*s++ == '\n') || (*s++ == '\n') || (*s++ == '\n') || (*s++ == '\n') || (*s++ == '\n') || (*s++ == '\n') || (*s++ == '\n') || (*s++ == '\n')) { --s; /* back up */ break; /* exit loop */ } /* final character-at-a-time scan */ while ((s < t) && (*s != '\n')) ++s; /* huge line? */ if ((j = s - bs->curpos) == bs->cursize) { SETPOS (bs,GETPOS (bs) + j); /* look for end of line (s-l-o-w!!) */ for (m = SIZE (bs); m && (SNX (bs) != '\n'); --m,++j); SETPOS (bs,k); /* go back to where it started */ } /* got size of data, make buffer for return */ ret = LOCAL->line = (char *) fs_get (i + j + 2); /* copy first chunk */ memcpy (ret,LOCAL->linebuf,i); while (j) { /* copy remainder */ if (!bs->cursize) SETPOS (bs,GETPOS (bs)); memcpy (ret + i,bs->curpos,k = min (j,bs->cursize)); i += k; /* account for this much read in */ j -= k; bs->curpos += k; /* increment new position */ bs->cursize -= k; /* eat that many bytes */ } if (!bs->cursize) SETPOS (bs,GETPOS (bs)); /* read newline at end */ if (SIZE (bs)) ret[i++] = SNX (bs); ret[i] = '\0'; /* makes debugging easier */ } else { /* this is easy */ ret = bs->curpos; /* string it at this position */ bs->curpos += ++i; /* increment new position */ bs->cursize -= i; /* eat that many bytes */ } *size = i; /* return that to user */ } else *size = 0; /* end of data, return empty */ return ret; } /* UNIX make pseudo-header * Accepts: MAIL stream * buffer to write pseudo-header * Returns: length of pseudo-header */ unsigned long unix_pseudo (MAILSTREAM *stream,char *hdr) { int i; char *s,tmp[MAILTMPLEN]; time_t now = time (0); rfc822_fixed_date (tmp); sprintf (hdr,"From %s %.24s\nDate: %s\nFrom: %s <%s@%.80s>\nSubject: %s\nMessage-ID: <%lu@%.80s>\nX-IMAP: %010lu %010lu", pseudo_from,ctime (&now), tmp,pseudo_name,pseudo_from,mylocalhost (),pseudo_subject, (unsigned long) now,mylocalhost (),stream->uid_validity, stream->uid_last); for (s = hdr + strlen (hdr),i = 0; i < NUSERFLAGS; ++i) if (stream->user_flags[i]) sprintf (s += strlen (s)," %s",stream->user_flags[i]); sprintf (s += strlen (s),"\nStatus: RO\n\n%s\n\n",pseudo_msg); return strlen (hdr); /* return header length */ } /* UNIX make status string * Accepts: MAIL stream * destination string to write * message cache entry * UID to write if non-zero (else use elt->private.uid) * non-zero flag to write UID (.LT. 0 to write UID base info too) * Returns: length of string */ unsigned long unix_xstatus (MAILSTREAM *stream,char *status,MESSAGECACHE *elt, unsigned long uid,long flag) { char *t,stack[64]; char *s = status; unsigned long n; int pad = 50; int sticky = uid ? T : !stream->uid_nosticky; /* This used to use sprintf(), but thanks to certain cretinous C libraries with horribly slow implementations of sprintf() I had to change it to this mess. At least it should be fast. */ if ((flag < 0) && sticky) { /* need to write X-IMAPbase: header? */ *s++ = 'X'; *s++ = '-'; *s++ = 'I'; *s++ = 'M'; *s++ = 'A'; *s++ = 'P'; *s++ = 'b'; *s++ = 'a'; *s++ = 's'; *s++ = 'e'; *s++ = ':'; *s++ = ' '; t = stack; n = stream->uid_validity; /* push UID validity digits on the stack */ do *t++ = (char) (n % 10) + '0'; while (n /= 10); /* pop UID validity digits from stack */ while (t > stack) *s++ = *--t; *s++ = ' '; n = stream->uid_last; /* push UID last digits on the stack */ do *t++ = (char) (n % 10) + '0'; while (n /= 10); /* pop UID last digits from stack */ while (t > stack) *s++ = *--t; for (n = 0; n < NUSERFLAGS; ++n) if (t = stream->user_flags[n]) for (*s++ = ' '; *t; *s++ = *t++); *s++ = '\n'; pad += 30; /* increased padding if have IMAPbase */ } *s++ = 'S'; *s++ = 't'; *s++ = 'a'; *s++ = 't'; *s++ = 'u'; *s++ = 's'; *s++ = ':'; *s++ = ' '; if (elt->seen) *s++ = 'R'; /* only write O if have a UID */ if (flag && (!elt->recent || !LOCAL->appending)) *s++ = 'O'; *s++ = '\n'; *s++ = 'X'; *s++ = '-'; *s++ = 'S'; *s++ = 't'; *s++ = 'a'; *s++ = 't'; *s++ = 'u'; *s++ = 's'; *s++ = ':'; *s++ = ' '; if (elt->deleted) *s++ = 'D'; if (elt->flagged) *s++ = 'F'; if (elt->answered) *s++ = 'A'; if (elt->draft) *s++ = 'T'; *s++ = '\n'; if (sticky) { /* only do this if UIDs sticky */ *s++ = 'X'; *s++ = '-'; *s++ = 'K'; *s++ = 'e'; *s++ = 'y'; *s++ = 'w'; *s++ = 'o'; *s++ = 'r'; *s++ = 'd'; *s++ = 's'; *s++ = ':'; if (n = elt->user_flags) do { *s++ = ' '; for (t = stream->user_flags[find_rightmost_bit (&n)]; *t; *s++ = *t++); } while (n); n = s - status; /* get size of stuff so far */ /* pad X-Keywords to make size constant */ if (n < pad) for (n = pad - n; n > 0; --n) *s++ = ' '; *s++ = '\n'; if (flag) { /* want to include UID? */ t = stack; /* push UID digits on the stack */ n = uid ? uid : elt->private.uid; do *t++ = (char) (n % 10) + '0'; while (n /= 10); *s++ = 'X'; *s++ = '-'; *s++ = 'U'; *s++ = 'I'; *s++ = 'D'; *s++ = ':'; *s++ = ' '; /* pop UID from stack */ while (t > stack) *s++ = *--t; *s++ = '\n'; } } *s++ = '\n'; *s = '\0'; /* end of extended message status */ return s - status; /* return size of resulting string */ } /* Rewrite mailbox file * Accepts: MAIL stream, must be critical and locked * return pointer to number of expunged messages if want expunge * lock file name * expunge sequence, not deleted flag * Returns: T if success and mailbox unlocked, NIL if failure */ #define OVERFLOWBUFLEN 8192 /* initial overflow buffer length */ long unix_rewrite (MAILSTREAM *stream,unsigned long *nexp,DOTLOCK *lock, long flags) { MESSAGECACHE *elt; UNIXFILE f; char *s; time_t tp[2]; long ret,flag; unsigned long i,j; unsigned long recent = stream->recent; unsigned long size = LOCAL->pseudo ? unix_pseudo (stream,LOCAL->buf) : 0; if (nexp) *nexp = 0; /* initially nothing expunged */ /* calculate size of mailbox after rewrite */ for (i = 1,flag = LOCAL->pseudo ? 1 : -1; i <= stream->nmsgs; i++) { elt = mail_elt (stream,i); /* get cache */ if (!(nexp && elt->deleted && (flags ? elt->sequence : T))) { /* add RFC822 size of this message */ size += elt->private.special.text.size + elt->private.spare.data + unix_xstatus (stream,LOCAL->buf,elt,NIL,flag) + elt->private.msg.text.text.size + 1; flag = 1; /* only count X-IMAPbase once */ } } /* no messages, has a life, and no pseudo */ if (!size && !mail_parameters (NIL,GET_USERHASNOLIFE,NIL)) { LOCAL->pseudo = T; /* so make a pseudo-message now */ size = unix_pseudo (stream,LOCAL->buf); } /* extend the file as necessary */ if (ret = unix_extend (stream,size)) { /* Set up buffered I/O file structure * curpos current position being written through buffering * filepos current position being written physically to the disk * bufpos current position being written in the buffer * protect current maximum position that can be written to the disk * before buffering is forced * The code tries to buffer so that that disk is written in multiples of * OVERBLOWBUFLEN bytes. */ f.stream = stream; /* note mail stream */ f.curpos = f.filepos = 0; /* start of file */ f.protect = stream->nmsgs ? /* initial protection pointer */ mail_elt (stream,1)->private.special.offset : 8192; f.bufpos = f.buf = (char *) fs_get (f.buflen = OVERFLOWBUFLEN); if (LOCAL->pseudo) /* update pseudo-header */ unix_write (&f,LOCAL->buf,unix_pseudo (stream,LOCAL->buf)); /* loop through all messages */ for (i = 1,flag = LOCAL->pseudo ? 1 : -1; i <= stream->nmsgs;) { elt = mail_elt (stream,i);/* get cache */ /* expunge this message? */ if (nexp && elt->deleted && (flags ? elt->sequence : T)) { /* one less recent message */ if (elt->recent) --recent; mail_expunged(stream,i);/* notify upper levels */ ++*nexp; /* count up one more expunged message */ } else { /* preserve this message */ i++; /* advance to next message */ if ((flag < 0) || /* need to rewrite message? */ elt->private.dirty || (f.curpos != elt->private.special.offset) || (elt->private.msg.header.text.size != (elt->private.spare.data + unix_xstatus (stream,LOCAL->buf,elt,NIL,flag)))) { unsigned long newoffset = f.curpos; /* yes, seek to internal header */ lseek (LOCAL->fd,elt->private.special.offset,L_SET); read (LOCAL->fd,LOCAL->buf,elt->private.special.text.size); /* see if need to squeeze out a CR */ if (LOCAL->buf[elt->private.special.text.size - 2] == '\r') { LOCAL->buf[--elt->private.special.text.size - 1] = '\n'; --size; /* squeezed out a CR from PC */ } /* protection pointer moves to RFC822 header */ f.protect = elt->private.special.offset + elt->private.msg.header.offset; /* write internal header */ unix_write (&f,LOCAL->buf,elt->private.special.text.size); /* get RFC822 header */ s = unix_header (stream,elt->msgno,&j,FT_INTERNAL); /* in case this got decremented */ elt->private.msg.header.offset = elt->private.special.text.size; /* header size, sans trailing newline */ if ((j < 2) || (s[j - 2] == '\n')) j--; /* this can happen if CRs were squeezed */ if (j < elt->private.spare.data) { /* so fix up counts */ size -= elt->private.spare.data - j; elt->private.spare.data = j; } else if (j != elt->private.spare.data) fatal ("header size inconsistent"); /* protection pointer moves to RFC822 text */ f.protect = elt->private.special.offset + elt->private.msg.text.offset; unix_write (&f,s,j); /* write RFC822 header */ /* write status and UID */ unix_write (&f,LOCAL->buf, j = unix_xstatus (stream,LOCAL->buf,elt,NIL,flag)); flag = 1; /* only write X-IMAPbase once */ /* new file header size */ elt->private.msg.header.text.size = elt->private.spare.data + j; /* did text move? */ if (f.curpos != f.protect) { /* get message text */ s = unix_text_work (stream,elt,&j,FT_INTERNAL); /* this can happen if CRs were squeezed */ if (j < elt->private.msg.text.text.size) { /* so fix up counts */ size -= elt->private.msg.text.text.size - j; elt->private.msg.text.text.size = j; } /* can't happen it says here */ else if (j > elt->private.msg.text.text.size) fatal ("text size inconsistent"); /* new text offset, status/UID may change it */ elt->private.msg.text.offset = f.curpos - newoffset; /* protection pointer moves to next message */ f.protect = (i <= stream->nmsgs) ? mail_elt (stream,i)->private.special.offset : (f.curpos + j + 1); unix_write (&f,s,j);/* write text */ /* write trailing newline */ unix_write (&f,"\n",1); } else { /* tie off header and status */ unix_write (&f,NIL,NIL); /* protection pointer moves to next message */ f.protect = (i <= stream->nmsgs) ? mail_elt (stream,i)->private.special.offset : size; /* locate end of message text */ j = f.filepos + elt->private.msg.text.text.size; /* trailing newline already there? */ if (f.protect == (j + 1)) f.curpos = f.filepos = f.protect; else { /* trailing newline missing, write it */ f.curpos = f.filepos = j; unix_write (&f,"\n",1); } } /* new internal header offset */ elt->private.special.offset = newoffset; elt->private.dirty =NIL;/* message is now clean */ } else { /* no need to rewrite this message */ /* tie off previous message if needed */ unix_write (&f,NIL,NIL); /* protection pointer moves to next message */ f.protect = (i <= stream->nmsgs) ? mail_elt (stream,i)->private.special.offset : size; /* locate end of message text */ j = f.filepos + elt->private.special.text.size + elt->private.msg.header.text.size + elt->private.msg.text.text.size; /* trailing newline already there? */ if (f.protect == (j + 1)) f.curpos = f.filepos = f.protect; else { /* trailing newline missing, write it */ f.curpos = f.filepos = j; unix_write (&f,"\n",1); } } } } unix_write (&f,NIL,NIL); /* tie off final message */ if (size != f.filepos) fatal ("file size inconsistent"); fs_give ((void **) &f.buf); /* free buffer */ /* make sure tied off */ ftruncate (LOCAL->fd,LOCAL->filesize = size); fsync (LOCAL->fd); /* make sure the updates take */ if (size && (flag < 0)) fatal ("lost UID base information"); /* no longer dirty */ LOCAL->ddirty = LOCAL->dirty = NIL; /* notify upper level of new mailbox sizes */ mail_exists (stream,stream->nmsgs); mail_recent (stream,recent); /* set atime to now, mtime a second earlier */ tp[1] = (tp[0] = time (0)) - 1; /* set the times, note change */ if (!utime (stream->mailbox,tp)) LOCAL->filetime = tp[1]; close (LOCAL->fd); /* close and reopen file */ if ((LOCAL->fd = open (stream->mailbox,O_RDWR, (long) mail_parameters (NIL,GET_MBXPROTECTION,NIL))) < 0) { sprintf (LOCAL->buf,"Mailbox open failed, aborted: %s",strerror (errno)); MM_LOG (LOCAL->buf,ERROR); unix_abort (stream); } dotlock_unlock (lock); /* flush the lock file */ } return ret; /* return state from algorithm */ } /* Extend UNIX mailbox file * Accepts: MAIL stream * new desired size * Return: T if success, else NIL */ long unix_extend (MAILSTREAM *stream,unsigned long size) { unsigned long i = (size > LOCAL->filesize) ? size - LOCAL->filesize : 0; if (i) { /* does the mailbox need to grow? */ if (i > LOCAL->buflen) { /* make sure have enough space */ /* this user won the lottery all right */ fs_give ((void **) &LOCAL->buf); LOCAL->buf = (char *) fs_get ((LOCAL->buflen = i) + 1); } memset (LOCAL->buf,'\0',i); /* get a block of nulls */ while (T) { /* until write successful or punt */ lseek (LOCAL->fd,LOCAL->filesize,L_SET); if ((write (LOCAL->fd,LOCAL->buf,i) >= 0) && !fsync (LOCAL->fd)) break; else { long e = errno; /* note error before doing ftruncate */ ftruncate (LOCAL->fd,LOCAL->filesize); if (MM_DISKERROR (stream,e,NIL)) { fsync (LOCAL->fd); /* user chose to punt */ sprintf (LOCAL->buf,"Unable to extend mailbox: %s",strerror (e)); if (!stream->silent) MM_LOG (LOCAL->buf,ERROR); return NIL; } } } } return LONGT; } /* Write data to buffered file * Accepts: buffered file pointer * file data or NIL to indicate "flush buffer" * date size (ignored for "flush buffer") * Does not return until success */ void unix_write (UNIXFILE *f,char *buf,unsigned long size) { unsigned long i,j,k; if (buf) { /* doing buffered write? */ i = f->bufpos - f->buf; /* yes, get size of current buffer data */ /* yes, have space in current buffer chunk? */ if (j = i ? ((f->buflen - i) % OVERFLOWBUFLEN) : f->buflen) { /* yes, fill up buffer as much as we can */ memcpy (f->bufpos,buf,k = min (j,size)); f->bufpos += k; /* new buffer position */ f->curpos += k; /* new current position */ if (j -= k) return; /* all done if still have buffer free space */ buf += k; /* full, get new unwritten data pointer */ size -= k; /* new data size */ i += k; /* new buffer data size */ } /* This chunk of the buffer is full. See if can make some space by * writing to the disk, if there's enough unprotected space to do so. * Try to fill out any unaligned chunk, along with any subsequent full * chunks that will fit in unprotected space. */ /* any unprotected space we can write to? */ if (j = min (i,f->protect - f->filepos)) { /* yes, filepos not at chunk boundary? */ if ((k = f->filepos % OVERFLOWBUFLEN) && ((k = OVERFLOWBUFLEN - k) < j)) j -= k; /* yes, and can write out partial chunk */ else k = 0; /* no partial chunk to write */ /* if at least a chunk free, write that too */ if (j > OVERFLOWBUFLEN) k += j - (j % OVERFLOWBUFLEN); if (k) { /* write data if there is anything we can */ unix_phys_write (f,f->buf,k); /* slide buffer */ if (i -= k) memmove (f->buf,f->buf + k,i); f->bufpos = f->buf + i; /* new end of buffer */ } } /* Have flushed the buffer as best as possible. All done if no more * data to write. Otherwise, if the buffer is empty AND if the unwritten * data is larger than a chunk AND the unprotected space is also larger * than a chunk, then write as many chunks as we can directly from the * data. Buffer the rest, expanding the buffer as needed. */ if (size) { /* have more data that we need to buffer? */ /* can write any of it to disk instead? */ if ((f->bufpos == f->buf) && ((j = min (f->protect - f->filepos,size)) > OVERFLOWBUFLEN)) { /* write as much as we can right now */ unix_phys_write (f,buf,j -= (j % OVERFLOWBUFLEN)); buf += j; /* new data pointer */ size -= j; /* new data size */ f->curpos += j; /* advance current pointer */ } if (size) { /* still have data that we need to buffer? */ /* yes, need to expand the buffer? */ if ((i = ((f->bufpos + size) - f->buf)) > f->buflen) { /* note current position in buffer */ j = f->bufpos - f->buf; i += OVERFLOWBUFLEN; /* yes, grow another chunk */ fs_resize ((void **) &f->buf,f->buflen = i - (i % OVERFLOWBUFLEN)); /* in case buffer relocated */ f->bufpos = f->buf + j; } /* buffer remaining data */ memcpy (f->bufpos,buf,size); f->bufpos += size; /* new end of buffer */ f->curpos += size; /* advance current pointer */ } } } else { /* flush buffer to disk */ unix_phys_write (f,f->buf,i = f->bufpos - f->buf); f->bufpos = f->buf; /* reset buffer */ /* update positions */ f->curpos = f->protect = f->filepos; } } /* Physical disk write * Accepts: buffered file pointer * buffer address * buffer size * Does not return until success */ void unix_phys_write (UNIXFILE *f,char *buf,size_t size) { MAILSTREAM *stream = f->stream; /* write data at desired position */ while (size && ((lseek (LOCAL->fd,f->filepos,L_SET) < 0) || (write (LOCAL->fd,buf,size) < 0))) { int e; char tmp[MAILTMPLEN]; sprintf (tmp,"Unable to write to mailbox: %s",strerror (e = errno)); MM_LOG (tmp,ERROR); MM_DISKERROR (NIL,e,T); /* serious problem, must retry */ } f->filepos += size; /* update file position */ } /* MBOX mail routines */ /* Driver dispatch used by MAIL */ DRIVER mboxdriver = { "mbox", /* driver name */ /* driver flags */ DR_LOCAL|DR_MAIL|DR_LOCKING|DR_NONEWMAILRONLY, (DRIVER *) NIL, /* next driver */ mbox_valid, /* mailbox is valid for us */ unix_parameters, /* manipulate parameters */ unix_scan, /* scan mailboxes */ unix_list, /* find mailboxes */ unix_lsub, /* find subscribed mailboxes */ NIL, /* subscribe to mailbox */ NIL, /* unsubscribe from mailbox */ mbox_create, /* create mailbox */ mbox_delete, /* delete mailbox */ mbox_rename, /* rename mailbox */ mbox_status, /* status of mailbox */ mbox_open, /* open mailbox */ unix_close, /* close mailbox */ NIL, /* fetch message "fast" attributes */ NIL, /* fetch message flags */ NIL, /* fetch overview */ NIL, /* fetch message structure */ unix_header, /* fetch message header */ unix_text, /* fetch message body */ NIL, /* fetch partial message text */ NIL, /* unique identifier */ NIL, /* message number */ NIL, /* modify flags */ unix_flagmsg, /* per-message modify flags */ NIL, /* search for message based on criteria */ NIL, /* sort messages */ NIL, /* thread messages */ mbox_ping, /* ping mailbox to see if still alive */ mbox_check, /* check for new messages */ mbox_expunge, /* expunge deleted messages */ unix_copy, /* copy messages to another mailbox */ mbox_append, /* append string message to mailbox */ NIL /* garbage collect stream */ }; /* prototype stream */ MAILSTREAM mboxproto = {&mboxdriver}; /* MBOX mail validate mailbox * Accepts: mailbox name * Returns: our driver if name is valid, NIL otherwise */ DRIVER *mbox_valid (char *name) { /* only INBOX, mbox must exist */ if (!compare_cstring (name,"INBOX") && (unix_valid ("mbox") || !errno) && (unix_valid (sysinbox()) || !errno || (errno == ENOENT))) return &mboxdriver; return NIL; /* can't win (yet, anyway) */ } /* MBOX mail create mailbox * Accepts: MAIL stream * mailbox name to create * Returns: T on success, NIL on failure */ long mbox_create (MAILSTREAM *stream,char *mailbox) { char tmp[MAILTMPLEN]; if (!compare_cstring (mailbox,"INBOX")) return unix_create (NIL,"mbox"); sprintf (tmp,"Can't create non-INBOX name as mbox: %.80s",mailbox); MM_LOG (tmp,ERROR); return NIL; } /* MBOX mail delete mailbox * Accepts: MAIL stream * mailbox name to delete * Returns: T on success, NIL on failure */ long mbox_delete (MAILSTREAM *stream,char *mailbox) { return mbox_rename (stream,mailbox,NIL); } /* MBOX mail rename mailbox * Accepts: MAIL stream * old mailbox name * new mailbox name (or NIL for delete) * Returns: T on success, NIL on failure */ long mbox_rename (MAILSTREAM *stream,char *old,char *newname) { char tmp[MAILTMPLEN]; long ret = unix_rename (stream,"~/mbox",newname); /* recreate file if renamed INBOX */ if (ret) unix_create (NIL,"mbox"); else MM_LOG (tmp,ERROR); /* log error */ return ret; /* return success */ } /* MBOX Mail status * Accepts: mail stream * mailbox name * status flags * Returns: T on success, NIL on failure */ long mbox_status (MAILSTREAM *stream,char *mbx,long flags) { MAILSTATUS status; unsigned long i; MAILSTREAM *tstream = NIL; MAILSTREAM *systream = NIL; /* make temporary stream (unless this mbx) */ if (!stream && !(stream = tstream = mail_open (NIL,mbx,OP_READONLY|OP_SILENT))) return NIL; status.flags = flags; /* return status values */ status.messages = stream->nmsgs; status.recent = stream->recent; if (flags & SA_UNSEEN) /* must search to get unseen messages */ for (i = 1,status.unseen = 0; i <= stream->nmsgs; i++) if (!mail_elt (stream,i)->seen) status.unseen++; status.uidnext = stream->uid_last + 1; status.uidvalidity = stream->uid_validity; if (!status.recent && /* calculate post-snarf results */ (systream = mail_open (NIL,sysinbox (),OP_READONLY|OP_SILENT))) { status.messages += systream->nmsgs; status.recent += systream->recent; if (flags & SA_UNSEEN) /* must search to get unseen messages */ for (i = 1; i <= systream->nmsgs; i++) if (!mail_elt (systream,i)->seen) status.unseen++; /* kludge but probably good enough */ status.uidnext += systream->nmsgs; } MM_STATUS(stream,mbx,&status);/* pass status to main program */ if (tstream) mail_close (tstream); if (systream) mail_close (systream); return T; /* success */ } /* MBOX mail open * Accepts: stream to open * Returns: stream on success, NIL on failure */ MAILSTREAM *mbox_open (MAILSTREAM *stream) { unsigned long i = 1; unsigned long recent = 0; /* return prototype for OP_PROTOTYPE call */ if (!stream) return &mboxproto; /* change mailbox file name */ fs_give ((void **) &stream->mailbox); stream->mailbox = cpystr ("mbox"); /* open mailbox, snarf new mail */ if (!(unix_open (stream) && mbox_ping (stream))) return NIL; stream->inbox = T; /* mark that this is an INBOX */ /* notify upper level of mailbox sizes */ mail_exists (stream,stream->nmsgs); while (i <= stream->nmsgs) if (mail_elt (stream,i++)->recent) ++recent; mail_recent (stream,recent); /* including recent messages */ return stream; } /* MBOX mail ping mailbox * Accepts: MAIL stream * Returns: T if stream alive, else NIL * No-op for readonly files, since read/writer can expunge it from under us! */ static int snarfed = 0; /* number of snarfs */ long mbox_ping (MAILSTREAM *stream) { int sfd; unsigned long size; struct stat sbuf; char *s; DOTLOCK lock,lockx; /* time to try snarf and sysinbox non-empty? */ if (LOCAL && !stream->rdonly && !stream->lock && (time (0) >= (LOCAL->lastsnarf + (long) mail_parameters (NIL,GET_SNARFINTERVAL,NIL))) && !stat (sysinbox (),&sbuf) && sbuf.st_size) { MM_CRITICAL (stream); /* yes, go critical */ /* open and lock sysinbox */ if ((sfd = unix_lock (sysinbox (),O_RDWR, (long) mail_parameters (NIL,GET_MBXPROTECTION,NIL), &lockx,LOCK_EX)) >= 0) { /* locked sysinbox in good format? */ if (fstat (sfd,&sbuf) || !(size = sbuf.st_size) || !unix_isvalid_fd (sfd)) { sprintf (LOCAL->buf,"Mail drop %s is not in standard Unix format", sysinbox ()); MM_LOG (LOCAL->buf,ERROR); } /* sysinbox good, parse and excl-lock mbox */ else if (unix_parse (stream,&lock,LOCK_EX)) { lseek (sfd,0,L_SET); /* read entire sysinbox into memory */ read (sfd,s = (char *) fs_get (size + 1),size); s[size] = '\0'; /* tie it off */ /* append to end of mbox */ lseek (LOCAL->fd,LOCAL->filesize,L_SET); /* copy to mbox */ if ((write (LOCAL->fd,s,size) < 0) || fsync (LOCAL->fd)) { sprintf (LOCAL->buf,"New mail move failed: %s",strerror (errno)); MM_LOG (LOCAL->buf,WARN); /* revert mbox to previous size */ ftruncate (LOCAL->fd,LOCAL->filesize); } /* sysinbox better not have changed */ else if (fstat (sfd,&sbuf) || (size != sbuf.st_size)) { sprintf (LOCAL->buf,"Mail drop %s lock failure, old=%lu now=%lu", sysinbox (),size,(unsigned long) sbuf.st_size); MM_LOG (LOCAL->buf,ERROR); /* revert mbox to previous size */ ftruncate (LOCAL->fd,LOCAL->filesize); /* Believe it or not, a Singaporean government system actually had * symlinks from /var/mail/user to ~user/mbox. To compound this * error, they used an SVR4 system; BSD and OSF locks would have * prevented it but not SVR4 locks. */ if (!fstat (sfd,&sbuf) && (size == sbuf.st_size)) syslog (LOG_ALERT,"File %s and %s are the same file!", sysinbox (),stream->mailbox); } else { /* data copied OK */ ftruncate (sfd,0); /* truncate sysinbox to zero bytes */ if (!snarfed++) { /* have we snarfed before? */ /* syslog if server, else user log */ sprintf (LOCAL->buf,"Moved %lu bytes of new mail to %s from %s", size,stream->mailbox,sysinbox ()); if (strcmp ((char *) mail_parameters (NIL,GET_SERVICENAME,NIL), "unknown")) syslog (LOG_INFO,"%s host= %s",LOCAL->buf,tcp_clienthost ()); else MM_LOG (LOCAL->buf,WARN); } } /* done with sysinbox text */ fs_give ((void **) &s); /* all done with mbox */ unix_unlock (LOCAL->fd,stream,&lock); mail_unlock (stream); /* unlock the stream */ MM_NOCRITICAL (stream); /* done with critical */ } /* all done with sysinbox */ unix_unlock (sfd,NIL,&lockx); } MM_NOCRITICAL (stream); /* done with critical */ LOCAL->lastsnarf = time (0);/* note time of last snarf */ } return unix_ping (stream); /* do the unix routine now */ } /* MBOX mail check mailbox * Accepts: MAIL stream */ void mbox_check (MAILSTREAM *stream) { /* do local ping, then do unix routine */ if (mbox_ping (stream)) unix_check (stream); } /* MBOX mail expunge mailbox * Accepts: MAIL stream * sequence to expunge if non-NIL * expunge options * Returns: T, always */ long mbox_expunge (MAILSTREAM *stream,char *sequence,long options) { long ret = unix_expunge (stream,sequence,options); mbox_ping (stream); /* do local ping */ return ret; } /* MBOX mail append message from stringstruct * Accepts: MAIL stream * destination mailbox * append callback * data for callback * Returns: T if append successful, else NIL */ long mbox_append (MAILSTREAM *stream,char *mailbox,append_t af,void *data) { char tmp[MAILTMPLEN]; if (mbox_valid (mailbox)) return unix_append (stream,"mbox",af,data); sprintf (tmp,"Can't append to that name: %.80s",mailbox); MM_LOG (tmp,ERROR); return NIL; } alpine-2.10+dfsg/imap/src/osdep/amiga/scandir.c0000600000175000017500000000515711512502124023040 0ustar paulproteuspaulproteus/* ======================================================================== * Copyright 1988-2006 University of Washington * * Licensed under the Apache License, Version 2.0 (the "License"); * you may not use this file except in compliance with the License. * You may obtain a copy of the License at * * http://www.apache.org/licenses/LICENSE-2.0 * * * ======================================================================== */ /* * Program: Scan directories * * Author: Mark Crispin * Networks and Distributed Computing * Computing & Communications * University of Washington * Administration Building, AG-44 * Seattle, WA 98195 * Internet: MRC@CAC.Washington.EDU * * Date: 1 August 1988 * Last Edited: 15 September 2006 */ /* Emulator for BSD scandir() call * Accepts: directory name * destination pointer of names array * selection function * comparison function * Returns: number of elements in the array or -1 if error */ int scandir (char *dirname,struct direct ***namelist,select_t select, compar_t compar) { struct direct *p,*d,**names; int nitems; struct stat stb; long nlmax; DIR *dirp = opendir (dirname);/* open directory and get status poop */ if ((!dirp) || (fstat (dirp->dd_fd,&stb) < 0)) return -1; nlmax = stb.st_size / 24; /* guesstimate at number of files */ names = (struct direct **) fs_get (nlmax * sizeof (struct direct *)); nitems = 0; /* initially none found */ while (d = readdir (dirp)) { /* read directory item */ /* matches select criterion? */ if (select && !(*select) (d)) continue; /* get size of direct record for this file */ p = (struct direct *) fs_get (DIR_SIZE (d)); p->d_ino = d->d_ino; /* copy the poop */ strcpy (p->d_name,d->d_name); if (++nitems >= nlmax) { /* if out of space, try bigger guesstimate */ void *s = (void *) names; /* stupid language */ nlmax *= 2; /* double it */ fs_resize ((void **) &s,nlmax * sizeof (struct direct *)); names = (struct direct **) s; } names[nitems - 1] = p; /* store this file there */ } closedir (dirp); /* done with directory */ /* sort if necessary */ if (nitems && compar) qsort (names,nitems,sizeof (struct direct *),compar); *namelist = names; /* return directory */ return nitems; /* and size */ } /* Alphabetic file name comparision * Accepts: first candidate directory entry * second candidate directory entry * Returns: negative if d1 < d2, 0 if d1 == d2, postive if d1 > d2 */ int alphasort (void *d1,void *d2) { return strcmp ((*(struct direct **) d1)->d_name, (*(struct direct **) d2)->d_name); } alpine-2.10+dfsg/imap/src/osdep/amiga/ssl_none.c0000600000175000017500000000511011512502124023222 0ustar paulproteuspaulproteus/* ======================================================================== * Copyright 1988-2006 University of Washington * * Licensed under the Apache License, Version 2.0 (the "License"); * you may not use this file except in compliance with the License. * You may obtain a copy of the License at * * http://www.apache.org/licenses/LICENSE-2.0 * * * ======================================================================== */ /* * Program: Dummy (no SSL) authentication/encryption module * * Author: Mark Crispin * Networks and Distributed Computing * Computing & Communications * University of Washington * Administration Building, AG-44 * Seattle, WA 98195 * Internet: MRC@CAC.Washington.EDU * * Date: 7 February 2001 * Last Edited: 30 August 2006 */ /* Init server for SSL * Accepts: server name */ void ssl_server_init (char *server) { syslog (LOG_ERR,"This server does not support SSL"); exit (1); /* punt this program too */ } /* Start TLS * Accepts: /etc/services service name * Returns: cpystr'd error string if TLS failed, else NIL for success */ char *ssl_start_tls (char *server) { return cpystr ("This server does not support TLS"); } /* Get character * Returns: character or EOF */ int PBIN (void) { return getchar (); } /* Get string * Accepts: destination string pointer * number of bytes available * Returns: destination string pointer or NIL if EOF */ char *PSIN (char *s,int n) { return fgets (s,n,stdin); } /* Get record * Accepts: destination string pointer * number of bytes to read * Returns: T if success, NIL otherwise */ long PSINR (char *s,unsigned long n) { unsigned long i; while (n && ((i = fread (s,1,n,stdin)) || (errno == EINTR))) s += i,n -= i; return n ? NIL : LONGT; } /* Wait for input * Accepts: timeout in seconds * Returns: T if have input on stdin, else NIL */ long INWAIT (long seconds) { return server_input_wait (seconds); } /* Put character * Accepts: character * Returns: character written or EOF */ int PBOUT (int c) { return putchar (c); } /* Put string * Accepts: source string pointer * Returns: 0 or EOF if error */ int PSOUT (char *s) { return fputs (s,stdout); } /* Put record * Accepts: source sized text * Returns: 0 or EOF if error */ int PSOUTR (SIZEDTEXT *s) { unsigned char *t; unsigned long i,j; for (t = s->data,i = s->size; (i && ((j = fwrite (t,1,i,stdout)) || (errno == EINTR))); t += j,i -= j); return i ? EOF : NIL; } /* Flush output * Returns: 0 or EOF if error */ int PFLUSH (void) { return fflush (stdout); } alpine-2.10+dfsg/imap/src/osdep/amiga/dummy.c0000600000175000017500000006124411512502124022547 0ustar paulproteuspaulproteus/* ======================================================================== * Copyright 1988-2007 University of Washington * * Licensed under the Apache License, Version 2.0 (the "License"); * you may not use this file except in compliance with the License. * You may obtain a copy of the License at * * http://www.apache.org/licenses/LICENSE-2.0 * * * ======================================================================== */ /* * Program: Dummy routines * * Author: Mark Crispin * Networks and Distributed Computing * Computing & Communications * University of Washington * Administration Building, AG-44 * Seattle, WA 98195 * Internet: MRC@CAC.Washington.EDU * * Date: 9 May 1991 * Last Edited: 1 June 2007 */ #include #include #include extern int errno; /* just in case */ #include "mail.h" #include "osdep.h" #include #include #include "dummy.h" #include "misc.h" /* Function prototypes */ DRIVER *dummy_valid (char *name); void *dummy_parameters (long function,void *value); void dummy_list_work (MAILSTREAM *stream,char *dir,char *pat,char *contents, long level); long dummy_listed (MAILSTREAM *stream,char delimiter,char *name, long attributes,char *contents); long dummy_subscribe (MAILSTREAM *stream,char *mailbox); MAILSTREAM *dummy_open (MAILSTREAM *stream); void dummy_close (MAILSTREAM *stream,long options); long dummy_ping (MAILSTREAM *stream); void dummy_check (MAILSTREAM *stream); long dummy_expunge (MAILSTREAM *stream,char *sequence,long options); long dummy_copy (MAILSTREAM *stream,char *sequence,char *mailbox,long options); long dummy_append (MAILSTREAM *stream,char *mailbox,append_t af,void *data); /* Dummy routines */ /* Driver dispatch used by MAIL */ DRIVER dummydriver = { "dummy", /* driver name */ DR_LOCAL|DR_MAIL, /* driver flags */ (DRIVER *) NIL, /* next driver */ dummy_valid, /* mailbox is valid for us */ dummy_parameters, /* manipulate parameters */ dummy_scan, /* scan mailboxes */ dummy_list, /* list mailboxes */ dummy_lsub, /* list subscribed mailboxes */ dummy_subscribe, /* subscribe to mailbox */ NIL, /* unsubscribe from mailbox */ dummy_create, /* create mailbox */ dummy_delete, /* delete mailbox */ dummy_rename, /* rename mailbox */ mail_status_default, /* status of mailbox */ dummy_open, /* open mailbox */ dummy_close, /* close mailbox */ NIL, /* fetch message "fast" attributes */ NIL, /* fetch message flags */ NIL, /* fetch overview */ NIL, /* fetch message structure */ NIL, /* fetch header */ NIL, /* fetch text */ NIL, /* fetch message data */ NIL, /* unique identifier */ NIL, /* message number from UID */ NIL, /* modify flags */ NIL, /* per-message modify flags */ NIL, /* search for message based on criteria */ NIL, /* sort messages */ NIL, /* thread messages */ dummy_ping, /* ping mailbox to see if still alive */ dummy_check, /* check for new messages */ dummy_expunge, /* expunge deleted messages */ dummy_copy, /* copy messages to another mailbox */ dummy_append, /* append string message to mailbox */ NIL /* garbage collect stream */ }; /* prototype stream */ MAILSTREAM dummyproto = {&dummydriver}; /* Dummy validate mailbox * Accepts: mailbox name * Returns: our driver if name is valid, NIL otherwise */ DRIVER *dummy_valid (char *name) { char *s,tmp[MAILTMPLEN]; struct stat sbuf; /* must be valid local mailbox */ if (name && *name && (*name != '{') && (s = mailboxfile (tmp,name))) { /* indeterminate clearbox INBOX */ if (!*s) return &dummydriver; else if (!stat (s,&sbuf)) switch (sbuf.st_mode & S_IFMT) { case S_IFREG: case S_IFDIR: return &dummydriver; } /* blackbox INBOX does not exist yet */ else if (!compare_cstring (name,"INBOX")) return &dummydriver; } return NIL; } /* Dummy manipulate driver parameters * Accepts: function code * function-dependent value * Returns: function-dependent return value */ void *dummy_parameters (long function,void *value) { void *ret = NIL; switch ((int) function) { case GET_INBOXPATH: if (value) ret = dummy_file ((char *) value,"INBOX"); break; } return ret; } /* Dummy scan mailboxes * Accepts: mail stream * reference * pattern to search * string to scan */ void dummy_scan (MAILSTREAM *stream,char *ref,char *pat,char *contents) { DRIVER *drivers; char *s,test[MAILTMPLEN],file[MAILTMPLEN]; long i; if (!pat || !*pat) { /* empty pattern? */ if (dummy_canonicalize (test,ref,"*")) { /* tie off name at root */ if (s = strchr (test,'/')) *++s = '\0'; else test[0] = '\0'; dummy_listed (stream,'/',test,LATT_NOSELECT,NIL); } } /* get canonical form of name */ else if (dummy_canonicalize (test,ref,pat)) { /* found any wildcards? */ if (s = strpbrk (test,"%*")) { /* yes, copy name up to that point */ strncpy (file,test,i = s - test); file[i] = '\0'; /* tie off */ } else strcpy (file,test); /* use just that name then */ if (s = strrchr (file,'/')){/* find directory name */ *++s = '\0'; /* found, tie off at that point */ s = file; } /* silly case */ else if ((file[0] == '~') || (file[0] == '#')) s = file; /* do the work */ dummy_list_work (stream,s,test,contents,0); /* always an INBOX */ if (pmatch ("INBOX",ucase (test))) { /* done if have a dirfmt INBOX */ for (drivers = (DRIVER *) mail_parameters (NIL,GET_DRIVERS,NIL); drivers && !(!(drivers->flags & DR_DISABLE) && (drivers->flags & DR_DIRFMT) && (*drivers->valid) ("INBOX")); drivers = drivers->next); /* list INBOX appropriately */ dummy_listed (stream,drivers ? '/' : NIL,"INBOX", drivers ? NIL : LATT_NOINFERIORS,contents); } } } /* Dummy list mailboxes * Accepts: mail stream * reference * pattern to search */ void dummy_list (MAILSTREAM *stream,char *ref,char *pat) { dummy_scan (stream,ref,pat,NIL); } /* Dummy list subscribed mailboxes * Accepts: mail stream * reference * pattern to search */ void dummy_lsub (MAILSTREAM *stream,char *ref,char *pat) { void *sdb = NIL; char *s,*t,test[MAILTMPLEN],tmp[MAILTMPLEN]; int showuppers = pat[strlen (pat) - 1] == '%'; /* get canonical form of name */ if (dummy_canonicalize (test,ref,pat) && (s = sm_read (&sdb))) do if (*s != '{') { if (!compare_cstring (s,"INBOX") && pmatch ("INBOX",ucase (strcpy (tmp,test)))) mm_lsub (stream,NIL,s,LATT_NOINFERIORS); else if (pmatch_full (s,test,'/')) mm_lsub (stream,'/',s,NIL); else while (showuppers && (t = strrchr (s,'/'))) { *t = '\0'; /* tie off the name */ if (pmatch_full (s,test,'/')) mm_lsub (stream,'/',s,LATT_NOSELECT); } } while (s = sm_read (&sdb)); /* until no more subscriptions */ } /* Dummy subscribe to mailbox * Accepts: mail stream * mailbox to add to subscription list * Returns: T on success, NIL on failure */ long dummy_subscribe (MAILSTREAM *stream,char *mailbox) { char *s,tmp[MAILTMPLEN]; struct stat sbuf; /* must be valid local mailbox */ if ((s = mailboxfile (tmp,mailbox)) && *s && !stat (s,&sbuf)) switch (sbuf.st_mode & S_IFMT) { case S_IFDIR: /* allow but snarl */ sprintf (tmp,"CLIENT BUG DETECTED: subscribe of non-mailbox directory %.80s", mailbox); MM_NOTIFY (stream,tmp,WARN); case S_IFREG: return sm_subscribe (mailbox); } sprintf (tmp,"Can't subscribe %.80s: not a mailbox",mailbox); MM_LOG (tmp,ERROR); return NIL; } /* Dummy list mailboxes worker routine * Accepts: mail stream * directory name to search * search pattern * string to scan * search level */ void dummy_list_work (MAILSTREAM *stream,char *dir,char *pat,char *contents, long level) { DRIVER *drivers; dirfmttest_t dt; DIR *dp; struct direct *d; struct stat sbuf; char tmp[MAILTMPLEN],path[MAILTMPLEN]; size_t len = 0; /* punt if bogus name */ if (!mailboxdir (tmp,dir,NIL)) return; if (dp = opendir (tmp)) { /* do nothing if can't open directory */ /* see if a non-namespace directory format */ for (drivers = (DRIVER *) mail_parameters (NIL,GET_DRIVERS,NIL), dt = NIL; dir && !dt && drivers; drivers = drivers->next) if (!(drivers->flags & DR_DISABLE) && (drivers->flags & DR_DIRFMT) && (*drivers->valid) (dir)) dt = mail_parameters ((*drivers->open) (NIL),GET_DIRFMTTEST,NIL); /* list it if at top-level */ if (!level && dir && pmatch_full (dir,pat,'/') && !pmatch (dir,"INBOX")) dummy_listed (stream,'/',dir,dt ? NIL : LATT_NOSELECT,contents); /* scan directory, ignore . and .. */ if (!dir || dir[(len = strlen (dir)) - 1] == '/') while (d = readdir (dp)) if ((!(dt && (*dt) (d->d_name))) && ((d->d_name[0] != '.') || (((long) mail_parameters (NIL,GET_HIDEDOTFILES,NIL)) ? NIL : (d->d_name[1] && (((d->d_name[1] != '.') || d->d_name[2]))))) && ((len + strlen (d->d_name)) <= NETMAXMBX)) { /* see if name is useful */ if (dir) sprintf (tmp,"%s%s",dir,d->d_name); else strcpy (tmp,d->d_name); /* make sure useful and can get info */ if ((pmatch_full (strcpy (path,tmp),pat,'/') || pmatch_full (strcat (path,"/"),pat,'/') || dmatch (path,pat,'/')) && mailboxdir (path,dir,"x") && (len = strlen (path)) && strcpy (path+len-1,d->d_name) && !stat (path,&sbuf)) { /* only interested in file type */ switch (sbuf.st_mode & S_IFMT) { case S_IFDIR: /* directory? */ /* form with trailing / */ sprintf (path,"%s/",tmp); /* skip listing if INBOX */ if (!pmatch (tmp,"INBOX")) { if (pmatch_full (tmp,pat,'/')) { if (!dummy_listed (stream,'/',tmp,LATT_NOSELECT,contents)) break; } /* try again with trailing / */ else if (pmatch_full (path,pat,'/') && !dummy_listed (stream,'/',path,LATT_NOSELECT,contents)) break; } if (dmatch (path,pat,'/') && (level < (long) mail_parameters (NIL,GET_LISTMAXLEVEL,NIL))) dummy_list_work (stream,path,pat,contents,level+1); break; case S_IFREG: /* ordinary name */ /* Must use ctime for systems that don't update mtime properly */ if (pmatch_full (tmp,pat,'/') && compare_cstring (tmp,"INBOX")) dummy_listed (stream,'/',tmp,LATT_NOINFERIORS + ((sbuf.st_size && (sbuf.st_atime < sbuf.st_ctime))? LATT_MARKED : LATT_UNMARKED),contents); break; } } } closedir (dp); /* all done, flush directory */ } } /* Scan file for contents * Accepts: driver to use * file name * desired contents * length of contents * size of file * Returns: NIL if contents not found, T if found */ long scan_contents (DRIVER *dtb,char *name,char *contents, unsigned long csiz,unsigned long fsiz) { scancontents_t sc = dtb ? (scancontents_t) (*dtb->parameters) (GET_SCANCONTENTS,NIL) : NIL; return (*(sc ? sc : dummy_scan_contents)) (name,contents,csiz,fsiz); } /* Scan file for contents * Accepts: file name * desired contents * length of contents * size of file * Returns: NIL if contents not found, T if found */ #define BUFSIZE 4*MAILTMPLEN long dummy_scan_contents (char *name,char *contents,unsigned long csiz, unsigned long fsiz) { int fd; unsigned long ssiz,bsiz; char *buf; /* forget it if can't select or open */ if ((fd = open (name,O_RDONLY,NIL)) >= 0) { /* get buffer including slop */ buf = (char *) fs_get (BUFSIZE + (ssiz = 4 * ((csiz / 4) + 1)) + 1); memset (buf,'\0',ssiz); /* no slop area the first time */ while (fsiz) { /* until end of file */ read (fd,buf+ssiz,bsiz = min (fsiz,BUFSIZE)); if (search ((unsigned char *) buf,bsiz+ssiz, (unsigned char *) contents,csiz)) break; memcpy (buf,buf+BUFSIZE,ssiz); fsiz -= bsiz; /* note that we read that much */ } fs_give ((void **) &buf); /* flush buffer */ close (fd); /* finished with file */ if (fsiz) return T; /* found */ } return NIL; /* not found */ } /* Mailbox found * Accepts: MAIL stream * hierarchy delimiter * mailbox name * attributes * contents to search before calling mm_list() * Returns: NIL if should abort hierarchy search, else T (currently always) */ long dummy_listed (MAILSTREAM *stream,char delimiter,char *name, long attributes,char *contents) { DRIVER *d; DIR *dp; struct direct *dr; dirfmttest_t dt; unsigned long csiz; struct stat sbuf; int nochild; char *s,tmp[MAILTMPLEN]; if (!(attributes & LATT_NOINFERIORS) && mailboxdir (tmp,name,NIL) && (dp = opendir (tmp))) { /* if not \NoInferiors */ /* locate dirfmttest if any */ for (d = (DRIVER *) mail_parameters (NIL,GET_DRIVERS,NIL), dt = NIL; !dt && d; d = d->next) if (!(d->flags & DR_DISABLE) && (d->flags & DR_DIRFMT) && (*d->valid) (name)) dt = mail_parameters ((*d->open) (NIL),GET_DIRFMTTEST,NIL); /* scan directory for children */ for (nochild = T; nochild && (dr = readdir (dp)); ) if ((!(dt && (*dt) (dr->d_name))) && ((dr->d_name[0] != '.') || (((long) mail_parameters (NIL,GET_HIDEDOTFILES,NIL)) ? NIL : (dr->d_name[1] && ((dr->d_name[1] != '.') || dr->d_name[2]))))) nochild = NIL; attributes |= nochild ? LATT_HASNOCHILDREN : LATT_HASCHILDREN; closedir (dp); /* all done, flush directory */ } d = NIL; /* don't \NoSelect dir if it has a driver */ if ((attributes & LATT_NOSELECT) && (d = mail_valid (NIL,name,NIL)) && (d != &dummydriver)) attributes &= ~LATT_NOSELECT; if (!contents || /* notify main program */ (!(attributes & LATT_NOSELECT) && (csiz = strlen (contents)) && (s = mailboxfile (tmp,name)) && (*s || (s = mail_parameters (NIL,GET_INBOXPATH,tmp))) && !stat (s,&sbuf) && (d || (csiz <= sbuf.st_size)) && SAFE_SCAN_CONTENTS (d,tmp,contents,csiz,sbuf.st_size))) mm_list (stream,delimiter,name,attributes); return T; } /* Dummy create mailbox * Accepts: mail stream * mailbox name to create * Returns: T on success, NIL on failure */ long dummy_create (MAILSTREAM *stream,char *mailbox) { char *s,tmp[MAILTMPLEN]; long ret = NIL; /* validate name */ if (!(compare_cstring (mailbox,"INBOX") && (s = dummy_file (tmp,mailbox)))) { sprintf (tmp,"Can't create %.80s: invalid name",mailbox); MM_LOG (tmp,ERROR); } /* create the name, done if made directory */ else if ((ret = dummy_create_path (stream,tmp,get_dir_protection(mailbox)))&& (s = strrchr (s,'/')) && !s[1]) return T; return ret ? set_mbx_protections (mailbox,tmp) : NIL; } /* Dummy create path * Accepts: mail stream * path name to create * directory mode * Returns: T on success, NIL on failure */ long dummy_create_path (MAILSTREAM *stream,char *path,long dirmode) { struct stat sbuf; char c,*s,tmp[MAILTMPLEN]; int fd; long ret = NIL; char *t = strrchr (path,'/'); int wantdir = t && !t[1]; int mask = umask (0); if (wantdir) *t = '\0'; /* flush trailing delimiter for directory */ if (s = strrchr (path,'/')) { /* found superior to this name? */ c = *++s; /* remember first character of inferior */ *s = '\0'; /* tie off to get just superior */ /* name doesn't exist, create it */ if ((stat (path,&sbuf) || ((sbuf.st_mode & S_IFMT) != S_IFDIR)) && !dummy_create_path (stream,path,dirmode)) { umask (mask); /* restore mask */ return NIL; } *s = c; /* restore full name */ } if (wantdir) { /* want to create directory? */ ret = !mkdir (path,(int) dirmode); *t = '/'; /* restore directory delimiter */ } /* create file */ else if ((fd = open (path,O_WRONLY|O_CREAT|O_EXCL, (long) mail_parameters(NIL,GET_MBXPROTECTION,NIL))) >=0) ret = !close (fd); if (!ret) { /* error? */ sprintf (tmp,"Can't create mailbox node %.80s: %.80s",path,strerror (errno)); MM_LOG (tmp,ERROR); } umask (mask); /* restore mask */ return ret; /* return status */ } /* Dummy delete mailbox * Accepts: mail stream * mailbox name to delete * Returns: T on success, NIL on failure */ long dummy_delete (MAILSTREAM *stream,char *mailbox) { struct stat sbuf; char *s,tmp[MAILTMPLEN]; if (!(s = dummy_file (tmp,mailbox))) { sprintf (tmp,"Can't delete - invalid name: %.80s",s); MM_LOG (tmp,ERROR); } /* no trailing / (workaround BSD kernel bug) */ if ((s = strrchr (tmp,'/')) && !s[1]) *s = '\0'; if (stat (tmp,&sbuf) || ((sbuf.st_mode & S_IFMT) == S_IFDIR) ? rmdir (tmp) : unlink (tmp)) { sprintf (tmp,"Can't delete mailbox %.80s: %.80s",mailbox,strerror (errno)); MM_LOG (tmp,ERROR); return NIL; } return T; /* return success */ } /* Mail rename mailbox * Accepts: mail stream * old mailbox name * new mailbox name * Returns: T on success, NIL on failure */ long dummy_rename (MAILSTREAM *stream,char *old,char *newname) { struct stat sbuf; char c,*s,tmp[MAILTMPLEN],mbx[MAILTMPLEN],oldname[MAILTMPLEN]; /* no trailing / allowed */ if (!dummy_file (oldname,old) || !(s = dummy_file (mbx,newname)) || stat (oldname,&sbuf) || ((s = strrchr (s,'/')) && !s[1] && ((sbuf.st_mode & S_IFMT) != S_IFDIR))) { sprintf (mbx,"Can't rename %.80s to %.80s: invalid name",old,newname); MM_LOG (mbx,ERROR); return NIL; } if (s) { /* found a directory delimiter? */ if (!s[1]) *s = '\0'; /* ignore trailing delimiter */ else { /* found superior to destination name? */ c = *++s; /* remember first character of inferior */ *s = '\0'; /* tie off to get just superior */ /* name doesn't exist, create it */ if ((stat (mbx,&sbuf) || ((sbuf.st_mode & S_IFMT) != S_IFDIR)) && !dummy_create (stream,mbx)) return NIL; *s = c; /* restore full name */ } } /* rename of non-ex INBOX creates dest */ if (!compare_cstring (old,"INBOX") && stat (oldname,&sbuf)) return dummy_create (NIL,mbx); if (rename (oldname,mbx)) { sprintf (tmp,"Can't rename mailbox %.80s to %.80s: %.80s",old,newname, strerror (errno)); MM_LOG (tmp,ERROR); return NIL; } return T; /* return success */ } /* Dummy open * Accepts: stream to open * Returns: stream on success, NIL on failure */ MAILSTREAM *dummy_open (MAILSTREAM *stream) { int fd; char err[MAILTMPLEN],tmp[MAILTMPLEN]; struct stat sbuf; /* OP_PROTOTYPE call */ if (!stream) return &dummyproto; err[0] = '\0'; /* no error message yet */ /* can we open the file? */ if (!dummy_file (tmp,stream->mailbox)) sprintf (err,"Can't open this name: %.80s",stream->mailbox); else if ((fd = open (tmp,O_RDONLY,NIL)) < 0) { /* no, error unless INBOX */ if (compare_cstring (stream->mailbox,"INBOX")) sprintf (err,"%.80s: %.80s",strerror (errno),stream->mailbox); } else { /* file had better be empty then */ fstat (fd,&sbuf); /* sniff at its size */ close (fd); if ((sbuf.st_mode & S_IFMT) != S_IFREG) sprintf (err,"Can't open %.80s: not a selectable mailbox", stream->mailbox); else if (sbuf.st_size) /* bogus format if non-empty */ sprintf (err,"Can't open %.80s (file %.80s): not in valid mailbox format", stream->mailbox,tmp); } if (err[0]) { /* if an error happened */ MM_LOG (err,stream->silent ? WARN : ERROR); return NIL; } else if (!stream->silent) { /* only if silence not requested */ mail_exists (stream,0); /* say there are 0 messages */ mail_recent (stream,0); /* and certainly no recent ones! */ stream->uid_validity = time (0); } stream->inbox = T; /* note that it's an INBOX */ return stream; /* return success */ } /* Dummy close * Accepts: MAIL stream * options */ void dummy_close (MAILSTREAM *stream,long options) { /* return silently */ } /* Dummy ping mailbox * Accepts: MAIL stream * Returns: T if stream alive, else NIL */ long dummy_ping (MAILSTREAM *stream) { MAILSTREAM *test; if (time (0) >= /* time to do another test? */ ((time_t) (stream->gensym + (long) mail_parameters (NIL,GET_SNARFINTERVAL,NIL)))) { /* has mailbox format changed? */ if ((test = mail_open (NIL,stream->mailbox,OP_PROTOTYPE)) && (test->dtb != stream->dtb) && (test = mail_open (NIL,stream->mailbox,NIL))) { /* preserve some resources */ test->original_mailbox = stream->original_mailbox; stream->original_mailbox = NIL; test->sparep = stream->sparep; stream->sparep = NIL; test->sequence = stream->sequence; mail_close ((MAILSTREAM *) /* flush resources used by dummy stream */ memcpy (fs_get (sizeof (MAILSTREAM)),stream, sizeof (MAILSTREAM))); /* swap the streams */ memcpy (stream,test,sizeof (MAILSTREAM)); fs_give ((void **) &test);/* flush test now that copied */ /* make sure application knows */ mail_exists (stream,stream->recent = stream->nmsgs); } /* still hasn't changed */ else stream->gensym = time (0); } return T; } /* Dummy check mailbox * Accepts: MAIL stream * No-op for readonly files, since read/writer can expunge it from under us! */ void dummy_check (MAILSTREAM *stream) { dummy_ping (stream); /* invoke ping */ } /* Dummy expunge mailbox * Accepts: MAIL stream * sequence to expunge if non-NIL * expunge options * Returns: T, always */ long dummy_expunge (MAILSTREAM *stream,char *sequence,long options) { return LONGT; } /* Dummy copy message(s) * Accepts: MAIL stream * sequence * destination mailbox * options * Returns: T if copy successful, else NIL */ long dummy_copy (MAILSTREAM *stream,char *sequence,char *mailbox,long options) { if ((options & CP_UID) ? mail_uid_sequence (stream,sequence) : mail_sequence (stream,sequence)) fatal ("Impossible dummy_copy"); return NIL; } /* Dummy append message string * Accepts: mail stream * destination mailbox * append callback function * data for callback * Returns: T on success, NIL on failure */ long dummy_append (MAILSTREAM *stream,char *mailbox,append_t af,void *data) { struct stat sbuf; int fd = -1; int e; char tmp[MAILTMPLEN]; MAILSTREAM *ts = default_proto (T); /* append to INBOX? */ if (!compare_cstring (mailbox,"INBOX")) { /* yes, if no empty proto try creating */ if (!ts && !(*(ts = default_proto (NIL))->dtb->create) (ts,"INBOX")) ts = NIL; } else if (dummy_file (tmp,mailbox) && ((fd = open (tmp,O_RDONLY,NIL)) < 0)) { if ((e = errno) == ENOENT) /* failed, was it no such file? */ MM_NOTIFY (stream,"[TRYCREATE] Must create mailbox before append",NIL); sprintf (tmp,"%.80s: %.80s",strerror (e),mailbox); MM_LOG (tmp,ERROR); /* pass up error */ return NIL; /* always fails */ } else if (fd >= 0) { /* found file? */ fstat (fd,&sbuf); /* get its size */ close (fd); /* toss out the fd */ if (sbuf.st_size) ts = NIL; /* non-empty file? */ } if (ts) return (*ts->dtb->append) (stream,mailbox,af,data); sprintf (tmp,"Indeterminate mailbox format: %.80s",mailbox); MM_LOG (tmp,ERROR); return NIL; } /* Dummy mail generate file string * Accepts: temporary buffer to write into * mailbox name string * Returns: local file string or NIL if failure */ char *dummy_file (char *dst,char *name) { char *s = mailboxfile (dst,name); /* return our standard inbox */ return (s && !*s) ? strcpy (dst,sysinbox ()) : s; } /* Dummy canonicalize name * Accepts: buffer to write name * reference * pattern * Returns: T if success, NIL if failure */ long dummy_canonicalize (char *tmp,char *ref,char *pat) { unsigned long i; char *s; if (ref) { /* preliminary reference check */ if (*ref == '{') return NIL;/* remote reference not allowed */ else if (!*ref) ref = NIL; /* treat empty reference as no reference */ } switch (*pat) { case '#': /* namespace name */ if (mailboxfile (tmp,pat)) strcpy (tmp,pat); else return NIL; /* unknown namespace */ break; case '{': /* remote names not allowed */ return NIL; case '/': /* rooted name */ case '~': /* home directory name */ if (!ref || (*ref != '#')) {/* non-namespace reference? */ strcpy (tmp,pat); /* yes, ignore */ break; } /* fall through */ default: /* apply reference for all other names */ if (!ref) strcpy (tmp,pat); /* just copy if no namespace */ else if ((*ref != '#') || mailboxfile (tmp,ref)) { /* wants root of name? */ if (*pat == '/') strcpy (strchr (strcpy (tmp,ref),'/'),pat); /* otherwise just append */ else sprintf (tmp,"%s%s",ref,pat); } else return NIL; /* unknown namespace */ } /* count wildcards */ for (i = 0, s = tmp; *s; *s++) if ((*s == '*') || (*s == '%')) ++i; if (i > MAXWILDCARDS) { /* ridiculous wildcarding? */ MM_LOG ("Excessive wildcards in LIST/LSUB",ERROR); return NIL; } return T; } alpine-2.10+dfsg/imap/src/osdep/dos/0000700000175000017500000000000011512502152020747 5ustar paulproteuspaulproteusalpine-2.10+dfsg/imap/src/osdep/dos/mkautaux.bat0000600000175000017500000000172411512502124023303 0ustar paulproteuspaulproteus@ECHO OFF REM ======================================================================== REM Copyright 1988-2006 University of Washington REM REM Licensed under the Apache License, Version 2.0 (the "License"); REM you may not use this file except in compliance with the License. REM You may obtain a copy of the License at REM REM http://www.apache.org/licenses/LICENSE-2.0 REM REM REM ======================================================================== REM Program: Authenticator Linkage Generator auxillary for DOS REM REM Author: Mark Crispin REM Networks and Distributed Computing REM Computing & Communications REM University of Washington REM Administration Building, AG-44 REM Seattle, WA 98195 REM Internet: MRC@CAC.Washington.EDU REM REM Date: 7 December 1995 REM Last Edited:30 August 2006 ECHO extern AUTHENTICATOR auth_%1; >> LINKAGE.H ECHO auth_link (&auth_%1); /* link in the %1 authenticator */ >> LINKAGE.C ECHO #include "auth_%1.c" >> AUTHS.C alpine-2.10+dfsg/imap/src/osdep/dos/os_dpc.h0000600000175000017500000000177011512502124022375 0ustar paulproteuspaulproteus/* ======================================================================== * Copyright 1988-2006 University of Washington * * Licensed under the Apache License, Version 2.0 (the "License"); * you may not use this file except in compliance with the License. * You may obtain a copy of the License at * * http://www.apache.org/licenses/LICENSE-2.0 * * * ======================================================================== */ /* * Program: Operating-system dependent routines -- DOS (PC/TCP) version * * Author: Mark Crispin * Networks and Distributed Computing * Computing & Communications * University of Washington * Administration Building, AG-44 * Seattle, WA 98195 * Internet: MRC@CAC.Washington.EDU * * Date: 11 May 1989 * Last Edited: 30 August 2006 */ #define INADEQUATE_MEMORY #include #include #include #include #include #include "env_dos.h" #include "fs.h" #include "ftl.h" #include "nl.h" #include "tcp.h" alpine-2.10+dfsg/imap/src/osdep/dos/mtestwsk.bat0000600000175000017500000000161111512502124023320 0ustar paulproteuspaulproteus@ECHO OFF REM ======================================================================== REM Copyright 1988-2006 University of Washington REM REM Licensed under the Apache License, Version 2.0 (the "License"); REM you may not use this file except in compliance with the License. REM You may obtain a copy of the License at REM REM http://www.apache.org/licenses/LICENSE-2.0 REM REM REM ======================================================================== REM Program: Portable C client makefile -- MS-DOS Winsock link REM REM Author: Mark Crispin REM Networks and Distributed Computing REM Computing & Communications REM University of Washington REM Administration Building, AG-44 REM Seattle, WA 98195 REM Internet: MRC@CAC.Washington.EDU REM REM Date: 26 June 1994 REM Last Edited:30 August 2006 link /NOD:llibce mtest.obj,mtest.exe,,cclient.lib winsock.lib llibcewq.lib libw.lib, mtest alpine-2.10+dfsg/imap/src/osdep/dos/os_dpc.c0000600000175000017500000000507611512502124022373 0ustar paulproteuspaulproteus/* ======================================================================== * Copyright 1988-2006 University of Washington * * Licensed under the Apache License, Version 2.0 (the "License"); * you may not use this file except in compliance with the License. * You may obtain a copy of the License at * * http://www.apache.org/licenses/LICENSE-2.0 * * * ======================================================================== */ /* * Program: Operating-system dependent routines -- MS-DOS (PC/TCP) version * * Author: Mark Crispin * Networks and Distributed Computing * Computing & Communications * University of Washington * Administration Building, AG-44 * Seattle, WA 98195 * Internet: MRC@CAC.Washington.EDU * * Date: 11 April 1989 * Last Edited: 30 August 2006 */ /* Private function prototypes */ #include "tcp_dos.h" /* must be before osdep includes tcp.h */ #include "mail.h" #include "osdep.h" #include #include #include #include #include #include <4bsddefs.h> #include #include #include #include #include #include "misc.h" #include "fs_dos.c" #include "ftl_dos.c" #include "nl_dos.c" #include "env_dos.c" #undef write #include "tcp_dos.c" /* Return my local host name * Returns: my local host name */ char *mylocalhost (void) { if (!myLocalHost) { /* known yet */ char *s,tmp[MAILTMPLEN]; long myip; /* see if known host name */ if (!gethostname (tmp,MAILTMPLEN-1)) s = tmp; /* no, try IP address */ else if (myip = gethostid ()) { struct in_addr in; in.s_addr = myip; sprintf (s = tmp,"[%s]",inet_ntoa (in)); } /* older kernel, look harder. */ else if (getconf ("ifcust","ip-address",tmp+1,MAILTMPLEN-2)) { *(s = tmp) = '['; /* wrap the brackets around it */ strcat (tmp,"]"); } else s = "random-pc"; /* say what? */ myLocalHost = cpystr (s); /* record for subsequent use */ } return myLocalHost; } /* Look up host address * Accepts: pointer to pointer to host name * socket address block * Returns: non-zero with host address in socket, official host name in host; * else NIL */ long lookuphost (char **host,struct sockaddr_in *sin) { long ret = -1; char tmp[MAILTMPLEN]; struct hostent *hn = gethostbyname (lcase (strcpy (tmp,*host))); if (!hn) return NIL; /* got a host name? */ *host = cpystr (hn->h_name); /* set official name */ /* copy host addresses */ memcpy (&sin->sin_addr,hn->h_addr,hn->h_length); return T; } alpine-2.10+dfsg/imap/src/osdep/dos/os_dnv.c0000600000175000017500000000454311512502124022412 0ustar paulproteuspaulproteus/* ======================================================================== * Copyright 1988-2006 University of Washington * * Licensed under the Apache License, Version 2.0 (the "License"); * you may not use this file except in compliance with the License. * You may obtain a copy of the License at * * http://www.apache.org/licenses/LICENSE-2.0 * * * ======================================================================== */ /* * Program: Operating-system dependent routines -- MS-DOS (Novell) version * * Author: Mark Crispin * Networks and Distributed Computing * Computing & Communications * University of Washington * Administration Building, AG-44 * Seattle, WA 98195 * Internet: MRC@CAC.Washington.EDU * * Date: 11 April 1989 * Last Edited: 30 August 2006 */ /* Private function prototypes */ #include "tcp_dos.h" /* must be before osdep includes tcp.h */ #include "mail.h" #include "osdep.h" #include #include #include #include #include #include #include #include #include "misc.h" #include "fs_dos.c" #include "ftl_dos.c" #include "nl_dos.c" #include "env_dos.c" #undef write #define read soread #define write sowrite #define close soclose #include "tcp_dos.c" /* Return my local host name * Returns: my local host name */ char *mylocalhost (void) { if (!myLocalHost) { /* known yet? */ char *s,tmp[MAILTMPLEN]; struct hostent *he; struct in_addr in; /* could we get local id? */ if ((in.s_addr = getmyipaddr ()) != -1) { if (he = gethostbyaddr ((char *) &in.s_addr,4,PF_INET)) s = he->h_name; else sprintf (s = tmp,"[%s]",inet_ntoa (in)); } else s = "random-pc"; /* say what? */ myLocalHost = cpystr (s); /* record for subsequent use */ } return myLocalHost; } /* Look up host address * Accepts: pointer to pointer to host name * socket address block * Returns: non-zero with host address in socket, official host name in host; * else NIL */ long lookuphost (char **host,struct sockaddr_in *sin) { char *s = *host; /* in case of error */ sin->sin_addr.s_addr = rhost (host); if (sin->sin_addr.s_addr == -1) { *host = s; /* error, restore old host name */ return NIL; } *host = cpystr (*host); /* make permanent copy of name */ return T; /* success */ } alpine-2.10+dfsg/imap/src/osdep/dos/os_dbw.c0000600000175000017500000000427011512502124022374 0ustar paulproteuspaulproteus/* ======================================================================== * Copyright 1988-2006 University of Washington * * Licensed under the Apache License, Version 2.0 (the "License"); * you may not use this file except in compliance with the License. * You may obtain a copy of the License at * * http://www.apache.org/licenses/LICENSE-2.0 * * * ======================================================================== */ /* * Program: Operating-system dependent routines -- MS-DOS (B&W) version * * Author: Mark Crispin * Networks and Distributed Computing * Computing & Communications * University of Washington * Administration Building, AG-44 * Seattle, WA 98195 * Internet: MRC@CAC.Washington.EDU * * Date: 11 April 1989 * Last Edited: 30 August 2006 */ /* Private function prototypes */ #include "tcp_dos.h" /* must be before osdep includes tcp.h */ #include "mail.h" #include "osdep.h" #include #include #include #include #include #include "misc.h" #include "stdlib.h" #include "bwtcp.h" #include "fs_dos.c" #include "ftl_dos.c" #include "nl_dos.c" #include "env_dos.c" #undef write #define read soread #define write sowrite #define close soclose #include "tcp_dos.c" /* Return my local host name * Returns: my local host name */ char *mylocalhost (void) { char *s; if (!myLocalHost) { /* known yet? */ /* get local host name from DISPLAY env var */ if (!((s = getenv ("DISPLAY")) || (s = getenv ("display")))) { mm_log ("Environment variable 'DISPLAY' is not set", ERROR); s = "random-pc"; } myLocalHost = cpystr (s); } return myLocalHost; } /* Look up host address * Accepts: pointer to pointer to host name * socket address block * Returns: non-zero with host address in socket, official host name in host; * else NIL */ long lookuphost (char **host,struct sockaddr_in *sin) { char *s = *host; /* in case of error */ sin->sin_addr.s_addr = rhost (host); if (sin->sin_addr.s_addr == -1) { *host = s; /* error, restore old host name */ return NIL; } *host = cpystr (*host); /* make permanent copy of name */ return T; /* success */ } alpine-2.10+dfsg/imap/src/osdep/dos/tcp_dos.h0000600000175000017500000000247611512502124022565 0ustar paulproteuspaulproteus/* ======================================================================== * Copyright 1988-2006 University of Washington * * Licensed under the Apache License, Version 2.0 (the "License"); * you may not use this file except in compliance with the License. * You may obtain a copy of the License at * * http://www.apache.org/licenses/LICENSE-2.0 * * * ======================================================================== */ /* * Program: OS2 routines * * Author: Mark Crispin * Networks and Distributed Computing * Computing & Communications * University of Washington * Administration Building, AG-44 * Seattle, WA 98195 * Internet: MRC@CAC.Washington.EDU * * Date: 11 April 1989 * Last Edited: 30 August 2006 */ /* TCP input buffer -- must be large enough to prevent overflow */ #define BUFLEN 8192 /* TCP I/O stream (must be before osdep.h is included) */ #define TCPSTREAM struct tcp_stream TCPSTREAM { char *host; /* host name */ unsigned long port; /* port number */ char *localhost; /* local host name */ int tcps; /* tcp socket */ long ictr; /* input counter */ char *iptr; /* input pointer */ char ibuf[BUFLEN]; /* input buffer */ }; /* Local function prototypes */ long lookuphost (char **host,struct sockaddr_in *sin); long tcp_abort (TCPSTREAM *stream); alpine-2.10+dfsg/imap/src/osdep/dos/mtestdwa.bat0000600000175000017500000000156411512502124023276 0ustar paulproteuspaulproteus@ECHO OFF REM ======================================================================== REM Copyright 1988-2006 University of Washington REM REM Licensed under the Apache License, Version 2.0 (the "License"); REM you may not use this file except in compliance with the License. REM You may obtain a copy of the License at REM REM http://www.apache.org/licenses/LICENSE-2.0 REM REM REM ======================================================================== REM Program: Portable C client makefile -- MS-DOS Waterloo link REM REM Author: Mark Crispin REM Networks and Distributed Computing REM Computing & Communications REM University of Washington REM Administration Building, AG-44 REM Seattle, WA 98195 REM Internet: MRC@CAC.Washington.EDU REM REM Date: 26 June 1994 REM Last Edited:30 August 2006 link /NOI /stack:32767 mtest.obj,mtest.exe,,cclient.lib wattcplg.lib alpine-2.10+dfsg/imap/src/osdep/dos/fdstring.h0000600000175000017500000000205711512502124022745 0ustar paulproteuspaulproteus/* ======================================================================== * Copyright 1988-2006 University of Washington * * Licensed under the Apache License, Version 2.0 (the "License"); * you may not use this file except in compliance with the License. * You may obtain a copy of the License at * * http://www.apache.org/licenses/LICENSE-2.0 * * * ======================================================================== */ /* * Program: File descriptor string routines * * Author: Mark Crispin * Networks and Distributed Computing * Computing & Communications * University of Washington * Administration Building, AG-44 * Seattle, WA 98195 * Internet: MRC@CAC.Washington.EDU * * Date: 15 April 1997 * Last Edited: 30 August 2006 */ /* Driver-dependent data passed to init method */ typedef struct fd_data { int fd; /* file descriptor */ unsigned long pos; /* initial position */ char *chunk; /* I/O buffer chunk */ unsigned long chunksize; /* I/O buffer chunk length */ } FDDATA; extern STRINGDRIVER fd_string; alpine-2.10+dfsg/imap/src/osdep/dos/dummy.h0000600000175000017500000000276411512502124022265 0ustar paulproteuspaulproteus/* ======================================================================== * Copyright 1988-2006 University of Washington * * Licensed under the Apache License, Version 2.0 (the "License"); * you may not use this file except in compliance with the License. * You may obtain a copy of the License at * * http://www.apache.org/licenses/LICENSE-2.0 * * * ======================================================================== */ /* * Program: Dummy routines * * Author: Mark Crispin * Networks and Distributed Computing * Computing & Communications * University of Washington * Administration Building, AG-44 * Seattle, WA 98195 * Internet: MRC@CAC.Washington.EDU * * Date: 9 May 1991 * Last Edited: 30 August 2006 */ /* Exported function prototypes */ void dummy_scan (MAILSTREAM *stream,char *ref,char *pat,char *contents); void dummy_list (MAILSTREAM *stream,char *ref,char *pat); void dummy_lsub (MAILSTREAM *stream,char *ref,char *pat); long scan_contents (DRIVER *dtb,char *name,char *contents, unsigned long csiz,unsigned long fsiz); long dummy_scan_contents (char *name,char *contents,unsigned long csiz, unsigned long fsiz); long dummy_create (MAILSTREAM *stream,char *mailbox); long dummy_create_path (MAILSTREAM *stream,char *path,long dirmode); long dummy_delete (MAILSTREAM *stream,char *mailbox); long dummy_rename (MAILSTREAM *stream,char *old,char *newname); char *dummy_file (char *dst,char *name); long dummy_canonicalize (char *tmp,char *ref,char *pat); alpine-2.10+dfsg/imap/src/osdep/dos/ftl_dos.c0000600000175000017500000000167311512502124022555 0ustar paulproteuspaulproteus/* ======================================================================== * Copyright 1988-2006 University of Washington * * Licensed under the Apache License, Version 2.0 (the "License"); * you may not use this file except in compliance with the License. * You may obtain a copy of the License at * * http://www.apache.org/licenses/LICENSE-2.0 * * * ======================================================================== */ /* * Program: DOS/VMS/TOPS-20 crash management routines * * Author: Mark Crispin * Networks and Distributed Computing * Computing & Communications * University of Washington * Administration Building, AG-44 * Seattle, WA 98195 * Internet: MRC@CAC.Washington.EDU * * Date: 1 August 1988 * Last Edited: 30 August 2006 */ /* Report a fatal error * Accepts: string to output */ void fatal (char *string) { mm_fatal (string); /* pass up the string */ abort (); /* die horribly */ } alpine-2.10+dfsg/imap/src/osdep/dos/os_wsk.c0000600000175000017500000000227311512502124022425 0ustar paulproteuspaulproteus/* ======================================================================== * Copyright 1988-2006 University of Washington * * Licensed under the Apache License, Version 2.0 (the "License"); * you may not use this file except in compliance with the License. * You may obtain a copy of the License at * * http://www.apache.org/licenses/LICENSE-2.0 * * * ======================================================================== */ /* * Program: Operating-system dependent routines -- Winsock version * * Author: Mike Seibel from Unix version by Mark Crispin * Networks and Distributed Computing * Computing & Communications * University of Washington * Administration Building, AG-44 * Seattle, WA 98195 * Internet: MikeS@CAC.Washington.EDU * * Date: 11 April 1989 * Last Edited: 30 August 2006 */ #include "tcp_wsk.h" /* must be before osdep includes tcp.h */ #undef ERROR /* quell conflicting def warning */ #include "mail.h" #include "osdep.h" #include #include #include #include #include #include "misc.h" #include "fs_dos.c" #include "ftl_dos.c" #include "nl_dos.c" #include "env_dos.c" #include "tcp_wsk.c" alpine-2.10+dfsg/imap/src/osdep/dos/tcp_dos.c0000600000175000017500000002710711512502124022556 0ustar paulproteuspaulproteus/* ======================================================================== * Copyright 1988-2008 University of Washington * * Licensed under the Apache License, Version 2.0 (the "License"); * you may not use this file except in compliance with the License. * You may obtain a copy of the License at * * http://www.apache.org/licenses/LICENSE-2.0 * * * ======================================================================== */ /* * Program: MS-DOS TCP/IP routines * * Author: Mark Crispin * Networks and Distributed Computing * Computing & Communications * University of Washington * Administration Building, AG-44 * Seattle, WA 98195 * Internet: MRC@CAC.Washington.EDU * * Date: 11 April 1989 * Last Edited: 13 January 2008 */ static tcptimeout_t tmoh = NIL; /* TCP timeout handler routine */ static long ttmo_read = 0; /* TCP timeouts, in seconds */ static long ttmo_write = 0; static char *tcp_getline_work (TCPSTREAM *stream,unsigned long *size, long *contd); /* TCP/IP manipulate parameters * Accepts: function code * function-dependent value * Returns: function-dependent return value */ void *tcp_parameters (long function,void *value) { void *ret = NIL; switch ((int) function) { case SET_TIMEOUT: tmoh = (tcptimeout_t) value; case GET_TIMEOUT: ret = (void *) tmoh; break; case SET_READTIMEOUT: ttmo_read = (long) value; case GET_READTIMEOUT: ret = (void *) ttmo_read; break; case SET_WRITETIMEOUT: ttmo_write = (long) value; case GET_WRITETIMEOUT: ret = (void *) ttmo_write; break; } return ret; } /* TCP/IP open * Accepts: host name * contact service name * contact port number * Returns: TCP/IP stream if success else NIL */ TCPSTREAM *tcp_open (char *host,char *service,unsigned long port) { TCPSTREAM *stream = NIL; struct sockaddr_in sin; int sock; char *s,tmp[MAILTMPLEN]; port &= 0xffff; /* erase flags */ /* The domain literal form is used (rather than simply the dotted decimal as with other Unix programs) because it has to be a valid "host name" in mailsystem terminology. */ sin.sin_family = AF_INET; /* family is always Internet */ /* look like domain literal? */ if (host[0] == '[' && host[(strlen (host))-1] == ']') { strcpy (tmp,host+1); /* yes, copy number part */ tmp[strlen (tmp)-1] = '\0'; if ((sin.sin_addr.s_addr = inet_addr (tmp)) == -1) { sprintf (tmp,"Bad format domain-literal: %.80s",host); mm_log (tmp,ERROR); return NIL; } } /* look up host name */ else if (!lookuphost (&host,&sin)) { sprintf (tmp,"Host not found: %s",host); mm_log (tmp,ERROR); return NIL; } /* copy port number in network format */ if (!(sin.sin_port = htons (port))) fatal ("Bad port argument to tcp_open"); /* get a TCP stream */ if ((sock = socket (sin.sin_family,SOCK_STREAM,0)) < 0) { sprintf (tmp,"Unable to create TCP socket (%d)",errno); mm_log (tmp,ERROR); fs_give ((void **) &host); return NIL; } #if 0 /* needed? */ else if (sock >= FD_SETSIZE) {/* unselectable sockets are useless */ sprintf (tmp,"Unable to create selectable TCP socket (%d >= %d)", sock,FD_SETSIZE); close (sock); errno = ENOBUFS; /* just in case */ return NIL; } #endif /* open connection */ if (connect (sock,(struct sockaddr *) &sin,sizeof (sin)) < 0) { switch (errno) { /* analyze error */ case ECONNREFUSED: s = "Refused"; break; case ENOBUFS: s = "Insufficient system resources"; break; case ETIMEDOUT: s = "Timed out"; break; default: s = "Unknown error"; break; } sprintf (tmp,"Can't connect to %.80s,%ld: %s (%d)",host,port,s,errno); mm_log (tmp,ERROR); close (sock); fs_give ((void **) &host); return NIL; } /* create TCP/IP stream */ stream = (TCPSTREAM *) fs_get (sizeof (TCPSTREAM)); stream->host = host; /* official host name */ stream->localhost = cpystr (mylocalhost ()); stream->port = port; /* port number */ stream->tcps = sock; /* init socket */ stream->ictr = 0; /* init input counter */ return stream; /* return success */ } /* TCP/IP authenticated open * Accepts: NETMBX specifier * service name * returned user name buffer * Returns: TCP/IP stream if success else NIL */ TCPSTREAM *tcp_aopen (NETMBX *mb,char *service,char *usrbuf) { return NIL; /* always NIL on DOS */ } /* TCP receive line * Accepts: TCP stream * Returns: text line string or NIL if failure */ char *tcp_getline (TCPSTREAM *stream) { unsigned long n,contd; char *ret = tcp_getline_work (stream,&n,&contd); if (ret && contd) { /* got a line needing continuation? */ STRINGLIST *stl = mail_newstringlist (); STRINGLIST *stc = stl; do { /* collect additional lines */ stc->text.data = (unsigned char *) ret; stc->text.size = n; stc = stc->next = mail_newstringlist (); ret = tcp_getline_work (stream,&n,&contd); } while (ret && contd); if (ret) { /* stash final part of line on list */ stc->text.data = (unsigned char *) ret; stc->text.size = n; /* determine how large a buffer we need */ for (n = 0, stc = stl; stc; stc = stc->next) n += stc->text.size; ret = fs_get (n + 1); /* copy parts into buffer */ for (n = 0, stc = stl; stc; n += stc->text.size, stc = stc->next) memcpy (ret + n,stc->text.data,stc->text.size); ret[n] = '\0'; } mail_free_stringlist (&stl);/* either way, done with list */ } return ret; } /* TCP receive line or partial line * Accepts: TCP stream * pointer to return size * pointer to return continuation flag * Returns: text line string, size and continuation flag, or NIL if failure */ static char *tcp_getline_work (TCPSTREAM *stream,unsigned long *size, long *contd) { unsigned long n; char *s,*ret,c,d; *contd = NIL; /* assume no continuation */ /* make sure have data */ if (!tcp_getdata (stream)) return NIL; for (s = stream->iptr, n = 0, c = '\0'; stream->ictr--; n++, c = d) { d = *stream->iptr++; /* slurp another character */ if ((c == '\015') && (d == '\012')) { ret = (char *) fs_get (n--); memcpy (ret,s,*size = n); /* copy into a free storage string */ ret[n] = '\0'; /* tie off string with null */ return ret; } } /* copy partial string from buffer */ memcpy ((ret = (char *) fs_get (n)),s,*size = n); /* get more data from the net */ if (!tcp_getdata (stream)) fs_give ((void **) &ret); /* special case of newline broken by buffer */ else if ((c == '\015') && (*stream->iptr == '\012')) { stream->iptr++; /* eat the line feed */ stream->ictr--; ret[*size = --n] = '\0'; /* tie off string with null */ } else *contd = LONGT; /* continuation needed */ return ret; } /* TCP/IP receive buffer * Accepts: TCP/IP stream * size in bytes * buffer to read into * Returns: T if success, NIL otherwise */ long tcp_getbuffer (TCPSTREAM *stream,unsigned long size,char *buffer) { unsigned long n; char *bufptr = buffer; while (size > 0) { /* until request satisfied */ if (!tcp_getdata (stream)) return NIL; n = min (size,stream->ictr);/* number of bytes to transfer */ /* do the copy */ memcpy (bufptr,stream->iptr,n); bufptr += n; /* update pointer */ stream->iptr +=n; size -= n; /* update # of bytes to do */ stream->ictr -=n; } bufptr[0] = '\0'; /* tie off string */ return T; } /* TCP/IP receive data * Accepts: TCP/IP stream * Returns: T if success, NIL otherwise */ long tcp_getdata (TCPSTREAM *stream) { int i; fd_set fds,efds; struct timeval tmo; time_t t = time (0); if (stream->tcps < 0) return NIL; while (stream->ictr < 1) { /* if nothing in the buffer */ time_t tl = time (0); /* start of request */ tmo.tv_sec = ttmo_read; /* read timeout */ tmo.tv_usec = 0; FD_ZERO (&fds); /* initialize selection vector */ FD_ZERO (&efds); /* handle errors too */ FD_SET (stream->tcps,&fds);/* set bit in selection vector */ FD_SET(stream->tcps,&efds);/* set bit in error selection vector */ errno = NIL; /* block and read */ while (((i = select (stream->tcps+1,&fds,0,&efds,ttmo_read ? &tmo : 0))<0) && (errno == EINTR)); if (!i) { /* timeout? */ time_t tc = time (0); if (tmoh && ((*tmoh) (tc - t,tc - tl))) continue; else return tcp_abort (stream); } else if (i < 0) return tcp_abort (stream); while (((i = read (stream->tcps,stream->ibuf,BUFLEN)) < 0) && (errno == EINTR)); if (i < 1) return tcp_abort (stream); stream->iptr = stream->ibuf;/* point at TCP buffer */ stream->ictr = i; /* set new byte count */ } return T; } /* TCP/IP send string as record * Accepts: TCP/IP stream * string pointer * Returns: T if success else NIL */ long tcp_soutr (TCPSTREAM *stream,char *string) { return tcp_sout (stream,string,(unsigned long) strlen (string)); } /* TCP/IP send string * Accepts: TCP/IP stream * string pointer * byte count * Returns: T if success else NIL */ long tcp_sout (TCPSTREAM *stream,char *string,unsigned long size) { int i; fd_set fds; struct timeval tmo; time_t t = time (0); if (stream->tcps < 0) return NIL; while (size > 0) { /* until request satisfied */ time_t tl = time (0); /* start of request */ tmo.tv_sec = ttmo_write; /* write timeout */ tmo.tv_usec = 0; FD_ZERO (&fds); /* initialize selection vector */ FD_SET (stream->tcps,&fds);/* set bit in selection vector */ errno = NIL; /* block and write */ while (((i = select (stream->tcps+1,0,&fds,0,ttmo_write ? &tmo : 0)) < 0) && (errno == EINTR)); if (!i) { /* timeout? */ time_t tc = time (0); if (tmoh && ((*tmoh) (tc - t,tc - tl))) continue; else return tcp_abort (stream); } else if (i < 0) return tcp_abort (stream); while (((i = write (stream->tcps,string,size)) < 0) && (errno == EINTR)); if (i < 0) return tcp_abort (stream); size -= i; /* how much we sent */ string += i; } return T; /* all done */ } /* TCP/IP close * Accepts: TCP/IP stream */ void tcp_close (TCPSTREAM *stream) { tcp_abort (stream); /* nuke the socket */ /* flush host names */ fs_give ((void **) &stream->host); fs_give ((void **) &stream->localhost); fs_give ((void **) &stream); /* flush the stream */ } /* TCP/IP abort stream * Accepts: TCP/IP stream * Returns: NIL always */ long tcp_abort (TCPSTREAM *stream) { if (stream->tcps >= 0) close (stream->tcps); stream->tcps = -1; return NIL; } /* TCP/IP get host name * Accepts: TCP/IP stream * Returns: host name for this stream */ char *tcp_host (TCPSTREAM *stream) { return stream->host; /* return host name */ } /* TCP/IP get remote host name * Accepts: TCP/IP stream * Returns: host name for this stream */ char *tcp_remotehost (TCPSTREAM *stream) { return stream->host; /* all we can do for now */ } /* TCP/IP return port for this stream * Accepts: TCP/IP stream * Returns: port number for this stream */ unsigned long tcp_port (TCPSTREAM *stream) { return stream->port; /* return port number */ } /* TCP/IP get local host name * Accepts: TCP/IP stream * Returns: local host name */ char *tcp_localhost (TCPSTREAM *stream) { return stream->localhost; /* return local host name */ } /* TCP/IP return canonical form of host name * Accepts: host name * Returns: canonical form of host name */ char *tcp_canonical (char *name) { return name; } /* TCP/IP get client host name (server calls only) * Returns: client host name */ char *tcp_clienthost () { return "UNKNOWN"; } alpine-2.10+dfsg/imap/src/osdep/dos/fs_dos.c0000600000175000017500000000260011512502124022367 0ustar paulproteuspaulproteus/* ======================================================================== * Copyright 1988-2006 University of Washington * * Licensed under the Apache License, Version 2.0 (the "License"); * you may not use this file except in compliance with the License. * You may obtain a copy of the License at * * http://www.apache.org/licenses/LICENSE-2.0 * * * ======================================================================== */ /* * Program: Free storage management routines * * Author: Mark Crispin * Networks and Distributed Computing * Computing & Communications * University of Washington * Administration Building, AG-44 * Seattle, WA 98195 * Internet: MRC@CAC.Washington.EDU * * Date: 1 August 1988 * Last Edited: 30 August 2006 */ /* Get a block of free storage * Accepts: size of desired block * Returns: free storage block */ void *fs_get (size_t size) { void *block = malloc (size ? size : (size_t) 1); if (!block) fatal ("Out of memory"); return (block); } /* Resize a block of free storage * Accepts: ** pointer to current block * new size */ void fs_resize (void **block,size_t size) { if (!(*block = realloc (*block,size ? size : (size_t) 1))) fatal ("Can't resize memory"); } /* Return a block of free storage * Accepts: ** pointer to free storage block */ void fs_give (void **block) { free (*block); *block = NIL; } alpine-2.10+dfsg/imap/src/osdep/dos/dummydos.c0000600000175000017500000005003311512502124022756 0ustar paulproteuspaulproteus/* ======================================================================== * Copyright 1988-2006 University of Washington * * Licensed under the Apache License, Version 2.0 (the "License"); * you may not use this file except in compliance with the License. * You may obtain a copy of the License at * * http://www.apache.org/licenses/LICENSE-2.0 * * * ======================================================================== */ /* * Program: Dummy routines for DOS * * Author: Mark Crispin * Networks and Distributed Computing * Computing & Communications * University of Washington * Administration Building, AG-44 * Seattle, WA 98195 * Internet: MRC@CAC.Washington.EDU * * Date: 24 May 1993 * Last Edited: 30 August 2006 */ #include #include #include #include "mail.h" #include "osdep.h" #include #include #include "dummy.h" #include "misc.h" /* Function prototypes */ DRIVER *dummy_valid (char *name); void *dummy_parameters (long function,void *value); void dummy_list_work (MAILSTREAM *stream,char *dir,char *pat,char *contents, long level); long dummy_listed (MAILSTREAM *stream,char delimiter,char *name, long attributes,char *contents); long dummy_subscribe (MAILSTREAM *stream,char *mailbox); MAILSTREAM *dummy_open (MAILSTREAM *stream); void dummy_close (MAILSTREAM *stream,long options); long dummy_ping (MAILSTREAM *stream); void dummy_check (MAILSTREAM *stream); long dummy_expunge (MAILSTREAM *stream,char *sequence,long options); long dummy_copy (MAILSTREAM *stream,char *sequence,char *mailbox,long options); long dummy_append (MAILSTREAM *stream,char *mailbox,append_t af,void *data); long dummy_badname (char *tmp,char *s); /* Dummy routines */ /* Driver dispatch used by MAIL */ DRIVER dummydriver = { "dummy", /* driver name */ DR_LOCAL|DR_MAIL, /* driver flags */ (DRIVER *) NIL, /* next driver */ dummy_valid, /* mailbox is valid for us */ dummy_parameters, /* manipulate parameters */ dummy_scan, /* scan mailboxes */ dummy_list, /* list mailboxes */ dummy_lsub, /* list subscribed mailboxes */ dummy_subscribe, /* subscribe to mailbox */ NIL, /* unsubscribe from mailbox */ dummy_create, /* create mailbox */ dummy_delete, /* delete mailbox */ dummy_rename, /* rename mailbox */ mail_status_default, /* status of mailbox */ dummy_open, /* open mailbox */ dummy_close, /* close mailbox */ NIL, /* fetch message "fast" attributes */ NIL, /* fetch message flags */ NIL, /* fetch overview */ NIL, /* fetch message structure */ NIL, /* fetch header */ NIL, /* fetch text */ NIL, /* fetch message data */ NIL, /* unique identifier */ NIL, /* message number from UID */ NIL, /* modify flags */ NIL, /* per-message modify flags */ NIL, /* search for message based on criteria */ NIL, /* sort messages */ NIL, /* thread messages */ dummy_ping, /* ping mailbox to see if still alive */ dummy_check, /* check for new messages */ dummy_expunge, /* expunge deleted messages */ dummy_copy, /* copy messages to another mailbox */ dummy_append, /* append string message to mailbox */ NIL /* garbage collect stream */ }; /* prototype stream */ MAILSTREAM dummyproto = {&dummydriver}; /* driver parameters */ static char *file_extension = NIL; /* Dummy validate mailbox * Accepts: mailbox name * Returns: our driver if name is valid, NIL otherwise */ DRIVER *dummy_valid (char *name) { char *s,tmp[MAILTMPLEN]; struct stat sbuf; /* must be valid local mailbox */ return (name && *name && (*name != '{') && (s = mailboxfile (tmp,name)) && (!*s || !stat (s,&sbuf))) ? &dummydriver : NIL; } /* Dummy manipulate driver parameters * Accepts: function code * function-dependent value * Returns: function-dependent return value */ void *dummy_parameters (long function,void *value) { void *ret = NIL; switch ((int) function) { case SET_EXTENSION: if (file_extension) fs_give ((void **) &file_extension); if (*(char *) value) file_extension = cpystr ((char *) value); case GET_EXTENSION: ret = (void *) file_extension; } return ret; } /* Dummy scan mailboxes * Accepts: mail stream * reference * pattern to search * string to scan */ #define LISTTMPLEN 128 void dummy_scan (MAILSTREAM *stream,char *ref,char *pat,char *contents) { char *s,test[LISTTMPLEN],file[LISTTMPLEN]; long i = 0; if (!pat || !*pat) { /* empty pattern? */ if (dummy_canonicalize (test,ref,"*")) { /* tie off name at root */ if (s = strchr (test,'\\')) *++s = '\0'; else test[0] = '\0'; dummy_listed (stream,'\\',test,LATT_NOINFERIORS,NIL); } } /* get canonical form of name */ else if (dummy_canonicalize (test,ref,pat)) { /* found any wildcards? */ if (s = strpbrk (test,"%*")) { /* yes, copy name up to that point */ strncpy (file,test,(size_t) (i = s - test)); file[i] = '\0'; /* tie off */ } else strcpy (file,test); /* use just that name then */ /* find directory name */ if (s = strrchr (file,'\\')) { *++s = '\0'; /* found, tie off at that point */ s = file; } /* silly case */ else if (file[0] == '#') s = file; /* do the work */ dummy_list_work (stream,s,test,contents,0); if (pmatch ("INBOX",test)) /* always an INBOX */ dummy_listed (stream,NIL,"INBOX",LATT_NOINFERIORS,contents); } } /* Dummy list mailboxes * Accepts: mail stream * reference * pattern to search */ void dummy_list (MAILSTREAM *stream,char *ref,char *pat) { dummy_scan (stream,ref,pat,NIL); } /* Dummy list subscribed mailboxes * Accepts: mail stream * pattern to search */ void dummy_lsub (MAILSTREAM *stream,char *ref,char *pat) { void *sdb = NIL; char *s,*t,test[MAILTMPLEN]; int showuppers = pat[strlen (pat) - 1] == '%'; /* get canonical form of name */ if (dummy_canonicalize (test,ref,pat) && (s = sm_read (&sdb))) do if (*s != '{') { if (pmatch_full (s,test,'\\')) { if (pmatch (s,"INBOX")) mm_lsub (stream,NIL,s,LATT_NOINFERIORS); else mm_lsub (stream,'\\',s,NIL); } else while (showuppers && (t = strrchr (s,'\\'))) { *t = '\0'; /* tie off the name */ if (pmatch_full (s,test,'\\')) mm_lsub (stream,'\\',s,LATT_NOSELECT); } } while (s = sm_read (&sdb)); /* until no more subscriptions */ } /* Dummy subscribe to mailbox * Accepts: mail stream * mailbox to add to subscription list * Returns: T on success, NIL on failure */ long dummy_subscribe (MAILSTREAM *stream,char *mailbox) { char *s,tmp[MAILTMPLEN]; struct stat sbuf; /* must be valid local mailbox */ if ((s = mailboxfile (tmp,mailbox)) && *s && !stat (s,&sbuf) && ((sbuf.st_mode & S_IFMT) == S_IFREG)) return sm_subscribe (mailbox); sprintf (tmp,"Can't subscribe %s: not a mailbox",mailbox); mm_log (tmp,ERROR); return NIL; } /* Dummy list mailboxes worker routine * Accepts: mail stream * directory name to search * search pattern * string to scan * search level */ void dummy_list_work (MAILSTREAM *stream,char *dir,char *pat,char *contents, long level) { struct find_t f; struct stat sbuf; char *s,tmp[LISTTMPLEN],tmpx[LISTTMPLEN]; char *base = (dir && (dir[0] == '\\')) ? NIL : myhomedir (); /* build name */ if (base) sprintf (tmpx,"%s\\",base); else tmpx[0] = '\0'; if (dir) strcat (tmpx,dir); /* punt if bogus name */ if (!mailboxfile (tmp,tmpx)) return; /* make directory wildcard */ strcat (tmp,(tmp[strlen (tmp) -1] == '\\') ? "*." : "\\*."); strcat (tmp,file_extension ? file_extension : "*"); /* do nothing if can't open directory */ if (!_dos_findfirst (tmp,_A_NORMAL|_A_SUBDIR,&f)) { /* list it if at top-level */ if (!level && dir && pmatch_full (dir,pat,'\\')) dummy_listed (stream,'\\',dir,LATT_NOSELECT,contents); /* scan directory */ if (tmpx[strlen (tmpx) - 1] == '\\') do if (*f.name != '.') { if (base) sprintf (tmpx,"%s\\",base); else tmpx[0] = '\0'; if (dir) sprintf (tmpx + strlen (tmpx),"%s%s",dir,f.name); else strcat (tmpx,f.name); if (mailboxfile (tmp,tmpx) && !stat (tmp,&sbuf)) { /* suppress extension */ if (file_extension && (s = strchr (f.name,'.'))) *s = '\0'; /* now make name we'd return */ if (dir) sprintf (tmp,"%s%s",dir,f.name); else strcpy (tmp,f.name); /* only interested in file type */ switch (sbuf.st_mode & S_IFMT) { case S_IFDIR: /* directory? */ if (pmatch_full (tmp,pat,'\\')) { dummy_listed (stream,'\\',tmp,LATT_NOSELECT,contents); strcat (tmp,"\\"); /* set up for dmatch call */ } /* try again with trailing / */ else if (pmatch_full (strcat (tmp,"\\"),pat,'\\')) dummy_listed (stream,'\\',tmp,LATT_NOSELECT,contents); if (dmatch (tmp,pat,'\\') && (level < (long) mail_parameters (NIL,GET_LISTMAXLEVEL,NIL))) dummy_list_work (stream,tmp,pat,contents,level+1); break; case S_IFREG: /* ordinary name */ if (pmatch_full (tmp,pat,'\\') && !pmatch ("INBOX",tmp)) dummy_listed (stream,'\\',tmp,LATT_NOINFERIORS,contents); break; } } } while (!_dos_findnext (&f)); } } /* Mailbox found * Accepts: hierarchy delimiter * mailbox name * attributes * contents to search before calling mm_list() * Returns: T, always */ #define BUFSIZE MAILTMPLEN long dummy_listed (MAILSTREAM *stream,char delimiter,char *name, long attributes,char *contents) { struct stat sbuf; int fd; size_t csiz,ssiz,bsiz; char *buf,tmp[MAILTMPLEN]; if (contents) { /* want to search contents? */ /* forget it if can't select or open */ if ((attributes & LATT_NOSELECT) || !(csiz = strlen (contents)) || !mailboxfile (tmp,name) || stat (tmp,&sbuf) || (csiz > sbuf.st_size) || ((fd = open (tmp,O_RDONLY,NIL)) < 0)) return T; /* get buffer including slop */ buf = (char *) fs_get (BUFSIZE + (ssiz = 4 * ((csiz / 4) + 1)) + 1); memset (buf,'\0',ssiz); /* no slop area the first time */ while (sbuf.st_size) { /* until end of file */ read (fd,buf+ssiz,bsiz = min (sbuf.st_size,BUFSIZE)); if (search ((unsigned char *) buf,bsiz+ssiz, (unsigned char *) contents,csiz)) break; memcpy (buf,buf+BUFSIZE,ssiz); sbuf.st_size -= bsiz; /* note that we read that much */ } fs_give ((void **) &buf); /* flush buffer */ close (fd); /* finished with file */ if (!sbuf.st_size) return T;/* not found */ } /* notify main program */ mm_list (stream,delimiter,name,attributes); return T; } /* Dummy create mailbox * Accepts: mail stream * mailbox name to create * Returns: T on success, NIL on failure */ long dummy_create (MAILSTREAM *stream,char *mailbox) { char tmp[MAILTMPLEN]; return (compare_cstring (mailbox,"INBOX") && mailboxfile (tmp,mailbox)) ? dummy_create_path (stream,tmp,NIL) : dummy_badname (tmp,mailbox); } /* Dummy create path * Accepts: mail stream * path name to create * directory mode * Returns: T on success, NIL on failure */ long dummy_create_path (MAILSTREAM *stream,char *path,long dirmode) { struct stat sbuf; char c,*s,tmp[MAILTMPLEN]; int fd; long ret = NIL; char *t = strrchr (path,'\\'); char *pt = (path[1] == ':') ? path + 2 : path; int wantdir = t && !t[1]; if (wantdir) *t = '\0'; /* flush trailing delimiter for directory */ /* found superior to this name? */ if ((s = strrchr (pt,'\\')) && (s != pt)) { strncpy (tmp,path,(size_t) (s - path)); tmp[s - path] = '\0'; /* make directory name for stat */ c = *++s; /* tie off in case need to recurse */ *s = '\0'; /* name doesn't exist, create it */ if ((stat (tmp,&sbuf) || ((sbuf.st_mode & S_IFMT) != S_IFDIR)) && !dummy_create_path (stream,path,dirmode)) return NIL; *s = c; /* restore full name */ } if (wantdir) { /* want to create directory? */ ret = !mkdir (path); *t = '\\'; /* restore directory delimiter */ } /* create file */ else if ((fd = open (path,O_WRONLY|O_CREAT|O_EXCL,S_IREAD|S_IWRITE)) >= 0) ret = !close (fd); /* close file */ if (!ret) { /* error? */ sprintf (tmp,"Can't create mailbox node %s: %s",path,strerror (errno)); mm_log (tmp,ERROR); } return ret; /* return status */ } /* Dummy delete mailbox * Accepts: mail stream * mailbox name to delete * Returns: T on success, NIL on failure */ long dummy_delete (MAILSTREAM *stream,char *mailbox) { struct stat sbuf; char *s,tmp[MAILTMPLEN]; if (!mailboxfile (tmp,mailbox)) return dummy_badname (tmp,mailbox); /* no trailing \ */ if ((s = strrchr (tmp,'\\')) && !s[1]) *s = '\0'; if (stat (tmp,&sbuf) || ((sbuf.st_mode & S_IFMT) == S_IFDIR) ? rmdir (tmp) : unlink (tmp)) { sprintf (tmp,"Can't delete mailbox %s: %s",mailbox,strerror (errno)); mm_log (tmp,ERROR); return NIL; } return T; /* return success */ } /* Mail rename mailbox * Accepts: mail stream * old mailbox name * new mailbox name * Returns: T on success, NIL on failure */ long dummy_rename (MAILSTREAM *stream,char *old,char *newname) { struct stat sbuf; char c,*s,tmp[MAILTMPLEN],file[MAILTMPLEN]; /* make file name */ if (!mailboxfile (file,old)) return dummy_badname (tmp,old); /* no trailing \ allowed */ if (!(s = mailboxfile (tmp,newname)) || ((s = strrchr (s,'\\')) && !s[1])) return dummy_badname (tmp,newname); if (s) { /* found superior to destination name? */ c = *++s; /* remember first character of inferior */ *s = '\0'; /* tie off to get just superior */ /* name doesn't exist, create it */ if ((stat (file,&sbuf) || ((sbuf.st_mode & S_IFMT) != S_IFDIR)) && !dummy_create (stream,file)) return NIL; *s = c; /* restore full name */ } if (rename (file,tmp)) { sprintf (tmp,"Can't rename mailbox %s to %s: %s",old,newname, strerror (errno)); mm_log (tmp,ERROR); return NIL; } return LONGT; /* return success */ } /* Dummy open * Accepts: stream to open * Returns: stream on success, NIL on failure */ MAILSTREAM *dummy_open (MAILSTREAM *stream) { char tmp[MAILTMPLEN]; struct stat sbuf; int fd = -1; /* OP_PROTOTYPE call or silence */ if (!stream || stream->silent) return NIL; if (!mailboxfile (tmp,stream->mailbox)) sprintf (tmp,"Can't open this name: %.80s",stream->mailbox); else if (compare_cstring (stream->mailbox,"INBOX") && ((fd = open (tmp,O_RDONLY,NIL)) < 0)) sprintf (tmp,"%s: %s",strerror (errno),stream->mailbox); else { if (fd >= 0) { /* if got a file */ fstat (fd,&sbuf); /* sniff at its size */ close (fd); if (sbuf.st_size) sprintf (tmp,"Not a mailbox: %s",stream->mailbox); else fd = -1; /* a-OK */ } if (fd < 0) { /* no file, right? */ if (!stream->silent) { /* only if silence not requested */ /* say there are 0 messages */ mail_exists (stream,(long) 0); mail_recent (stream,(long) 0); stream->uid_validity = time (0); } stream->inbox = T; /* note that it's an INBOX */ return stream; /* return success */ } } mm_log (tmp,stream->silent ? WARN: ERROR); return NIL; /* always fails */ } /* Dummy close * Accepts: MAIL stream * options */ void dummy_close (MAILSTREAM *stream,long options) { /* return silently */ } /* Dummy ping mailbox * Accepts: MAIL stream * Returns: T if stream alive, else NIL * No-op for readonly files, since read/writer can expunge it from under us! */ long dummy_ping (MAILSTREAM *stream) { MAILSTREAM *test; /* time to do another test? */ if (time (0) >= ((time_t) (stream->gensym + 30))) { /* has mailbox format changed? */ if ((test = mail_open (NIL,stream->mailbox,OP_PROTOTYPE)) && (test->dtb != stream->dtb) && (test = mail_open (NIL,stream->mailbox,NIL))) { /* preserve some resources */ test->original_mailbox = stream->original_mailbox; stream->original_mailbox = NIL; test->sparep = stream->sparep; stream->sparep = NIL; test->sequence = stream->sequence; mail_close ((MAILSTREAM *) /* flush resources used by dummy stream */ memcpy (fs_get (sizeof (MAILSTREAM)),stream, sizeof (MAILSTREAM))); /* swap the streams */ memcpy (stream,test,sizeof (MAILSTREAM)); fs_give ((void **) &test);/* flush test now that copied */ /* make sure application knows */ mail_exists (stream,stream->recent = stream->nmsgs); } /* still hasn't changed */ else stream->gensym = time (0); } return T; } /* Dummy check mailbox * Accepts: MAIL stream * No-op for readonly files, since read/writer can expunge it from under us! */ void dummy_check (MAILSTREAM *stream) { dummy_ping (stream); /* invoke ping */ } /* Dummy expunge mailbox * Accepts: MAIL stream * sequence to expunge if non-NIL * expunge options * Returns: T, always */ long dummy_expunge (MAILSTREAM *stream,char *sequence,long options) { return LONGT; } /* Dummy copy message(s) * Accepts: MAIL stream * sequence * destination mailbox * options * Returns: T if copy successful, else NIL */ long dummy_copy (MAILSTREAM *stream,char *sequence,char *mailbox,long options) { if ((options & CP_UID) ? mail_uid_sequence (stream,sequence) : mail_sequence (stream,sequence)) fatal ("Impossible dummy_copy"); return NIL; } /* Dummy append message string * Accepts: mail stream * destination mailbox * append callback function * data for callback * Returns: T on success, NIL on failure */ long dummy_append (MAILSTREAM *stream,char *mailbox,append_t af,void *data) { struct stat sbuf; int fd = -1; int e; char tmp[MAILTMPLEN]; MAILSTREAM *ts = default_proto (T); if (compare_cstring (mailbox,"INBOX") && mailboxfile (tmp,mailbox) && ((fd = open (tmp,O_RDONLY,NIL)) < 0)) { if ((e = errno) == ENOENT) /* failed, was it no such file? */ mm_notify (stream,"[TRYCREATE] Must create mailbox before append", (long) NIL); sprintf (tmp,"%s: %s",strerror (e),mailbox); mm_log (tmp,ERROR); /* pass up error */ return NIL; /* always fails */ } if (fd >= 0) { /* found file? */ fstat (fd,&sbuf); /* get its size */ close (fd); /* toss out the fd */ if (sbuf.st_size) ts = NIL; /* non-empty file? */ } if (ts) return (*ts->dtb->append) (stream,mailbox,af,data); sprintf (tmp,"Indeterminate mailbox format: %s",mailbox); mm_log (tmp,ERROR); return NIL; } /* Return bad file name error message * Accepts: temporary buffer * file name * Returns: long NIL always */ long dummy_badname (char *tmp,char *s) { sprintf (tmp,"Invalid mailbox name: %s",s); mm_log (tmp,ERROR); return (long) NIL; } /* Dummy canonicalize name * Accepts: buffer to write name * reference * pattern * Returns: T if success, NIL if failure */ long dummy_canonicalize (char *tmp,char *ref,char *pat) { unsigned long i; char *s,dev[4]; /* initially no device */ dev[0] = dev[1] = dev[2] = dev[3] = '\0'; if (ref) switch (*ref) { /* preliminary reference check */ case '{': /* remote names not allowed */ return NIL; /* disallowed */ case '\0': /* empty reference string */ break; default: /* all other names */ if (ref[1] == ':') { /* start with device name? */ dev[0] = *ref++; dev[1] = *ref++; } break; } if (pat[1] == ':') { /* device name in pattern? */ dev[0] = *pat++; dev[1] = *pat++; ref = NIL; /* ignore reference */ } switch (*pat) { case '#': /* namespace names */ if (mailboxfile (tmp,pat)) strcpy (tmp,pat); else return NIL; /* unknown namespace */ break; case '{': /* remote names not allowed */ return NIL; case '\\': /* rooted name */ ref = NIL; /* ignore reference */ break; } /* make sure device names are rooted */ if (dev[0] && (*(ref ? ref : pat) != '\\')) dev[2] = '\\'; /* build name */ sprintf (tmp,"%s%s%s",dev,ref ? ref : "",pat); ucase (tmp); /* force upper case */ /* count wildcards */ for (i = 0, s = tmp; *s; *s++) if ((*s == '*') || (*s == '%')) ++i; if (i > MAXWILDCARDS) { /* ridiculous wildcarding? */ MM_LOG ("Excessive wildcards in LIST/LSUB",ERROR); return NIL; } return T; } alpine-2.10+dfsg/imap/src/osdep/dos/os_dnf.c0000600000175000017500000000457311512502124022375 0ustar paulproteuspaulproteus/* ======================================================================== * Copyright 1988-2006 University of Washington * * Licensed under the Apache License, Version 2.0 (the "License"); * you may not use this file except in compliance with the License. * You may obtain a copy of the License at * * http://www.apache.org/licenses/LICENSE-2.0 * * * ======================================================================== */ /* * Program: Operating-system dependent routines -- MS-DOS (PC-NFS) version * * Author: Mark Crispin * Networks and Distributed Computing * Computing & Communications * University of Washington * Administration Building, AG-44 * Seattle, WA 98195 * Internet: MRC@CAC.Washington.EDU * * Date: 11 April 1989 * Last Edited: 30 August 2006 */ /* Private function prototypes */ #include "tcp_dos.h" /* must be before osdep includes tcp.h */ #include "mail.h" #include "osdep.h" #include #include #include #include #include #include #include #include #include #include #include #include #include "misc.h" #include "fs_dos.c" #include "ftl_dos.c" #include "nl_dos.c" #include "env_dos.c" #undef write #include "tcp_dos.c" /* Return my local host name * Returns: my local host name */ char *mylocalhost (void) { if (!myLocalHost) { /* known yet? */ char *s,tmp[MAILTMPLEN]; unsigned long myip; /* see if known host name */ if (!gethostname (tmp,MAILTMPLEN-1)) s = tmp; /* no, try host address */ else if (get_myipaddr ((char *) &myip)) sprintf (s = tmp,"[%s]",inet_ntoa (myip)); else s = "random-pc"; /* say what? */ myLocalHost = cpystr (s); /* record for subsequent use */ } return myLocalHost; } /* Look up host address * Accepts: pointer to pointer to host name * socket address block * Returns: non-zero with host address in socket, official host name in host; * else NIL */ long lookuphost (char **host,struct sockaddr_in *sin) { long ret = -1; char tmp[MAILTMPLEN]; struct hostent *hn = gethostbyname (lcase (strcpy (tmp,*host))); if (!hn) return NIL; /* got a host name? */ *host = cpystr (hn->h_name); /* set official name */ /* copy host addresses */ memcpy (&sin->sin_addr,hn->h_addr,hn->h_length); return T; } alpine-2.10+dfsg/imap/src/osdep/dos/tcp_dwa.h0000600000175000017500000000232711512502124022546 0ustar paulproteuspaulproteus/* ======================================================================== * Copyright 1988-2006 University of Washington * * Licensed under the Apache License, Version 2.0 (the "License"); * you may not use this file except in compliance with the License. * You may obtain a copy of the License at * * http://www.apache.org/licenses/LICENSE-2.0 * * * ======================================================================== */ /* * Program: Waterloo DOS TCP/IP routines * * Author: Mark Crispin * Networks and Distributed Computing * Computing & Communications * University of Washington * Administration Building, AG-44 * Seattle, WA 98195 * Internet: MRC@CAC.Washington.EDU * * Date: 11 April 1989 * Last Edited: 30 August 2006 */ /* TCP input buffer -- must be large enough to prevent overflow */ #define BUFLEN 8192 /* TCP I/O stream (must be before osdep.h is included) */ #define TCPSTREAM struct tcp_stream TCPSTREAM { char *host; /* host name */ unsigned long port; /* port number */ char *localhost; /* local host name */ tcp_Socket *tcps; /* tcp socket */ long ictr; /* input counter */ char *iptr; /* input pointer */ char ibuf[BUFLEN]; /* input buffer */ }; alpine-2.10+dfsg/imap/src/osdep/dos/tcp_dwa.c0000600000175000017500000002160411512502124022540 0ustar paulproteuspaulproteus/* ======================================================================== * Copyright 1988-2008 University of Washington * * Licensed under the Apache License, Version 2.0 (the "License"); * you may not use this file except in compliance with the License. * You may obtain a copy of the License at * * http://www.apache.org/licenses/LICENSE-2.0 * * * ======================================================================== */ /* * Program: Waterloo DOS TCP/IP routines * * Author: Mark Crispin * Networks and Distributed Computing * Computing & Communications * University of Washington * Administration Building, AG-44 * Seattle, WA 98195 * Internet: MRC@CAC.Washington.EDU * * Date: 11 April 1989 * Last Edited: 13 January 2008 */ /* Global data */ short sock_initted = 0; /* global so others using net can see it */ static char *tcp_getline_work (TCPSTREAM *stream,unsigned long *size, long *contd); /* TCP/IP manipulate parameters * Accepts: function code * function-dependent value * Returns: function-dependent return value */ void *tcp_parameters (long function,void *value) { return NIL; } /* TCP/IP open * Accepts: host name * contact service name * contact port number * Returns: TCP/IP stream if success else NIL */ TCPSTREAM *TCP_open (char *host,char *service,unsigned long port) { TCPSTREAM *stream = NIL; tcp_Socket *sock; char *s,tmp[MAILTMPLEN]; unsigned long adr,i,j,k,l; port &= 0xffff; /* erase flags */ /* initialize if first time here */ if (!sock_initted++) sock_init(); /* The domain literal form is used (rather than simply the dotted decimal as with other Unix programs) because it has to be a valid "host name" in mailsystem terminology. */ /* look like domain literal? */ if (host[0] == '[' && host[strlen (host)-1] == ']') { if (((i = strtoul (s = host+1,&s,10)) <= 255) && *s++ == '.' && ((j = strtoul (s,&s,10)) <= 255) && *s++ == '.' && ((k = strtoul (s,&s,10)) <= 255) && *s++ == '.' && ((l = strtoul (s,&s,10)) <= 255) && *s++ == ']' && !*s) adr = (i << 24) + (j << 16) + (k << 8) + l; else { sprintf (tmp,"Bad format domain-literal: %.80s",host); mm_log (tmp,ERROR); return NIL; } } else { /* lookup host name */ if (!(adr = resolve (host))) { sprintf (tmp,"Host not found: %s",host); mm_log (tmp,ERROR); return NIL; } } /* OK to instantiate socket now */ sock = (tcp_Socket *) fs_get (sizeof (tcp_Socket)); /* open connection */ if (!tcp_open (sock,(word) 0,adr,(word) port,NULL)) { sprintf (tmp,"Can't connect to %.80s,%ld",host,port); mm_log (tmp,ERROR); fs_give ((void **) &sock); return NIL; } /* create TCP/IP stream */ stream = (TCPSTREAM *) fs_get (sizeof (TCPSTREAM)); stream->host = cpystr (host); /* official host name */ stream->localhost = cpystr (mylocalhost ()); stream->port = port; /* port number */ stream->tcps = sock; /* init socket */ stream->ictr = 0; /* init input counter */ return stream; /* return success */ } /* TCP/IP authenticated open * Accepts: NETMBX specifier * service name * returned user name buffer * Returns: TCP/IP stream if success else NIL */ TCPSTREAM *tcp_aopen (NETMBX *mb,char *service,char *usrbuf) { return NIL; /* always NIL on DOS */ } /* TCP receive line * Accepts: TCP stream * Returns: text line string or NIL if failure */ char *tcp_getline (TCPSTREAM *stream) { unsigned long n,contd; char *ret = tcp_getline_work (stream,&n,&contd); if (ret && contd) { /* got a line needing continuation? */ STRINGLIST *stl = mail_newstringlist (); STRINGLIST *stc = stl; do { /* collect additional lines */ stc->text.data = (unsigned char *) ret; stc->text.size = n; stc = stc->next = mail_newstringlist (); ret = tcp_getline_work (stream,&n,&contd); } while (ret && contd); if (ret) { /* stash final part of line on list */ stc->text.data = (unsigned char *) ret; stc->text.size = n; /* determine how large a buffer we need */ for (n = 0, stc = stl; stc; stc = stc->next) n += stc->text.size; ret = fs_get (n + 1); /* copy parts into buffer */ for (n = 0, stc = stl; stc; n += stc->text.size, stc = stc->next) memcpy (ret + n,stc->text.data,stc->text.size); ret[n] = '\0'; } mail_free_stringlist (&stl);/* either way, done with list */ } return ret; } /* TCP receive line or partial line * Accepts: TCP stream * pointer to return size * pointer to return continuation flag * Returns: text line string, size and continuation flag, or NIL if failure */ static char *tcp_getline_work (TCPSTREAM *stream,unsigned long *size, long *contd) { unsigned long n; char *s,*ret,c,d; *contd = NIL; /* assume no continuation */ /* make sure have data */ if (!tcp_getdata (stream)) return NIL; for (s = stream->iptr, n = 0, c = '\0'; stream->ictr--; n++, c = d) { d = *stream->iptr++; /* slurp another character */ if ((c == '\015') && (d == '\012')) { ret = (char *) fs_get (n--); memcpy (ret,s,*size = n); /* copy into a free storage string */ ret[n] = '\0'; /* tie off string with null */ return ret; } } /* copy partial string from buffer */ memcpy ((ret = (char *) fs_get (n)),s,*size = n); /* get more data from the net */ if (!tcp_getdata (stream)) fs_give ((void **) &ret); /* special case of newline broken by buffer */ else if ((c == '\015') && (*stream->iptr == '\012')) { stream->iptr++; /* eat the line feed */ stream->ictr--; ret[*size = --n] = '\0'; /* tie off string with null */ } else *contd = LONGT; /* continuation needed */ return ret; } /* TCP/IP receive buffer * Accepts: TCP/IP stream * size in bytes * buffer to read into * Returns: T if success, NIL otherwise */ long tcp_getbuffer (TCPSTREAM *stream,unsigned long size,char *buffer) { unsigned long n; char *bufptr = buffer; while (size > 0) { /* until request satisfied */ if (!tcp_getdata (stream)) return NIL; n = min (size,stream->ictr);/* number of bytes to transfer */ /* do the copy */ memcpy (bufptr,stream->iptr,(size_t) n); bufptr += n; /* update pointer */ stream->iptr +=n; size -= n; /* update # of bytes to do */ stream->ictr -=n; } bufptr[0] = '\0'; /* tie off string */ return T; } /* TCP/IP receive data * Accepts: TCP/IP stream * Returns: T if success, NIL otherwise */ long tcp_getdata (TCPSTREAM *stream) { int status; if (!stream->tcps) return NIL;/* no-no nuked socket */ while (stream->ictr < 1) { /* if buffer empty, block for input and read */ if (!_ip_delay1 (stream->tcps,600,NULL,&status)) stream->ictr = sock_fastread (stream->tcps, stream->iptr = stream->ibuf,BUFLEN); else if (status == 1) { /* nuke the socket if closed */ sock_close (stream->tcps); fs_give ((void **) &stream->tcps); return NIL; } } return T; } /* TCP/IP send string as record * Accepts: TCP/IP stream * Returns: T if success else NIL */ long tcp_soutr (TCPSTREAM *stream,char *string) { /* output the cruft */ sock_puts (stream->tcps,string); return T; /* all done */ } /* TCP/IP send string * Accepts: TCP/IP stream * string pointer * byte count * Returns: T if success else NIL */ long tcp_sout (TCPSTREAM *stream,char *string,unsigned long size) { sock_write (stream->tcps,string,(int) size); return T; } /* TCP/IP close * Accepts: TCP/IP stream */ void tcp_close (TCPSTREAM *stream) { if (stream->tcps){ /* nuke the socket */ sock_close (stream->tcps); _ip_delay2 (stream->tcps,0,NULL,NULL); } fs_give ((void **) &stream->tcps); /* flush host names */ fs_give ((void **) &stream->host); fs_give ((void **) &stream->localhost); fs_give ((void **) &stream); /* flush the stream */ } /* TCP/IP get host name * Accepts: TCP/IP stream * Returns: host name for this stream */ char *tcp_host (TCPSTREAM *stream) { return stream->host; /* return host name */ } /* TCP/IP get remote host name * Accepts: TCP/IP stream * Returns: host name for this stream */ char *tcp_remotehost (TCPSTREAM *stream) { return stream->host; /* return host name */ } /* TCP/IP return port for this stream * Accepts: TCP/IP stream * Returns: port number for this stream */ unsigned long tcp_port (TCPSTREAM *stream) { return stream->port; /* return port number */ } /* TCP/IP get local host name * Accepts: TCP/IP stream * Returns: local host name */ char *tcp_localhost (TCPSTREAM *stream) { return stream->localhost; /* return local host name */ } /* TCP/IP return canonical form of host name * Accepts: host name * Returns: canonical form of host name */ char *tcp_canonical (char *name) { return name; } /* TCP/IP get client host name (server calls only) * Returns: client host name */ char *tcp_clienthost () { return "UNKNOWN"; } alpine-2.10+dfsg/imap/src/osdep/dos/drivraux.bat0000600000175000017500000000163311512502124023307 0ustar paulproteuspaulproteus@ECHO OFF REM ======================================================================== REM Copyright 1988-2006 University of Washington REM REM Licensed under the Apache License, Version 2.0 (the "License"); REM you may not use this file except in compliance with the License. REM You may obtain a copy of the License at REM REM http://www.apache.org/licenses/LICENSE-2.0 REM REM REM ======================================================================== REM Program: Driver Linkage Generator auxillary for DOS REM REM Author: Mark Crispin REM Networks and Distributed Computing REM Computing & Communications REM University of Washington REM Administration Building, AG-44 REM Seattle, WA 98195 REM Internet: MRC@CAC.Washington.EDU REM REM Date: 11 October 1989 REM Last Edited:30 August 2006 ECHO extern DRIVER %1driver; >> LINKAGE.H ECHO mail_link (&%1driver); /* link in the %1 driver */ >> LINKAGE.C alpine-2.10+dfsg/imap/src/osdep/dos/mkauths.bat0000600000175000017500000000172411512502124023120 0ustar paulproteuspaulproteus@ECHO OFF REM ======================================================================== REM Copyright 1988-2006 University of Washington REM REM Licensed under the Apache License, Version 2.0 (the "License"); REM you may not use this file except in compliance with the License. REM You may obtain a copy of the License at REM REM http://www.apache.org/licenses/LICENSE-2.0 REM REM REM ======================================================================== REM Program: Authenticator Linkage Generator for DOS and Windows REM REM Author: Mark Crispin REM Networks and Distributed Computing REM Computing & Communications REM University of Washington REM Administration Building, AG-44 REM Seattle, WA 98195 REM Internet: MRC@CAC.Washington.EDU REM REM Date: 6 December 1995 REM Last Edited:30 August 2006 REM Erase old authenticators list IF EXIST AUTHS.C DEL AUTHS.C REM Now define the new list FOR %%D IN (%1 %2 %3 %4 %5 %6 %7 %8 %9) DO CALL MKAUTAUX %%D EXIT 0 alpine-2.10+dfsg/imap/src/osdep/dos/drivers.bat0000600000175000017500000000170311512502124023117 0ustar paulproteuspaulproteus@ECHO OFF REM ======================================================================== REM Copyright 1988-2006 University of Washington REM REM Licensed under the Apache License, Version 2.0 (the "License"); REM you may not use this file except in compliance with the License. REM You may obtain a copy of the License at REM REM http://www.apache.org/licenses/LICENSE-2.0 REM REM REM ======================================================================== REM Program: Driver Linkage Generator for DOS/NT REM REM Author: Mark Crispin REM Networks and Distributed Computing REM Computing & Communications REM University of Washington REM Administration Building, AG-44 REM Seattle, WA 98195 REM Internet: MRC@CAC.Washington.EDU REM REM Date: 11 October 1989 REM Last Edited:30 August 2006 REM Erase old driver linkage IF EXIST LINKAGE.* DEL LINKAGE.* REM Now define the new list FOR %%D IN (%1 %2 %3 %4 %5 %6 %7 %8 %9) DO CALL DRIVRAUX %%D EXIT 0 alpine-2.10+dfsg/imap/src/osdep/dos/bezrkdos.c0000600000175000017500000007043711512502124022752 0ustar paulproteuspaulproteus/* ======================================================================== * Copyright 1988-2006 University of Washington * * Licensed under the Apache License, Version 2.0 (the "License"); * you may not use this file except in compliance with the License. * You may obtain a copy of the License at * * http://www.apache.org/licenses/LICENSE-2.0 * * * ======================================================================== */ /* * Program: Berkeley mail routines * * Author: Mark Crispin * Networks and Distributed Computing * Computing & Communications * University of Washington * Administration Building, AG-44 * Seattle, WA 98195 * Internet: MRC@CAC.Washington.EDU * * Date: 24 June 1992 * Last Edited: 30 August 2006 */ /* Dedication: * This file is dedicated with affection to those Merry Marvels of Musical * Madness . . . * -> The Incomparable Leland Stanford Junior University Marching Band <- * who entertain, awaken, and outrage Stanford fans in the fact of repeated * losing seasons and shattered Rose Bowl dreams [Cardinal just don't have * HUSKY FEVER!!!]. * */ #include #include #include #include "mail.h" #include "osdep.h" #include #include #include #include "rfc822.h" #include "dummy.h" #include "misc.h" #include "fdstring.h" /* Berkeley I/O stream local data */ typedef struct bezerk_local { int fd; /* file descriptor for I/O */ off_t filesize; /* file size parsed */ char *buf; /* temporary buffer */ } BEZERKLOCAL; /* Convenient access to local data */ #define LOCAL ((BEZERKLOCAL *) stream->local) /* Function prototypes */ DRIVER *bezerk_valid (char *name); long bezerk_isvalid (char *name,char *tmp); int bezerk_valid_line (char *s,char **rx,int *rzn); void *bezerk_parameters (long function,void *value); void bezerk_scan (MAILSTREAM *stream,char *ref,char *pat,char *contents); void bezerk_list (MAILSTREAM *stream,char *ref,char *pat); void bezerk_lsub (MAILSTREAM *stream,char *ref,char *pat); long bezerk_create (MAILSTREAM *stream,char *mailbox); long bezerk_delete (MAILSTREAM *stream,char *mailbox); long bezerk_rename (MAILSTREAM *stream,char *old,char *newname); MAILSTREAM *bezerk_open (MAILSTREAM *stream); void bezerk_close (MAILSTREAM *stream,long options); char *bezerk_header (MAILSTREAM *stream,unsigned long msgno, unsigned long *length,long flags); long bezerk_text (MAILSTREAM *stream,unsigned long msgno,STRING *bs, long flags); long bezerk_ping (MAILSTREAM *stream); void bezerk_check (MAILSTREAM *stream); long bezerk_expunge (MAILSTREAM *stream,char *sequence,long options); long bezerk_copy (MAILSTREAM *stream,char *sequence,char *mailbox, long options); long bezerk_append (MAILSTREAM *stream,char *mailbox,append_t af,void *data); int bezerk_append_msg (MAILSTREAM *stream,FILE *sf,char *flags,char *date, STRING *msg); void bezerk_gc (MAILSTREAM *stream,long gcflags); char *bezerk_file (char *dst,char *name); long bezerk_badname (char *tmp,char *s); long bezerk_parse (MAILSTREAM *stream); unsigned long bezerk_hdrpos (MAILSTREAM *stream,unsigned long msgno, unsigned long *size); /* Berkeley mail routines */ /* Driver dispatch used by MAIL */ DRIVER bezerkdriver = { "bezerk", /* driver name */ /* driver flags */ DR_LOCAL|DR_MAIL|DR_LOWMEM|DR_CRLF|DR_NOSTICKY, (DRIVER *) NIL, /* next driver */ bezerk_valid, /* mailbox is valid for us */ bezerk_parameters, /* manipulate parameters */ bezerk_scan, /* scan mailboxes */ bezerk_list, /* list mailboxes */ bezerk_lsub, /* list subscribed mailboxes */ NIL, /* subscribe to mailbox */ NIL, /* unsubscribe from mailbox */ bezerk_create, /* create mailbox */ bezerk_delete, /* delete mailbox */ bezerk_rename, /* rename mailbox */ mail_status_default, /* status of mailbox */ bezerk_open, /* open mailbox */ bezerk_close, /* close mailbox */ NIL, /* fetch message "fast" attributes */ NIL, /* fetch message flags */ NIL, /* fetch overview */ NIL, /* fetch message envelopes */ bezerk_header, /* fetch message header */ bezerk_text, /* fetch message text */ NIL, /* fetch partial message text */ NIL, /* unique identifier */ NIL, /* message number */ NIL, /* modify flags */ NIL, /* per-message modify flags */ NIL, /* search for message based on criteria */ NIL, /* sort messages */ NIL, /* thread messages */ bezerk_ping, /* ping mailbox to see if still alive */ bezerk_check, /* check for new messages */ bezerk_expunge, /* expunge deleted messages */ bezerk_copy, /* copy messages to another mailbox */ bezerk_append, /* append string message to mailbox */ NIL /* garbage collect stream */ }; /* prototype stream */ MAILSTREAM bezerkproto = {&bezerkdriver}; /* Berkeley mail validate mailbox * Accepts: mailbox name * Returns: our driver if name is valid, NIL otherwise */ DRIVER *bezerk_valid (char *name) { char tmp[MAILTMPLEN]; return bezerk_isvalid (name,tmp) ? &bezerkdriver : (DRIVER *) NIL; } /* Berkeley mail test for valid mailbox * Accepts: mailbox name * Returns: T if valid, NIL otherwise */ long bezerk_isvalid (char *name,char *tmp) { int fd; long ret = NIL; struct stat sbuf; errno = EINVAL; /* assume invalid argument */ /* if file, get its status */ if ((*name != '{') && mailboxfile (tmp,name) && !stat (tmp,&sbuf)) { if (!sbuf.st_size)errno = 0;/* empty file */ else if ((fd = open (tmp,O_BINARY|O_RDONLY,NIL)) >= 0) { memset (tmp,'\0',MAILTMPLEN); errno = -1; /* in case bezerk_valid_line fails */ if (read (fd,tmp,MAILTMPLEN-1) >= 0) ret = bezerk_valid_line (tmp,NIL,NIL); close (fd); /* close the file */ } } /* in case INBOX but not bezerk format */ else if ((errno == ENOENT) && ((name[0] == 'I') || (name[0] == 'i')) && ((name[1] == 'N') || (name[1] == 'n')) && ((name[2] == 'B') || (name[2] == 'b')) && ((name[3] == 'O') || (name[3] == 'o')) && ((name[4] == 'X') || (name[4] == 'x')) && !name[5]) errno = -1; return ret; /* return what we should */ } /* Validate line * Accepts: pointer to candidate string to validate as a From header * return pointer to end of date/time field * return pointer to offset from t of time (hours of ``mmm dd hh:mm'') * return pointer to offset from t of time zone (if non-zero) * Returns: t,ti,zn set if valid From string, else ti is NIL */ int bezerk_valid_line (char *s,char **rx,int *rzn) { char *x; int zn; int ti = 0; /* line must begin with "From " */ if ((*s != 'F') || (s[1] != 'r') || (s[2] != 'o') || (s[3] != 'm') || (s[4] != ' ')) return NIL; /* find end of line */ for (x = s + 5; *x && *x != '\012'; x++); if (!x) return NIL; /* end of line not found */ if (x[-1] == '\015') x--; /* ignore CR */ if ((x - s < 27)) return NIL; /* line too short */ if (x - s >= 41) { /* possible search for " remote from " */ for (zn = -1; x[zn] != ' '; zn--); if ((x[zn-1] == 'm') && (x[zn-2] == 'o') && (x[zn-3] == 'r') && (x[zn-4] == 'f') && (x[zn-5] == ' ') && (x[zn-6] == 'e') && (x[zn-7] == 't') && (x[zn-8] == 'o') && (x[zn-9] == 'm') && (x[zn-10] == 'e') && (x[zn-11] == 'r') && (x[zn-12] == ' ')) x += zn - 12; } if (x[-5] == ' ') { /* ends with year? */ /* no timezone? */ if (x[-8] == ':') zn = 0,ti = -5; /* three letter timezone? */ else if (x[-9] == ' ') ti = zn = -9; /* numeric timezone? */ else if ((x[-11]==' ') && ((x[-10]=='+') || (x[-10]=='-'))) ti = zn = -11; } else if (x[-4] == ' ') { /* no year and three leter timezone? */ if (x[-9] == ' ') zn = -4,ti = -9; } else if (x[-6] == ' ') { /* no year and numeric timezone? */ if ((x[-11] == ' ') && ((x[-5] == '+') || (x[-5] == '-'))) zn = -6,ti = -11; } /* time must be www mmm dd hh:mm[:ss] */ if (ti && !((x[ti - 3] == ':') && (x[ti -= ((x[ti - 6] == ':') ? 9 : 6)] == ' ') && (x[ti - 3] == ' ') && (x[ti - 7] == ' ') && (x[ti - 11] == ' '))) return NIL; if (rx) *rx = x; /* set return values */ if (rzn) *rzn = zn; return ti; } /* Berkeley manipulate driver parameters * Accepts: function code * function-dependent value * Returns: function-dependent return value */ void *bezerk_parameters (long function,void *value) { return NIL; } /* Berkeley mail scan mailboxes * Accepts: mail stream * reference * pattern to search * string to scan */ void bezerk_scan (MAILSTREAM *stream,char *ref,char *pat,char *contents) { if (stream) dummy_scan (NIL,ref,pat,contents); } /* Berkeley mail list mailboxes * Accepts: mail stream * reference * pattern to search */ void bezerk_list (MAILSTREAM *stream,char *ref,char *pat) { if (stream) dummy_list (stream,ref,pat); } /* Berkeley mail list subscribed mailboxes * Accepts: mail stream * reference * pattern to search */ void bezerk_lsub (MAILSTREAM *stream,char *ref,char *pat) { if (stream) dummy_lsub (stream,ref,pat); } /* Berkeley mail create mailbox * Accepts: MAIL stream * mailbox name to create * Returns: T on success, NIL on failure */ long bezerk_create (MAILSTREAM *stream,char *mailbox) { return dummy_create (stream,mailbox); } /* Berkeley mail delete mailbox * Accepts: MAIL stream * mailbox name to delete * Returns: T on success, NIL on failure */ long bezerk_delete (MAILSTREAM *stream,char *mailbox) { return dummy_delete (stream,mailbox); } /* Berkeley mail rename mailbox * Accepts: MAIL stream * old mailbox name * new mailbox name (or NIL for delete) * Returns: T on success, NIL on failure */ long bezerk_rename (MAILSTREAM *stream,char *old,char *newname) { return dummy_rename (stream,old,newname); } /* Berkeley mail open * Accepts: stream to open * Returns: stream on success, NIL on failure */ MAILSTREAM *bezerk_open (MAILSTREAM *stream) { long i; int fd; char *s; char tmp[MAILTMPLEN]; /* return prototype for OP_PROTOTYPE call */ if (!stream) return &bezerkproto; if (stream->local) fatal ("bezerk recycle stream"); if (!mailboxfile (tmp,stream->mailbox)) return (MAILSTREAM *) bezerk_badname (tmp,stream->mailbox); if (((fd = open (tmp,O_BINARY|O_RDONLY,NIL)) < 0)) { sprintf (tmp,"Can't open mailbox: %s",strerror (errno)); mm_log (tmp,ERROR); return NIL; } stream->rdonly = T; /* this driver is readonly */ stream->local = fs_get (sizeof (BEZERKLOCAL)); /* canonicalize the stream mailbox name */ fs_give ((void **) &stream->mailbox); if (s = strchr ((s = strrchr (tmp,'\\')) ? s : tmp,'.')) *s = '\0'; stream->mailbox = cpystr (tmp); LOCAL->fd = fd; /* note the file */ LOCAL->filesize = 0; /* initialize parsed file size */ LOCAL->buf = NIL; /* initially no local buffer */ stream->sequence++; /* bump sequence number */ stream->uid_validity = time (0); /* parse mailbox */ stream->nmsgs = stream->recent = 0; if (!bezerk_ping (stream)) return NIL; if (!stream->nmsgs) mm_log ("Mailbox is empty",(long) NIL); stream->perm_seen = stream->perm_deleted = stream->perm_flagged = stream->perm_answered = stream->perm_draft = NIL; stream->perm_user_flags = NIL; return stream; /* return stream to caller */ } /* Berkeley mail close * Accepts: MAIL stream * close options */ void bezerk_close (MAILSTREAM *stream,long options) { if (stream && LOCAL) { /* only if a file is open */ int silent = stream->silent; stream->silent = T; if (options & CL_EXPUNGE) bezerk_expunge (stream,NIL,NIL); close (LOCAL->fd); /* close the local file */ if (LOCAL->buf) fs_give ((void **) &LOCAL->buf); /* nuke the local data */ fs_give ((void **) &stream->local); stream->dtb = NIL; /* log out the DTB */ } } /* Berkeley mail fetch message header * Accepts: MAIL stream * message # to fetch * pointer to returned header text length * option flags * Returns: message header in RFC822 format */ char *bezerk_header (MAILSTREAM *stream,unsigned long msgno, unsigned long *length,long flags) { char tmp[MAILTMPLEN]; *length = 0; /* default to empty */ if (flags & FT_UID) return "";/* UID call "impossible" */ /* get to header position */ lseek (LOCAL->fd,bezerk_hdrpos (stream,msgno,length),L_SET); /* is buffer big enough? */ if (LOCAL->buf) fs_give ((void **) &LOCAL->buf); LOCAL->buf = (char *) fs_get ((size_t) *length + 1); LOCAL->buf[*length] = '\0'; /* tie off string */ /* slurp the data */ read (LOCAL->fd,LOCAL->buf,(size_t) *length); return LOCAL->buf; } /* Berkeley mail fetch message text (body only) * Accepts: MAIL stream * message # to fetch * pointer to returned header text length * option flags * Returns: T, always */ long bezerk_text (MAILSTREAM *stream,unsigned long msgno,STRING *bs,long flags) { MESSAGECACHE *elt; FDDATA d; unsigned long hdrsize,hdrpos; /* UID call "impossible" */ if (flags & FT_UID) return NIL; elt = mail_elt (stream,msgno);/* if message not seen */ /* mark message as seen */ if (elt->seen && !(flags & FT_PEEK)) { elt->seen = T; mm_flags (stream,msgno); } /* get location of text data */ hdrpos = bezerk_hdrpos (stream,msgno,&hdrsize); d.fd = LOCAL->fd; /* set initial stringstruct */ d.pos = hdrpos + hdrsize; /* flush old buffer */ if (LOCAL->buf) fs_give ((void **) &LOCAL->buf); d.chunk = LOCAL->buf = (char *) fs_get ((size_t) d.chunksize = CHUNKSIZE); INIT (bs,fd_string,(void *) &d,elt->rfc822_size - hdrsize); return T; /* success */ } /* Berkeley mail ping mailbox * Accepts: MAIL stream * Returns: T if stream still alive, NIL if not */ long bezerk_ping (MAILSTREAM *stream) { /* punt if stream no longer alive */ if (!(stream && LOCAL)) return NIL; /* parse mailbox, punt if parse dies */ return (bezerk_parse (stream)) ? T : NIL; } /* Berkeley mail check mailbox (reparses status too) * Accepts: MAIL stream */ void bezerk_check (MAILSTREAM *stream) { unsigned long i = 1; if (bezerk_ping (stream)) { /* ping mailbox */ /* get new message status */ while (i <= stream->nmsgs) mail_elt (stream,i++); mm_log ("Check completed",(long) NIL); } } /* Berkeley mail expunge mailbox * Accepts: MAIL stream * sequence to expunge if non-NIL * expunge options * Returns: T, always */ long bezerk_expunge (MAILSTREAM *stream,char *sequence,long options) { if (!stream->silent) mm_log ("Expunge ignored on readonly mailbox",WARN); return LONGT; } /* Berkeley mail copy message(s) * Accepts: MAIL stream * sequence * destination mailbox * copy options * Returns: T if success, NIL if failed */ long bezerk_copy (MAILSTREAM *stream,char *sequence,char *mailbox,long options) { char tmp[MAILTMPLEN]; struct stat sbuf; MESSAGECACHE *elt; unsigned long i,j,k; int fd; mailproxycopy_t pc = (mailproxycopy_t) mail_parameters (stream,GET_MAILPROXYCOPY,NIL); if (!((options & CP_UID) ? mail_uid_sequence (stream,sequence) : mail_sequence (stream,sequence))) return NIL; /* make sure valid mailbox */ if (!bezerk_isvalid (mailbox,tmp) && errno) { if (errno == ENOENT) mm_notify (stream,"[TRYCREATE] Must create mailbox before append", (long) NIL); else if (pc) return (*pc) (stream,sequence,mailbox,options); else if (mailboxfile (tmp,mailbox)) { sprintf (tmp,"Not a Bezerk-format mailbox: %s",mailbox); mm_log (tmp,ERROR); } else bezerk_badname (tmp,mailbox); return NIL; } /* open the destination */ if (!mailboxfile (tmp,mailbox) || (fd = open (tmp,O_BINARY|O_WRONLY|O_APPEND|O_CREAT, S_IREAD|S_IWRITE)) < 0) { sprintf (tmp,"Unable to open copy mailbox: %s",strerror (errno)); mm_log (tmp,ERROR); return NIL; } mm_critical (stream); /* go critical */ fstat (fd,&sbuf); /* get current file size */ /* for each requested message */ for (i = 1; i <= stream->nmsgs; i++) if ((elt = mail_elt (stream,i))->sequence) { lseek (LOCAL->fd,elt->private.special.offset,SEEK_SET); /* number of bytes to copy */ j = elt->private.msg.full.offset + elt->rfc822_size; do { /* read from source position */ k = min (j,(unsigned long) MAILTMPLEN); read (LOCAL->fd,tmp,(unsigned int) k); if (write (fd,tmp,(unsigned int) k) < 0) { sprintf (tmp,"Unable to write message: %s",strerror (errno)); mm_log (tmp,ERROR); chsize (fd,sbuf.st_size); close (fd); /* punt */ mm_nocritical (stream); return NIL; } } while (j -= k); /* until done */ } close (fd); /* close the file */ mm_nocritical (stream); /* release critical */ /* delete all requested messages */ if (options & CP_MOVE) for (i = 1; i <= stream->nmsgs; i++) if ((elt = mail_elt (stream,i))->sequence) elt->deleted = T; if (mail_parameters (NIL,GET_COPYUID,NIL)) mm_log ("Can not return meaningful COPYUID with this mailbox format",WARN); return T; } /* Berkeley mail append message from stringstruct * Accepts: MAIL stream * destination mailbox * append callback * data for callback * Returns: T if append successful, else NIL */ #define BUFLEN MAILTMPLEN long bezerk_append (MAILSTREAM *stream,char *mailbox,append_t af,void *data) { struct stat sbuf; int fd; unsigned long i,j; char *flags,*date,buf[BUFLEN],tmp[MAILTMPLEN],file[MAILTMPLEN]; FILE *sf,*df; MESSAGECACHE elt; STRING *message; long ret = LONGT; /* default stream to prototype */ if (!stream) stream = &bezerkproto; /* make sure valid mailbox */ if (!bezerk_isvalid (mailbox,tmp) && errno) { if (errno == ENOENT) { if (((mailbox[0] == 'I') || (mailbox[0] == 'i')) && ((mailbox[1] == 'N') || (mailbox[1] == 'n')) && ((mailbox[2] == 'B') || (mailbox[2] == 'b')) && ((mailbox[3] == 'O') || (mailbox[3] == 'o')) && ((mailbox[4] == 'X') || (mailbox[4] == 'x')) && !mailbox[5]) bezerk_create (NIL,"INBOX"); else { mm_notify (stream,"[TRYCREATE] Must create mailbox before append",NIL); return NIL; } } else if (mailboxfile (tmp,mailbox)) { sprintf (tmp,"Not a Bezerk-format mailbox: %.80ss",mailbox); mm_log (tmp,ERROR); } else bezerk_badname (tmp,mailbox); return NIL; } tzset (); /* initialize timezone stuff */ /* get first message */ if (!(*af) (stream,data,&flags,&date,&message)) return NIL; if (!(sf = tmpfile ())) { /* must have scratch file */ sprintf (tmp,"Unable to create scratch file: %.80s",strerror (errno)); mm_log (tmp,ERROR); } do { /* parse date */ if (!date) rfc822_date (date = tmp); if (!mail_parse_date (&elt,date)) { sprintf (tmp,"Bad date in append: %.80s",date); mm_log (tmp,ERROR); } else { /* user wants to suppress time zones? */ if (mail_parameters (NIL,GET_NOTIMEZONES,NIL)) { time_t when = mail_longdate (&elt); date = ctime (&when); /* use traditional date */ } /* use POSIX-style date */ else date = mail_cdate (tmp,&elt); if (!SIZE (message)) mm_log ("Append of zero-length message",ERROR); else if (!bezerk_append_msg (stream,sf,flags,date,message)) { sprintf (tmp,"Error writing scratch file: %.80s",strerror (errno)); mm_log (tmp,ERROR); } /* get next message */ else if ((*af) (stream,data,&flags,&date,&message)) continue; } fclose (sf); /* punt scratch file */ return NIL; /* give up */ } while (message); /* until no more messages */ if (fflush (sf) || fstat (fileno (sf),&sbuf)) { sprintf (tmp,"Error finishing scratch file: %.80s",strerror (errno)); mm_log (tmp,ERROR); fclose (sf); /* punt scratch file */ return NIL; /* give up */ } i = sbuf.st_size; /* size of scratch file */ mm_critical (stream); /* go critical */ /* open the destination */ if (!mailboxfile (tmp,mailbox) || ((fd = open (tmp,O_BINARY|O_WRONLY|O_APPEND|O_CREAT, S_IREAD|S_IWRITE)) < 0) || !(df = fdopen (fd,"ab"))) { mm_nocritical (stream); /* done with critical */ sprintf (tmp,"Can't open append mailbox: %s",strerror (errno)); mm_log (tmp,ERROR); return NIL; } fstat (fd,&sbuf); /* get current file size */ while (i) /* until written all bytes */ if ((j = fread (buf,1,min ((long) BUFLEN,i),sf)) && (fwrite (buf,1,j,df) == j)) i -= j; fclose (sf); /* done with scratch file */ /* make sure append wins */ if (i || (fflush (df) == EOF)) { chsize (fd,sbuf.st_size); /* revert file */ close (fd); /* make sure fclose() doesn't corrupt us */ sprintf (buf,"Message append failed: %s",strerror (errno)); mm_log (buf,ERROR); ret = NIL; /* return error */ } fclose (df); mm_nocritical (stream); /* release critical */ if (ret && mail_parameters (NIL,GET_APPENDUID,NIL)) mm_log ("Can not return meaningful APPENDUID with this mailbox format", WARN); return ret; } /* Write single message to append scratch file * Accepts: MAIL stream * scratch file * flags * message stringstruct * Returns: NIL if write error, else T */ int bezerk_append_msg (MAILSTREAM *stream,FILE *sf,char *flags,char *date, STRING *msg) { int c; unsigned long i,uf; char tmp[MAILTMPLEN]; long f = mail_parse_flags (stream,flags,&uf); /* build initial header */ if ((fprintf (sf,"From %s@%s %sStatus: ", myusername (),mylocalhost (),date) < 0) || (f&fSEEN && (putc ('R',sf) == EOF)) || (fputs ("\nX-Status: ",sf) == EOF) || (f&fDELETED && (putc ('D',sf) == EOF)) || (f&fFLAGGED && (putc ('F',sf) == EOF)) || (f&fANSWERED && (putc ('A',sf) == EOF)) || (f&fDRAFT && (putc ('T',sf) == EOF)) || (fputs ("\nX-Keywords:",sf) == EOF)) return NIL; while (uf) /* write user flags */ if (fprintf (sf," %s",stream->user_flags[find_rightmost_bit (&uf)]) < 0) return NIL; /* tie off flags */ if (putc ('\n',sf) == EOF) return NIL; while (SIZE (msg)) { /* copy text to scratch file */ /* possible delimiter if line starts with F */ if ((c = 0xff & SNX (msg)) == 'F') { /* copy line to buffer */ for (i = 1,tmp[0] = c; SIZE (msg) && (c != '\n') && (i < MAILTMPLEN);) if (((c = 0xff & SNX (msg)) != '\r') || !(SIZE (msg)) || (CHR (msg) != '\n')) tmp[i++] = c; if ((i > 4) && (tmp[1] == 'r') && (tmp[2] == 'o') && (tmp[3] == 'm') && (tmp[4] == ' ')) { /* possible "From " line? */ /* yes, see if need to write a widget */ if (((c != '\n') || bezerk_valid_line (tmp,NIL,NIL)) && (putc ('>',sf) == EOF)) return NIL; } /* write buffered text */ if (fwrite (tmp,1,i,sf) != i) return NIL; if (c == '\n') continue; /* all done if got a complete line */ } /* copy line, toss out CR from CRLF */ do if (((c == '\r') && SIZE (msg) && ((c = 0xff & SNX (msg)) != '\n') && (putc ('\r',sf) == EOF)) || (putc (c,sf) == EOF)) return NIL; while ((c != '\n') && SIZE (msg) && ((c = 0xff & SNX (msg)) ? c : T)); } /* write trailing newline and return */ return (putc ('\n',sf) == EOF) ? NIL : T; } /* Return bad file name error message * Accepts: temporary buffer * file name * Returns: long NIL always */ long bezerk_badname (char *tmp,char *s) { sprintf (tmp,"Invalid mailbox name: %s",s); mm_log (tmp,ERROR); return (long) NIL; } /* Parse mailbox * Accepts: MAIL stream * Returns: T if parse OK * NIL if failure, stream aborted */ long bezerk_parse (MAILSTREAM *stream) { struct stat sbuf; MESSAGECACHE *elt; char *s,*t,tmp[MAILTMPLEN + 1],*db,datemsg[100]; long i; int j,ti,zn; long curpos = LOCAL->filesize; long nmsgs = stream->nmsgs; long recent = stream->recent; short silent = stream->silent; fstat (LOCAL->fd,&sbuf); /* get status */ if (sbuf.st_size < curpos) { /* sanity check */ sprintf (tmp,"Mailbox shrank from %ld to %ld!",curpos,sbuf.st_size); mm_log (tmp,ERROR); bezerk_close (stream,NIL); return NIL; } stream->silent = T; /* don't pass up mm_exists() events yet */ db = datemsg + strlen (strcpy (datemsg,"Unparsable date: ")); /* while there is data to read */ while (i = sbuf.st_size - curpos){ /* get to that position in the file */ lseek (LOCAL->fd,curpos,SEEK_SET); /* read first buffer's worth */ read (LOCAL->fd,tmp,j = (int) min (i,(long) MAILTMPLEN)); tmp[j] = '\0'; /* tie off buffer */ if (!(ti = bezerk_valid_line (tmp,&t,&zn))) { mm_log ("Mailbox format invalidated (consult an expert), aborted",ERROR); bezerk_close (stream,NIL); return NIL; } /* swell the cache */ mail_exists (stream,++nmsgs); /* instantiate an elt for this message */ (elt = mail_elt (stream,nmsgs))->valid = T; elt->private.uid = ++stream->uid_last; /* note file offset of header */ elt->private.special.offset = curpos; /* note offset of message */ elt->private.msg.full.offset = (s = ((*t == '\015') ? (t + 2) : (t + 1))) - tmp; /* generate plausable IMAPish date string */ db[2] = db[6] = db[20] = '-'; db[11] = ' '; db[14] = db[17] = ':'; /* dd */ db[0] = t[ti - 2]; db[1] = t[ti - 1]; /* mmm */ db[3] = t[ti - 6]; db[4] = t[ti - 5]; db[5] = t[ti - 4]; /* hh */ db[12] = t[ti + 1]; db[13] = t[ti + 2]; /* mm */ db[15] = t[ti + 4]; db[16] = t[ti + 5]; if (t[ti += 6] == ':') { /* ss if present */ db[18] = t[++ti]; db[19] = t[++ti]; ti++; /* move to space */ } else db[18] = db[19] = '0'; /* assume 0 seconds */ /* yy -- advance over timezone if necessary */ if (++zn == ++ti) ti += (((t[zn] == '+') || (t[zn] == '-')) ? 6 : 4); db[7] = t[ti]; db[8] = t[ti + 1]; db[9] = t[ti + 2]; db[10] = t[ti + 3]; t = zn ? (t + zn) : "LCL"; /* zzz */ db[21] = *t++; db[22] = *t++; db[23] = *t++; if ((db[21] != '+') && (db[21] != '-')) db[24] = '\0'; else { /* numeric time zone */ db[20] = ' '; db[24] = *t++; db[25] = *t++; db[26] = '\0'; } /* set internal date */ if (!mail_parse_date (elt,db)) mm_log (datemsg,WARN); curpos += s - tmp; /* advance position after header */ t = strchr (s,'\012'); /* start of next line */ /* find start of next message */ while (!(bezerk_valid_line (s,NIL,NIL))) { if (t) { /* have next line? */ t++; /* advance to new line */ curpos += t - s; /* update position and size */ elt->rfc822_size += ((t - s) + ((t[-2] == '\015') ? 0 : 1)); s = t; /* move to next line */ t = strchr (s,'\012'); } else { /* try next buffer */ j = strlen (s); /* length of unread data in buffer */ if ((i = sbuf.st_size - curpos) && (i != j)) { /* get to that position in the file */ lseek (LOCAL->fd,curpos,SEEK_SET); /* read another buffer's worth */ read (LOCAL->fd,s = tmp,j = (int) min (i,(long) MAILTMPLEN)); tmp[j] = '\0'; /* tie off buffer */ if (!(t = strchr (s,'\012'))) fatal ("Line too long in mailbox"); } else { curpos += j; /* last bit of data */ elt->rfc822_size += j; break; } } } } /* update parsed file size */ LOCAL->filesize = sbuf.st_size; stream->silent = silent; /* can pass up events now */ mail_exists (stream,nmsgs); /* notify upper level of new mailbox size */ mail_recent (stream,recent); /* and of change in recent messages */ return T; /* return the winnage */ } /* Berkeley locate header for a message * Accepts: MAIL stream * message number * pointer to returned header size * Returns: position of header in file */ unsigned long bezerk_hdrpos (MAILSTREAM *stream,unsigned long msgno, unsigned long *size) { long siz; size_t i = 0; char c = '\0'; char *s; char tmp[MAILTMPLEN]; MESSAGECACHE *elt = mail_elt (stream,msgno); long pos = elt->private.special.offset + elt->private.msg.full.offset; /* is size known? */ if (!(*size = elt->private.msg.header.text.size)) { /* get to header position */ lseek (LOCAL->fd,pos,SEEK_SET); /* search message for CRLF CRLF */ for (siz = 1; siz <= elt->rfc822_size; siz++) { if (!i && /* buffer empty? */ (read (LOCAL->fd,s = tmp, i = (size_t) min(elt->rfc822_size-siz,(long)MAILTMPLEN))<= 0)) return pos; else i--; /* two newline sequence? */ if ((c == '\012') && (*s == '\012')) { /* yes, note for later */ elt->private.msg.header.text.size = (*size = siz); return pos; /* return to caller */ } else if ((c == '\012') && (*s == '\015')) { /* yes, note for later */ elt->private.msg.header.text.size = (*size = siz + 1); return pos; /* return to caller */ } else c = *s++; /* next character */ } } return pos; /* have position */ } alpine-2.10+dfsg/imap/src/osdep/dos/mtestdnf.bat0000600000175000017500000000156011512502124023266 0ustar paulproteuspaulproteus@ECHO OFF REM ======================================================================== REM Copyright 1988-2006 University of Washington REM REM Licensed under the Apache License, Version 2.0 (the "License"); REM you may not use this file except in compliance with the License. REM You may obtain a copy of the License at REM REM http://www.apache.org/licenses/LICENSE-2.0 REM REM REM ======================================================================== REM Program: Portable C client makefile -- MS-DOS PC-NFS link REM REM Author: Mark Crispin REM Networks and Distributed Computing REM Computing & Communications REM University of Washington REM Administration Building, AG-44 REM Seattle, WA 98195 REM Internet: MRC@CAC.Washington.EDU REM REM Date: 26 June 1994 REM Last Edited:30 August 2006 link /NOI /stack:32767 mtest.obj,mtest.exe,,cclient.lib ltklib.lib alpine-2.10+dfsg/imap/src/osdep/dos/makefile0000600000175000017500000000544411512502124022457 0ustar paulproteuspaulproteus# ======================================================================== # Copyright 1988-2007 University of Washington # # Licensed under the Apache License, Version 2.0 (the "License"); # you may not use this file except in compliance with the License. # You may obtain a copy of the License at # # http://www.apache.org/licenses/LICENSE-2.0 # # # ======================================================================== # Program: Portable C client makefile -- MS-DOS version # # Author: Mark Crispin # Networks and Distributed Computing # Computing & Communications # University of Washington # Administration Building, AG-44 # Seattle, WA 98195 # Internet: MRC@CAC.Washington.EDU # # Date: 11 May 1989 # Last Edited: 23 May 2007 OS = wsk EXTRAAUTHENTICATORS= DEFAULTAUTHENTICATORS= ext md5 pla log EXTRADRIVERS = DRIVERS = imap nntp pop3 mtx bezerk DEFAULTDRIVER = mtx CFLAGS= -AL /DCHUNKSIZE=4096 -nologo $(EXTRACFLAGS) CC = cl all: mtest.exe .c.obj: $(CC) -c $(CFLAGS) $*.c osdep.h: os_$(OS).h copy os_$(OS).h osdep.h drivers $(EXTRADRIVERS) $(DRIVERS) dummy mkauths $(EXTRAAUTHENTICATORS) $(DEFAULTAUTHENTICATORS) ECHO #define DEFAULTPROTO $(DEFAULTDRIVER)proto >> LINKAGE.H ECHO if (!mail_parameters (NIL,GET_GETS)) >> LINKAGE.C ECHO mail_parameters (NIL,SET_GETS,(void *) dos_default_gets); >> LINKAGE.C ECHO mail_versioncheck (CCLIENTVERSION); >> LINKAGE.C mtest.obj: mail.h smtp.h misc.h osdep.h mtest.c mail.obj: mail.h misc.h osdep.h mail.c misc.obj: mail.h misc.h misc.c fdstring.obj: mail.h misc.h osdep.h fdstring.h fdstring.c flstring.obj: mail.h misc.h osdep.h flstring.h flstring.c netmsg.obj: mail.h misc.h netmsg.h osdep.h netmsg.c newsrc.obj: mail.h misc.h newsrc.h osdep.h newsrc.c rfc822.obj: mail.h rfc822.h misc.h rfc822.c smanager.obj: mail.h misc.h smanager.c utf8.obj: mail.h misc.h osdep.h utf8.h utf8aux.obj: mail.h misc.h osdep.h utf8.h imap4r1.obj: mail.h imap4r1.h misc.h osdep.h imap4r1.c nntp.obj: mail.h nntp.h smtp.h rfc822.h misc.h osdep.h nntp.c pop3.obj: mail.h rfc822.h misc.h osdep.h pop3.c smtp.obj: mail.h smtp.h rfc822.h misc.h osdep.h smtp.c os_$(OS).obj: mail.h osdep.h env_dos.h fs.h ftl.h nl.h tcp.h \ os_$(OS).c fs_dos.c ftl_dos.c nl_dos.c env_dos.c pmatch.c write.c mtxdos.obj: mail.h misc.h osdep.h mtxdos.c bezrkdos.obj: mail.h misc.h osdep.h bezrkdos.c dummydos.obj: mail.h dummy.h misc.h osdep.h dummydos.c cclient.lib: mail.obj misc.obj fdstring.obj flstring.obj netmsg.obj \ newsrc.obj rfc822.obj smanager.obj utf8.obj utf8aux.obj \ imap4r1.obj nntp.obj pop3.obj smtp.obj os_$(OS).obj \ mtxdos.obj bezrkdos.obj dummydos.obj erase cclient.lib lib cclient +mail+misc+fdstring+flstring+netmsg+newsrc+rfc822+smanager+utf8+utf8aux+imap4r1+nntp+pop3+smtp+os_$(OS)+mtxdos+bezrkdos+dummydos; mtest.exe: cclient.lib mtest.obj mtest$(OS) alpine-2.10+dfsg/imap/src/osdep/dos/os_dwa.h0000600000175000017500000000202511512502124022374 0ustar paulproteuspaulproteus/* ======================================================================== * Copyright 1988-2006 University of Washington * * Licensed under the Apache License, Version 2.0 (the "License"); * you may not use this file except in compliance with the License. * You may obtain a copy of the License at * * http://www.apache.org/licenses/LICENSE-2.0 * * * ======================================================================== */ /* * Program: Operating-system dependent routines -- DOS (Waterloo) version * * Author: Mark Crispin * Networks and Distributed Computing * Computing & Communications * University of Washington * Administration Building, AG-44 * Seattle, WA 98195 * Internet: MRC@CAC.Washington.EDU * * Date: 11 May 1989 * Last Edited: 30 August 2006 */ #define INADEQUATE_MEMORY #include #include #include #include #include #define tcp_open TCP_open #include "env_dos.h" #include "fs.h" #include "ftl.h" #include "nl.h" #include "tcp.h" alpine-2.10+dfsg/imap/src/osdep/dos/mtestdbw.bat0000600000175000017500000000157111512502124023275 0ustar paulproteuspaulproteus@ECHO OFF REM ======================================================================== REM Copyright 1988-2006 University of Washington REM REM Licensed under the Apache License, Version 2.0 (the "License"); REM you may not use this file except in compliance with the License. REM You may obtain a copy of the License at REM REM http://www.apache.org/licenses/LICENSE-2.0 REM REM REM ======================================================================== REM Program: Portable C client makefile -- MS-DOS B&W link REM REM Author: Mark Crispin REM Networks and Distributed Computing REM Computing & Communications REM University of Washington REM Administration Building, AG-44 REM Seattle, WA 98195 REM Internet: MRC@CAC.Washington.EDU REM REM Date: 26 June 1994 REM Last Edited:30 August 2006 link /NOI /stack:32767 mtest.obj,mtest.exe,,cclient.lib llbwtcp.lib llibce.lib alpine-2.10+dfsg/imap/src/osdep/dos/write.c0000600000175000017500000000336711512502124022257 0ustar paulproteuspaulproteus/* ======================================================================== * Copyright 1988-2006 University of Washington * * Licensed under the Apache License, Version 2.0 (the "License"); * you may not use this file except in compliance with the License. * You may obtain a copy of the License at * * http://www.apache.org/licenses/LICENSE-2.0 * * * ======================================================================== */ /* * Program: Write data, treating partial writes as an error * * Author: Mark Crispin * Networks and Distributed Computing * Computing & Communications * University of Washington * Administration Building, AG-44 * Seattle, WA 98195 * Internet: MRC@CAC.Washington.EDU * * Date: 26 May 1995 * Last Edited: 30 August 2006 */ /* The whole purpose of this unfortunate routine is to deal with DOS and * certain cretinous versions of UNIX which decided that the "bytes actually * written" return value from write() gave them license to use that for things * that are really errors, such as disk quota exceeded, maximum file size * exceeded, disk full, etc. * * BSD won't screw us this way on the local filesystem, but who knows what * some NFS-mounted filesystem will do. */ #undef write /* Write data to file * Accepts: file descriptor * I/O vector structure * number of vectors in structure * Returns: number of bytes written if successful, -1 if failure */ long maxposint = (long)((((unsigned long) 1) << ((sizeof(int) * 8) - 1)) - 1); long safe_write (int fd,char *buf,long nbytes) { long i,j; if (nbytes > 0) for (i = nbytes; i; i -= j,buf += j) { while (((j = write (fd,buf,(int) min (maxposint,i))) < 0) && (errno == EINTR)); if (j < 0) return j; } return nbytes; } alpine-2.10+dfsg/imap/src/osdep/dos/os_dwa.c0000600000175000017500000000336711512502124022401 0ustar paulproteuspaulproteus/* ======================================================================== * Copyright 1988-2006 University of Washington * * Licensed under the Apache License, Version 2.0 (the "License"); * you may not use this file except in compliance with the License. * You may obtain a copy of the License at * * http://www.apache.org/licenses/LICENSE-2.0 * * * ======================================================================== */ /* * Program: Operating-system dependent routines -- DOS (Waterloo) version * * Author: Mark Crispin * Networks and Distributed Computing * Computing & Communications * University of Washington * Administration Building, AG-44 * Seattle, WA 98195 * Internet: MRC@CAC.Washington.EDU * * Date: 11 April 1989 * Last Edited: 30 August 2006 */ #include /* must be before TCPSTREAM definition */ #include "tcp_dwa.h" /* must be before osdep include our tcp.h */ #include "mail.h" #include "osdep.h" #include #include #include #include #include #include "misc.h" /* Undo compatibility definition */ #undef tcp_open #include "fs_dos.c" #include "ftl_dos.c" #include "nl_dos.c" #include "env_dos.c" #include "tcp_dwa.c" /* Return my local host name * Returns: my local host name */ char *mylocalhost (void) { if (!myLocalHost) { char *s,hname[32],tmp[MAILTMPLEN]; long myip; if (!sock_initted++) sock_init(); tcp_cbrk (0x01); /* turn off ctrl-break catching */ /* * haven't discovered a way to find out the local host's * name with wattcp yet. */ if (myip = gethostid ()) sprintf (s = tmp,"[%s]",inet_ntoa (hname,myip)); else s = "random-pc"; myLocalHost = cpystr (s); } return myLocalHost; } alpine-2.10+dfsg/imap/src/osdep/dos/mtxdos.c0000600000175000017500000006470211512502124022443 0ustar paulproteuspaulproteus/* ======================================================================== * Copyright 1988-2006 University of Washington * * Licensed under the Apache License, Version 2.0 (the "License"); * you may not use this file except in compliance with the License. * You may obtain a copy of the License at * * http://www.apache.org/licenses/LICENSE-2.0 * * * ======================================================================== */ /* * Program: MTX mail routines * * Author: Mark Crispin * Networks and Distributed Computing * Computing & Communications * University of Washington * Administration Building, AG-44 * Seattle, WA 98195 * Internet: MRC@CAC.Washington.EDU * * Date: 24 June 1992 * Last Edited: 30 August 2006 */ #include #include #include #include "mail.h" #include "osdep.h" #include #include #include #include "rfc822.h" #include "dummy.h" #include "misc.h" #include "fdstring.h" /* MTX I/O stream local data */ typedef struct mtx_local { int fd; /* file descriptor for I/O */ off_t filesize; /* file size parsed */ unsigned char *buf; /* temporary buffer */ } MTXLOCAL; /* Drive-dependent data passed to init method */ typedef struct mtx_data { int fd; /* file data */ unsigned long pos; /* initial position */ } MTXDATA; /* Convenient access to local data */ #define LOCAL ((MTXLOCAL *) stream->local) /* Function prototypes */ DRIVER *mtx_valid (char *name); long mtx_isvalid (char *name,char *tmp); void *mtx_parameters (long function,void *value); void mtx_scan (MAILSTREAM *stream,char *ref,char *pat,char *contents); void mtx_list (MAILSTREAM *stream,char *ref,char *pat); void mtx_lsub (MAILSTREAM *stream,char *ref,char *pat); long mtx_create (MAILSTREAM *stream,char *mailbox); long mtx_delete (MAILSTREAM *stream,char *mailbox); long mtx_rename (MAILSTREAM *stream,char *old,char *newname); MAILSTREAM *mtx_open (MAILSTREAM *stream); void mtx_close (MAILSTREAM *stream,long options); char *mtx_header (MAILSTREAM *stream,unsigned long msgno, unsigned long *length,long flags); long mtx_text (MAILSTREAM *stream,unsigned long msgno,STRING *bs,long flags); void mtx_flagmsg (MAILSTREAM *stream,MESSAGECACHE *elt); long mtx_ping (MAILSTREAM *stream); void mtx_check (MAILSTREAM *stream); long mtx_expunge (MAILSTREAM *stream,char *sequence,long options); long mtx_copy (MAILSTREAM *stream,char *sequence,char *mailbox,long options); long mtx_append (MAILSTREAM *stream,char *mailbox,append_t af,void *data); char *mtx_file (char *dst,char *name); long mtx_badname (char *tmp,char *s); long mtx_parse (MAILSTREAM *stream); void mtx_update_status (MAILSTREAM *stream,unsigned long msgno); unsigned long mtx_hdrpos (MAILSTREAM *stream,unsigned long msgno, unsigned long *size); /* MTX mail routines */ /* Driver dispatch used by MAIL */ DRIVER mtxdriver = { "mtx", /* driver name */ /* driver flags */ DR_LOCAL|DR_MAIL|DR_LOWMEM|DR_CRLF|DR_NOSTICKY, (DRIVER *) NIL, /* next driver */ mtx_valid, /* mailbox is valid for us */ mtx_parameters, /* manipulate parameters */ mtx_scan, /* scan mailboxes */ mtx_list, /* list mailboxes */ mtx_lsub, /* list subscribed mailboxes */ NIL, /* subscribe to mailbox */ NIL, /* unsubscribe from mailbox */ mtx_create, /* create mailbox */ mtx_delete, /* delete mailbox */ mtx_rename, /* rename mailbox */ mail_status_default, /* status of mailbox */ mtx_open, /* open mailbox */ mtx_close, /* close mailbox */ NIL, /* fetch message "fast" attributes */ NIL, /* fetch message flags */ NIL, /* fetch overview */ NIL, /* fetch message envelopes */ mtx_header, /* fetch message header */ mtx_text, /* fetch message body */ NIL, /* fetch partial message text */ NIL, /* unique identifier */ NIL, /* message number */ NIL, /* modify flags */ mtx_flagmsg, /* per-message modify flags */ NIL, /* search for message based on criteria */ NIL, /* sort messages */ NIL, /* thread messages */ mtx_ping, /* ping mailbox to see if still alive */ mtx_check, /* check for new messages */ mtx_expunge, /* expunge deleted messages */ mtx_copy, /* copy messages to another mailbox */ mtx_append, /* append string message to mailbox */ NIL /* garbage collect stream */ }; /* prototype stream */ MAILSTREAM mtxproto = {&mtxdriver}; /* MTX mail validate mailbox * Accepts: mailbox name * Returns: our driver if name is valid, NIL otherwise */ DRIVER *mtx_valid (char *name) { char tmp[MAILTMPLEN]; return mtx_isvalid (name,tmp) ? &mtxdriver : (DRIVER *) NIL; } /* MTX mail test for valid mailbox * Accepts: mailbox name * Returns: T if valid, NIL otherwise */ long mtx_isvalid (char *name,char *tmp) { int fd; long ret = NIL; char *s; struct stat sbuf; errno = EINVAL; /* assume invalid argument */ /* if file, get its status */ if ((*name != '{') && mailboxfile (tmp,name) && !stat (tmp,&sbuf)) { if (!sbuf.st_size)errno = 0;/* empty file */ else if ((fd = open (tmp,O_BINARY|O_RDONLY,NIL)) >= 0) { memset (tmp,'\0',MAILTMPLEN); if ((read (fd,tmp,64) >= 0) && (s = strchr (tmp,'\015')) && (s[1] == '\012')) { /* valid format? */ *s = '\0'; /* tie off header */ /* must begin with dd-mmm-yy" */ ret = (((tmp[2] == '-' && tmp[6] == '-') || (tmp[1] == '-' && tmp[5] == '-')) && (s = strchr (tmp+18,',')) && strchr (s+2,';')) ? T : NIL; } else errno = -1; /* bogus format */ close (fd); /* close the file */ } } /* in case INBOX but not mtx format */ else if ((errno == ENOENT) && ((name[0] == 'I') || (name[0] == 'i')) && ((name[1] == 'N') || (name[1] == 'n')) && ((name[2] == 'B') || (name[2] == 'b')) && ((name[3] == 'O') || (name[3] == 'o')) && ((name[4] == 'X') || (name[4] == 'x')) && !name[5]) errno = -1; return ret; /* return what we should */ } /* MTX manipulate driver parameters * Accepts: function code * function-dependent value * Returns: function-dependent return value */ void *mtx_parameters (long function,void *value) { return NIL; } /* MTX mail scan mailboxes * Accepts: mail stream * reference * pattern to search * string to scan */ void mtx_scan (MAILSTREAM *stream,char *ref,char *pat,char *contents) { if (stream) dummy_scan (NIL,ref,pat,contents); } /* MTX mail list mailboxes * Accepts: mail stream * reference * pattern to search */ void mtx_list (MAILSTREAM *stream,char *ref,char *pat) { if (stream) dummy_list (stream,ref,pat); } /* MTX mail list subscribed mailboxes * Accepts: mail stream * reference * pattern to search */ void mtx_lsub (MAILSTREAM *stream,char *ref,char *pat) { if (stream) dummy_lsub (stream,ref,pat); } /* MTX mail create mailbox * Accepts: MAIL stream * mailbox name to create * Returns: T on success, NIL on failure */ long mtx_create (MAILSTREAM *stream,char *mailbox) { return dummy_create (stream,mailbox); } /* MTX mail delete mailbox * Accepts: MAIL stream * mailbox name to delete * Returns: T on success, NIL on failure */ long mtx_delete (MAILSTREAM *stream,char *mailbox) { return dummy_delete (stream,mailbox); } /* MTX mail rename mailbox * Accepts: MAIL stream * old mailbox name * new mailbox name (or NIL for delete) * Returns: T on success, NIL on failure */ long mtx_rename (MAILSTREAM *stream,char *old,char *newname) { return dummy_rename (stream,old,newname); } /* MTX mail open * Accepts: stream to open * Returns: stream on success, NIL on failure */ MAILSTREAM *mtx_open (MAILSTREAM *stream) { long i; int fd; char *s; char tmp[MAILTMPLEN]; /* return prototype for OP_PROTOTYPE call */ if (!stream) return &mtxproto; if (stream->local) fatal ("mtx recycle stream"); if (!mailboxfile (tmp,stream->mailbox)) return (MAILSTREAM *) mtx_badname (tmp,stream->mailbox); /* open, possibly creating INBOX */ if (((fd = open (tmp,O_BINARY|(stream->rdonly ? O_RDONLY:O_RDWR),NIL)) < 0)&& (compare_cstring (stream->mailbox,"INBOX") || ((fd = open (tmp,O_BINARY|O_RDWR|O_CREAT|O_EXCL,S_IREAD|S_IWRITE))<0))){ sprintf (tmp,"Can't open mailbox: %s",strerror (errno)); mm_log (tmp,ERROR); return NIL; } stream->local = fs_get (sizeof (MTXLOCAL)); /* canonicalize the stream mailbox name */ fs_give ((void **) &stream->mailbox); if (s = strchr ((s = strrchr (tmp,'\\')) ? s : tmp,'.')) *s = '\0'; stream->mailbox = cpystr (tmp); LOCAL->fd = fd; /* note the file */ LOCAL->filesize = 0; /* initialize parsed file size */ LOCAL->buf = NIL; /* initially no local buffer */ stream->sequence++; /* bump sequence number */ stream->uid_validity = time (0); /* parse mailbox */ stream->nmsgs = stream->recent = 0; if (!mtx_ping (stream)) return NIL; if (!stream->nmsgs) mm_log ("Mailbox is empty",(long) NIL); stream->perm_seen = stream->perm_deleted = stream->perm_flagged = stream->perm_answered = stream->perm_draft = stream->rdonly ? NIL : T; stream->perm_user_flags = stream->rdonly ? NIL : 0xffffffff; return stream; /* return stream to caller */ } /* MTX mail close * Accepts: MAIL stream * close options */ void mtx_close (MAILSTREAM *stream,long options) { if (stream && LOCAL) { /* only if a file is open */ int silent = stream->silent; stream->silent = T; if (options & CL_EXPUNGE) mtx_expunge (stream,NIL,NIL); close (LOCAL->fd); /* close the local file */ if (LOCAL->buf) fs_give ((void **) &LOCAL->buf); /* nuke the local data */ fs_give ((void **) &stream->local); stream->dtb = NIL; /* log out the DTB */ } } /* MTX mail fetch message header * Accepts: MAIL stream * message # to fetch * pointer to returned header text length * option flags * Returns: message header in RFC822 format */ char *mtx_header (MAILSTREAM *stream,unsigned long msgno,unsigned long *length, long flags) { *length = 0; /* default to empty */ if (flags & FT_UID) return "";/* UID call "impossible" */ /* get to header position */ lseek (LOCAL->fd,mtx_hdrpos (stream,msgno,length),L_SET); /* is buffer big enough? */ if (LOCAL->buf) fs_give ((void **) &LOCAL->buf); LOCAL->buf = (char *) fs_get ((size_t) *length + 1); LOCAL->buf[*length] = '\0'; /* tie off string */ /* slurp the data */ read (LOCAL->fd,LOCAL->buf,(size_t) *length); return LOCAL->buf; } /* MTX mail fetch message text (body only) * Accepts: MAIL stream * message # to fetch * pointer to returned header text length * option flags * Returns: T, always */ long mtx_text (MAILSTREAM *stream,unsigned long msgno,STRING *bs,long flags) { MESSAGECACHE *elt; FDDATA d; unsigned long hdrsize,hdrpos; /* UID call "impossible" */ if (flags & FT_UID) return NIL; elt = mail_elt (stream,msgno);/* if message not seen */ if (elt->seen && !(flags & FT_PEEK)) { elt->seen = T; /* mark message as seen */ /* recalculate status */ mtx_update_status (stream,msgno); mm_flags (stream,msgno); } /* get location of text data */ hdrpos = mtx_hdrpos (stream,msgno,&hdrsize); d.fd = LOCAL->fd; /* set initial stringstruct */ d.pos = hdrpos + hdrsize; /* flush old buffer */ if (LOCAL->buf) fs_give ((void **) &LOCAL->buf); d.chunk = LOCAL->buf = (char *) fs_get ((size_t) d.chunksize = CHUNKSIZE); INIT (bs,fd_string,(void *) &d,elt->rfc822_size - hdrsize); return T; /* success */ } /* MTX mail per-message modify flags * Accepts: MAIL stream * message cache element */ void mtx_flagmsg (MAILSTREAM *stream,MESSAGECACHE *elt) { /* recalculate status */ mtx_update_status (stream,elt->msgno); } /* MTX mail ping mailbox * Accepts: MAIL stream * Returns: T if stream still alive, NIL if not */ long mtx_ping (MAILSTREAM *stream) { /* punt if stream no longer alive */ if (!(stream && LOCAL)) return NIL; /* parse mailbox, punt if parse dies */ return (mtx_parse (stream)) ? T : NIL; } /* MTX mail check mailbox (reparses status too) * Accepts: MAIL stream */ void mtx_check (MAILSTREAM *stream) { unsigned long i = 1; if (mtx_ping (stream)) { /* ping mailbox */ /* get new message status */ while (i <= stream->nmsgs) mail_elt (stream,i++); mm_log ("Check completed",(long) NIL); } } /* MTX mail expunge mailbox * Accepts: MAIL stream * sequence to expunge if non-NIL * expunge options * Returns: T, always */ long mtx_expunge (MAILSTREAM *stream,char *sequence,long options) { long ret; unsigned long i = 1; unsigned long j,k,m,recent; unsigned long n = 0; unsigned long delta = 0; MESSAGECACHE *elt; char tmp[MAILTMPLEN]; if (!(ret = (sequence ? ((options & EX_UID) ? mail_uid_sequence (stream,sequence) : mail_sequence (stream,sequence)) : LONGT) && mtx_ping (stream))); /* parse sequence if given, ping stream */ else if (stream->rdonly) mm_log ("Expunge ignored on readonly mailbox",WARN); else { mm_critical (stream); /* go critical */ recent = stream->recent; /* get recent now that pinged */ while (i <= stream->nmsgs) {/* for each message */ elt = mail_elt (stream,i);/* get cache element */ /* number of bytes to smash or preserve */ k = elt->private.special.text.size + elt->rfc822_size; /* if need to expunge this message */ if (elt->deleted && (sequence ? elt->sequence : T)) { /* if recent, note one less recent message */ if (elt->recent) --recent; delta += k; /* number of bytes to delete */ /* notify upper levels */ mail_expunged (stream,i); n++; /* count up one more deleted message */ } else if (i++ && delta) { /* preserved message */ /* first byte to preserve */ j = elt->private.special.offset; do { /* read from source position */ m = min (k,(unsigned long) MAILTMPLEN); lseek (LOCAL->fd,j,SEEK_SET); read (LOCAL->fd,tmp,(size_t) m); /* write to destination position */ lseek (LOCAL->fd,j - delta,SEEK_SET); write (LOCAL->fd,tmp,(size_t) m); j += m; /* next chunk, perhaps */ } while (k -= m); /* until done */ elt->private.special.offset -= delta; } } if (n) { /* truncate file after last message */ chsize (LOCAL->fd,LOCAL->filesize -= delta); sprintf (tmp,"Expunged %ld messages",n); mm_log (tmp,(long) NIL); /* output the news */ } else mm_log ("No messages deleted, so no update needed",(long) NIL); mm_nocritical (stream); /* release critical */ /* notify upper level of new mailbox size */ mail_exists (stream,stream->nmsgs); mail_recent (stream,recent); } return ret; } /* MTX mail copy message(s) * Accepts: MAIL stream * sequence * destination mailbox * copy options * Returns: T if success, NIL if failed */ long mtx_copy (MAILSTREAM *stream,char *sequence,char *mailbox,long options) { char tmp[MAILTMPLEN]; struct stat sbuf; MESSAGECACHE *elt; unsigned long i,j,k; long ret = LONGT; int fd; mailproxycopy_t pc = (mailproxycopy_t) mail_parameters (stream,GET_MAILPROXYCOPY,NIL); if (!((options & CP_UID) ? mail_uid_sequence (stream,sequence) : mail_sequence (stream,sequence))) return NIL; if (!mtx_isvalid (mailbox,tmp)) switch (errno) { case ENOENT: /* no such file? */ mm_notify (stream,"[TRYCREATE] Must create mailbox before append", (long) NIL); return NIL; case 0: /* merely empty file? */ break; case EINVAL: /* name is bogus */ if (pc) return (*pc) (stream,sequence,mailbox,options); return mtx_badname (tmp,mailbox); default: /* file exists, but not valid format */ if (pc) return (*pc) (stream,sequence,mailbox,options); sprintf (tmp,"Not a MTX-format mailbox: %s",mailbox); mm_log (tmp,ERROR); return NIL; } /* open the destination */ if (!mailboxfile (tmp,mailbox) || (fd = open (tmp,O_BINARY|O_WRONLY|O_APPEND|O_CREAT, S_IREAD|S_IWRITE)) < 0) { sprintf (tmp,"Unable to open copy mailbox: %s",strerror (errno)); mm_log (tmp,ERROR); return NIL; } mm_critical (stream); /* go critical */ fstat (fd,&sbuf); /* get current file size */ /* for each requested message */ for (i = 1; ret && (i <= stream->nmsgs); i++) if ((elt = mail_elt (stream,i))->sequence) { lseek (LOCAL->fd,elt->private.special.offset,SEEK_SET); /* number of bytes to copy */ k = elt->private.special.text.size + elt->rfc822_size; do { /* read from source position */ j = min (k,(long) MAILTMPLEN); read (LOCAL->fd,tmp,(size_t) j); if (write (fd,tmp,(size_t) j) < 0) { sprintf (tmp,"Unable to write message: %s",strerror (errno)); mm_log (tmp,ERROR); chsize (fd,sbuf.st_size); j = k; ret = NIL; /* note error */ break; } } while (k -= j); /* until done */ } close (fd); /* close the file */ mm_nocritical (stream); /* release critical */ /* delete all requested messages */ if (ret && (options & CP_MOVE)) for (i = 1; i <= stream->nmsgs; i++) if ((elt = mail_elt (stream,i))->sequence) { elt->deleted = T; /* mark message deleted */ /* recalculate status */ mtx_update_status (stream,i); } if (ret && mail_parameters (NIL,GET_COPYUID,NIL)) mm_log ("Can not return meaningful COPYUID with this mailbox format",WARN); return ret; } /* MTX mail append message from stringstruct * Accepts: MAIL stream * destination mailbox * append callback * data for callback * Returns: T if append successful, else NIL */ long mtx_append (MAILSTREAM *stream,char *mailbox,append_t af,void *data) { struct stat sbuf; int fd,ld,c; char *flags,*date,tmp[MAILTMPLEN],file[MAILTMPLEN]; FILE *df; MESSAGECACHE elt; long f; unsigned long i,uf; STRING *message; long ret = LONGT; /* default stream to prototype */ if (!stream) stream = &mtxproto; /* make sure valid mailbox */ if (!mtx_isvalid (mailbox,tmp)) switch (errno) { case ENOENT: /* no such file? */ if (((mailbox[0] == 'I') || (mailbox[0] == 'i')) && ((mailbox[1] == 'N') || (mailbox[1] == 'n')) && ((mailbox[2] == 'B') || (mailbox[2] == 'b')) && ((mailbox[3] == 'O') || (mailbox[3] == 'o')) && ((mailbox[4] == 'X') || (mailbox[4] == 'x')) && !mailbox[5]) dummy_create (NIL,"INBOX.MTX"); else { mm_notify (stream,"[TRYCREATE] Must create mailbox before append",NIL); return NIL; } /* falls through */ case 0: /* merely empty file? */ break; case EINVAL: return mtx_badname (tmp,mailbox); default: sprintf (tmp,"Not a MTX-format mailbox: %.80s",mailbox); mm_log (tmp,ERROR); return NIL; } /* get first message */ if (!(*af) (stream,data,&flags,&date,&message)) return NIL; /* open destination mailbox */ if (!mailboxfile (file,mailbox) || ((fd = open (file,O_BINARY|O_WRONLY|O_APPEND|O_CREAT, S_IREAD|S_IWRITE)) < 0) || !(df = fdopen (fd,"ab"))) { sprintf (tmp,"Can't open append mailbox: %s",strerror (errno)); mm_log (tmp,ERROR); return NIL; } mm_critical (stream); /* go critical */ fstat (fd,&sbuf); /* get current file size */ errno = 0; do { /* parse flags */ if (!SIZE (message)) { /* guard against zero-length */ mm_log ("Append of zero-length message",ERROR); ret = NIL; break; } f = mail_parse_flags (stream,flags,&i); /* reverse bits (dontcha wish we had CIRC?) */ for (uf = 0; i; uf |= 1 << (29 - find_rightmost_bit (&i))); if (date) { /* parse date if given */ if (!mail_parse_date (&elt,date)) { sprintf (tmp,"Bad date in append: %.80s",date); mm_log (tmp,ERROR); ret = NIL; /* mark failure */ break; } mail_date (tmp,&elt); /* write preseved date */ } else internal_date (tmp); /* get current date in IMAP format */ /* write header */ if (fprintf (df,"%s,%lu;%010lo%02lo\015\012",tmp,i = SIZE (message),uf, (unsigned long) f) < 0) ret = NIL; else { /* write message */ if (i) do c = 0xff & SNX (message); while ((putc (c,df) != EOF) && --i); /* get next message */ if (i || !(*af) (stream,data,&flags,&date,&message)) ret = NIL; } } while (ret && message); /* revert file if failure */ if (!ret || (fflush (df) == EOF)) { chsize (fd,sbuf.st_size); /* revert file */ close (fd); /* make sure fclose() doesn't corrupt us */ if (errno) { sprintf (tmp,"Message append failed: %s",strerror (errno)); mm_log (tmp,ERROR); } ret = NIL; } fclose (df); /* close the file */ mm_nocritical (stream); /* release critical */ if (ret && mail_parameters (NIL,GET_APPENDUID,NIL)) mm_log ("Can not return meaningful APPENDUID with this mailbox format", WARN); return ret; } /* Return bad file name error message * Accepts: temporary buffer * file name * Returns: long NIL always */ long mtx_badname (char *tmp,char *s) { sprintf (tmp,"Invalid mailbox name: %s",s); mm_log (tmp,ERROR); return (long) NIL; } /* Parse mailbox * Accepts: MAIL stream * Returns: T if parse OK * NIL if failure, stream aborted */ long mtx_parse (MAILSTREAM *stream) { struct stat sbuf; MESSAGECACHE *elt = NIL; unsigned char *s,*t,*x,lbuf[65]; char tmp[MAILTMPLEN]; long i; long curpos = LOCAL->filesize; long nmsgs = stream->nmsgs; long recent = stream->recent; fstat (LOCAL->fd,&sbuf); /* get status */ if (sbuf.st_size < curpos) { /* sanity check */ sprintf (tmp,"Mailbox shrank from %ld to %ld!",curpos,sbuf.st_size); mm_log (tmp,ERROR); mtx_close (stream,NIL); return NIL; } /* while there is stuff to parse */ while (i = sbuf.st_size - curpos) { /* get to that position in the file */ lseek (LOCAL->fd,curpos,SEEK_SET); if ((i = read (LOCAL->fd,lbuf,64)) <= 0) { sprintf (tmp,"Unable to read internal header at %ld, size = %ld: %s", curpos,sbuf.st_size,i ? strerror (errno) : "no data read"); mm_log (tmp,ERROR); mtx_close (stream,NIL); return NIL; } lbuf[i] = '\0'; /* tie off buffer just in case */ if (!((s = strchr (lbuf,'\015')) && (s[1] == '\012'))) { sprintf (tmp,"Unable to find end of line at %ld in %ld bytes, text: %s", curpos,i,(char *) lbuf); mm_log (tmp,ERROR); mtx_close (stream,NIL); return NIL; } *s = '\0'; /* tie off header line */ i = (s + 2) - lbuf; /* note start of text offset */ if (!((s = strchr (lbuf,',')) && (t = strchr (s+1,';')))) { sprintf (tmp,"Unable to parse internal header at %ld: %s",curpos, (char *) lbuf); mm_log (tmp,ERROR); mtx_close (stream,NIL); return NIL; } *s++ = '\0'; *t++ = '\0'; /* tie off fields */ /* intantiate an elt for this message */ (elt = mail_elt (stream,++nmsgs))->valid = T; elt->private.uid = ++stream->uid_last; /* note file offset of header */ elt->private.special.offset = curpos; /* as well as offset from header of message */ elt->private.special.text.size = i; /* header size not known yet */ elt->private.msg.header.text.size = 0; /* parse the header components */ if (!(mail_parse_date (elt,lbuf) && (elt->rfc822_size = strtol (x = s,(char **) &s,10)) && (!(s && *s))&& isdigit (t[0]) && isdigit (t[1]) && isdigit (t[2]) && isdigit (t[3]) && isdigit (t[4]) && isdigit (t[5]) && isdigit (t[6]) && isdigit (t[7]) && isdigit (t[8]) && isdigit (t[9]) && isdigit (t[10]) && isdigit (t[11]) && !t[12])) { sprintf (tmp,"Unable to parse internal header elements at %ld: %s,%s;%s", curpos,(char *) lbuf,(char *) x,(char *) t); mtx_close (stream,NIL); return NIL; } /* update current position to next header */ curpos += i + elt->rfc822_size; /* calculate system flags */ if ((i = ((t[10]-'0') * 8) + t[11]-'0') & fSEEN) elt->seen = T; if (i & fDELETED) elt->deleted = T; if (i & fFLAGGED) elt->flagged = T; if (i & fANSWERED) elt->answered = T; if (i & fDRAFT) elt->draft = T; if (curpos > sbuf.st_size) { sprintf (tmp,"Last message (at %lu) runs past end of file (%lu > %lu)", elt->private.special.offset,curpos,sbuf.st_size); mm_log (tmp,ERROR); mtx_close (stream,NIL); return NIL; } } /* update parsed file size */ LOCAL->filesize = sbuf.st_size; mail_exists (stream,nmsgs); /* notify upper level of new mailbox size */ mail_recent (stream,recent); /* and of change in recent messages */ return T; /* return the winnage */ } /* Update status string * Accepts: MAIL stream * message number */ void mtx_update_status (MAILSTREAM *stream,unsigned long msgno) { char tmp[MAILTMPLEN]; MESSAGECACHE *elt = mail_elt (stream,msgno); unsigned long j,k = 0; /* not if readonly you don't */ if (stream->rdonly || !elt->valid) return; j = elt->user_flags; /* get user flags */ /* reverse bits (dontcha wish we had CIRC?) */ while (j) k |= 1 << 29 - find_rightmost_bit (&j); sprintf (tmp,"%010lo%02o",k, /* print new flag string */ fOLD + (fSEEN * elt->seen) + (fDELETED * elt->deleted) + (fFLAGGED * elt->flagged) + (fANSWERED * elt->answered) + (fDRAFT * elt->draft)); /* get to that place in the file */ lseek (LOCAL->fd,(off_t) elt->private.special.offset + elt->private.special.text.size - 14,SEEK_SET); write (LOCAL->fd,tmp,12); /* write new flags */ } /* MTX locate header for a message * Accepts: MAIL stream * message number * pointer to returned header size * Returns: position of header in file */ unsigned long mtx_hdrpos (MAILSTREAM *stream,unsigned long msgno, unsigned long *size) { unsigned long siz; size_t i = 0; int q = 0; char *s,tmp[MAILTMPLEN]; MESSAGECACHE *elt = mail_elt (stream,msgno); long pos = elt->private.special.offset + elt->private.special.text.size; /* is header size known? */ if (!(*size = elt->private.msg.header.text.size)) { /* get to header position */ lseek (LOCAL->fd,pos,SEEK_SET); /* search message for CRLF CRLF */ for (siz = 1; siz <= elt->rfc822_size; siz++) { if (!i && /* buffer empty? */ (read (LOCAL->fd,s = tmp, i = (size_t) min(elt->rfc822_size-siz,(long)MAILTMPLEN))<= 0)) return pos; else i--; switch (q) { /* sniff at buffer */ case 0: /* first character */ q = (*s++ == '\015') ? 1 : 0; break; case 1: /* second character */ q = (*s++ == '\012') ? 2 : 0; break; case 2: /* third character */ q = (*s++ == '\015') ? 3 : 0; break; case 3: /* fourth character */ if (*s++ == '\012') { /* have the sequence? */ /* yes, note for later */ elt->private.msg.header.text.size = (*size = siz); return pos; /* return to caller */ } q = 0; /* lost... */ break; } } } return pos; /* have position */ } alpine-2.10+dfsg/imap/src/osdep/dos/env_dos.h0000600000175000017500000000416711512502124022566 0ustar paulproteuspaulproteus/* ======================================================================== * Copyright 1988-2006 University of Washington * * Licensed under the Apache License, Version 2.0 (the "License"); * you may not use this file except in compliance with the License. * You may obtain a copy of the License at * * http://www.apache.org/licenses/LICENSE-2.0 * * * ======================================================================== */ /* * Program: DOS environment routines * * Author: Mark Crispin * Networks and Distributed Computing * Computing & Communications * University of Washington * Administration Building, AG-44 * Seattle, WA 98195 * Internet: MRC@CAC.Washington.EDU * * Date: 1 August 1988 * Last Edited: 30 August 2006 */ #define SUBSCRIPTIONFILE(t) sprintf (t,"%s/MAILBOX.LST",myhomedir ()) #define SUBSCRIPTIONTEMP(t) sprintf (t,"%s/MAILBOX.TMP",myhomedir ()) #define L_SET SEEK_SET /* Function prototypes */ #include "env.h" char *dos_default_gets (readfn_t f,void *stream,unsigned long size, GETS_DATA *md); long safe_write (int fd,char *buf,long nbytes); long random (); #if _MSC_VER < 700 #define getpid random #endif /* syslog() emulation */ #define LOG_MAIL (2<<3) /* mail system */ #define LOG_DAEMON (3<<3) /* system daemons */ #define LOG_AUTH (4<<3) /* security/authorization messages */ #define LOG_EMERG 0 /* system is unusable */ #define LOG_ALERT 1 /* action must be taken immediately */ #define LOG_CRIT 2 /* critical conditions */ #define LOG_ERR 3 /* error conditions */ #define LOG_WARNING 4 /* warning conditions */ #define LOG_NOTICE 5 /* normal but signification condition */ #define LOG_INFO 6 /* informational */ #define LOG_DEBUG 7 /* debug-level messages */ #define LOG_PID 0x01 /* log the pid with each message */ #define LOG_CONS 0x02 /* log on the console if errors in sending */ #define LOG_ODELAY 0x04 /* delay open until syslog() is called */ #define LOG_NDELAY 0x08 /* don't delay open */ #define LOG_NOWAIT 0x10 /* if forking to log on console, don't wait() */ void openlog (const char *ident,int logopt,int facility); void syslog (int priority,const char *message,...); alpine-2.10+dfsg/imap/src/osdep/dos/tcp_wsk.c0000600000175000017500000005656511512502124022607 0ustar paulproteuspaulproteus/* ======================================================================== * Copyright 1988-2008 University of Washington * * Licensed under the Apache License, Version 2.0 (the "License"); * you may not use this file except in compliance with the License. * You may obtain a copy of the License at * * http://www.apache.org/licenses/LICENSE-2.0 * * * ======================================================================== */ /* * Program: Winsock TCP/IP routines * * Author: Mark Crispin from Mike Seibel's Winsock code * Networks and Distributed Computing * Computing & Communications * University of Washington * Administration Building, AG-44 * Seattle, WA 98195 * Internet: MRC@CAC.Washington.EDU * * Date: 11 April 1989 * Last Edited: 13 January 2008 */ #define TCPMAXSEND 32768 /* Private functions */ int tcp_socket_open (struct sockaddr_in *sin,char *tmp,char *hst, unsigned long port); static char *tcp_getline_work (TCPSTREAM *stream,unsigned long *size, long *contd); long tcp_abort (TCPSTREAM *stream); long tcp_close_socket (SOCKET *sock); char *tcp_name (struct sockaddr_in *sin,long flag); char *tcp_name_valid (char *s); /* Private data */ int wsa_initted = 0; /* init ? */ static int wsa_sock_open = 0; /* keep track of open sockets */ static tcptimeout_t tmoh = NIL; /* TCP timeout handler routine */ static long ttmo_read = 0; /* TCP timeouts, in seconds */ static long ttmo_write = 0; static long allowreversedns = T;/* allow reverse DNS lookup */ static long tcpdebug = NIL; /* extra TCP debugging telemetry */ /* TCP/IP manipulate parameters * Accepts: function code * function-dependent value * Returns: function-dependent return value */ void *tcp_parameters (long function,void *value) { void *ret = NIL; switch ((int) function) { case SET_TIMEOUT: tmoh = (tcptimeout_t) value; case GET_TIMEOUT: ret = (void *) tmoh; break; case SET_READTIMEOUT: ttmo_read = (long) value; case GET_READTIMEOUT: ret = (void *) ttmo_read; break; case SET_WRITETIMEOUT: ttmo_write = (long) value; case GET_WRITETIMEOUT: ret = (void *) ttmo_write; break; case SET_ALLOWREVERSEDNS: allowreversedns = (long) value; case GET_ALLOWREVERSEDNS: ret = (void *) allowreversedns; break; case SET_TCPDEBUG: tcpdebug = (long) value; case GET_TCPDEBUG: ret = (void *) tcpdebug; break; } return ret; } /* TCP/IP open * Accepts: host name * contact service name * contact port number and optional silent flag * Returns: TCP/IP stream if success else NIL */ TCPSTREAM *tcp_open (char *host,char *service,unsigned long port) { TCPSTREAM *stream = NIL; int i; SOCKET sock = INVALID_SOCKET; int silent = (port & NET_SILENT) ? T : NIL; char *s; struct sockaddr_in sin; struct hostent *he; char hostname[MAILTMPLEN]; char tmp[MAILTMPLEN]; struct servent *sv = NIL; blocknotify_t bn = (blocknotify_t) mail_parameters (NIL,GET_BLOCKNOTIFY,NIL); if (!wsa_initted++) { /* init Windows Sockets */ WSADATA wsock; if (i = (int) WSAStartup (WSA_VERSION,&wsock)) { wsa_initted = 0; /* in case we try again */ sprintf (tmp,"Unable to start Windows Sockets (%d)",i); mm_log (tmp,ERROR); return NIL; } } port &= 0xffff; /* erase flags */ /* lookup service */ if (service && (sv = getservbyname (service,"tcp"))) port = ntohs (sin.sin_port = sv->s_port); /* copy port number in network format */ else sin.sin_port = htons ((u_short) port); /* The domain literal form is used (rather than simply the dotted decimal as with other Windows programs) because it has to be a valid "host name" in mailsystem terminology. */ sin.sin_family = AF_INET; /* family is always Internet */ /* look like domain literal? */ if (host[0] == '[' && host[(strlen (host))-1] == ']') { strcpy (tmp,host+1); /* yes, copy number part */ tmp[strlen (tmp)-1] = '\0'; if ((sin.sin_addr.s_addr = inet_addr (tmp)) == INADDR_NONE) { sprintf (tmp,"Bad format domain-literal: %.80s",host); mm_log (tmp,ERROR); return NIL; } else { sin.sin_family = AF_INET; /* family is always Internet */ strcpy (hostname,host); (*bn) (BLOCK_TCPOPEN,NIL); sock = tcp_socket_open (&sin,tmp,hostname,port); (*bn) (BLOCK_NONE,NIL); } } else { /* lookup host name */ if (tcpdebug) { sprintf (tmp,"DNS resolution %.80s",host); mm_log (tmp,TCPDEBUG); } (*bn) (BLOCK_DNSLOOKUP,NIL);/* look up name */ if (!(he = gethostbyname (lcase (strcpy (tmp,host))))) sprintf (tmp,"Host not found (#%d): %s",WSAGetLastError(),host); (*bn) (BLOCK_NONE,NIL); if (he) { /* DNS resolution won? */ if (tcpdebug) mm_log ("DNS resolution done",TCPDEBUG); /* copy address type */ sin.sin_family = he->h_addrtype; /* copy host name */ strcpy (hostname,he->h_name); wsa_sock_open++; /* prevent tcp_close_socket() from freeing in loop */ for (i = 0; (sock == INVALID_SOCKET) && (s = he->h_addr_list[i]); i++) { if (i && !silent) mm_log (tmp,WARN); memcpy (&sin.sin_addr,s,he->h_length); (*bn) (BLOCK_TCPOPEN,NIL); sock = tcp_socket_open (&sin,tmp,hostname,port); (*bn) (BLOCK_NONE,NIL); } wsa_sock_open--; /* undo protection */ } } if (sock == INVALID_SOCKET) { /* error? */ if (!silent) mm_log (tmp,ERROR); tcp_close_socket (&sock); /* do possible cleanup action */ } else { /* got a socket, create TCP/IP stream */ stream = (TCPSTREAM *) memset (fs_get (sizeof (TCPSTREAM)),0, sizeof (TCPSTREAM)); stream->port = port; /* port number */ /* init socket */ stream->tcpsi = stream->tcpso = sock; stream->ictr = 0; /* init input counter */ /* copy official host name */ stream->host = cpystr (hostname); if (tcpdebug) mm_log ("Stream open and ready for read",TCPDEBUG); } return stream; /* return success */ } /* Open a TCP socket * Accepts: Internet socket address block * scratch buffer * host name for error message * port number for error message * Returns: socket if success, else -1 with error string in scratch buffer */ int tcp_socket_open (struct sockaddr_in *sin,char *tmp,char *hst, unsigned long port) { int sock; char *s; sprintf (tmp,"Trying IP address [%s]",inet_ntoa (sin->sin_addr)); mm_log (tmp,NIL); /* get a TCP stream */ if ((sock = socket (sin->sin_family,SOCK_STREAM,0)) == INVALID_SOCKET) { sprintf (tmp,"Unable to create TCP socket (%d)",WSAGetLastError()); return -1; } wsa_sock_open++; /* count this socket as open */ /* open connection */ if (connect (sock,(struct sockaddr *) sin,sizeof (struct sockaddr_in)) == SOCKET_ERROR) { switch (WSAGetLastError ()){/* analyze error */ case WSAECONNREFUSED: s = "Refused"; break; case WSAENOBUFS: s = "Insufficient system resources"; break; case WSAETIMEDOUT: s = "Timed out"; break; case WSAEHOSTUNREACH: s = "Host unreachable"; break; default: s = "Unknown error"; break; } sprintf (tmp,"Can't connect to %.80s,%ld: %s (%d)",hst,port,s, WSAGetLastError ()); tcp_close_socket (&sock); /* flush socket */ sock = INVALID_SOCKET; } return sock; /* return the socket */ } /* TCP/IP authenticated open * Accepts: NETMBX specifier * service name * returned user name buffer * Returns: TCP/IP stream if success else NIL */ TCPSTREAM *tcp_aopen (NETMBX *mb,char *service,char *usrbuf) { return NIL; /* always NIL on Windows */ } /* TCP receive line * Accepts: TCP stream * Returns: text line string or NIL if failure */ char *tcp_getline (TCPSTREAM *stream) { unsigned long n,contd; char *ret = tcp_getline_work (stream,&n,&contd); if (ret && contd) { /* got a line needing continuation? */ STRINGLIST *stl = mail_newstringlist (); STRINGLIST *stc = stl; do { /* collect additional lines */ stc->text.data = (unsigned char *) ret; stc->text.size = n; stc = stc->next = mail_newstringlist (); ret = tcp_getline_work (stream,&n,&contd); } while (ret && contd); if (ret) { /* stash final part of line on list */ stc->text.data = (unsigned char *) ret; stc->text.size = n; /* determine how large a buffer we need */ for (n = 0, stc = stl; stc; stc = stc->next) n += stc->text.size; ret = fs_get (n + 1); /* copy parts into buffer */ for (n = 0, stc = stl; stc; n += stc->text.size, stc = stc->next) memcpy (ret + n,stc->text.data,stc->text.size); ret[n] = '\0'; } mail_free_stringlist (&stl);/* either way, done with list */ } return ret; } /* TCP receive line or partial line * Accepts: TCP stream * pointer to return size * pointer to return continuation flag * Returns: text line string, size and continuation flag, or NIL if failure */ static char *tcp_getline_work (TCPSTREAM *stream,unsigned long *size, long *contd) { unsigned long n; char *s,*ret,c,d; *contd = NIL; /* assume no continuation */ /* make sure have data */ if (!tcp_getdata (stream)) return NIL; for (s = stream->iptr, n = 0, c = '\0'; stream->ictr--; n++, c = d) { d = *stream->iptr++; /* slurp another character */ if ((c == '\015') && (d == '\012')) { ret = (char *) fs_get (n--); memcpy (ret,s,*size = n); /* copy into a free storage string */ ret[n] = '\0'; /* tie off string with null */ return ret; } } /* copy partial string from buffer */ memcpy ((ret = (char *) fs_get (n)),s,*size = n); /* get more data from the net */ if (!tcp_getdata (stream)) fs_give ((void **) &ret); /* special case of newline broken by buffer */ else if ((c == '\015') && (*stream->iptr == '\012')) { stream->iptr++; /* eat the line feed */ stream->ictr--; ret[*size = --n] = '\0'; /* tie off string with null */ } else *contd = LONGT; /* continuation needed */ return ret; } /* TCP/IP receive buffer * Accepts: TCP/IP stream * size in bytes * buffer to read into * Returns: T if success, NIL otherwise */ long tcp_getbuffer (TCPSTREAM *stream,unsigned long size,char *s) { unsigned long n; /* make sure socket still alive */ if (stream->tcpsi == INVALID_SOCKET) return NIL; /* can transfer bytes from buffer? */ if (n = min (size,stream->ictr)) { memcpy (s,stream->iptr,n); /* yes, slurp as much as we can from it */ s += n; /* update pointer */ stream->iptr +=n; size -= n; /* update # of bytes to do */ stream->ictr -=n; } if (size) { int i; fd_set fds; struct timeval tmo; time_t tc,t = time (0); blocknotify_t bn=(blocknotify_t) mail_parameters (NIL,GET_BLOCKNOTIFY,NIL); (*bn) (BLOCK_TCPREAD,NIL); while (size > 0) { /* until request satisfied */ time_t tl = time (0); if (tcpdebug) mm_log ("Reading TCP buffer",TCPDEBUG); FD_ZERO (&fds); /* initialize selection vector */ FD_SET (stream->tcpsi,&fds);/* set bit in selection vector */ tmo.tv_sec = ttmo_read; tmo.tv_usec = 0; /* block and read */ switch ((stream->tcpsi == stream->tcpso) ? select (stream->tcpsi+1,&fds,0,0, ttmo_read ? &tmo : (struct timeval *) 0) : 1) { case SOCKET_ERROR: /* error */ if (WSAGetLastError () != WSAEINTR) return tcp_abort (stream); break; case 0: /* timeout */ tc = time (0); if (tmoh && ((*tmoh) (tc - t,tc - tl))) break; return tcp_abort (stream); default: if (stream->tcpsi == stream->tcpso) while (((i = recv (stream->tcpsi,s,(int) min (maxposint,size),0)) == SOCKET_ERROR) && (WSAGetLastError () == WSAEINTR)); else while (((i = read (stream->tcpsi,s,(int) min (maxposint,size))) < 0) && (errno == EINTR)); switch (i) { case SOCKET_ERROR: /* error */ case 0: /* no data read */ return tcp_abort (stream); default: s += i; /* point at new place to write */ size -= i; /* reduce byte count */ if (tcpdebug) mm_log ("Successfully read TCP buffer",TCPDEBUG); } } } (*bn) (BLOCK_NONE,NIL); } *s = '\0'; /* tie off string */ return T; } /* TCP/IP receive data * Accepts: TCP/IP stream * Returns: T if success, NIL otherwise */ long tcp_getdata (TCPSTREAM *stream) { struct timeval tmo; int i; fd_set fds; time_t tc,t = time (0); blocknotify_t bn = (blocknotify_t) mail_parameters (NIL,GET_BLOCKNOTIFY,NIL); FD_ZERO (&fds); /* initialize selection vector */ if (stream->tcpsi == INVALID_SOCKET) return NIL; (*bn) (BLOCK_TCPREAD,NIL); tmo.tv_sec = ttmo_read; tmo.tv_usec = 0; while (stream->ictr < 1) { /* if nothing in the buffer */ time_t tl = time (0); if (tcpdebug) mm_log ("Reading TCP data",TCPDEBUG); FD_SET (stream->tcpsi,&fds);/* set bit in selection vector */ /* block and read */ switch ((stream->tcpsi == stream->tcpso) ? select (stream->tcpsi+1,&fds,0,0, ttmo_read ? &tmo : (struct timeval *) 0) : 1) { case SOCKET_ERROR: /* error */ if (WSAGetLastError () != WSAEINTR) return tcp_abort (stream); break; case 0: /* timeout */ tc = time (0); if (tmoh && ((*tmoh) (tc - t,tc - tl))) break; return tcp_abort (stream); default: if (stream->tcpsi == stream->tcpso) while (((i = recv (stream->tcpsi,stream->ibuf,BUFLEN,0)) == SOCKET_ERROR) && (WSAGetLastError () == WSAEINTR)); else while (((i = read (stream->tcpsi,stream->ibuf,BUFLEN)) < 0) && (errno == EINTR)); switch (i) { case SOCKET_ERROR: /* error */ case 0: /* no data read */ return tcp_abort (stream); default: stream->ictr = i; /* set new byte count */ /* point at TCP buffer */ stream->iptr = stream->ibuf; if (tcpdebug) mm_log ("Successfully read TCP data",TCPDEBUG); } } } (*bn) (BLOCK_NONE,NIL); return T; } /* TCP/IP send string as record * Accepts: TCP/IP stream * string pointer * Returns: T if success else NIL */ long tcp_soutr (TCPSTREAM *stream,char *string) { return tcp_sout (stream,string,(unsigned long) strlen (string)); } /* TCP/IP send string * Accepts: TCP/IP stream * string pointer * byte count * Returns: T if success else NIL */ long tcp_sout (TCPSTREAM *stream,char *string,unsigned long size) { int i; struct timeval tmo; fd_set fds; time_t tc,t = time (0); blocknotify_t bn = (blocknotify_t) mail_parameters (NIL,GET_BLOCKNOTIFY,NIL); tmo.tv_sec = ttmo_write; tmo.tv_usec = 0; FD_ZERO (&fds); /* initialize selection vector */ if (stream->tcpso == INVALID_SOCKET) return NIL; (*bn) (BLOCK_TCPWRITE,NIL); while (size > 0) { /* until request satisfied */ time_t tl = time (0); if (tcpdebug) mm_log ("Writing to TCP",TCPDEBUG); FD_SET (stream->tcpso,&fds);/* set bit in selection vector */ /* block and write */ switch ((stream->tcpsi == stream->tcpso) ? select (stream->tcpso+1,NULL,&fds,NULL, tmo.tv_sec ? &tmo : (struct timeval *) 0) : 1) { case SOCKET_ERROR: /* error */ if (WSAGetLastError () != WSAEINTR) return tcp_abort (stream); break; case 0: /* timeout */ tc = time (0); if (tmoh && ((*tmoh) (tc - t,tc - tl))) break; return tcp_abort (stream); default: if (stream->tcpsi == stream->tcpso) while (((i = send (stream->tcpso,string, (int) min (size,TCPMAXSEND),0)) == SOCKET_ERROR) && (WSAGetLastError () == WSAEINTR)); else while (((i = write (stream->tcpso,string, min (size,TCPMAXSEND))) < 0) && (errno == EINTR)); if (i == SOCKET_ERROR) return tcp_abort (stream); size -= i; /* count this size */ if (tcpdebug) mm_log ("successfully wrote to TCP",TCPDEBUG); string += i; } } (*bn) (BLOCK_NONE,NIL); return T; /* all done */ } /* TCP/IP close * Accepts: TCP/IP stream */ void tcp_close (TCPSTREAM *stream) { tcp_abort (stream); /* nuke the sockets */ /* flush host names */ if (stream->host) fs_give ((void **) &stream->host); if (stream->remotehost) fs_give ((void **) &stream->remotehost); if (stream->localhost) fs_give ((void **) &stream->localhost); fs_give ((void **) &stream); /* flush the stream */ } /* TCP/IP abort sockets * Accepts: TCP/IP stream * Returns: NIL, always */ long tcp_abort (TCPSTREAM *stream) { if (stream->tcpsi != stream->tcpso) tcp_close_socket (&stream->tcpso); else stream->tcpso = INVALID_SOCKET; return tcp_close_socket (&stream->tcpsi); } /* TCP/IP abort stream * Accepts: WinSock socket * Returns: NIL, always */ long tcp_close_socket (SOCKET *sock) { blocknotify_t bn = (blocknotify_t) mail_parameters (NIL,GET_BLOCKNOTIFY,NIL); /* something to close? */ if (sock && (*sock != INVALID_SOCKET)) { (*bn) (BLOCK_TCPCLOSE,NIL); closesocket (*sock); /* WinSock socket close */ *sock = INVALID_SOCKET; (*bn) (BLOCK_NONE,NIL); wsa_sock_open--; /* drop this socket */ } /* no more open streams? */ if (wsa_initted && !wsa_sock_open) { mm_log ("Winsock cleanup",NIL); wsa_initted = 0; /* no more sockets, so... */ WSACleanup (); /* free up resources until needed */ } return NIL; } /* TCP/IP get host name * Accepts: TCP/IP stream * Returns: host name for this stream */ char *tcp_host (TCPSTREAM *stream) { return stream->host; /* use tcp_remotehost() if want guarantees */ } /* TCP/IP get remote host name * Accepts: TCP/IP stream * Returns: host name for this stream */ char *tcp_remotehost (TCPSTREAM *stream) { if (!stream->remotehost) { struct sockaddr_in sin; int sinlen = sizeof (struct sockaddr_in); stream->remotehost = /* get socket's peer name */ ((getpeername (stream->tcpsi,(struct sockaddr *) &sin,&sinlen) == SOCKET_ERROR) || (sinlen <= 0)) ? cpystr (stream->host) : tcp_name (&sin,NIL); } return stream->remotehost; } /* TCP/IP return port for this stream * Accepts: TCP/IP stream * Returns: port number for this stream */ unsigned long tcp_port (TCPSTREAM *stream) { return stream->port; /* return port number */ } /* TCP/IP get local host name * Accepts: TCP/IP stream * Returns: local host name */ char *tcp_localhost (TCPSTREAM *stream) { if (!stream->localhost) { struct sockaddr_in sin; int sinlen = sizeof (struct sockaddr_in); stream->localhost = /* get socket's name */ ((stream->port & 0xffff000) || ((getsockname (stream->tcpsi,(struct sockaddr *) &sin,&sinlen) == SOCKET_ERROR) || (sinlen <= 0))) ? cpystr (mylocalhost ()) : tcp_name (&sin,NIL); } return stream->localhost; /* return local host name */ } /* TCP/IP get client host address (server calls only) * Returns: client host address */ char *tcp_clientaddr () { if (!myClientAddr) { struct sockaddr_in sin; int sinlen = sizeof (struct sockaddr_in); myClientAddr = /* get stdin's peer name */ ((getpeername (0,(struct sockaddr *) &sin,&sinlen) == SOCKET_ERROR) || (sinlen <= 0)) ? cpystr ("UNKNOWN") : cpystr (inet_ntoa (sin.sin_addr)); } return myClientAddr; } /* TCP/IP get client host name (server calls only) * Returns: client host name */ char *tcp_clienthost () { if (!myClientHost) { struct sockaddr_in sin; int sinlen = sizeof (struct sockaddr_in); myClientHost = /* get stdin's peer name */ ((getpeername (0,(struct sockaddr *) &sin,&sinlen) == SOCKET_ERROR) || (sinlen <= 0)) ? cpystr ("UNKNOWN") : tcp_name (&sin,T); } return myClientHost; } /* TCP/IP get server host address (server calls only) * Returns: server host address */ char *tcp_serveraddr () { if (!myServerAddr) { struct sockaddr_in sin; int sinlen = sizeof (struct sockaddr_in); myServerAddr = /* get stdin's peer name */ ((getsockname (0,(struct sockaddr *) &sin,&sinlen) == SOCKET_ERROR) || (sinlen <= 0)) ? cpystr ("UNKNOWN") : cpystr (inet_ntoa (sin.sin_addr)); } return myServerAddr; } /* TCP/IP get server host name (server calls only) * Returns: server host name */ static long myServerPort = -1; char *tcp_serverhost () { if (!myServerHost) { struct sockaddr_in sin; int sinlen = sizeof (struct sockaddr_in); if (!wsa_initted++) { /* init Windows Sockets */ WSADATA wsock; if (WSAStartup (WSA_VERSION,&wsock)) { wsa_initted = 0; return "random-pc"; /* try again later? */ } } /* get stdin's name */ if ((getsockname (0,(struct sockaddr *) &sin,&sinlen) == SOCKET_ERROR) || (sinlen <= 0)) myServerHost = cpystr (mylocalhost ()); else { myServerHost = tcp_name (&sin,NIL); myServerPort = ntohs (sin.sin_port); } } return myServerHost; } /* TCP/IP get server port number (server calls only) * Returns: server port number */ long tcp_serverport () { if (!myServerHost) tcp_serverhost (); return myServerPort; } /* TCP/IP return canonical form of host name * Accepts: host name * Returns: canonical form of host name */ char *tcp_canonical (char *name) { char *ret,host[MAILTMPLEN]; struct hostent *he; blocknotify_t bn = (blocknotify_t) mail_parameters (NIL,GET_BLOCKNOTIFY,NIL); /* look like domain literal? */ if (name[0] == '[' && name[strlen (name) - 1] == ']') return name; (*bn) (BLOCK_DNSLOOKUP,NIL); if (tcpdebug) { sprintf (host,"DNS canonicalization %.80s",name); mm_log (host,TCPDEBUG); } /* note that NT requires lowercase! */ ret = (he = gethostbyname (lcase (strcpy (host,name)))) ? he->h_name : name; (*bn) (BLOCK_NONE,NIL); if (tcpdebug) mm_log ("DNS canonicalization done",TCPDEBUG); return ret; } /* TCP/IP return name from socket * Accepts: socket * verbose flag * Returns: cpystr name */ char *tcp_name (struct sockaddr_in *sin,long flag) { char *ret,*t,adr[MAILTMPLEN],tmp[MAILTMPLEN]; sprintf (ret = adr,"[%.80s]",inet_ntoa (sin->sin_addr)); if (allowreversedns) { struct hostent *he; blocknotify_t bn = (blocknotify_t)mail_parameters(NIL,GET_BLOCKNOTIFY,NIL); void *data; if (tcpdebug) { sprintf (tmp,"Reverse DNS resolution %s",adr); mm_log (tmp,TCPDEBUG); } (*bn) (BLOCK_DNSLOOKUP,NIL);/* quell alarms */ data = (*bn) (BLOCK_SENSITIVE,NIL); /* translate address to name */ if (t = tcp_name_valid ((he = gethostbyaddr ((char *) &sin->sin_addr, sizeof (struct in_addr), sin->sin_family)) ? (char *) he->h_name : NIL)) { /* produce verbose form if needed */ if (flag) sprintf (ret = tmp,"%s %s",t,adr); else ret = t; } (*bn) (BLOCK_NONSENSITIVE,data); (*bn) (BLOCK_NONE,NIL); /* alarms OK now */ if (tcpdebug) mm_log ("Reverse DNS resolution done",TCPDEBUG); } return cpystr (ret); } /* Return my local host name * Returns: my local host name */ char *mylocalhost (void) { if (!myLocalHost) { char tmp[MAILTMPLEN]; if (!wsa_initted++) { /* init Windows Sockets */ WSADATA wsock; if (WSAStartup (WSA_VERSION,&wsock)) { wsa_initted = 0; return "random-pc"; /* try again later? */ } } myLocalHost = cpystr ((gethostname (tmp,MAILTMPLEN-1) == SOCKET_ERROR) ? "random-pc" : tcp_canonical (tmp)); } return myLocalHost; } /* Validate name * Accepts: domain name * Returns: T if valid, NIL otherwise */ char *tcp_name_valid (char *s) { int c; char *ret,*tail; /* must be non-empty and not too long */ if ((ret = (s && *s) ? s : NIL) && (tail = ret + NETMAXHOST)) { /* must be alnum, dot, or hyphen */ while ((c = *s++) && (s <= tail) && (((c >= 'A') && (c <= 'Z')) || ((c >= 'a') && (c <= 'z')) || ((c >= '0') && (c <= '9')) || (c == '-') || (c == '.'))); if (c) ret = NIL; } return ret; } alpine-2.10+dfsg/imap/src/osdep/dos/os_dbw.h0000600000175000017500000000202511512502124022375 0ustar paulproteuspaulproteus/* ======================================================================== * Copyright 1988-2006 University of Washington * * Licensed under the Apache License, Version 2.0 (the "License"); * you may not use this file except in compliance with the License. * You may obtain a copy of the License at * * http://www.apache.org/licenses/LICENSE-2.0 * * * ======================================================================== */ /* * Program: Operating-system dependent routines -- DOS (B&W/Novell) version * * Author: Mark Crispin * Networks and Distributed Computing * Computing & Communications * University of Washington * Administration Building, AG-44 * Seattle, WA 98195 * Internet: MRC@CAC.Washington.EDU * * Date: 11 May 1989 * Last Edited: 30 August 2006 */ #define INADEQUATE_MEMORY #include #include #include #include #include #define gethostid clock #include "env_dos.h" #include "fs.h" #include "ftl.h" #include "nl.h" #include "tcp.h" alpine-2.10+dfsg/imap/src/osdep/dos/os_wsk.h0000600000175000017500000000216511512502124022432 0ustar paulproteuspaulproteus/* ======================================================================== * Copyright 1988-2006 University of Washington * * Licensed under the Apache License, Version 2.0 (the "License"); * you may not use this file except in compliance with the License. * You may obtain a copy of the License at * * http://www.apache.org/licenses/LICENSE-2.0 * * * ======================================================================== */ /* * Program: Operating-system dependent routines -- 16-bit Winsock version * * Author: Mike Seibel from Novell version by Mark Crispin * Networks and Distributed Computing * Computing & Communications * University of Washington * Administration Building, AG-44 * Seattle, WA 98195 * Internet: MikeS@CAC.Washington.EDU * * Date: 11 May 1989 * Last Edited: 30 August 2006 */ #define INADEQUATE_MEMORY #include #include #include #include #include #define gethostid clock #define WSA_VERSION ((1 << 8) | 1) #include "env_dos.h" #include "fs.h" #include "ftl.h" #include "nl.h" #include "tcp.h" #undef noErr #undef MAC alpine-2.10+dfsg/imap/src/osdep/dos/os_dnf.h0000600000175000017500000000211111512502124022364 0ustar paulproteuspaulproteus/* ======================================================================== * Copyright 1988-2006 University of Washington * * Licensed under the Apache License, Version 2.0 (the "License"); * you may not use this file except in compliance with the License. * You may obtain a copy of the License at * * http://www.apache.org/licenses/LICENSE-2.0 * * * ======================================================================== */ /* * Program: Operating-system dependent routines -- DOS (PC-NFS) version * * Author: Mike Seibel from Novell version by Mark Crispin * Networks and Distributed Computing * Computing & Communications * University of Washington * Administration Building, AG-44 * Seattle, WA 98195 * Internet: MikeS@CAC.Washington.EDU * * Date: 11 May 1989 * Last Edited: 30 August 2006 */ #define INADEQUATE_MEMORY #include #include #include #include #include #include #define gethostid clock #include "env_dos.h" #include "fs.h" #include "ftl.h" #include "nl.h" #include "tcp.h" alpine-2.10+dfsg/imap/src/osdep/dos/fdstring.c0000600000175000017500000000540711512502124022742 0ustar paulproteuspaulproteus/* ======================================================================== * Copyright 1988-2007 University of Washington * * Licensed under the Apache License, Version 2.0 (the "License"); * you may not use this file except in compliance with the License. * You may obtain a copy of the License at * * http://www.apache.org/licenses/LICENSE-2.0 * * * ======================================================================== */ /* * Program: File descriptor string routines * * Author: Mark Crispin * Networks and Distributed Computing * Computing & Communications * University of Washington * Administration Building, AG-44 * Seattle, WA 98195 * Internet: MRC@CAC.Washington.EDU * * Date: 15 April 1997 * Last Edited: 4 April 2007 */ #include "mail.h" #include "osdep.h" #include "misc.h" #include "fdstring.h" /* String driver for fd stringstructs */ static void fd_string_init (STRING *s,void *data,unsigned long size); static char fd_string_next (STRING *s); static void fd_string_setpos (STRING *s,unsigned long i); STRINGDRIVER fd_string = { fd_string_init, /* initialize string structure */ fd_string_next, /* get next byte in string structure */ fd_string_setpos /* set position in string structure */ }; /* Initialize string structure for fd stringstruct * Accepts: string structure * pointer to string * size of string */ static void fd_string_init (STRING *s,void *data,unsigned long size) { FDDATA *d = (FDDATA *) data; /* note fd */ s->data = (void *) (unsigned long) d->fd; s->data1 = d->pos; /* note file offset */ s->size = size; /* note size */ s->curpos = s->chunk = d->chunk; s->chunksize = (unsigned long) d->chunksize; s->offset = 0; /* initial position */ /* and size of data */ s->cursize = min (s->chunksize,size); /* move to that position in the file */ lseek (d->fd,d->pos,L_SET); read (d->fd,s->chunk,(size_t) s->cursize); } /* Get next character from fd stringstruct * Accepts: string structure * Returns: character, string structure chunk refreshed */ static char fd_string_next (STRING *s) { char c = *s->curpos++; /* get next byte */ SETPOS (s,GETPOS (s)); /* move to next chunk */ return c; /* return the byte */ } /* Set string pointer position for fd stringstruct * Accepts: string structure * new position */ static void fd_string_setpos (STRING *s,unsigned long i) { if (i > s->size) i = s->size; /* don't permit setting beyond EOF */ s->offset = i; /* set new offset */ s->curpos = s->chunk; /* reset position */ /* set size of data */ if (s->cursize = min (s->chunksize,SIZE (s))) { /* move to that position in the file */ lseek ((long) s->data,s->data1 + s->offset,L_SET); read ((long) s->data,s->curpos,(size_t) s->cursize); } } alpine-2.10+dfsg/imap/src/osdep/dos/os_dnv.h0000600000175000017500000000202511512502124022410 0ustar paulproteuspaulproteus/* ======================================================================== * Copyright 1988-2006 University of Washington * * Licensed under the Apache License, Version 2.0 (the "License"); * you may not use this file except in compliance with the License. * You may obtain a copy of the License at * * http://www.apache.org/licenses/LICENSE-2.0 * * * ======================================================================== */ /* * Program: Operating-system dependent routines -- DOS (B&W/Novell) version * * Author: Mark Crispin * Networks and Distributed Computing * Computing & Communications * University of Washington * Administration Building, AG-44 * Seattle, WA 98195 * Internet: MRC@CAC.Washington.EDU * * Date: 11 May 1989 * Last Edited: 30 August 2006 */ #define INADEQUATE_MEMORY #include #include #include #include #include #define gethostid clock #include "env_dos.h" #include "fs.h" #include "ftl.h" #include "nl.h" #include "tcp.h" alpine-2.10+dfsg/imap/src/osdep/dos/mtestdpc.bat0000600000175000017500000000163511512502124023270 0ustar paulproteuspaulproteus@ECHO OFF REM ======================================================================== REM Copyright 1988-2006 University of Washington REM REM Licensed under the Apache License, Version 2.0 (the "License"); REM you may not use this file except in compliance with the License. REM You may obtain a copy of the License at REM REM http://www.apache.org/licenses/LICENSE-2.0 REM REM REM ======================================================================== REM Program: Portable C client makefile -- MS-DOS PC/TCP link REM REM Author: Mark Crispin REM Networks and Distributed Computing REM Computing & Communications REM University of Washington REM Administration Building, AG-44 REM Seattle, WA 98195 REM Internet: MRC@CAC.Washington.EDU REM REM Date: 26 June 1994 REM Last Edited:30 August 2006 link /NOI /stack:32767 mtest.obj,mtest.exe,,cclient.lib lsocket.lib lnetlib.lib lpc.lib lconfig.lib llibce.lib; alpine-2.10+dfsg/imap/src/osdep/dos/mtestdnv.bat0000600000175000017500000000156211512502124023310 0ustar paulproteuspaulproteus@ECHO OFF REM ======================================================================== REM Copyright 1988-2006 University of Washington REM REM Licensed under the Apache License, Version 2.0 (the "License"); REM you may not use this file except in compliance with the License. REM You may obtain a copy of the License at REM REM http://www.apache.org/licenses/LICENSE-2.0 REM REM REM ======================================================================== REM Program: Portable C client makefile -- MS-DOS Novell link REM REM Author: Mark Crispin REM Networks and Distributed Computing REM Computing & Communications REM University of Washington REM Administration Building, AG-44 REM Seattle, WA 98195 REM Internet: MRC@CAC.Washington.EDU REM REM Date: 26 June 1994 REM Last Edited:30 August 2006 link /NOI /stack:32767 mtest.obj,mtest.exe,,cclient.lib llibsock.lib alpine-2.10+dfsg/imap/src/osdep/dos/pmatch.c0000600000175000017500000000545411512502124022400 0ustar paulproteuspaulproteus/* ======================================================================== * Copyright 1988-2006 University of Washington * * Licensed under the Apache License, Version 2.0 (the "License"); * you may not use this file except in compliance with the License. * You may obtain a copy of the License at * * http://www.apache.org/licenses/LICENSE-2.0 * * * ======================================================================== */ /* * Program: IMAP Wildcard Matching Routines (case-independent) * * Author: Mark Crispin * Networks and Distributed Computing * Computing & Communications * University of Washington * Administration Building, AG-44 * Seattle, WA 98195 * Internet: MRC@CAC.Washington.EDU * * Date: 15 June 2000 * Last Edited: 30 August 2006 */ /* Wildcard pattern match * Accepts: base string * pattern string * delimiter character * Returns: T if pattern matches base, else NIL */ long pmatch_full (unsigned char *s,unsigned char *pat,unsigned char delim) { switch (*pat) { case '%': /* non-recursive */ /* % at end, OK if no inferiors */ if (!pat[1]) return (delim && strchr (s,delim)) ? NIL : T; /* scan remainder of string until delimiter */ do if (pmatch_full (s,pat+1,delim)) return T; while ((*s != delim) && *s++); break; case '*': /* match 0 or more characters */ if (!pat[1]) return T; /* * at end, unconditional match */ /* scan remainder of string */ do if (pmatch_full (s,pat+1,delim)) return T; while (*s++); break; case '\0': /* end of pattern */ return *s ? NIL : T; /* success if also end of base */ default: /* match this character */ return compare_uchar (*pat,*s) ? NIL : pmatch_full (s+1,pat+1,delim); } return NIL; } /* Directory pattern match * Accepts: base string * pattern string * delimiter character * Returns: T if base is a matching directory of pattern, else NIL */ long dmatch (unsigned char *s,unsigned char *pat,unsigned char delim) { switch (*pat) { case '%': /* non-recursive */ if (!*s) return T; /* end of base means have a subset match */ if (!*++pat) return NIL; /* % at end, no inferiors permitted */ /* scan remainder of string until delimiter */ do if (dmatch (s,pat,delim)) return T; while ((*s != delim) && *s++); if (*s && !s[1]) return T; /* ends with delimiter, must be subset */ return dmatch (s,pat,delim);/* do new scan */ case '*': /* match 0 or more characters */ return T; /* unconditional match */ case '\0': /* end of pattern */ break; default: /* match this character */ if (*s) return compare_uchar (*pat,*s) ? NIL : dmatch (s+1,pat+1,delim); /* end of base, return if at delimiter */ else if (*pat == delim) return T; break; } return NIL; } alpine-2.10+dfsg/imap/src/osdep/dos/nl_dos.c0000600000175000017500000000331711512502124022376 0ustar paulproteuspaulproteus/* ======================================================================== * Copyright 1988-2006 University of Washington * * Licensed under the Apache License, Version 2.0 (the "License"); * you may not use this file except in compliance with the License. * You may obtain a copy of the License at * * http://www.apache.org/licenses/LICENSE-2.0 * * * ======================================================================== */ /* * Program: Windows/TOPS-20 newline routines * * Author: Mark Crispin * Networks and Distributed Computing * Computing & Communications * University of Washington * Administration Building, AG-44 * Seattle, WA 98195 * Internet: MRC@CAC.Washington.EDU * * Date: 1 August 1988 * Last Edited: 30 August 2006 */ /* Copy string with CRLF newlines * Accepts: destination string * pointer to size of destination string buffer * source string * length of source string * Returns: length of copied string */ unsigned long strcrlfcpy (unsigned char **dst,unsigned long *dstl, unsigned char *src,unsigned long srcl) { /* flush destination buffer if too small */ if (*dst && (srcl > *dstl)) fs_give ((void **) dst); if (!*dst) { /* make a new buffer if needed */ *dst = (char *) fs_get ((size_t) (*dstl = srcl) + 1); if (dstl) *dstl = srcl; /* return new buffer length to main program */ } /* copy strings */ if (srcl) memcpy (*dst,src,(size_t) srcl); *(*dst + srcl) = '\0'; /* tie off destination */ return srcl; /* return length */ } /* Length of string after strcrlfcpy applied * Accepts: source string * Returns: length of string */ unsigned long strcrlflen (STRING *s) { return SIZE (s); /* no-brainer on DOS! */ } alpine-2.10+dfsg/imap/src/osdep/dos/tcp_wsk.h0000600000175000017500000000260211512502124022573 0ustar paulproteuspaulproteus/* ======================================================================== * Copyright 1988-2006 University of Washington * * Licensed under the Apache License, Version 2.0 (the "License"); * you may not use this file except in compliance with the License. * You may obtain a copy of the License at * * http://www.apache.org/licenses/LICENSE-2.0 * * * ======================================================================== */ /* * Program: Winsock TCP/IP routines * * Author: Mike Seibel from Unix version by Mark Crispin * Computing & Communications * University of Washington * Administration Building, AG-44 * Seattle, WA 98195 * Internet: MRC@CAC.Washington.EDU * * Date: 11 April 1989 * Last Edited: 30 August 2006 */ /* TCP input buffer -- must be large enough to prevent overflow */ #define BUFLEN 16384 /* 32768 causes stdin read() to barf */ #include #define _INC_WINDOWS #include /* TCP I/O stream (must be before osdep.h is included) */ #define TCPSTREAM struct tcp_stream TCPSTREAM { char *host; /* host name */ char *remotehost; /* remote host name */ unsigned long port; /* port number */ char *localhost; /* local host name */ SOCKET tcpsi; /* tcp socket */ SOCKET tcpso; /* tcp socket */ long ictr; /* input counter */ char *iptr; /* input pointer */ char ibuf[BUFLEN]; /* input buffer */ }; alpine-2.10+dfsg/imap/src/osdep/dos/env_dos.c0000600000175000017500000002047511512502124022561 0ustar paulproteuspaulproteus/* ======================================================================== * Copyright 1988-2006 University of Washington * * Licensed under the Apache License, Version 2.0 (the "License"); * you may not use this file except in compliance with the License. * You may obtain a copy of the License at * * http://www.apache.org/licenses/LICENSE-2.0 * * * ======================================================================== */ /* * Program: DOS environment routines * * Author: Mark Crispin * Networks and Distributed Computing * Computing & Communications * University of Washington * Administration Building, AG-44 * Seattle, WA 98195 * Internet: MRC@CAC.Washington.EDU * * Date: 1 August 1988 * Last Edited: 30 August 2006 */ static char *myLocalHost = NIL; /* local host name */ static char *myClientAddr = NIL;/* client host address */ static char *myClientHost = NIL;/* client host name */ static char *myServerAddr = NIL;/* server host address */ static char *myServerHost = NIL;/* server host name */ static char *myHomeDir = NIL; /* home directory name */ static char *myNewsrc = NIL; /* newsrc file name */ static long list_max_level = 5; /* maximum level of list recursion */ static short no822tztext = NIL; /* disable RFC [2]822 timezone text */ /* home namespace */ static NAMESPACE nshome = {"",'\\',NIL,NIL}; /* namespace list */ static NAMESPACE *nslist[3] = {&nshome,NIL,NIL}; #include "write.c" /* include safe writing routines */ #include "pmatch.c" /* include wildcard pattern matcher */ /* Dummy definitions to prevent errors */ #define server_login(user,pass,authuser,argc,argv) NIL #define authserver_login(user,authuser,argc,argv) NIL #define myusername() "" #define MD5ENABLE "\\.nosuch.." /* Get all authenticators */ #include "auths.c" /* Environment manipulate parameters * Accepts: function code * function-dependent value * Returns: function-dependent return value */ void *env_parameters (long function,void *value) { void *ret = NIL; switch ((int) function) { case GET_NAMESPACE: ret = (void *) nslist; break; case SET_HOMEDIR: myHomeDir = cpystr ((char *) value); case GET_HOMEDIR: ret = (void *) myHomeDir; break; case SET_LOCALHOST: myLocalHost = cpystr ((char *) value); case GET_LOCALHOST: ret = (void *) myLocalHost; break; case SET_NEWSRC: if (myNewsrc) fs_give ((void **) &myNewsrc); myNewsrc = cpystr ((char *) value); case GET_NEWSRC: if (!myNewsrc) { /* set news file name if not defined */ char tmp[MAILTMPLEN]; sprintf (tmp,"%s\\NEWSRC",myhomedir ()); myNewsrc = cpystr (tmp); } ret = (void *) myNewsrc; break; case SET_LISTMAXLEVEL: list_max_level = (long) value; case GET_LISTMAXLEVEL: ret = (void *) list_max_level; break; case SET_DISABLE822TZTEXT: no822tztext = value ? T : NIL; case GET_DISABLE822TZTEXT: ret = (void *) (no822tztext ? VOIDT : NIL); break; } return ret; } /* Write current time * Accepts: destination string * optional format of day-of-week prefix * format of date and time * flag whether to append symbolic timezone */ static void do_date (char *date,char *prefix,char *fmt,int suffix) { time_t tn = time (0); struct tm *t = gmtime (&tn); int zone = t->tm_hour * 60 + t->tm_min; int julian = t->tm_yday; t = localtime (&tn); /* get local time now */ /* minus UTC minutes since midnight */ zone = t->tm_hour * 60 + t->tm_min - zone; /* julian can be one of: * 36x local time is December 31, UTC is January 1, offset -24 hours * 1 local time is 1 day ahead of UTC, offset +24 hours * 0 local time is same day as UTC, no offset * -1 local time is 1 day behind UTC, offset -24 hours * -36x local time is January 1, UTC is December 31, offset +24 hours */ if (julian = t->tm_yday -julian) zone += ((julian < 0) == (abs (julian) == 1)) ? -24*60 : 24*60; if (prefix) { /* want day of week? */ sprintf (date,prefix,days[t->tm_wday]); date += strlen (date); /* make next sprintf append */ } /* output the date */ sprintf (date,fmt,t->tm_mday,months[t->tm_mon],t->tm_year+1900, t->tm_hour,t->tm_min,t->tm_sec,zone/60,abs (zone) % 60); if (suffix) { /* append timezone suffix if desired */ tzset (); /* get timezone from TZ environment stuff */ sprintf (date + strlen (date)," (%.50s)", tzname[daylight ? (((struct tm *) t)->tm_isdst > 0) : 0]); } } /* Write current time in RFC 822 format * Accepts: destination string */ void rfc822_date (char *date) { do_date (date,"%s, ","%d %s %d %02d:%02d:%02d %+03d%02d", no822tztext ? NIL : T); } /* Write current time in internal format * Accepts: destination string */ void internal_date (char *date) { do_date (date,NIL,"%02d-%s-%d %02d:%02d:%02d %+03d%02d",NIL); } /* Return my home directory name * Returns: my home directory name */ char *myhomedir () { int i; char *s; if (!myHomeDir) { /* get home directory name if not yet known */ i = strlen (myHomeDir = cpystr ((s = getenv ("HOME")) ? s : "")); if (i && ((myHomeDir[i-1] == '\\') || (myHomeDir[i-1]=='/'))) myHomeDir[i-1] = '\0'; /* tie off trailing directory delimiter */ } return myHomeDir; } /* Return mailbox file name * Accepts: destination buffer * mailbox name * Returns: file name */ char *mailboxfile (char *dst,char *name) { char *s; char *ext = (char *) mail_parameters (NIL,GET_EXTENSION,NIL); /* forbid extraneous extensions */ if ((s = strchr ((s = strrchr (name,'\\')) ? s : name,'.')) && ((ext = (char *) mail_parameters (NIL,GET_EXTENSION,NIL)) || strchr (s+1,'.'))) return NIL; /* absolute path name? */ if ((*name == '\\') || (name[1] == ':')) strcpy (dst,name); else sprintf (dst,"%s\\%s",myhomedir (),name); if (ext) sprintf (dst + strlen (dst),".%s",ext); return ucase (dst); } /* Determine default prototype stream to user * Accepts: type (NIL for create, T for append) * Returns: default prototype stream */ MAILSTREAM *default_proto (long type) { extern MAILSTREAM DEFAULTPROTO; return &DEFAULTPROTO; /* return default driver's prototype */ } /* Global data */ static unsigned rndm = 0; /* initial `random' number */ /* Return random number */ long random () { if (!rndm) srand (rndm = (unsigned) time (0L)); return (long) rand (); } /* Default mailgets routine on DOS * Accepts: readin function pointer * stream to use * number of bytes * identifier data * Returns: string read in, truncated if necessary * * This is a sample mailgets routine. It simply truncates any data larger * than 63K. On most systems, you generally don't use a mailgets * routine at all, but on DOS it's required to prevent the application from * crashing. */ static char *dos_gets_buf = NIL; char *dos_default_gets (readfn_t f,void *stream,unsigned long size, GETS_DATA *md) { readprogress_t *rp = mail_parameters (NIL,GET_READPROGRESS,NIL); char *ret,tmp[MAILTMPLEN+1]; unsigned long i,j,dsc,rdi = 0; unsigned long dos_max = 63 * 1024; if (!dos_gets_buf) /* one-time initialization */ dos_gets_buf = (char *) fs_get ((size_t) dos_max + 1); ret = (md->flags & MG_COPY) ? ((char *) fs_get ((size_t) size + 1)) : dos_gets_buf; if (size > dos_max) { sprintf (tmp,"Mailbox %s, %s %lu[%.80s], %lu octets truncated to %ld", md->stream->mailbox,(md->flags & MG_UID) ? "UID" : "#", md->msgno,md->what,size,(long) dos_max); mm_log (tmp,WARN); /* warn user */ dsc = size - dos_max; /* number of bytes to discard */ size = dos_max; /* maximum length string we can read */ } else dsc = 0; /* nothing to discard */ dos_gets_buf[size] = '\0'; /* tie off string */ if (rp) for (i = size; j = min ((long) MAILTMPLEN,(long) i); i -= j) { (*f) (stream,j,ret + rdi); (*rp) (md,rdi += j); } else (*f) (stream,size,dos_gets_buf); /* toss out everything after that */ for (i = dsc; j = min ((long) MAILTMPLEN,(long) i); i -= j) { (*f) (stream,j,tmp); if (rp) (*rp) (md,rdi += j); } return ret; } /* Emulator for BSD syslog() routine * Accepts: priority * message * parameters */ void syslog (int priority,const char *message,...) { } /* Emulator for BSD openlog() routine * Accepts: identity * options * facility */ void openlog (const char *ident,int logopt,int facility) { } alpine-2.10+dfsg/imap/src/osdep/unix/0000700000175000017500000000000012074461275021163 5ustar paulproteuspaulproteusalpine-2.10+dfsg/imap/src/osdep/unix/os_sos.c0000600000175000017500000000262211512502123022620 0ustar paulproteuspaulproteus/* ======================================================================== * Copyright 1988-2006 University of Washington * * Licensed under the Apache License, Version 2.0 (the "License"); * you may not use this file except in compliance with the License. * You may obtain a copy of the License at * * http://www.apache.org/licenses/LICENSE-2.0 * * * ======================================================================== */ /* * Program: Operating-system dependent routines -- S OSF/Digital UNIX/Tru64 * * Author: Mark Crispin * Networks and Distributed Computing * Computing & Communications * University of Washington * Administration Building, AG-44 * Seattle, WA 98195 * Internet: MRC@CAC.Washington.EDU * * Date: 1 August 1988 * Last Edited: 30 August 2006 */ #include "tcp_unix.h" /* must be before osdep includes tcp.h */ #include "mail.h" #include "osdep.h" #include #include #include #include #include #include #include #include #include extern int errno; /* just in case */ #include #include "misc.h" #include #include #include #include "fs_unix.c" #include "ftl_unix.c" #include "nl_unix.c" #include "env_unix.c" #include "tcp_unix.c" #include "gr_waitp.c" #include "tz_bsd.c" #undef flock #include "flocksim.c" alpine-2.10+dfsg/imap/src/osdep/unix/os_a41.c0000600000175000017500000000304111512502123022375 0ustar paulproteuspaulproteus/* ======================================================================== * Copyright 1988-2006 University of Washington * * Licensed under the Apache License, Version 2.0 (the "License"); * you may not use this file except in compliance with the License. * You may obtain a copy of the License at * * http://www.apache.org/licenses/LICENSE-2.0 * * * ======================================================================== */ /* * Program: Operating-system dependent routines -- AIX 4.1 on RS 6000 * * Author: Mark Crispin * Networks and Distributed Computing * Computing & Communications * University of Washington * Administration Building, AG-44 * Seattle, WA 98195 * Internet: MRC@CAC.Washington.EDU * * Date: 1 August 1988 * Last Edited: 30 August 2006 */ #include "tcp_unix.h" /* must be before osdep includes tcp.h */ #include "mail.h" #include "osdep.h" #include #include #include #include #include #include #include #include #include extern int errno; /* just in case */ #include #include "misc.h" #include #include /* needed for authenticate() */ int authenticate (char *UserName,char *Response,int *Reenter,char **Message); extern int sys_nerr; extern char *sys_errlist[]; #include "fs_unix.c" #include "ftl_unix.c" #include "nl_unix.c" #include "env_unix.c" #include "tcp_unix.c" #include "gr_waitp.c" #include "tz_sv4.c" #include "flocksim.c" #include "utime.c" alpine-2.10+dfsg/imap/src/osdep/unix/os_d-g.h0000600000175000017500000000254311512502123022472 0ustar paulproteuspaulproteus/* ======================================================================== * Copyright 1988-2006 University of Washington * * Licensed under the Apache License, Version 2.0 (the "License"); * you may not use this file except in compliance with the License. * You may obtain a copy of the License at * * http://www.apache.org/licenses/LICENSE-2.0 * * * ======================================================================== */ /* * Program: Operating-system dependent routines -- D-G version * * Author: Mark Crispin * Networks and Distributed Computing * Computing & Communications * University of Washington * Administration Building, AG-44 * Seattle, WA 98195 * Internet: MRC@CAC.Washington.EDU * * Date: 1 August 1988 * Last Edited: 30 August 2006 */ #include #include #include #include #include #include #include /* for struct tm */ #include #define _USEC_UTIME_FLAVOR /* break it for compatibility with */ #include /* the incompatible past */ #include #include /* D-G gets this wrong */ #define setpgrp setpgrp2 #define utime portable_utime int portable_utime (char *file,time_t timep[2]); #include "env_unix.h" #include "fs.h" #include "ftl.h" #include "nl.h" #include "tcp.h" #include "flocksim.h" alpine-2.10+dfsg/imap/src/osdep/unix/os_cvx.c0000600000175000017500000000261111512502123022612 0ustar paulproteuspaulproteus/* ======================================================================== * Copyright 1988-2007 University of Washington * * Licensed under the Apache License, Version 2.0 (the "License"); * you may not use this file except in compliance with the License. * You may obtain a copy of the License at * * http://www.apache.org/licenses/LICENSE-2.0 * * * ======================================================================== */ /* * Program: Operating-system dependent routines -- Convex version * * Author: Mark Crispin * Networks and Distributed Computing * Computing & Communications * University of Washington * Administration Building, AG-44 * Seattle, WA 98195 * * Date: 11 May 1989 * Last Edited: 16 August 2007 */ #define isodigit(c) (((unsigned)(c)>=060)&((unsigned)(c)<=067)) #define toint(c) ((c)-'0') #include #include "tcp_unix.h" /* must be before osdep includes tcp.h */ #include "mail.h" #include "osdep.h" #include #include #include #include #include #include #include #include #include extern int errno; /* just in case */ #include #include "misc.h" #include "fs_unix.c" #include "ftl_unix.c" #include "nl_unix.c" #include "env_unix.c" #define fork vfork #include "tcp_unix.c" #include "gr_wait.c" #include "tz_nul.c" alpine-2.10+dfsg/imap/src/osdep/unix/os_cyg.h0000600000175000017500000000314211512502123022601 0ustar paulproteuspaulproteus/* ======================================================================== * Copyright 1988-2006 University of Washington * * Licensed under the Apache License, Version 2.0 (the "License"); * you may not use this file except in compliance with the License. * You may obtain a copy of the License at * * http://www.apache.org/licenses/LICENSE-2.0 * * * ======================================================================== */ /* * Program: Operating-system dependent routines -- Cygwin version * * Author: Mark Crispin * Networks and Distributed Computing * Computing & Communications * University of Washington * Administration Building, AG-44 * Seattle, WA 98195 * Internet: MRC@CAC.Washington.EDU * * Date: 1 August 1988 * Last Edited: 30 August 2006 */ #include #include #include #include #include #include #include #include #include #include #define direct dirent #define CYGKLUDGEOFFSET 1 /* don't write 1st byte of shared-lock files */ /* Cygwin gets this wrong */ #define setpgrp setpgid #define SYSTEMUID 18 /* Cygwin returns this for SYSTEM */ #define geteuid Geteuid uid_t Geteuid (void); /* Now Cygwin has reportedly joined this madness. Use ifndef in case it shares the SVR4 silliness too */ #ifndef L_SET #define L_SET SEEK_SET #endif #ifndef L_INCR #define L_INCR SEEK_CUR #endif #ifndef L_XTND #define L_XTND SEEK_END #endif #include "env_unix.h" #include "fs.h" #include "ftl.h" #include "nl.h" #include "tcp.h" #include "flockcyg.h" alpine-2.10+dfsg/imap/src/osdep/unix/sig_sv4.c0000600000175000017500000000167311512502123022676 0ustar paulproteuspaulproteus/* ======================================================================== * Copyright 1988-2006 University of Washington * * Licensed under the Apache License, Version 2.0 (the "License"); * you may not use this file except in compliance with the License. * You may obtain a copy of the License at * * http://www.apache.org/licenses/LICENSE-2.0 * * * ======================================================================== */ /* * Program: SVR4 Signals * * Author: Mark Crispin * Networks and Distributed Computing * Computing & Communications * University of Washington * Administration Building, AG-44 * Seattle, WA 98195 * Internet: MRC@CAC.Washington.EDU * * Date: 29 April 1997 * Last Edited: 30 August 2006 */ #include /* Arm a signal * Accepts: signal number * desired action * Returns: old action */ void *arm_signal (int sig,void *action) { return (void *) sigset (sig,action); } alpine-2.10+dfsg/imap/src/osdep/unix/os_ptx.h0000600000175000017500000000331211512502123022631 0ustar paulproteuspaulproteus/* ======================================================================== * Copyright 1988-2006 University of Washington * * Licensed under the Apache License, Version 2.0 (the "License"); * you may not use this file except in compliance with the License. * You may obtain a copy of the License at * * http://www.apache.org/licenses/LICENSE-2.0 * * * ======================================================================== */ /* * Program: Operating-system dependent routines -- PTX version * * Author: Mark Crispin * Networks and Distributed Computing * Computing & Communications * University of Washington * Administration Building, AG-44 * Seattle, WA 98195 * Internet: MRC@CAC.Washington.EDU * * Date: 11 May 1989 * Last Edited: 15 September 2006 */ #include #include #include #include #include #include #include #include #include #include /* needed in daemons */ #include #include #include /* Different names, equivalent things in BSD and SysV */ #define L_SET SEEK_SET #define L_INCR SEEK_CUR #define L_XTND SEEK_END #define direct dirent #define random lrand48 #define utime portable_utime int portable_utime (char *file,time_t timep[2]); long gethostid (void); typedef int (*select_t) (struct direct *name); typedef int (*compar_t) (void *d1,void *d2); int scandir (char *dirname,struct direct ***namelist,select_t select, compar_t compar); int alphasort (void *d1,void *d2); long ENV_INIT (char *user,char *home); #include "env_unix.h" #include "fs.h" #include "ftl.h" #include "nl.h" #include "tcp.h" #include "flocksim.h" alpine-2.10+dfsg/imap/src/osdep/unix/os_sol.c0000600000175000017500000000325211512502123022611 0ustar paulproteuspaulproteus/* ======================================================================== * Copyright 1988-2007 University of Washington * * Licensed under the Apache License, Version 2.0 (the "License"); * you may not use this file except in compliance with the License. * You may obtain a copy of the License at * * http://www.apache.org/licenses/LICENSE-2.0 * * * ======================================================================== */ /* * Program: Operating-system dependent routines -- Solaris version * * Author: Mark Crispin * Networks and Distributed Computing * Computing & Communications * University of Washington * Administration Building, AG-44 * Seattle, WA 98195 * Internet: MRC@CAC.Washington.EDU * * Date: 10 April 1992 * Last Edited: 16 August 2007 */ #include "tcp_unix.h" /* must be before osdep includes tcp.h */ #include "mail.h" #include "osdep.h" #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include "misc.h" extern int sys_nerr; extern char *sys_errlist[]; #define DIR_SIZE(d) d->d_reclen #define toint(c) ((c)-'0') #define isodigit(c) (((unsigned)(c)>=060)&((unsigned)(c)<=067)) #include "fs_unix.c" #include "ftl_unix.c" #include "nl_unix.c" #include "env_unix.c" #include "getspnam.c" #define fork vfork #include "tcp_unix.c" #include "gr_waitp.c" #include "flocksim.c" #include "scandir.c" #include "tz_sv4.c" #include "gethstid.c" #undef setpgrp #include "setpgrp.c" #include "utime.c" alpine-2.10+dfsg/imap/src/osdep/unix/ckp_3rd.c0000600000175000017500000000146011512502123022637 0ustar paulproteuspaulproteus/* ======================================================================== * Copyright 1988-2006 University of Washington * * Licensed under the Apache License, Version 2.0 (the "License"); * you may not use this file except in compliance with the License. * You may obtain a copy of the License at * * http://www.apache.org/licenses/LICENSE-2.0 * * * ======================================================================== */ /* * Program: Dual check password part 3 * * Author: Mark Crispin * Networks and Distributed Computing * Computing & Communications * University of Washington * Administration Building, AG-44 * Seattle, WA 98195 * Internet: MRC@CAC.Washington.EDU * * Date: 1 August 1988 * Last Edited: 30 August 2006 */ /* Undefine routine name */ #undef checkpw alpine-2.10+dfsg/imap/src/osdep/unix/ip6_unix.c0000600000175000017500000002105011512502123023050 0ustar paulproteuspaulproteus/* ======================================================================== * Copyright 1988-2006 University of Washington * * Licensed under the Apache License, Version 2.0 (the "License"); * you may not use this file except in compliance with the License. * You may obtain a copy of the License at * * http://www.apache.org/licenses/LICENSE-2.0 * * * ======================================================================== */ /* * Program: UNIX IPv6 routines * * Author: Mark Crispin * Networks and Distributed Computing * Computing & Communications * University of Washington * Administration Building, AG-44 * Seattle, WA 98195 * Internet: MRC@CAC.Washington.EDU * * Date: 18 December 2003 * Last Edited: 30 August 2006 */ /* * There is some amazingly bad design in IPv6 sockets. * * Supposedly, the new getnameinfo() and getaddrinfo() functions create an * abstraction that is not dependent upon IPv4 or IPv6. However, the * definition of getnameinfo() requires that the caller pass the length of * the sockaddr instead of deriving it from sa_family. The man page says * that there's an sa_len member in the sockaddr, but actually there isn't. * This means that any caller to getnameinfo() and getaddrinfo() has to know * the size for the protocol family used by that sockaddr. * * The new sockaddr_in6 is bigger than the generic sockaddr (which is what * connect(), accept(), bind(), getpeername(), getsockname(), etc. expect). * Rather than increase the size of sockaddr, there's a new sockaddr_storage * which is only usable for allocating space. */ #define SADRLEN sizeof (struct sockaddr_storage) #define SADR4(sadr) ((struct sockaddr_in *) sadr) #define SADR4LEN sizeof (struct sockaddr_in) #define SADR4ADR(sadr) SADR4 (sadr)->sin_addr #define ADR4LEN sizeof (struct in_addr) #define SADR4PORT(sadr) SADR4 (sadr)->sin_port #define SADR6(sadr) ((struct sockaddr_in6 *) sadr) #define SADR6LEN sizeof (struct sockaddr_in6) #define SADR6ADR(sadr) SADR6 (sadr)->sin6_addr #define ADR6LEN sizeof (struct in6_addr) #define SADR6PORT(sadr) SADR6 (sadr)->sin6_port /* IP abstraction layer */ char *ip_sockaddrtostring (struct sockaddr *sadr); long ip_sockaddrtoport (struct sockaddr *sadr); void *ip_stringtoaddr (char *text,size_t *len,int *family); struct sockaddr *ip_newsockaddr (size_t *len); struct sockaddr *ip_sockaddr (int family,void *adr,size_t adrlen, unsigned short port,size_t *len); char *ip_sockaddrtoname (struct sockaddr *sadr); void *ip_nametoaddr (char *name,size_t *len,int *family,char **canonical, void **next); /* Return IP address string from socket address * Accepts: socket address * Returns: IP address as name string */ char *ip_sockaddrtostring (struct sockaddr *sadr) { static char tmp[NI_MAXHOST]; switch (sadr->sa_family) { case PF_INET: /* IPv4 */ if (!getnameinfo (sadr,SADR4LEN,tmp,NI_MAXHOST,NIL,NIL,NI_NUMERICHOST)) return tmp; break; case PF_INET6: /* IPv6 */ if (!getnameinfo (sadr,SADR6LEN,tmp,NI_MAXHOST,NIL,NIL,NI_NUMERICHOST)) return tmp; break; } return "NON-IP"; } /* Return port from socket address * Accepts: socket address * Returns: port number or -1 if can't determine it */ long ip_sockaddrtoport (struct sockaddr *sadr) { switch (sadr->sa_family) { case PF_INET: return ntohs (SADR4PORT (sadr)); case PF_INET6: return ntohs (SADR6PORT (sadr)); } return -1; } /* Return IP address from string * Accepts: name string * pointer to returned length * pointer to returned address family * Returns: address if valid, length and family updated, or NIL */ void *ip_stringtoaddr (char *text,size_t *len,int *family) { char tmp[MAILTMPLEN]; static struct addrinfo *hints; struct addrinfo *ai; void *adr = NIL; if (!hints) { /* hints set up yet? */ hints = (struct addrinfo *) /* one-time setup */ memset (fs_get (sizeof (struct addrinfo)),0,sizeof (struct addrinfo)); hints->ai_family = AF_UNSPEC;/* allow any address family */ hints->ai_socktype = SOCK_STREAM; /* numeric name only */ hints->ai_flags = AI_NUMERICHOST; } /* case-independent lookup */ if (text && (strlen (text) < MAILTMPLEN) && (!getaddrinfo (lcase (strcpy (tmp,text)),NIL,hints,&ai))) { switch (*family = ai->ai_family) { case AF_INET: /* IPv4 */ adr = fs_get (*len = ADR4LEN); memcpy (adr,(void *) &SADR4ADR (ai->ai_addr),*len); break; case AF_INET6: /* IPv6 */ adr = fs_get (*len = ADR6LEN); memcpy (adr,(void *) &SADR6ADR (ai->ai_addr),*len); break; } freeaddrinfo (ai); /* free addrinfo */ } return adr; } /* Create a maximum-size socket address * Accepts: pointer to return maximum socket address length * Returns: new, empty socket address of maximum size */ struct sockaddr *ip_newsockaddr (size_t *len) { return (struct sockaddr *) memset (fs_get (SADRLEN),0,*len = SADRLEN); } /* Stuff a socket address * Accepts: address family * IPv4 address * length of address * port number * pointer to return socket address length * Returns: socket address */ struct sockaddr *ip_sockaddr (int family,void *adr,size_t adrlen, unsigned short port,size_t *len) { struct sockaddr *sadr = ip_newsockaddr (len); switch (family) { /* build socket address based upon family */ case AF_INET: /* IPv4 */ sadr->sa_family = PF_INET; /* copy host address */ memcpy (&SADR4ADR (sadr),adr,adrlen); /* copy port number in network format */ SADR4PORT (sadr) = htons (port); *len = SADR4LEN; break; case AF_INET6: /* IPv6 */ sadr->sa_family = PF_INET6; /* copy host address */ memcpy (&SADR6ADR (sadr),adr,adrlen); /* copy port number in network format */ SADR6PORT (sadr) = htons (port); *len = SADR6LEN; break; default: /* non-IP?? */ sadr->sa_family = PF_UNSPEC; break; } return sadr; } /* Return name from socket address * Accepts: socket address * Returns: canonical name for that address or NIL if none */ char *ip_sockaddrtoname (struct sockaddr *sadr) { static char tmp[NI_MAXHOST]; switch (sadr->sa_family) { case PF_INET: /* IPv4 */ if (!getnameinfo (sadr,SADR4LEN,tmp,NI_MAXHOST,NIL,NIL,NI_NAMEREQD)) return tmp; break; case PF_INET6: /* IPv6 */ if (!getnameinfo (sadr,SADR6LEN,tmp,NI_MAXHOST,NIL,NIL,NI_NAMEREQD)) return tmp; break; } return NIL; } /* Return address from name * Accepts: name or NIL to return next address * pointer to previous/returned length * pointer to previous/returned address family * pointer to previous/returned canonical name * pointer to previous/return state for next-address calls * Returns: address with length/family/canonical updated if needed, or NIL */ void *ip_nametoaddr (char *name,size_t *len,int *family,char **canonical, void **next) { struct addrinfo *cur = NIL; static struct addrinfo *hints; static struct addrinfo *ai = NIL; static char lcname[MAILTMPLEN]; if (!hints) { /* hints set up yet? */ hints = (struct addrinfo *) /* one-time setup */ memset (fs_get (sizeof (struct addrinfo)),0,sizeof (struct addrinfo)); /* allow any address family */ hints->ai_family = AF_UNSPEC; hints->ai_socktype = SOCK_STREAM; /* need canonical name */ hints->ai_flags = AI_CANONNAME; } if (name) { /* name supplied? */ if (ai) { freeaddrinfo (ai); /* free old addrinfo */ ai = NIL; } /* case-independent lookup */ if ((strlen (name) < MAILTMPLEN) && (!getaddrinfo (lcase (strcpy (lcname,name)),NIL,hints,&ai))) { cur = ai; /* current block */ if (canonical) /* set canonical name */ *canonical = cur->ai_canonname ? cur->ai_canonname : lcname; /* remember as next block */ if (next) *next = (void *) ai; } else { /* error */ cur = NIL; if (len) *len = 0; if (family) *family = 0; if (canonical) *canonical = NIL; if (next) *next = NIL; } } /* return next in series */ else if (next && (cur = ((struct addrinfo *) *next)->ai_next)) { *next = cur; /* set as last address */ /* set canonical in case changed */ if (canonical && cur->ai_canonname) *canonical = cur->ai_canonname; } if (cur) { /* got data? */ if (family) *family = cur->ai_family; switch (cur->ai_family) { case AF_INET: if (len) *len = ADR4LEN; return (void *) &SADR4ADR (cur->ai_addr); case AF_INET6: if (len) *len = ADR6LEN; return (void *) &SADR6ADR (cur->ai_addr); } } if (len) *len = 0; /* error return */ return NIL; } alpine-2.10+dfsg/imap/src/osdep/unix/mtx.c0000600000175000017500000013214111512502123022123 0ustar paulproteuspaulproteus/* ======================================================================== * Copyright 1988-2007 University of Washington * * Licensed under the Apache License, Version 2.0 (the "License"); * you may not use this file except in compliance with the License. * You may obtain a copy of the License at * * http://www.apache.org/licenses/LICENSE-2.0 * * * ======================================================================== */ /* * Program: MTX mail routines * * Author: Mark Crispin * Networks and Distributed Computing * Computing & Communications * University of Washington * Administration Building, AG-44 * Seattle, WA 98195 * Internet: MRC@CAC.Washington.EDU * * Date: 22 May 1990 * Last Edited: 11 October 2007 */ /* FILE TIME SEMANTICS * * The atime is the last read time of the file. * The mtime is the last flags update time of the file. * The ctime is the last write time of the file. */ #include #include #include extern int errno; /* just in case */ #include "mail.h" #include "osdep.h" #include #include #include #include "misc.h" #include "dummy.h" #include "fdstring.h" /* MTX I/O stream local data */ typedef struct mtx_local { unsigned int shouldcheck: 1; /* if ping should do a check instead */ unsigned int mustcheck: 1; /* if ping must do a check instead */ int fd; /* file descriptor for I/O */ off_t filesize; /* file size parsed */ time_t filetime; /* last file time */ time_t lastsnarf; /* last snarf time */ unsigned char *buf; /* temporary buffer */ unsigned long buflen; /* current size of temporary buffer */ } MTXLOCAL; /* Convenient access to local data */ #define LOCAL ((MTXLOCAL *) stream->local) /* Function prototypes */ DRIVER *mtx_valid (char *name); int mtx_isvalid (char *name,char *tmp); void *mtx_parameters (long function,void *value); void mtx_scan (MAILSTREAM *stream,char *ref,char *pat,char *contents); void mtx_list (MAILSTREAM *stream,char *ref,char *pat); void mtx_lsub (MAILSTREAM *stream,char *ref,char *pat); long mtx_create (MAILSTREAM *stream,char *mailbox); long mtx_delete (MAILSTREAM *stream,char *mailbox); long mtx_rename (MAILSTREAM *stream,char *old,char *newname); long mtx_status (MAILSTREAM *stream,char *mbx,long flags); MAILSTREAM *mtx_open (MAILSTREAM *stream); void mtx_close (MAILSTREAM *stream,long options); void mtx_flags (MAILSTREAM *stream,char *sequence,long flags); char *mtx_header (MAILSTREAM *stream,unsigned long msgno, unsigned long *length,long flags); long mtx_text (MAILSTREAM *stream,unsigned long msgno,STRING *bs,long flags); void mtx_flag (MAILSTREAM *stream,char *sequence,char *flag,long flags); void mtx_flagmsg (MAILSTREAM *stream,MESSAGECACHE *elt); long mtx_ping (MAILSTREAM *stream); void mtx_check (MAILSTREAM *stream); void mtx_snarf (MAILSTREAM *stream); long mtx_expunge (MAILSTREAM *stream,char *sequence,long options); long mtx_copy (MAILSTREAM *stream,char *sequence,char *mailbox,long options); long mtx_append (MAILSTREAM *stream,char *mailbox,append_t af,void *data); char *mtx_file (char *dst,char *name); long mtx_parse (MAILSTREAM *stream); MESSAGECACHE *mtx_elt (MAILSTREAM *stream,unsigned long msgno); void mtx_read_flags (MAILSTREAM *stream,MESSAGECACHE *elt); void mtx_update_status (MAILSTREAM *stream,unsigned long msgno,long syncflag); unsigned long mtx_hdrpos (MAILSTREAM *stream,unsigned long msgno, unsigned long *size); /* MTX mail routines */ /* Driver dispatch used by MAIL */ DRIVER mtxdriver = { "mtx", /* driver name */ /* driver flags */ DR_LOCAL|DR_MAIL|DR_CRLF|DR_NOSTICKY|DR_LOCKING, (DRIVER *) NIL, /* next driver */ mtx_valid, /* mailbox is valid for us */ mtx_parameters, /* manipulate parameters */ mtx_scan, /* scan mailboxes */ mtx_list, /* list mailboxes */ mtx_lsub, /* list subscribed mailboxes */ NIL, /* subscribe to mailbox */ NIL, /* unsubscribe from mailbox */ dummy_create, /* create mailbox */ mtx_delete, /* delete mailbox */ mtx_rename, /* rename mailbox */ mtx_status, /* status of mailbox */ mtx_open, /* open mailbox */ mtx_close, /* close mailbox */ mtx_flags, /* fetch message "fast" attributes */ mtx_flags, /* fetch message flags */ NIL, /* fetch overview */ NIL, /* fetch message envelopes */ mtx_header, /* fetch message header */ mtx_text, /* fetch message body */ NIL, /* fetch partial message text */ NIL, /* unique identifier */ NIL, /* message number */ mtx_flag, /* modify flags */ mtx_flagmsg, /* per-message modify flags */ NIL, /* search for message based on criteria */ NIL, /* sort messages */ NIL, /* thread messages */ mtx_ping, /* ping mailbox to see if still alive */ mtx_check, /* check for new messages */ mtx_expunge, /* expunge deleted messages */ mtx_copy, /* copy messages to another mailbox */ mtx_append, /* append string message to mailbox */ NIL /* garbage collect stream */ }; /* prototype stream */ MAILSTREAM mtxproto = {&mtxdriver}; /* MTX mail validate mailbox * Accepts: mailbox name * Returns: our driver if name is valid, NIL otherwise */ DRIVER *mtx_valid (char *name) { char tmp[MAILTMPLEN]; return mtx_isvalid (name,tmp) ? &mtxdriver : NIL; } /* MTX mail test for valid mailbox * Accepts: mailbox name * Returns: T if valid, NIL otherwise */ int mtx_isvalid (char *name,char *tmp) { int fd; int ret = NIL; char *s,file[MAILTMPLEN]; struct stat sbuf; time_t tp[2]; errno = EINVAL; /* assume invalid argument */ /* if file, get its status */ if ((s = mtx_file (file,name)) && !stat (s,&sbuf)) { if (!sbuf.st_size) { /* allow empty file if INBOX */ if ((s = mailboxfile (tmp,name)) && !*s) ret = T; else errno = 0; /* empty file */ } else if ((fd = open (file,O_RDONLY,NIL)) >= 0) { memset (tmp,'\0',MAILTMPLEN); if ((read (fd,tmp,64) >= 0) && (s = strchr (tmp,'\015')) && (s[1] == '\012')) { /* valid format? */ *s = '\0'; /* tie off header */ /* must begin with dd-mmm-yy" */ ret = (((tmp[2] == '-' && tmp[6] == '-') || (tmp[1] == '-' && tmp[5] == '-')) && (s = strchr (tmp+18,',')) && strchr (s+2,';')) ? T : NIL; } else errno = -1; /* bogus format */ close (fd); /* close the file */ /* \Marked status? */ if (sbuf.st_ctime > sbuf.st_atime) { tp[0] = sbuf.st_atime; /* preserve atime and mtime */ tp[1] = sbuf.st_mtime; utime (file,tp); /* set the times */ } } } /* in case INBOX but not mtx format */ else if ((errno == ENOENT) && !compare_cstring (name,"INBOX")) errno = -1; return ret; /* return what we should */ } /* MTX manipulate driver parameters * Accepts: function code * function-dependent value * Returns: function-dependent return value */ void *mtx_parameters (long function,void *value) { void *ret = NIL; switch ((int) function) { case GET_INBOXPATH: if (value) ret = mtx_file ((char *) value,"INBOX"); break; } return ret; } /* MTX mail scan mailboxes * Accepts: mail stream * reference * pattern to search * string to scan */ void mtx_scan (MAILSTREAM *stream,char *ref,char *pat,char *contents) { if (stream) dummy_scan (NIL,ref,pat,contents); } /* MTX mail list mailboxes * Accepts: mail stream * reference * pattern to search */ void mtx_list (MAILSTREAM *stream,char *ref,char *pat) { if (stream) dummy_list (NIL,ref,pat); } /* MTX mail list subscribed mailboxes * Accepts: mail stream * reference * pattern to search */ void mtx_lsub (MAILSTREAM *stream,char *ref,char *pat) { if (stream) dummy_lsub (NIL,ref,pat); } /* MTX mail delete mailbox * Accepts: MAIL stream * mailbox name to delete * Returns: T on success, NIL on failure */ long mtx_delete (MAILSTREAM *stream,char *mailbox) { return mtx_rename (stream,mailbox,NIL); } /* MTX mail rename mailbox * Accepts: MAIL stream * old mailbox name * new mailbox name (or NIL for delete) * Returns: T on success, NIL on failure */ long mtx_rename (MAILSTREAM *stream,char *old,char *newname) { long ret = T; char c,*s,tmp[MAILTMPLEN],file[MAILTMPLEN],lock[MAILTMPLEN]; int fd,ld; struct stat sbuf; if (!mtx_file (file,old) || (newname && (!((s = mailboxfile (tmp,newname)) && *s) || ((s = strrchr (tmp,'/')) && !s[1])))) { sprintf (tmp,newname ? "Can't rename mailbox %.80s to %.80s: invalid name" : "Can't delete mailbox %.80s: invalid name", old,newname); MM_LOG (tmp,ERROR); return NIL; } else if ((fd = open (file,O_RDWR,NIL)) < 0) { sprintf (tmp,"Can't open mailbox %.80s: %s",old,strerror (errno)); MM_LOG (tmp,ERROR); return NIL; } /* get exclusive parse/append permission */ if ((ld = lockfd (fd,lock,LOCK_EX)) < 0) { MM_LOG ("Unable to lock rename mailbox",ERROR); return NIL; } /* lock out other users */ if (flock (fd,LOCK_EX|LOCK_NB)) { close (fd); /* couldn't lock, give up on it then */ sprintf (tmp,"Mailbox %.80s is in use by another process",old); MM_LOG (tmp,ERROR); unlockfd (ld,lock); /* release exclusive parse/append permission */ return NIL; } if (newname) { /* want rename? */ if (s = strrchr (tmp,'/')) {/* found superior to destination name? */ c = *++s; /* remember first character of inferior */ *s = '\0'; /* tie off to get just superior */ /* name doesn't exist, create it */ if ((stat (tmp,&sbuf) || ((sbuf.st_mode & S_IFMT) != S_IFDIR)) && !dummy_create_path (stream,tmp,get_dir_protection (newname))) ret = NIL; else *s = c; /* restore full name */ } /* rename the file */ if (ret && rename (file,tmp)) { sprintf (tmp,"Can't rename mailbox %.80s to %.80s: %s",old,newname, strerror (errno)); MM_LOG (tmp,ERROR); ret = NIL; /* set failure */ } } else if (unlink (file)) { sprintf (tmp,"Can't delete mailbox %.80s: %s",old,strerror (errno)); MM_LOG (tmp,ERROR); ret = NIL; /* set failure */ } flock (fd,LOCK_UN); /* release lock on the file */ close (fd); /* close the file */ unlockfd (ld,lock); /* release exclusive parse/append permission */ /* recreate file if renamed INBOX */ if (ret && !compare_cstring (old,"INBOX")) dummy_create (NIL,"INBOX.MTX"); return ret; /* return success */ } /* Mtx Mail status * Accepts: mail stream * mailbox name * status flags * Returns: T on success, NIL on failure */ long mtx_status (MAILSTREAM *stream,char *mbx,long flags) { MAILSTATUS status; unsigned long i; MAILSTREAM *tstream = NIL; MAILSTREAM *systream = NIL; /* make temporary stream (unless this mbx) */ if (!stream && !(stream = tstream = mail_open (NIL,mbx,OP_READONLY|OP_SILENT))) return NIL; status.flags = flags; /* return status values */ status.messages = stream->nmsgs; status.recent = stream->recent; if (flags & SA_UNSEEN) /* must search to get unseen messages */ for (i = 1,status.unseen = 0; i <= stream->nmsgs; i++) if (!mail_elt (stream,i)->seen) status.unseen++; status.uidnext = stream->uid_last + 1; status.uidvalidity = stream->uid_validity; /* calculate post-snarf results */ if (!status.recent && stream->inbox && (systream = mail_open (NIL,sysinbox (),OP_READONLY|OP_SILENT))) { status.messages += systream->nmsgs; status.recent += systream->recent; if (flags & SA_UNSEEN) /* must search to get unseen messages */ for (i = 1; i <= systream->nmsgs; i++) if (!mail_elt (systream,i)->seen) status.unseen++; /* kludge but probably good enough */ status.uidnext += systream->nmsgs; } MM_STATUS(stream,mbx,&status);/* pass status to main program */ if (tstream) mail_close (tstream); if (systream) mail_close (systream); return T; /* success */ } /* MTX mail open * Accepts: stream to open * Returns: stream on success, NIL on failure */ MAILSTREAM *mtx_open (MAILSTREAM *stream) { int fd,ld; char tmp[MAILTMPLEN]; blocknotify_t bn = (blocknotify_t) mail_parameters (NIL,GET_BLOCKNOTIFY,NIL); /* return prototype for OP_PROTOTYPE call */ if (!stream) return user_flags (&mtxproto); if (stream->local) fatal ("mtx recycle stream"); user_flags (stream); /* set up user flags */ /* canonicalize the mailbox name */ if (!mtx_file (tmp,stream->mailbox)) { sprintf (tmp,"Can't open - invalid name: %.80s",stream->mailbox); MM_LOG (tmp,ERROR); } if (stream->rdonly || (fd = open (tmp,O_RDWR,NIL)) < 0) { if ((fd = open (tmp,O_RDONLY,NIL)) < 0) { sprintf (tmp,"Can't open mailbox: %.80s",strerror (errno)); MM_LOG (tmp,ERROR); return NIL; } else if (!stream->rdonly) { /* got it, but readonly */ MM_LOG ("Can't get write access to mailbox, access is readonly",WARN); stream->rdonly = T; } } stream->local = fs_get (sizeof (MTXLOCAL)); LOCAL->fd = fd; /* bind the file */ LOCAL->buf = (char *) fs_get (CHUNKSIZE); LOCAL->buflen = CHUNKSIZE - 1; /* note if an INBOX or not */ stream->inbox = !compare_cstring (stream->mailbox,"INBOX"); fs_give ((void **) &stream->mailbox); stream->mailbox = cpystr (tmp); /* get shared parse permission */ if ((ld = lockfd (fd,tmp,LOCK_SH)) < 0) { MM_LOG ("Unable to lock open mailbox",ERROR); return NIL; } (*bn) (BLOCK_FILELOCK,NIL); flock (LOCAL->fd,LOCK_SH); /* lock the file */ (*bn) (BLOCK_NONE,NIL); unlockfd (ld,tmp); /* release shared parse permission */ LOCAL->filesize = 0; /* initialize parsed file size */ /* time not set up yet */ LOCAL->lastsnarf = LOCAL->filetime = 0; LOCAL->mustcheck = LOCAL->shouldcheck = NIL; stream->sequence++; /* bump sequence number */ /* parse mailbox */ stream->nmsgs = stream->recent = 0; if (mtx_ping (stream) && !stream->nmsgs) MM_LOG ("Mailbox is empty",(long) NIL); if (!LOCAL) return NIL; /* failure if stream died */ stream->perm_seen = stream->perm_deleted = stream->perm_flagged = stream->perm_answered = stream->perm_draft = stream->rdonly ? NIL : T; stream->perm_user_flags = stream->rdonly ? NIL : 0xffffffff; return stream; /* return stream to caller */ } /* MTX mail close * Accepts: MAIL stream * close options */ void mtx_close (MAILSTREAM *stream,long options) { if (stream && LOCAL) { /* only if a file is open */ int silent = stream->silent; stream->silent = T; /* note this stream is dying */ if (options & CL_EXPUNGE) mtx_expunge (stream,NIL,NIL); stream->silent = silent; /* restore previous status */ flock (LOCAL->fd,LOCK_UN); /* unlock local file */ close (LOCAL->fd); /* close the local file */ /* free local text buffer */ if (LOCAL->buf) fs_give ((void **) &LOCAL->buf); /* nuke the local data */ fs_give ((void **) &stream->local); stream->dtb = NIL; /* log out the DTB */ } } /* MTX mail fetch flags * Accepts: MAIL stream * sequence * option flags * Sniffs at file to see if some other process changed the flags */ void mtx_flags (MAILSTREAM *stream,char *sequence,long flags) { unsigned long i; if (mtx_ping (stream) && /* ping mailbox, get new status for messages */ ((flags & FT_UID) ? mail_uid_sequence (stream,sequence) : mail_sequence (stream,sequence))) for (i = 1; i <= stream->nmsgs; i++) if (mail_elt (stream,i)->sequence) mtx_elt (stream,i); } /* MTX mail fetch message header * Accepts: MAIL stream * message # to fetch * pointer to returned header text length * option flags * Returns: message header in RFC822 format */ char *mtx_header (MAILSTREAM *stream,unsigned long msgno,unsigned long *length, long flags) { *length = 0; /* default to empty */ if (flags & FT_UID) return "";/* UID call "impossible" */ /* get to header position */ lseek (LOCAL->fd,mtx_hdrpos (stream,msgno,length),L_SET); /* is buffer big enough? */ if (*length > LOCAL->buflen) { fs_give ((void **) &LOCAL->buf); LOCAL->buf = (char *) fs_get ((LOCAL->buflen = *length) + 1); } LOCAL->buf[*length] = '\0'; /* tie off string */ /* slurp the data */ read (LOCAL->fd,LOCAL->buf,*length); return (char *) LOCAL->buf; } /* MTX mail fetch message text (body only) * Accepts: MAIL stream * message # to fetch * pointer to returned header text length * option flags * Returns: T, always */ long mtx_text (MAILSTREAM *stream,unsigned long msgno,STRING *bs,long flags) { FDDATA d; unsigned long i,j; MESSAGECACHE *elt; /* UID call "impossible" */ if (flags & FT_UID) return NIL; elt = mtx_elt (stream,msgno); /* get message status */ /* if message not seen */ if (!(flags & FT_PEEK) && !elt->seen) { elt->seen = T; /* mark message as seen */ /* recalculate status */ mtx_update_status (stream,msgno,NIL); MM_FLAGS (stream,msgno); } /* find header position */ i = mtx_hdrpos (stream,msgno,&j); d.fd = LOCAL->fd; /* set up file descriptor */ d.pos = i + j; d.chunk = LOCAL->buf; /* initial buffer chunk */ d.chunksize = CHUNKSIZE; INIT (bs,fd_string,&d,elt->rfc822_size - j); return T; /* success */ } /* MTX mail modify flags * Accepts: MAIL stream * sequence * flag(s) * option flags */ void mtx_flag (MAILSTREAM *stream,char *sequence,char *flag,long flags) { time_t tp[2]; struct stat sbuf; if (!stream->rdonly) { /* make sure the update takes */ fsync (LOCAL->fd); fstat (LOCAL->fd,&sbuf); /* get current write time */ tp[1] = LOCAL->filetime = sbuf.st_mtime; tp[0] = time (0); /* make sure read comes after all that */ utime (stream->mailbox,tp); } } /* MTX mail per-message modify flags * Accepts: MAIL stream * message cache element */ void mtx_flagmsg (MAILSTREAM *stream,MESSAGECACHE *elt) { struct stat sbuf; /* maybe need to do a checkpoint? */ if (LOCAL->filetime && !LOCAL->shouldcheck) { fstat (LOCAL->fd,&sbuf); /* get current write time */ if (LOCAL->filetime < sbuf.st_mtime) LOCAL->shouldcheck = T; LOCAL->filetime = 0; /* don't do this test for any other messages */ } /* recalculate status */ mtx_update_status (stream,elt->msgno,NIL); } /* MTX mail ping mailbox * Accepts: MAIL stream * Returns: T if stream still alive, NIL if not */ long mtx_ping (MAILSTREAM *stream) { unsigned long i = 1; long r = T; int ld; char lock[MAILTMPLEN]; struct stat sbuf; if (stream && LOCAL) { /* only if stream already open */ fstat (LOCAL->fd,&sbuf); /* get current file poop */ if (LOCAL->filetime && !(LOCAL->mustcheck || LOCAL->shouldcheck) && (LOCAL->filetime < sbuf.st_mtime)) LOCAL->shouldcheck = T; /* check for changed message status */ if (LOCAL->mustcheck || LOCAL->shouldcheck) { LOCAL->filetime = sbuf.st_mtime; if (LOCAL->shouldcheck) /* babble when we do this unilaterally */ MM_NOTIFY (stream,"[CHECK] Checking for flag updates",NIL); while (i <= stream->nmsgs) mtx_elt (stream,i++); LOCAL->mustcheck = LOCAL->shouldcheck = NIL; } /* get shared parse/append permission */ if ((sbuf.st_size != LOCAL->filesize) && ((ld = lockfd (LOCAL->fd,lock,LOCK_SH)) >= 0)) { /* parse resulting mailbox */ r = (mtx_parse (stream)) ? T : NIL; unlockfd (ld,lock); /* release shared parse/append permission */ } if (LOCAL) { /* stream must still be alive */ /* snarf if this is a read-write inbox */ if (stream->inbox && !stream->rdonly) { mtx_snarf (stream); fstat (LOCAL->fd,&sbuf);/* see if file changed now */ if ((sbuf.st_size != LOCAL->filesize) && ((ld = lockfd (LOCAL->fd,lock,LOCK_SH)) >= 0)) { /* parse resulting mailbox */ r = (mtx_parse (stream)) ? T : NIL; unlockfd (ld,lock); /* release shared parse/append permission */ } } } } return r; /* return result of the parse */ } /* MTX mail check mailbox (reparses status too) * Accepts: MAIL stream */ void mtx_check (MAILSTREAM *stream) { /* mark that a check is desired */ if (LOCAL) LOCAL->mustcheck = T; if (mtx_ping (stream)) MM_LOG ("Check completed",(long) NIL); } /* MTX mail snarf messages from system inbox * Accepts: MAIL stream */ void mtx_snarf (MAILSTREAM *stream) { unsigned long i = 0; unsigned long j,r,hdrlen,txtlen; struct stat sbuf; char *hdr,*txt,lock[MAILTMPLEN],tmp[MAILTMPLEN]; MESSAGECACHE *elt; MAILSTREAM *sysibx = NIL; int ld; /* give up if can't get exclusive permission */ if ((time (0) >= (LOCAL->lastsnarf + (long) mail_parameters (NIL,GET_SNARFINTERVAL,NIL))) && strcmp (sysinbox (),stream->mailbox) && ((ld = lockfd (LOCAL->fd,lock,LOCK_EX)) >= 0)) { MM_CRITICAL (stream); /* go critical */ /* sizes match and anything in sysinbox? */ if (!stat (sysinbox (),&sbuf) && sbuf.st_size && !fstat (LOCAL->fd,&sbuf) && (sbuf.st_size == LOCAL->filesize) && (sysibx = mail_open (sysibx,sysinbox (),OP_SILENT)) && (!sysibx->rdonly) && (r = sysibx->nmsgs)) { /* yes, go to end of file in our mailbox */ lseek (LOCAL->fd,sbuf.st_size,L_SET); /* for each message in sysibx mailbox */ while (r && (++i <= sysibx->nmsgs)) { /* snarf message from system INBOX */ hdr = cpystr (mail_fetchheader_full (sysibx,i,NIL,&hdrlen,NIL)); txt = mail_fetchtext_full (sysibx,i,&txtlen,FT_PEEK); /* if have a message */ if (j = hdrlen + txtlen) { /* calculate header line */ mail_date (LOCAL->buf,elt = mail_elt (sysibx,i)); sprintf (LOCAL->buf + strlen (LOCAL->buf), ",%lu;0000000000%02o\015\012",j,(unsigned) ((fSEEN * elt->seen) + (fDELETED * elt->deleted) + (fFLAGGED * elt->flagged) + (fANSWERED * elt->answered) + (fDRAFT * elt->draft))); /* copy message */ if ((write (LOCAL->fd,LOCAL->buf,strlen (LOCAL->buf)) < 0) || (write (LOCAL->fd,hdr,hdrlen) < 0) || (write (LOCAL->fd,txt,txtlen) < 0)) r = 0; } fs_give ((void **) &hdr); } /* make sure all the updates take */ if (fsync (LOCAL->fd)) r = 0; if (r) { /* delete all the messages we copied */ if (r == 1) strcpy (tmp,"1"); else sprintf (tmp,"1:%lu",r); mail_flag (sysibx,tmp,"\\Deleted",ST_SET); mail_expunge (sysibx); /* now expunge all those messages */ } else { sprintf (LOCAL->buf,"Can't copy new mail: %s",strerror (errno)); MM_LOG (LOCAL->buf,WARN); ftruncate (LOCAL->fd,sbuf.st_size); } fstat (LOCAL->fd,&sbuf); /* yes, get current file size */ LOCAL->filetime = sbuf.st_mtime; } if (sysibx) mail_close (sysibx); MM_NOCRITICAL (stream); /* release critical */ unlockfd (ld,lock); /* release exclusive parse/append permission */ LOCAL->lastsnarf = time (0);/* note time of last snarf */ } } /* MTX mail expunge mailbox * Accepts: MAIL stream * sequence to expunge if non-NIL * expunge options * Returns: T, always */ long mtx_expunge (MAILSTREAM *stream,char *sequence,long options) { long ret; time_t tp[2]; struct stat sbuf; off_t pos = 0; int ld; unsigned long i = 1; unsigned long j,k,m,recent; unsigned long n = 0; unsigned long delta = 0; char lock[MAILTMPLEN]; MESSAGECACHE *elt; blocknotify_t bn = (blocknotify_t) mail_parameters (NIL,GET_BLOCKNOTIFY,NIL); if (!(ret = (sequence ? ((options & EX_UID) ? mail_uid_sequence (stream,sequence) : mail_sequence (stream,sequence)) : LONGT) && mtx_ping (stream))); /* parse sequence if given, ping stream */ else if (stream->rdonly) MM_LOG ("Expunge ignored on readonly mailbox",WARN); else { if (LOCAL->filetime && !LOCAL->shouldcheck) { fstat (LOCAL->fd,&sbuf); /* get current write time */ if (LOCAL->filetime < sbuf.st_mtime) LOCAL->shouldcheck = T; } /* The cretins who designed flock() created a window of vulnerability in * upgrading locks from shared to exclusive or downgrading from exclusive * to shared. Rather than maintain the lock at shared status at a minimum, * flock() actually *releases* the former lock. Obviously they never talked * to any database guys. Fortunately, we have the parse/append permission * lock. If we require this lock before going exclusive on the mailbox, * another process can not sneak in and steal the exclusive mailbox lock on * us, because it will block on trying to get parse/append permission first. */ /* get exclusive parse/append permission */ if ((ld = lockfd (LOCAL->fd,lock,LOCK_EX)) < 0) MM_LOG ("Unable to lock expunge mailbox",ERROR); /* make sure see any newly-arrived messages */ else if (!mtx_parse (stream)); /* get exclusive access */ else if (flock (LOCAL->fd,LOCK_EX|LOCK_NB)) { (*bn) (BLOCK_FILELOCK,NIL); flock (LOCAL->fd,LOCK_SH);/* recover previous lock */ (*bn) (BLOCK_NONE,NIL); MM_LOG ("Can't expunge because mailbox is in use by another process", ERROR); unlockfd (ld,lock); /* release exclusive parse/append permission */ } else { MM_CRITICAL (stream); /* go critical */ recent = stream->recent; /* get recent now that pinged and locked */ /* for each message */ while (i <= stream->nmsgs) { /* get cache element */ elt = mtx_elt (stream,i); /* number of bytes to smash or preserve */ k = elt->private.special.text.size + elt->rfc822_size; /* if need to expunge this message */ if (elt->deleted && (sequence ? elt->sequence : T)) { /* if recent, note one less recent message */ if (elt->recent) --recent; delta += k; /* number of bytes to delete */ /* notify upper levels */ mail_expunged (stream,i); n++; /* count up one more expunged message */ } else if (i++ && delta) {/* preserved message */ /* first byte to preserve */ j = elt->private.special.offset; do { /* read from source position */ m = min (k,LOCAL->buflen); lseek (LOCAL->fd,j,L_SET); read (LOCAL->fd,LOCAL->buf,m); pos = j - delta; /* write to destination position */ lseek (LOCAL->fd,pos,L_SET); while (T) { lseek (LOCAL->fd,pos,L_SET); if (write (LOCAL->fd,LOCAL->buf,m) > 0) break; MM_NOTIFY (stream,strerror (errno),WARN); MM_DISKERROR (stream,errno,T); } pos += m; /* new position */ j += m; /* next chunk, perhaps */ } while (k -= m); /* until done */ /* note the new address of this text */ elt->private.special.offset -= delta; } /* preserved but no deleted messages */ else pos = elt->private.special.offset + k; } if (n) { /* truncate file after last message */ if (pos != (LOCAL->filesize -= delta)) { sprintf (LOCAL->buf, "Calculated size mismatch %lu != %lu, delta = %lu", (unsigned long) pos,(unsigned long) LOCAL->filesize,delta); MM_LOG (LOCAL->buf,WARN); LOCAL->filesize = pos;/* fix it then */ } ftruncate (LOCAL->fd,LOCAL->filesize); sprintf (LOCAL->buf,"Expunged %lu messages",n); /* output the news */ MM_LOG (LOCAL->buf,(long) NIL); } else MM_LOG ("No messages deleted, so no update needed",(long) NIL); fsync (LOCAL->fd); /* force disk update */ fstat (LOCAL->fd,&sbuf); /* get new write time */ tp[1] = LOCAL->filetime = sbuf.st_mtime; tp[0] = time (0); /* reset atime to now */ utime (stream->mailbox,tp); MM_NOCRITICAL (stream); /* release critical */ /* notify upper level of new mailbox size */ mail_exists (stream,stream->nmsgs); mail_recent (stream,recent); (*bn) (BLOCK_FILELOCK,NIL); flock (LOCAL->fd,LOCK_SH);/* allow sharers again */ (*bn) (BLOCK_NONE,NIL); unlockfd (ld,lock); /* release exclusive parse/append permission */ } } return ret; } /* MTX mail copy message(s) * Accepts: MAIL stream * sequence * destination mailbox * copy options * Returns: T if success, NIL if failed */ long mtx_copy (MAILSTREAM *stream,char *sequence,char *mailbox,long options) { struct stat sbuf; time_t tp[2]; MESSAGECACHE *elt; unsigned long i,j,k; long ret = LONGT; int fd,ld; char file[MAILTMPLEN],lock[MAILTMPLEN]; mailproxycopy_t pc = (mailproxycopy_t) mail_parameters (stream,GET_MAILPROXYCOPY,NIL); /* make sure valid mailbox */ if (!mtx_isvalid (mailbox,LOCAL->buf)) switch (errno) { case ENOENT: /* no such file? */ MM_NOTIFY (stream,"[TRYCREATE] Must create mailbox before copy",NIL); return NIL; case 0: /* merely empty file? */ break; case EACCES: /* file protected */ sprintf (LOCAL->buf,"Can't access destination: %.80s",mailbox); MM_LOG (LOCAL->buf,ERROR); return NIL; case EINVAL: if (pc) return (*pc) (stream,sequence,mailbox,options); sprintf (LOCAL->buf,"Invalid MTX-format mailbox name: %.80s",mailbox); MM_LOG (LOCAL->buf,ERROR); return NIL; default: if (pc) return (*pc) (stream,sequence,mailbox,options); sprintf (LOCAL->buf,"Not a MTX-format mailbox: %.80s",mailbox); MM_LOG (LOCAL->buf,ERROR); return NIL; } if (!((options & CP_UID) ? mail_uid_sequence (stream,sequence) : mail_sequence (stream,sequence))) return NIL; /* got file? */ if ((fd = open (mtx_file (file,mailbox),O_RDWR,NIL)) < 0) { sprintf (LOCAL->buf,"Unable to open copy mailbox: %s",strerror (errno)); MM_LOG (LOCAL->buf,ERROR); return NIL; } MM_CRITICAL (stream); /* go critical */ /* get exclusive parse/append permission */ if (flock (fd,LOCK_SH) || ((ld = lockfd (fd,lock,LOCK_EX)) < 0)) { MM_LOG ("Unable to lock copy mailbox",ERROR); MM_NOCRITICAL (stream); return NIL; } fstat (fd,&sbuf); /* get current file size */ lseek (fd,sbuf.st_size,L_SET);/* move to end of file */ /* for each requested message */ for (i = 1; ret && (i <= stream->nmsgs); i++) if ((elt = mail_elt (stream,i))->sequence) { lseek (LOCAL->fd,elt->private.special.offset,L_SET); /* number of bytes to copy */ k = elt->private.special.text.size + elt->rfc822_size; do { /* read from source position */ j = min (k,LOCAL->buflen); read (LOCAL->fd,LOCAL->buf,j); if (write (fd,LOCAL->buf,j) < 0) ret = NIL; } while (ret && (k -= j));/* until done */ } /* make sure all the updates take */ if (!(ret && (ret = !fsync (fd)))) { sprintf (LOCAL->buf,"Unable to write message: %s",strerror (errno)); MM_LOG (LOCAL->buf,ERROR); ftruncate (fd,sbuf.st_size); } if (ret) tp[0] = time (0) - 1;/* set atime to now-1 if successful copy */ /* else preserve \Marked status */ else tp[0] = (sbuf.st_ctime > sbuf.st_atime) ? sbuf.st_atime : time(0); tp[1] = sbuf.st_mtime; /* preserve mtime */ utime (file,tp); /* set the times */ close (fd); /* close the file */ unlockfd (ld,lock); /* release exclusive parse/append permission */ MM_NOCRITICAL (stream); /* release critical */ /* delete all requested messages */ if (ret && (options & CP_MOVE)) { for (i = 1; i <= stream->nmsgs; i++) if ((elt = mtx_elt (stream,i))->sequence) { elt->deleted = T; /* mark message deleted */ /* recalculate status */ mtx_update_status (stream,i,NIL); } if (!stream->rdonly) { /* make sure the update takes */ fsync (LOCAL->fd); fstat (LOCAL->fd,&sbuf); /* get current write time */ tp[1] = LOCAL->filetime = sbuf.st_mtime; tp[0] = time (0); /* make sure atime remains greater */ utime (stream->mailbox,tp); } } if (ret && mail_parameters (NIL,GET_COPYUID,NIL)) MM_LOG ("Can not return meaningful COPYUID with this mailbox format",WARN); return ret; } /* MTX mail append message from stringstruct * Accepts: MAIL stream * destination mailbox * append callback * data for callback * Returns: T if append successful, else NIL */ long mtx_append (MAILSTREAM *stream,char *mailbox,append_t af,void *data) { struct stat sbuf; int fd,ld,c; char *flags,*date,tmp[MAILTMPLEN],file[MAILTMPLEN],lock[MAILTMPLEN]; time_t tp[2]; FILE *df; MESSAGECACHE elt; long f; unsigned long i,uf; STRING *message; long ret = LONGT; /* default stream to prototype */ if (!stream) stream = user_flags (&mtxproto); /* make sure valid mailbox */ if (!mtx_isvalid (mailbox,tmp)) switch (errno) { case ENOENT: /* no such file? */ if (!compare_cstring (mailbox,"INBOX")) dummy_create (NIL,"INBOX.MTX"); else { MM_NOTIFY (stream,"[TRYCREATE] Must create mailbox before append",NIL); return NIL; } /* falls through */ case 0: /* merely empty file? */ break; case EACCES: /* file protected */ sprintf (tmp,"Can't access destination: %.80s",mailbox); MM_LOG (tmp,ERROR); return NIL; case EINVAL: sprintf (tmp,"Invalid MTX-format mailbox name: %.80s",mailbox); MM_LOG (tmp,ERROR); return NIL; default: sprintf (tmp,"Not a MTX-format mailbox: %.80s",mailbox); MM_LOG (tmp,ERROR); return NIL; } /* get first message */ if (!MM_APPEND (af) (stream,data,&flags,&date,&message)) return NIL; /* open destination mailbox */ if (((fd = open (mtx_file (file,mailbox),O_WRONLY|O_APPEND,NIL)) < 0) || !(df = fdopen (fd,"ab"))) { sprintf (tmp,"Can't open append mailbox: %s",strerror (errno)); MM_LOG (tmp,ERROR); return NIL; } /* get parse/append permission */ if (flock (fd,LOCK_SH) || ((ld = lockfd (fd,lock,LOCK_EX)) < 0)) { MM_LOG ("Unable to lock append mailbox",ERROR); close (fd); return NIL; } MM_CRITICAL (stream); /* go critical */ fstat (fd,&sbuf); /* get current file size */ errno = 0; do { /* parse flags */ if (!SIZE (message)) { /* guard against zero-length */ MM_LOG ("Append of zero-length message",ERROR); ret = NIL; break; } f = mail_parse_flags (stream,flags,&i); /* reverse bits (dontcha wish we had CIRC?) */ for (uf = 0; i; uf |= 1 << (29 - find_rightmost_bit (&i))); if (date) { /* parse date if given */ if (!mail_parse_date (&elt,date)) { sprintf (tmp,"Bad date in append: %.80s",date); MM_LOG (tmp,ERROR); ret = NIL; /* mark failure */ break; } mail_date (tmp,&elt); /* write preseved date */ } else internal_date (tmp); /* get current date in IMAP format */ /* write header */ if (fprintf (df,"%s,%lu;%010lo%02lo\015\012",tmp,i = SIZE (message),uf, (unsigned long) f) < 0) ret = NIL; else { /* write message */ if (i) do c = 0xff & SNX (message); while ((putc (c,df) != EOF) && --i); /* get next message */ if (i || !MM_APPEND (af) (stream,data,&flags,&date,&message)) ret = NIL; } } while (ret && message); /* if error... */ if (!ret || (fflush (df) == EOF)) { ftruncate (fd,sbuf.st_size);/* revert file */ close (fd); /* make sure fclose() doesn't corrupt us */ if (errno) { sprintf (tmp,"Message append failed: %s",strerror (errno)); MM_LOG (tmp,ERROR); } ret = NIL; } if (ret) tp[0] = time (0) - 1;/* set atime to now-1 if successful copy */ /* else preserve \Marked status */ else tp[0] = (sbuf.st_ctime > sbuf.st_atime) ? sbuf.st_atime : time(0); tp[1] = sbuf.st_mtime; /* preserve mtime */ utime (file,tp); /* set the times */ fclose (df); /* close the file */ unlockfd (ld,lock); /* release exclusive parse/append permission */ MM_NOCRITICAL (stream); /* release critical */ if (ret && mail_parameters (NIL,GET_APPENDUID,NIL)) MM_LOG ("Can not return meaningful APPENDUID with this mailbox format", WARN); return ret; } /* Internal routines */ /* MTX mail generate file string * Accepts: temporary buffer to write into * mailbox name string * Returns: local file string or NIL if failure */ char *mtx_file (char *dst,char *name) { char tmp[MAILTMPLEN]; char *s = mailboxfile (dst,name); /* return our standard inbox */ return (s && !*s) ? mailboxfile (dst,mtx_isvalid ("~/INBOX",tmp) ? "~/INBOX" : "INBOX.MTX") : s; } /* MTX mail parse mailbox * Accepts: MAIL stream * Returns: T if parse OK * NIL if failure, stream aborted */ long mtx_parse (MAILSTREAM *stream) { struct stat sbuf; MESSAGECACHE *elt = NIL; unsigned char c,*s,*t,*x; char tmp[MAILTMPLEN]; unsigned long i,j; long curpos = LOCAL->filesize; long nmsgs = stream->nmsgs; long recent = stream->recent; short added = NIL; short silent = stream->silent; fstat (LOCAL->fd,&sbuf); /* get status */ if (sbuf.st_size < curpos) { /* sanity check */ sprintf (tmp,"Mailbox shrank from %lu to %lu!", (unsigned long) curpos,(unsigned long) sbuf.st_size); MM_LOG (tmp,ERROR); mtx_close (stream,NIL); return NIL; } stream->silent = T; /* don't pass up exists events yet */ while (sbuf.st_size - curpos){/* while there is stuff to parse */ /* get to that position in the file */ lseek (LOCAL->fd,curpos,L_SET); if ((i = read (LOCAL->fd,LOCAL->buf,64)) <= 0) { sprintf (tmp,"Unable to read internal header at %lu, size = %lu: %s", (unsigned long) curpos,(unsigned long) sbuf.st_size, i ? strerror (errno) : "no data read"); MM_LOG (tmp,ERROR); mtx_close (stream,NIL); return NIL; } LOCAL->buf[i] = '\0'; /* tie off buffer just in case */ if (!((s = strchr (LOCAL->buf,'\015')) && (s[1] == '\012'))) { sprintf (tmp,"Unable to find CRLF at %lu in %lu bytes, text: %s", (unsigned long) curpos,i,(char *) LOCAL->buf); MM_LOG (tmp,ERROR); mtx_close (stream,NIL); return NIL; } *s = '\0'; /* tie off header line */ i = (s + 2) - LOCAL->buf; /* note start of text offset */ if (!((s = strchr (LOCAL->buf,',')) && (t = strchr (s+1,';')))) { sprintf (tmp,"Unable to parse internal header at %lu: %s", (unsigned long) curpos,(char *) LOCAL->buf); MM_LOG (tmp,ERROR); mtx_close (stream,NIL); return NIL; } *s++ = '\0'; *t++ = '\0'; /* tie off fields */ added = T; /* note that a new message was added */ /* swell the cache */ mail_exists (stream,++nmsgs); /* instantiate an elt for this message */ (elt = mail_elt (stream,nmsgs))->valid = T; elt->private.uid = ++stream->uid_last; /* note file offset of header */ elt->private.special.offset = curpos; /* in case error */ elt->private.special.text.size = 0; /* header size not known yet */ elt->private.msg.header.text.size = 0; x = s; /* parse the header components */ if (mail_parse_date (elt,LOCAL->buf) && (elt->rfc822_size = strtoul (s,(char **) &s,10)) && (!(s && *s)) && isdigit (t[0]) && isdigit (t[1]) && isdigit (t[2]) && isdigit (t[3]) && isdigit (t[4]) && isdigit (t[5]) && isdigit (t[6]) && isdigit (t[7]) && isdigit (t[8]) && isdigit (t[9]) && isdigit (t[10]) && isdigit (t[11]) && !t[12]) elt->private.special.text.size = i; else { /* oops */ sprintf (tmp,"Unable to parse internal header elements at %ld: %s,%s;%s", curpos,(char *) LOCAL->buf,(char *) x,(char *) t); MM_LOG (tmp,ERROR); mtx_close (stream,NIL); return NIL; } /* make sure didn't run off end of file */ if ((curpos += (elt->rfc822_size + i)) > sbuf.st_size) { sprintf (tmp,"Last message (at %lu) runs past end of file (%lu > %lu)", elt->private.special.offset,(unsigned long) curpos, (unsigned long) sbuf.st_size); MM_LOG (tmp,ERROR); mtx_close (stream,NIL); return NIL; } c = t[10]; /* remember first system flags byte */ t[10] = '\0'; /* tie off flags */ j = strtoul (t,NIL,8); /* get user flags value */ t[10] = c; /* restore first system flags byte */ /* set up all valid user flags (reversed!) */ while (j) if (((i = 29 - find_rightmost_bit (&j)) < NUSERFLAGS) && stream->user_flags[i]) elt->user_flags |= 1 << i; /* calculate system flags */ if ((j = ((t[10]-'0') * 8) + t[11]-'0') & fSEEN) elt->seen = T; if (j & fDELETED) elt->deleted = T; if (j & fFLAGGED) elt->flagged = T; if (j & fANSWERED) elt->answered = T; if (j & fDRAFT) elt->draft = T; if (!(j & fOLD)) { /* newly arrived message? */ elt->recent = T; recent++; /* count up a new recent message */ /* mark it as old */ mtx_update_status (stream,nmsgs,NIL); } } fsync (LOCAL->fd); /* make sure all the fOLD flags take */ /* update parsed file size and time */ LOCAL->filesize = sbuf.st_size; fstat (LOCAL->fd,&sbuf); /* get status again to ensure time is right */ LOCAL->filetime = sbuf.st_mtime; if (added && !stream->rdonly){/* make sure atime updated */ time_t tp[2]; tp[0] = time (0); tp[1] = LOCAL->filetime; utime (stream->mailbox,tp); } stream->silent = silent; /* can pass up events now */ mail_exists (stream,nmsgs); /* notify upper level of new mailbox size */ mail_recent (stream,recent); /* and of change in recent messages */ return LONGT; /* return the winnage */ } /* MTX get cache element with status updating from file * Accepts: MAIL stream * message number * Returns: cache element */ MESSAGECACHE *mtx_elt (MAILSTREAM *stream,unsigned long msgno) { MESSAGECACHE *elt = mail_elt (stream,msgno); struct { /* old flags */ unsigned int seen : 1; unsigned int deleted : 1; unsigned int flagged : 1; unsigned int answered : 1; unsigned int draft : 1; unsigned long user_flags; } old; old.seen = elt->seen; old.deleted = elt->deleted; old.flagged = elt->flagged; old.answered = elt->answered; old.draft = elt->draft; old.user_flags = elt->user_flags; mtx_read_flags (stream,elt); if ((old.seen != elt->seen) || (old.deleted != elt->deleted) || (old.flagged != elt->flagged) || (old.answered != elt->answered) || (old.draft != elt->draft) || (old.user_flags != elt->user_flags)) MM_FLAGS (stream,msgno); /* let top level know */ return elt; } /* MTX read flags from file * Accepts: MAIL stream * Returns: cache element */ void mtx_read_flags (MAILSTREAM *stream,MESSAGECACHE *elt) { unsigned long i,j; /* noop if readonly and have valid flags */ if (stream->rdonly && elt->valid) return; /* set the seek pointer */ lseek (LOCAL->fd,(off_t) elt->private.special.offset + elt->private.special.text.size - 14,L_SET); /* read the new flags */ if (read (LOCAL->fd,LOCAL->buf,12) < 0) { sprintf (LOCAL->buf,"Unable to read new status: %s",strerror (errno)); fatal (LOCAL->buf); } /* calculate system flags */ i = (((LOCAL->buf[10]-'0') * 8) + LOCAL->buf[11]-'0'); elt->seen = i & fSEEN ? T : NIL; elt->deleted = i & fDELETED ? T : NIL; elt->flagged = i & fFLAGGED ? T : NIL; elt->answered = i & fANSWERED ? T : NIL; elt->draft = i & fDRAFT ? T : NIL; LOCAL->buf[10] = '\0'; /* tie off flags */ j = strtoul(LOCAL->buf,NIL,8);/* get user flags value */ /* set up all valid user flags (reversed!) */ while (j) if (((i = 29 - find_rightmost_bit (&j)) < NUSERFLAGS) && stream->user_flags[i]) elt->user_flags |= 1 << i; elt->valid = T; /* have valid flags now */ } /* MTX update status string * Accepts: MAIL stream * message number * flag saying whether or not to sync */ void mtx_update_status (MAILSTREAM *stream,unsigned long msgno,long syncflag) { time_t tp[2]; struct stat sbuf; MESSAGECACHE *elt = mail_elt (stream,msgno); unsigned long j,k = 0; /* readonly */ if (stream->rdonly || !elt->valid) mtx_read_flags (stream,elt); else { /* readwrite */ j = elt->user_flags; /* get user flags */ /* reverse bits (dontcha wish we had CIRC?) */ while (j) k |= 1 << (29 - find_rightmost_bit (&j)); /* print new flag string */ sprintf (LOCAL->buf,"%010lo%02o",k,(unsigned) (fOLD + (fSEEN * elt->seen) + (fDELETED * elt->deleted) + (fFLAGGED * elt->flagged) + (fANSWERED * elt->answered) + (fDRAFT * elt->draft))); /* get to that place in the file */ lseek (LOCAL->fd,(off_t) elt->private.special.offset + elt->private.special.text.size - 14,L_SET); /* write new flags */ write (LOCAL->fd,LOCAL->buf,12); if (syncflag) { /* sync if requested */ fsync (LOCAL->fd); fstat (LOCAL->fd,&sbuf); /* get new write time */ tp[1] = LOCAL->filetime = sbuf.st_mtime; tp[0] = time (0); /* make sure read is later */ utime (stream->mailbox,tp); } } } /* MTX locate header for a message * Accepts: MAIL stream * message number * pointer to returned header size * Returns: position of header in file */ unsigned long mtx_hdrpos (MAILSTREAM *stream,unsigned long msgno, unsigned long *size) { unsigned long siz; long i = 0; int q = 0; char *s,tmp[MAILTMPLEN]; MESSAGECACHE *elt = mtx_elt (stream,msgno); unsigned long ret = elt->private.special.offset + elt->private.special.text.size; /* is header size known? */ if (!(*size = elt->private.msg.header.text.size)) { lseek (LOCAL->fd,ret,L_SET);/* get to header position */ /* search message for CRLF CRLF */ for (siz = 1,s = tmp; siz <= elt->rfc822_size; siz++) { /* read another buffer as necessary */ if ((--i <= 0) && /* buffer empty? */ (read (LOCAL->fd,s = tmp, i = min (elt->rfc822_size - siz,(long) MAILTMPLEN)) < 0)) return ret; /* I/O error? */ switch (q) { /* sniff at buffer */ case 0: /* first character */ q = (*s++ == '\015') ? 1 : 0; break; case 1: /* second character */ q = (*s++ == '\012') ? 2 : 0; break; case 2: /* third character */ q = (*s++ == '\015') ? 3 : 0; break; case 3: /* fourth character */ if (*s++ == '\012') { /* have the sequence? */ /* yes, note for later */ elt->private.msg.header.text.size = *size = siz; return ret; } q = 0; /* lost... */ break; } } /* header consumes entire message */ elt->private.msg.header.text.size = *size = elt->rfc822_size; } return ret; } alpine-2.10+dfsg/imap/src/osdep/unix/flockcyg.c0000600000175000017500000000576711512502123023131 0ustar paulproteuspaulproteus/* ======================================================================== * Copyright 1988-2006 University of Washington * * Licensed under the Apache License, Version 2.0 (the "License"); * you may not use this file except in compliance with the License. * You may obtain a copy of the License at * * http://www.apache.org/licenses/LICENSE-2.0 * * * ======================================================================== */ /* * Program: flock emulation via fcntl() locking * * Author: Mark Crispin * Networks and Distributed Computing * Computing & Communications * University of Washington * Administration Building, AG-44 * Seattle, WA 98195 * Internet: MRC@CAC.Washington.EDU * * Date: 10 April 2001 * Last Edited: 30 August 2006 */ /* Cygwin does not seem to have the design flaw in fcntl() locking that * most other systems do (see flocksim.c for details). If some cretin * decides to implement that design flaw, then Cygwin will have to use * flocksim. Also, we don't test NFS either. * * However, Cygwin does have the Windows misfeature (introduced in NT 4.0) * that you can not write to any segment which has a shared lock, and you * can't lock a zero-byte segment either. This screws up the shared-write * mailbox drivers (mbx, mtx, mx, and tenex). As a workaround, we'll only * lock the first byte of the file, meaning that you can't write that byte * shared. It's been suggested to lock the maximum off_t type, but that * risks having a future version of Windows (or Cygwin) deciding that this * also means "no lock". */ #undef flock /* name is used as a struct for fcntl */ /* Emulator for flock() call * Accepts: file descriptor * operation bitmask * Returns: 0 if successful, -1 if failure under BSD conditions */ int flocksim (int fd,int op) { char tmp[MAILTMPLEN]; int logged = 0; struct flock fl; /* lock one bytes at byte 0 */ fl.l_whence = SEEK_SET; fl.l_start = 0; fl.l_len = 1; fl.l_pid = getpid (); /* shouldn't be necessary */ switch (op & ~LOCK_NB) { /* translate to fcntl() operation */ case LOCK_EX: /* exclusive */ fl.l_type = F_WRLCK; break; case LOCK_SH: /* shared */ fl.l_type = F_RDLCK; break; case LOCK_UN: /* unlock */ fl.l_type = F_UNLCK; break; default: /* default */ errno = EINVAL; return -1; } while (fcntl (fd,(op & LOCK_NB) ? F_SETLK : F_SETLKW,&fl)) if (errno != EINTR) { /* Can't use switch here because these error codes may resolve to the * same value on some systems. */ if ((errno != EWOULDBLOCK) && (errno != EAGAIN) && (errno != EACCES)) { sprintf (tmp,"Unexpected file locking failure: %s",strerror (errno)); /* give the user a warning of what happened */ MM_NOTIFY (NIL,tmp,WARN); if (!logged++) syslog (LOG_ERR,"%s",tmp); if (op & LOCK_NB) return -1; sleep (5); /* slow things down for loops */ } /* return failure for non-blocking lock */ else if (op & LOCK_NB) return -1; } return 0; /* success */ } alpine-2.10+dfsg/imap/src/osdep/unix/os_slx.c0000600000175000017500000000265311512502123022626 0ustar paulproteuspaulproteus/* ======================================================================== * Copyright 1988-2007 University of Washington * * Licensed under the Apache License, Version 2.0 (the "License"); * you may not use this file except in compliance with the License. * You may obtain a copy of the License at * * http://www.apache.org/licenses/LICENSE-2.0 * * * ======================================================================== */ /* * Program: Operating-system dependent routines -- modern Linux version * * Author: Mark Crispin * Networks and Distributed Computing * Computing & Communications * University of Washington * Administration Building, AG-44 * Seattle, WA 98195 * Internet: MRC@CAC.Washington.EDU * * Date: 1 August 1993 * Last Edited: 16 August 2007 */ #include "tcp_unix.h" /* must be before osdep includes tcp.h */ #include "mail.h" #include "osdep.h" #include #include #include #include #include #include #include #include #include extern int errno; /* just in case */ #include #include #include "misc.h" #include "fs_unix.c" #include "ftl_unix.c" #include "nl_unix.c" #include "env_unix.c" #include "getspnam.c" /* has socklen_t in spite of man page?? */ #define fork vfork #include "tcp_unix.c" #include "gr_waitp.c" #include "tz_sv4.c" #include "flocklnx.c" alpine-2.10+dfsg/imap/src/osdep/unix/os_aix.c0000600000175000017500000000277411512502123022605 0ustar paulproteuspaulproteus/* ======================================================================== * Copyright 1988-2007 University of Washington * * Licensed under the Apache License, Version 2.0 (the "License"); * you may not use this file except in compliance with the License. * You may obtain a copy of the License at * * http://www.apache.org/licenses/LICENSE-2.0 * * * ======================================================================== */ /* * Program: Operating-system dependent routines -- AIX version * * Author: Mark Crispin * Networks and Distributed Computing * Computing & Communications * University of Washington * Administration Building, AG-44 * Seattle, WA 98195 * Internet: MRC@CAC.Washington.EDU * * Date: 1 August 1988 * Last Edited: 16 August 2007 */ #include "tcp_unix.h" /* must be before osdep includes tcp.h */ #include "mail.h" #include "osdep.h" #include #include #include #include #include #include #include #include #include extern int errno; /* just in case */ #include #include "misc.h" char *crypt (char *key,char *salt); extern long timezone; extern int daylight; extern char *tzname[2]; extern int sys_nerr; extern char *sys_errlist[]; #include "fs_unix.c" #include "ftl_unix.c" #include "nl_unix.c" #include "env_unix.c" #define fork vfork #include "tcp_unix.c" #include "gr_waitp.c" #include "memmove.c" #include "strerror.c" #include "tz_sv4.c" alpine-2.10+dfsg/imap/src/osdep/unix/nl_unix.c0000600000175000017500000000507711512502123022776 0ustar paulproteuspaulproteus/* ======================================================================== * Copyright 1988-2006 University of Washington * * Licensed under the Apache License, Version 2.0 (the "License"); * you may not use this file except in compliance with the License. * You may obtain a copy of the License at * * http://www.apache.org/licenses/LICENSE-2.0 * * * ======================================================================== */ /* * Program: UNIX/VMS newline routines * * Author: Mark Crispin * Networks and Distributed Computing * Computing & Communications * University of Washington * Administration Building, AG-44 * Seattle, WA 98195 * Internet: MRC@CAC.Washington.EDU * * Date: 1 August 1988 * Last Edited: 30 August 2006 */ /* Copy string with CRLF newlines * Accepts: destination string * pointer to size of destination string buffer * source string * length of source string * Returns: length of copied string */ unsigned long strcrlfcpy (unsigned char **dst,unsigned long *dstl, unsigned char *src,unsigned long srcl) { long i = srcl * 2,j; unsigned char c,*d = src; if (*dst) { /* candidate destination provided? */ /* count NLs if doesn't fit worst-case */ if (i > *dstl) for (i = j = srcl; j; --j) if (*d++ == '\012') i++; /* still too small, must reset destination */ if (i > *dstl) fs_give ((void **) dst); } /* make a new buffer if needed */ if (!*dst) *dst = (char *) fs_get ((*dstl = i) + 1); d = *dst; /* destination string */ if (srcl) do { /* main copy loop */ if ((c = *src++) < '\016') { /* prepend CR to LF */ if (c == '\012') *d++ = '\015'; /* unlikely CR */ else if ((c == '\015') && (srcl > 1) && (*src == '\012')) { *d++ = c; /* copy the CR */ c = *src++; /* grab the LF */ --srcl; /* adjust the count */ } } *d++ = c; /* copy character */ } while (--srcl); *d = '\0'; /* tie off destination */ return d - *dst; /* return length */ } /* Length of string after strcrlfcpy applied * Accepts: source string * Returns: length of string */ unsigned long strcrlflen (STRING *s) { unsigned long pos = GETPOS (s); unsigned long i = SIZE (s); unsigned long j = i; while (j--) switch (SNX (s)) {/* search for newlines */ case '\015': /* unlikely carriage return */ if (j && (CHR (s) == '\012')) { SNX (s); /* eat the line feed */ j--; } break; case '\012': /* line feed? */ i++; default: /* ordinary chararacter */ break; } SETPOS (s,pos); /* restore old position */ return i; } alpine-2.10+dfsg/imap/src/osdep/unix/os_sco.h0000600000175000017500000000341711512502123022610 0ustar paulproteuspaulproteus/* ======================================================================== * Copyright 1988-2006 University of Washington * * Licensed under the Apache License, Version 2.0 (the "License"); * you may not use this file except in compliance with the License. * You may obtain a copy of the License at * * http://www.apache.org/licenses/LICENSE-2.0 * * * ======================================================================== */ /* * Program: Operating-system dependent routines -- SCO Unix version * * Author: Mark Crispin * Networks and Distributed Computing * Computing & Communications * University of Washington * Administration Building, AG-44 * Seattle, WA 98195 * Internet: MRC@CAC.Washington.EDU * * Date: 1 August 1988 * Last Edited: 20 December 2006 */ #include #include #include #include #include #include #include #include #include #include #include #include /* SCO gets this wrong */ #define setpgrp Setpgrp int Setpgrp (int pid,int gid); #define rename Rename /* Different names, equivalent things in BSD and SysV */ #define L_SET SEEK_SET #define L_INCR SEEK_CUR #define L_XTND SEEK_END #define direct dirent #define utime portable_utime int portable_utime (char *file,time_t timep[2]); #define ftruncate chsize #define random rand long gethostid (void); typedef int (*select_t) (struct direct *name); typedef int (*compar_t) (void *d1,void *d2); int scandir (char *dirname,struct direct ***namelist,select_t select, compar_t compar); int alphasort (void *d1,void *d2); int fsync (int fd); #include "env_unix.h" #include "fs.h" #include "ftl.h" #include "nl.h" #include "tcp.h" #include "flocksim.h" alpine-2.10+dfsg/imap/src/osdep/unix/os_cvx.h0000600000175000017500000000213111512502123022614 0ustar paulproteuspaulproteus/* ======================================================================== * Copyright 1988-2006 University of Washington * * Licensed under the Apache License, Version 2.0 (the "License"); * you may not use this file except in compliance with the License. * You may obtain a copy of the License at * * http://www.apache.org/licenses/LICENSE-2.0 * * * ======================================================================== */ /* * Program: Operating-system dependent routines -- Convex version * * Author: Mark Crispin * Networks and Distributed Computing * Computing & Communications * University of Washington * Administration Building, AG-44 * Seattle, WA 98195 * Internet: MRC@CAC.Washington.EDU * * Date: 11 May 1989 * Last Edited: 30 August 2006 */ #include #include #include #include #include #include #include void *malloc (size_t byteSize); void *realloc (void *oldptr,size_t newsize); #include "env_unix.h" #include "fs.h" #include "ftl.h" #include "nl.h" #include "tcp.h" alpine-2.10+dfsg/imap/src/osdep/unix/ckp_ult.c0000600000175000017500000000210511512502123022750 0ustar paulproteuspaulproteus/* ======================================================================== * Copyright 1988-2006 University of Washington * * Licensed under the Apache License, Version 2.0 (the "License"); * you may not use this file except in compliance with the License. * You may obtain a copy of the License at * * http://www.apache.org/licenses/LICENSE-2.0 * * * ======================================================================== */ /* * Program: ULTRIX check password * * Author: Mark Crispin * Networks and Distributed Computing * Computing & Communications * University of Washington * Administration Building, AG-44 * Seattle, WA 98195 * Internet: MRC@CAC.Washington.EDU * * Date: 1 August 1988 * Last Edited: 30 August 2006 */ /* Check password * Accepts: login passwd struct * password string * argument count * argument vector * Returns: passwd struct if password validated, NIL otherwise */ struct passwd *checkpw (struct passwd *pw,char *pass,int argc,char *argv[]) { return (authenticate_user (pw,pass,NIL) >= 0) ? pw : NIL; } alpine-2.10+dfsg/imap/src/osdep/unix/ckp_cyg.c0000600000175000017500000000341412074110156022737 0ustar paulproteuspaulproteus/* ======================================================================== * Copyright 1988-2006 University of Washington * * Licensed under the Apache License, Version 2.0 (the "License"); * you may not use this file except in compliance with the License. * You may obtain a copy of the License at * * http://www.apache.org/licenses/LICENSE-2.0 * * * ======================================================================== */ /* * Program: Cygwin check password * * Author: Mark Crispin * Networks and Distributed Computing * Computing & Communications * University of Washington * Administration Building, AG-44 * Seattle, WA 98195 * Internet: MRC@CAC.Washington.EDU * * Date: 1 August 1988 * Last Edited: 30 August 2006 */ /* This module is against my better judgement. If you want to run an imapd * or ipop[23]d you should use the native NT or W2K ports intead of this * Cygwin port. There is no surety that this module works right or will work * right in the future. */ #undef ERROR #define NOCRYPT #include #include /* Check password * Accepts: login passwd struct * password string * argument count * argument vector * Returns: passwd struct if password validated, NIL otherwise */ static char *cyg_user = NIL; static HANDLE cyg_hdl = NIL; struct passwd *checkpw (struct passwd *pw,char *pass,int argc,char *argv[]) { /* flush last pw-checked user */ if (cyg_user) fs_give ((void **) &cyg_user); /* forbid if UID 0 or SYSTEM uid */ if (!pw->pw_uid || (pw->pw_uid == SYSTEMUID) || ((cyg_hdl = cygwin_logon_user (pw,pass)) == INVALID_HANDLE_VALUE)) return NIL; /* bad UID or password */ /* remember user for this handle */ cyg_user = cpystr (pw->pw_name); return pw; } alpine-2.10+dfsg/imap/src/osdep/unix/gr_waitp.c0000600000175000017500000000207111512502123023125 0ustar paulproteuspaulproteus/* ======================================================================== * Copyright 1988-2006 University of Washington * * Licensed under the Apache License, Version 2.0 (the "License"); * you may not use this file except in compliance with the License. * You may obtain a copy of the License at * * http://www.apache.org/licenses/LICENSE-2.0 * * * ======================================================================== */ /* * Program: UNIX Grim PID Reaper -- waitpid() version * * Author: Mark Crispin * Networks and Distributed Computing * Computing & Communications * University of Washington * Administration Building, AG-44 * Seattle, WA 98195 * Internet: MRC@CAC.Washington.EDU * * Date: 30 November 1993 * Last Edited: 30 August 2006 */ /* Grim PID reaper * Accepts: process ID * kill request flag * status return value */ void grim_pid_reap_status (int pid,int killreq,void *status) { if (killreq) kill(pid,SIGHUP);/* kill if not already dead */ while ((waitpid (pid,status,NIL) < 0) && (errno != ECHILD)); } alpine-2.10+dfsg/imap/src/osdep/unix/os_vu2.c0000600000175000017500000000401711512502123022530 0ustar paulproteuspaulproteus/* ======================================================================== * Copyright 1988-2007 University of Washington * * Licensed under the Apache License, Version 2.0 (the "License"); * you may not use this file except in compliance with the License. * You may obtain a copy of the License at * * http://www.apache.org/licenses/LICENSE-2.0 * * * ======================================================================== */ /* * Program: Operating-system dependent routines -- VAX Ultrix 2.3 version * * Author: Mark Crispin * Networks and Distributed Computing * Computing & Communications * University of Washington * Administration Building, AG-44 * Seattle, WA 98195 * * Date: 11 May 1989 * Last Edited: 16 August 2007 */ #include "tcp_unix.h" /* must be before osdep includes tcp.h */ #include "mail.h" #include "osdep.h" #include #include #include #include #include #include #include #include #include extern int errno; /* just in case */ #include #include "misc.h" #define NFDBITS (sizeof(long) * 8) #define FD_SET(n, p) ((p)->fds_bits[(n)/NFDBITS] |= \ (1 << ((n) % NFDBITS))) #define FD_CLR(n, p) ((p)->fds_bits[(n)/NFDBITS] &= \ ~(1 << ((n) % NFDBITS))) #define FD_ISSET(n, p) ((p)->fds_bits[(n)/NFDBITS] & \ (1 << ((n) % NFDBITS))) #define FD_ZERO(p) bzero((char *)(p), sizeof(*(p))) /* Old Ultrix has its own wierd inet_addr() that returns a in_addr struct. */ /* Portable inet_addr () that returns a u_long * Accepts: dotted host string * Returns: u_long */ u_long portable_inet_addr (char *hostname) { struct in_addr *in = &inet_addr (hostname); return in->s_addr; } #define inet_addr portable_inet_addr #include "fs_unix.c" #include "ftl_unix.c" #include "nl_unix.c" #include "env_unix.c" #define fork vfork #include "tcp_unix.c" #include "gr_wait.c" #include "memmove.c" #include "strerror.c" #include "strstr.c" #include "strtoul.c" #include "tz_nul.c" alpine-2.10+dfsg/imap/src/osdep/unix/os_aux.h0000600000175000017500000000227511512502123022622 0ustar paulproteuspaulproteus/* ======================================================================== * Copyright 1988-2006 University of Washington * * Licensed under the Apache License, Version 2.0 (the "License"); * you may not use this file except in compliance with the License. * You may obtain a copy of the License at * * http://www.apache.org/licenses/LICENSE-2.0 * * * ======================================================================== */ /* * Program: Operating-system dependent routines -- A/UX version * * Author: Mark Crispin * Networks and Distributed Computing * Computing & Communications * University of Washington * Administration Building, AG-44 * Seattle, WA 98195 * Internet: MRC@CAC.Washington.EDU * * Date: 11 May 1989 * Last Edited: 30 August 2006 */ #include #include #include #include #include #include #include #include extern int errno; char *strerror (int n); unsigned long strtoul (char *s,char **endp,int base); void *memmove (void *s,void *ct,size_t n); #include "env_unix.h" #include "fs.h" #include "ftl.h" #include "nl.h" #include "tcp.h" #include "flocksim.h" alpine-2.10+dfsg/imap/src/osdep/unix/os_mnt.c0000600000175000017500000000246711512502123022621 0ustar paulproteuspaulproteus/* ======================================================================== * Copyright 1988-2007 University of Washington * * Licensed under the Apache License, Version 2.0 (the "License"); * you may not use this file except in compliance with the License. * You may obtain a copy of the License at * * http://www.apache.org/licenses/LICENSE-2.0 * * * ======================================================================== */ /* * Program: Operating-system dependent routines -- Mint version * * Author: Mark Crispin * Networks and Distributed Computing * Computing & Communications * University of Washington * Administration Building, AG-44 * Seattle, WA 98195 * Internet: MRC@CAC.Washington.EDU * * Date: 1 August 1988 * Last Edited: 16 August 2007 */ #include "tcp_unix.h" /* must be before osdep includes tcp.h */ #include "mail.h" #include "osdep.h" #include #include #include #include #include #include #include #include #include extern int errno; /* just in case */ #include #include "misc.h" #include "fs_unix.c" #include "ftl_unix.c" #include "nl_unix.c" #include "env_unix.c" #define fork vfork #include "tcp_unix.c" #include "gr_waitp.c" #include "tz_nul.c" alpine-2.10+dfsg/imap/src/osdep/unix/mmdf.c0000600000175000017500000026254111512502123022246 0ustar paulproteuspaulproteus/* ======================================================================== * Copyright 1988-2008 University of Washington * * Licensed under the Apache License, Version 2.0 (the "License"); * you may not use this file except in compliance with the License. * You may obtain a copy of the License at * * http://www.apache.org/licenses/LICENSE-2.0 * * * ======================================================================== */ /* * Program: MMDF mail routines * * Author: Mark Crispin * UW Technology * University of Washington * Seattle, WA 98195 * Internet: MRC@Washington.EDU * * Date: 20 December 1989 * Last Edited: 27 March 2008 */ #include #include #include extern int errno; /* just in case */ #include #include "mail.h" #include "osdep.h" #include #include #include "pseudo.h" #include "fdstring.h" #include "misc.h" #include "dummy.h" /* Supposedly, this page has everything the MMDF driver needs to know about * the MMDF delimiter. By changing these macros, the MMDF driver should * change with it. Note that if you change the length of MMDFHDRTXT you * also need to change the ISMMDF and RETIFMMDFWRD macros to reflect the new * size. */ /* Useful MMDF constants */ #define MMDFCHR '\01' /* MMDF character */ #define MMDFCHRS 0x01010101 /* MMDF header character spread in a word */ /* MMDF header text */ #define MMDFHDRTXT "\01\01\01\01\n" /* length of MMDF header text */ #define MMDFHDRLEN (sizeof (MMDFHDRTXT) - 1) /* Validate MMDF header * Accepts: pointer to candidate string to validate as an MMDF header * Returns: T if valid; else NIL */ #define ISMMDF(s) \ ((*(s) == MMDFCHR) && ((s)[1] == MMDFCHR) && ((s)[2] == MMDFCHR) && \ ((s)[3] == MMDFCHR) && ((s)[4] == '\n')) /* Return if a 32-bit word has the start of an MMDF header * Accepts: pointer to word of four bytes to validate as an MMDF header * Returns: pointer to MMDF header, else proceeds */ #define RETIFMMDFWRD(s) { \ if (s[3] == MMDFCHR) { \ if ((s[4] == MMDFCHR) && (s[5] == MMDFCHR) && (s[6] == MMDFCHR) && \ (s[7] == '\n')) return s + 3; \ else if (s[2] == MMDFCHR) { \ if ((s[4] == MMDFCHR) && (s[5] == MMDFCHR) && (s[6] == '\n')) \ return s + 2; \ else if (s[1] == MMDFCHR) { \ if ((s[4] == MMDFCHR) && (s[5] == '\n')) return s + 1; \ else if ((*s == MMDFCHR) && (s[4] == '\n')) return s; \ } \ } \ } \ } /* Validate line * Accepts: pointer to candidate string to validate as a From header * return pointer to end of date/time field * return pointer to offset from t of time (hours of ``mmm dd hh:mm'') * return pointer to offset from t of time zone (if non-zero) * Returns: t,ti,zn set if valid From string, else ti is NIL */ #define VALID(s,x,ti,zn) { \ ti = 0; \ if ((*s == 'F') && (s[1] == 'r') && (s[2] == 'o') && (s[3] == 'm') && \ (s[4] == ' ')) { \ for (x = s + 5; *x && *x != '\n'; x++); \ if (*x) { \ if (x - s >= 41) { \ for (zn = -1; x[zn] != ' '; zn--); \ if ((x[zn-1] == 'm') && (x[zn-2] == 'o') && (x[zn-3] == 'r') && \ (x[zn-4] == 'f') && (x[zn-5] == ' ') && (x[zn-6] == 'e') && \ (x[zn-7] == 't') && (x[zn-8] == 'o') && (x[zn-9] == 'm') && \ (x[zn-10] == 'e') && (x[zn-11] == 'r') && (x[zn-12] == ' '))\ x += zn - 12; \ } \ if (x - s >= 27) { \ if (x[-5] == ' ') { \ if (x[-8] == ':') zn = 0,ti = -5; \ else if (x[-9] == ' ') ti = zn = -9; \ else if ((x[-11] == ' ') && ((x[-10]=='+') || (x[-10]=='-'))) \ ti = zn = -11; \ } \ else if (x[-4] == ' ') { \ if (x[-9] == ' ') zn = -4,ti = -9; \ } \ else if (x[-6] == ' ') { \ if ((x[-11] == ' ') && ((x[-5] == '+') || (x[-5] == '-'))) \ zn = -6,ti = -11; \ } \ if (ti && !((x[ti - 3] == ':') && \ (x[ti -= ((x[ti - 6] == ':') ? 9 : 6)] == ' ') && \ (x[ti - 3] == ' ') && (x[ti - 7] == ' ') && \ (x[ti - 11] == ' '))) ti = 0; \ } \ } \ } \ } /* You are not expected to understand this macro, but read the next page if * you are not faint of heart. * * Known formats to the VALID macro are: * From user Wed Dec 2 05:53 1992 * BSD From user Wed Dec 2 05:53:22 1992 * SysV From user Wed Dec 2 05:53 PST 1992 * rn From user Wed Dec 2 05:53:22 PST 1992 * From user Wed Dec 2 05:53 -0700 1992 * emacs From user Wed Dec 2 05:53:22 -0700 1992 * From user Wed Dec 2 05:53 1992 PST * From user Wed Dec 2 05:53:22 1992 PST * From user Wed Dec 2 05:53 1992 -0700 * Solaris From user Wed Dec 2 05:53:22 1992 -0700 * * Plus all of the above with `` remote from xxx'' after it. Thank you very * much, smail and Solaris, for making my life considerably more complicated. */ /* * What? You want to understand the VALID macro anyway? Alright, since you * insist. Actually, it isn't really all that difficult, provided that you * take it step by step. * * Line 1 Initializes the return ti value to failure (0); * Lines 2-3 Validates that the 1st-5th characters are ``From ''. * Lines 4-5 Validates that there is an end of line and points x at it. * Lines 6-13 First checks to see if the line is at least 41 characters long. * If so, it scans backwards to find the rightmost space. From * that point, it scans backwards to see if the string matches * `` remote from''. If so, it sets x to point to the space at * the start of the string. * Line 14 Makes sure that there are at least 27 characters in the line. * Lines 15-20 Checks if the date/time ends with the year (there is a space * five characters back). If there is a colon three characters * further back, there is no timezone field, so zn is set to 0 * and ti is set in front of the year. Otherwise, there must * either to be a space four characters back for a three-letter * timezone, or a space six characters back followed by a + or - * for a numeric timezone; in either case, zn and ti become the * offset of the space immediately before it. * Lines 21-23 Are the failure case for line 14. If there is a space four * characters back, it is a three-letter timezone; there must be a * space for the year nine characters back. zn is the zone * offset; ti is the offset of the space. * Lines 24-27 Are the failure case for line 20. If there is a space six * characters back, it is a numeric timezone; there must be a * space eleven characters back and a + or - five characters back. * zn is the zone offset; ti is the offset of the space. * Line 28-31 If ti is valid, make sure that the string before ti is of the * form www mmm dd hh:mm or www mmm dd hh:mm:ss, otherwise * invalidate ti. There must be a colon three characters back * and a space six or nine characters back (depending upon * whether or not the character six characters back is a colon). * There must be a space three characters further back (in front * of the day), one seven characters back (in front of the month), * and one eleven characters back (in front of the day of week). * ti is set to be the offset of the space before the time. * * Why a macro? It gets invoked a *lot* in a tight loop. On some of the * newer pipelined machines it is faster being open-coded than it would be if * subroutines are called. * * Why does it scan backwards from the end of the line, instead of doing the * much easier forward scan? There is no deterministic way to parse the * ``user'' field, because it may contain unquoted spaces! Yes, I tested it to * see if unquoted spaces were possible. They are, and I've encountered enough * evil mail to be totally unwilling to trust that ``it will never happen''. */ /* Build parameters */ #define KODRETRY 15 /* kiss-of-death retry in seconds */ #define LOCKTIMEOUT 5 /* lock timeout in minutes */ /* MMDF I/O stream local data */ typedef struct mmdf_local { unsigned int dirty : 1; /* disk copy needs updating */ unsigned int ddirty : 1; /* double-dirty, ping becomes checkpoint */ unsigned int pseudo : 1; /* uses a pseudo message */ unsigned int appending : 1; /* don't mark new messages as old */ int fd; /* mailbox file descriptor */ int ld; /* lock file descriptor */ char *lname; /* lock file name */ off_t filesize; /* file size parsed */ time_t filetime; /* last file time */ unsigned char *buf; /* temporary buffer */ unsigned long buflen; /* current size of temporary buffer */ unsigned long uid; /* current text uid */ SIZEDTEXT text; /* current text */ unsigned long textlen; /* current text length */ char *line; /* returned line */ char *linebuf; /* line readin buffer */ unsigned long linebuflen; /* current line readin buffer length */ } MMDFLOCAL; /* Convenient access to local data */ #define LOCAL ((MMDFLOCAL *) stream->local) /* MMDF protected file structure */ typedef struct mmdf_file { MAILSTREAM *stream; /* current stream */ off_t curpos; /* current file position */ off_t protect; /* protected position */ off_t filepos; /* current last written file position */ char *buf; /* overflow buffer */ size_t buflen; /* current overflow buffer length */ char *bufpos; /* current buffer position */ } MMDFFILE; /* Function prototypes */ DRIVER *mmdf_valid (char *name); long mmdf_isvalid (char *name,char *tmp); long mmdf_isvalid_fd (int fd,char *tmp); void *mmdf_parameters (long function,void *value); void mmdf_scan (MAILSTREAM *stream,char *ref,char *pat,char *contents); void mmdf_list (MAILSTREAM *stream,char *ref,char *pat); void mmdf_lsub (MAILSTREAM *stream,char *ref,char *pat); long mmdf_create (MAILSTREAM *stream,char *mailbox); long mmdf_delete (MAILSTREAM *stream,char *mailbox); long mmdf_rename (MAILSTREAM *stream,char *old,char *newname); MAILSTREAM *mmdf_open (MAILSTREAM *stream); void mmdf_close (MAILSTREAM *stream,long options); char *mmdf_header (MAILSTREAM *stream,unsigned long msgno, unsigned long *length,long flags); long mmdf_text (MAILSTREAM *stream,unsigned long msgno,STRING *bs,long flags); char *mmdf_text_work (MAILSTREAM *stream,MESSAGECACHE *elt, unsigned long *length,long flags); void mmdf_flagmsg (MAILSTREAM *stream,MESSAGECACHE *elt); long mmdf_ping (MAILSTREAM *stream); void mmdf_check (MAILSTREAM *stream); long mmdf_expunge (MAILSTREAM *stream,char *sequence,long options); long mmdf_copy (MAILSTREAM *stream,char *sequence,char *mailbox,long options); long mmdf_append (MAILSTREAM *stream,char *mailbox,append_t af,void *data); int mmdf_collect_msg (MAILSTREAM *stream,FILE *sf,char *flags,char *date, STRING *msg); int mmdf_append_msgs (MAILSTREAM *stream,FILE *sf,FILE *df,SEARCHSET *set); void mmdf_abort (MAILSTREAM *stream); char *mmdf_file (char *dst,char *name); int mmdf_lock (char *file,int flags,int mode,DOTLOCK *lock,int op); void mmdf_unlock (int fd,MAILSTREAM *stream,DOTLOCK *lock); int mmdf_parse (MAILSTREAM *stream,DOTLOCK *lock,int op); char *mmdf_mbxline (MAILSTREAM *stream,STRING *bs,unsigned long *size); unsigned long mmdf_pseudo (MAILSTREAM *stream,char *hdr); unsigned long mmdf_xstatus (MAILSTREAM *stream,char *status,MESSAGECACHE *elt, unsigned long uid,long flag); long mmdf_rewrite (MAILSTREAM *stream,unsigned long *nexp,DOTLOCK *lock, long flags); long mmdf_extend (MAILSTREAM *stream,unsigned long size); void mmdf_write (MMDFFILE *f,char *s,unsigned long i); void mmdf_phys_write (MMDFFILE *f,char *buf,size_t size); /* MMDF mail routines */ /* Driver dispatch used by MAIL */ DRIVER mmdfdriver = { "mmdf", /* driver name */ /* driver flags */ DR_LOCAL|DR_MAIL|DR_LOCKING|DR_NONEWMAILRONLY|DR_XPOINT, (DRIVER *) NIL, /* next driver */ mmdf_valid, /* mailbox is valid for us */ mmdf_parameters, /* manipulate parameters */ mmdf_scan, /* scan mailboxes */ mmdf_list, /* list mailboxes */ mmdf_lsub, /* list subscribed mailboxes */ NIL, /* subscribe to mailbox */ NIL, /* unsubscribe from mailbox */ mmdf_create, /* create mailbox */ mmdf_delete, /* delete mailbox */ mmdf_rename, /* rename mailbox */ mail_status_default, /* status of mailbox */ mmdf_open, /* open mailbox */ mmdf_close, /* close mailbox */ NIL, /* fetch message "fast" attributes */ NIL, /* fetch message flags */ NIL, /* fetch overview */ NIL, /* fetch message envelopes */ mmdf_header, /* fetch message header */ mmdf_text, /* fetch message text */ NIL, /* fetch partial message text */ NIL, /* unique identifier */ NIL, /* message number */ NIL, /* modify flags */ mmdf_flagmsg, /* per-message modify flags */ NIL, /* search for message based on criteria */ NIL, /* sort messages */ NIL, /* thread messages */ mmdf_ping, /* ping mailbox to see if still alive */ mmdf_check, /* check for new messages */ mmdf_expunge, /* expunge deleted messages */ mmdf_copy, /* copy messages to another mailbox */ mmdf_append, /* append string message to mailbox */ NIL /* garbage collect stream */ }; /* prototype stream */ MAILSTREAM mmdfproto = {&mmdfdriver}; char *mmdfhdr = MMDFHDRTXT; /* MMDF header */ /* MMDF mail validate mailbox * Accepts: mailbox name * Returns: our driver if name is valid, NIL otherwise */ DRIVER *mmdf_valid (char *name) { char tmp[MAILTMPLEN]; return mmdf_isvalid (name,tmp) ? &mmdfdriver : NIL; } /* MMDF mail test for valid mailbox name * Accepts: mailbox name * scratch buffer * Returns: T if valid, NIL otherwise */ long mmdf_isvalid (char *name,char *tmp) { int fd; int ret = NIL; char *t,file[MAILTMPLEN]; struct stat sbuf; time_t tp[2]; errno = EINVAL; /* assume invalid argument */ /* must be non-empty file */ if ((t = dummy_file (file,name)) && !stat (t,&sbuf)) { if (!sbuf.st_size)errno = 0;/* empty file */ else if ((fd = open (file,O_RDONLY,NIL)) >= 0) { /* error -1 for invalid format */ if (!(ret = mmdf_isvalid_fd (fd,tmp))) errno = -1; close (fd); /* close the file */ /* \Marked status? */ if ((sbuf.st_ctime > sbuf.st_atime) || (sbuf.st_mtime > sbuf.st_atime)) { tp[0] = sbuf.st_atime; /* preserve atime and mtime */ tp[1] = sbuf.st_mtime; utime (file,tp); /* set the times */ } } } return ret; /* return what we should */ } /* MMDF mail test for valid mailbox * Accepts: file descriptor * scratch buffer * Returns: T if valid, NIL otherwise */ long mmdf_isvalid_fd (int fd,char *tmp) { int ret = NIL; memset (tmp,'\0',MAILTMPLEN); if (read (fd,tmp,MAILTMPLEN-1) >= 0) ret = ISMMDF (tmp) ? T : NIL; return ret; /* return what we should */ } /* MMDF manipulate driver parameters * Accepts: function code * function-dependent value * Returns: function-dependent return value */ void *mmdf_parameters (long function,void *value) { void *ret = NIL; switch ((int) function) { case GET_INBOXPATH: if (value) ret = dummy_file ((char *) value,"INBOX"); break; } return ret; } /* MMDF mail scan mailboxes * Accepts: mail stream * reference * pattern to search * string to scan */ void mmdf_scan (MAILSTREAM *stream,char *ref,char *pat,char *contents) { if (stream) dummy_scan (NIL,ref,pat,contents); } /* MMDF mail list mailboxes * Accepts: mail stream * reference * pattern to search */ void mmdf_list (MAILSTREAM *stream,char *ref,char *pat) { if (stream) dummy_list (NIL,ref,pat); } /* MMDF mail list subscribed mailboxes * Accepts: mail stream * reference * pattern to search */ void mmdf_lsub (MAILSTREAM *stream,char *ref,char *pat) { if (stream) dummy_lsub (NIL,ref,pat); } /* MMDF mail create mailbox * Accepts: MAIL stream * mailbox name to create * Returns: T on success, NIL on failure */ long mmdf_create (MAILSTREAM *stream,char *mailbox) { char *s,mbx[MAILTMPLEN],tmp[MAILTMPLEN]; long ret = NIL; int i,fd; time_t ti = time (0); if (!(s = dummy_file (mbx,mailbox))) { sprintf (tmp,"Can't create %.80s: invalid name",mailbox); MM_LOG (tmp,ERROR); } /* create underlying file */ else if (dummy_create_path (stream,s,get_dir_protection (mailbox))) { /* done if dir-only or whiner */ if (((s = strrchr (s,'/')) && !s[1]) || mail_parameters (NIL,GET_USERHASNOLIFE,NIL)) ret = T; else if ((fd = open (mbx,O_WRONLY, (long) mail_parameters (NIL,GET_MBXPROTECTION,NIL))) < 0) { sprintf (tmp,"Can't reopen mailbox node %.80s: %s",mbx,strerror (errno)); MM_LOG (tmp,ERROR); unlink (mbx); /* delete the file */ } else { /* initialize header */ memset (tmp,'\0',MAILTMPLEN); sprintf (tmp,"%sFrom %s %sDate: ",mmdfhdr,pseudo_from,ctime (&ti)); rfc822_date (s = tmp + strlen (tmp)); sprintf (s += strlen (s), /* write the pseudo-header */ "\nFrom: %s <%s@%s>\nSubject: %s\nX-IMAP: %010lu 0000000000", pseudo_name,pseudo_from,mylocalhost (),pseudo_subject, (unsigned long) ti); for (i = 0; i < NUSERFLAGS; ++i) if (default_user_flag (i)) sprintf (s += strlen (s)," %s",default_user_flag (i)); sprintf (s += strlen (s),"\nStatus: RO\n\n%s\n%s",pseudo_msg,mmdfhdr); if (write (fd,tmp,strlen (tmp)) > 0) ret = T; else { sprintf (tmp,"Can't initialize mailbox node %.80s: %s",mbx, strerror (errno)); MM_LOG (tmp,ERROR); unlink (mbx); /* delete the file */ } close (fd); /* close file */ } } /* set proper protections */ return ret ? set_mbx_protections (mailbox,mbx) : NIL; } /* MMDF mail delete mailbox * Accepts: MAIL stream * mailbox name to delete * Returns: T on success, NIL on failure */ long mmdf_delete (MAILSTREAM *stream,char *mailbox) { return mmdf_rename (stream,mailbox,NIL); } /* MMDF mail rename mailbox * Accepts: MAIL stream * old mailbox name * new mailbox name (or NIL for delete) * Returns: T on success, NIL on failure */ long mmdf_rename (MAILSTREAM *stream,char *old,char *newname) { long ret = NIL; char c,*s = NIL; char tmp[MAILTMPLEN],file[MAILTMPLEN],lock[MAILTMPLEN]; DOTLOCK lockx; int fd,ld; long i; struct stat sbuf; MM_CRITICAL (stream); /* get the c-client lock */ if (!dummy_file (file,old) || (newname && (!((s = mailboxfile (tmp,newname)) && *s) || ((s = strrchr (tmp,'/')) && !s[1])))) sprintf (tmp,newname ? "Can't rename mailbox %.80s to %.80s: invalid name" : "Can't delete mailbox %.80s: invalid name", old,newname); /* lock out other c-clients */ else if ((ld = lockname (lock,file,LOCK_EX|LOCK_NB,&i)) < 0) sprintf (tmp,"Mailbox %.80s is in use by another process",old); else { if ((fd = mmdf_lock (file,O_RDWR, (long) mail_parameters (NIL,GET_MBXPROTECTION,NIL), &lockx,LOCK_EX)) < 0) sprintf (tmp,"Can't lock mailbox %.80s: %s",old,strerror (errno)); else { if (newname) { /* want rename? */ /* found superior to destination name? */ if (s = strrchr (s,'/')) { c = *++s; /* remember first character of inferior */ *s = '\0'; /* tie off to get just superior */ /* name doesn't exist, create it */ if ((stat (tmp,&sbuf) || ((sbuf.st_mode & S_IFMT) != S_IFDIR)) && !dummy_create_path (stream,tmp,get_dir_protection (newname))) { mmdf_unlock (fd,NIL,&lockx); mmdf_unlock (ld,NIL,NIL); unlink (lock); MM_NOCRITICAL (stream); return ret; /* return success or failure */ } *s = c; /* restore full name */ } if (rename (file,tmp)) sprintf (tmp,"Can't rename mailbox %.80s to %.80s: %s",old,newname, strerror (errno)); else ret = T; /* set success */ } else if (unlink (file)) sprintf (tmp,"Can't delete mailbox %.80s: %s",old,strerror (errno)); else ret = T; /* set success */ mmdf_unlock (fd,NIL,&lockx); } mmdf_unlock (ld,NIL,NIL); /* flush the lock */ unlink (lock); } MM_NOCRITICAL (stream); /* no longer critical */ if (!ret) MM_LOG (tmp,ERROR); /* log error */ return ret; /* return success or failure */ } /* MMDF mail open * Accepts: Stream to open * Returns: Stream on success, NIL on failure */ MAILSTREAM *mmdf_open (MAILSTREAM *stream) { long i; int fd; char tmp[MAILTMPLEN]; DOTLOCK lock; long retry; /* return prototype for OP_PROTOTYPE call */ if (!stream) return user_flags (&mmdfproto); retry = stream->silent ? 1 : KODRETRY; if (stream->local) fatal ("mmdf recycle stream"); stream->local = memset (fs_get (sizeof (MMDFLOCAL)),0,sizeof (MMDFLOCAL)); /* note if an INBOX or not */ stream->inbox = !compare_cstring (stream->mailbox,"INBOX"); /* canonicalize the stream mailbox name */ if (!dummy_file (tmp,stream->mailbox)) { sprintf (tmp,"Can't open - invalid name: %.80s",stream->mailbox); MM_LOG (tmp,ERROR); return NIL; } /* flush old name */ fs_give ((void **) &stream->mailbox); /* save canonical name */ stream->mailbox = cpystr (tmp); LOCAL->fd = LOCAL->ld = -1; /* no file or state locking yet */ LOCAL->buf = (char *) fs_get (CHUNKSIZE); LOCAL->buflen = CHUNKSIZE - 1; LOCAL->text.data = (unsigned char *) fs_get (CHUNKSIZE); LOCAL->text.size = CHUNKSIZE - 1; LOCAL->linebuf = (char *) fs_get (CHUNKSIZE); LOCAL->linebuflen = CHUNKSIZE - 1; stream->sequence++; /* bump sequence number */ /* make lock for read/write access */ if (!stream->rdonly) while (retry) { /* try to lock file */ if ((fd = lockname (tmp,stream->mailbox,LOCK_EX|LOCK_NB,&i)) < 0) { /* suppressing kiss-of-death? */ if (stream->nokod) retry = 0; /* no, first time through? */ else if (retry-- == KODRETRY) { /* learned other guy's PID and can signal? */ if (i && !kill ((int) i,SIGUSR2)) { sprintf (tmp,"Trying to get mailbox lock from process %ld",i); MM_LOG (tmp,WARN); } else retry = 0; /* give up */ } if (!stream->silent) { /* nothing if silent stream */ if (retry) sleep (1); /* wait a second before trying again */ else MM_LOG ("Mailbox is open by another process, access is readonly", WARN); } } else { /* got the lock, nobody else can alter state */ LOCAL->ld = fd; /* note lock's fd and name */ LOCAL->lname = cpystr (tmp); /* make sure mode OK (don't use fchmod()) */ chmod (LOCAL->lname,(long) mail_parameters (NIL,GET_LOCKPROTECTION,NIL)); if (stream->silent) i = 0;/* silent streams won't accept KOD */ else { /* note our PID in the lock */ sprintf (tmp,"%d",getpid ()); write (fd,tmp,(i = strlen (tmp))+1); } ftruncate (fd,i); /* make sure tied off */ fsync (fd); /* make sure it's available */ retry = 0; /* no more need to try */ } } /* parse mailbox */ stream->nmsgs = stream->recent = 0; /* will we be able to get write access? */ if ((LOCAL->ld >= 0) && access (stream->mailbox,W_OK) && (errno == EACCES)) { MM_LOG ("Can't get write access to mailbox, access is readonly",WARN); flock (LOCAL->ld,LOCK_UN); /* release the lock */ close (LOCAL->ld); /* close the lock file */ LOCAL->ld = -1; /* no more lock fd */ unlink (LOCAL->lname); /* delete it */ } /* reset UID validity */ stream->uid_validity = stream->uid_last = 0; if (stream->silent && !stream->rdonly && (LOCAL->ld < 0)) mmdf_abort (stream); /* abort if can't get RW silent stream */ /* parse mailbox */ else if (mmdf_parse (stream,&lock,LOCK_SH)) { mmdf_unlock (LOCAL->fd,stream,&lock); mail_unlock (stream); MM_NOCRITICAL (stream); /* done with critical */ } if (!LOCAL) return NIL; /* failure if stream died */ /* make sure upper level knows readonly */ stream->rdonly = (LOCAL->ld < 0); /* notify about empty mailbox */ if (!(stream->nmsgs || stream->silent)) MM_LOG ("Mailbox is empty",NIL); if (!stream->rdonly) { /* flags stick if readwrite */ stream->perm_seen = stream->perm_deleted = stream->perm_flagged = stream->perm_answered = stream->perm_draft = T; if (!stream->uid_nosticky) {/* users with lives get permanent keywords */ stream->perm_user_flags = 0xffffffff; /* and maybe can create them too! */ stream->kwd_create = stream->user_flags[NUSERFLAGS-1] ? NIL : T; } } return stream; /* return stream alive to caller */ } /* MMDF mail close * Accepts: MAIL stream * close options */ void mmdf_close (MAILSTREAM *stream,long options) { int silent = stream->silent; stream->silent = T; /* go silent */ /* expunge if requested */ if (options & CL_EXPUNGE) mmdf_expunge (stream,NIL,NIL); /* else dump final checkpoint */ else if (LOCAL->dirty) mmdf_check (stream); stream->silent = silent; /* restore old silence state */ mmdf_abort (stream); /* now punt the file and local data */ } /* MMDF mail fetch message header * Accepts: MAIL stream * message # to fetch * pointer to returned header text length * option flags * Returns: message header in RFC822 format */ /* lines to filter from header */ static STRINGLIST *mmdf_hlines = NIL; char *mmdf_header (MAILSTREAM *stream,unsigned long msgno, unsigned long *length,long flags) { MESSAGECACHE *elt; unsigned char *s,*t,*tl; *length = 0; /* default to empty */ if (flags & FT_UID) return "";/* UID call "impossible" */ elt = mail_elt (stream,msgno);/* get cache */ if (!mmdf_hlines) { /* once only code */ STRINGLIST *lines = mmdf_hlines = mail_newstringlist (); lines->text.size = strlen ((char *) (lines->text.data = (unsigned char *) "Status")); lines = lines->next = mail_newstringlist (); lines->text.size = strlen ((char *) (lines->text.data = (unsigned char *) "X-Status")); lines = lines->next = mail_newstringlist (); lines->text.size = strlen ((char *) (lines->text.data = (unsigned char *) "X-Keywords")); lines = lines->next = mail_newstringlist (); lines->text.size = strlen ((char *) (lines->text.data = (unsigned char *) "X-UID")); lines = lines->next = mail_newstringlist (); lines->text.size = strlen ((char *) (lines->text.data = (unsigned char *) "X-IMAP")); lines = lines->next = mail_newstringlist (); lines->text.size = strlen ((char *) (lines->text.data = (unsigned char *) "X-IMAPbase")); } /* go to header position */ lseek (LOCAL->fd,elt->private.special.offset + elt->private.msg.header.offset,L_SET); if (flags & FT_INTERNAL) { /* initial data OK? */ if (elt->private.msg.header.text.size > LOCAL->buflen) { fs_give ((void **) &LOCAL->buf); LOCAL->buf = (char *) fs_get ((LOCAL->buflen = elt->private.msg.header.text.size) + 1); } /* read message */ read (LOCAL->fd,LOCAL->buf,elt->private.msg.header.text.size); /* got text, tie off string */ LOCAL->buf[*length = elt->private.msg.header.text.size] = '\0'; /* squeeze out CRs (in case from PC) */ for (s = t = LOCAL->buf,tl = LOCAL->buf + *length; t < tl; t++) if (*t != '\r') *s++ = *t; *s = '\0'; *length = s - LOCAL->buf; /* adjust length */ } else { /* need to make a CRLF version */ read (LOCAL->fd,s = (char *) fs_get (elt->private.msg.header.text.size+1), elt->private.msg.header.text.size); /* tie off string, and convert to CRLF */ s[elt->private.msg.header.text.size] = '\0'; *length = strcrlfcpy (&LOCAL->buf,&LOCAL->buflen,s, elt->private.msg.header.text.size); fs_give ((void **) &s); /* free readin buffer */ /* squeeze out spurious CRs */ for (s = t = LOCAL->buf,tl = LOCAL->buf + *length; t < tl; t++) if ((*t != '\r') || (t[1] == '\n')) *s++ = *t; *s = '\0'; *length = s - LOCAL->buf; /* adjust length */ } *length = mail_filter (LOCAL->buf,*length,mmdf_hlines,FT_NOT); return (char *) LOCAL->buf; /* return processed copy */ } /* MMDF mail fetch message text * Accepts: MAIL stream * message # to fetch * pointer to returned stringstruct * option flags * Returns: T on success, NIL if failure */ long mmdf_text (MAILSTREAM *stream,unsigned long msgno,STRING *bs,long flags) { char *s; unsigned long i; MESSAGECACHE *elt; /* UID call "impossible" */ if (flags & FT_UID) return NIL; elt = mail_elt (stream,msgno);/* get cache element */ /* if message not seen */ if (!(flags & FT_PEEK) && !elt->seen) { /* mark message seen and dirty */ elt->seen = elt->private.dirty = LOCAL->dirty = T; MM_FLAGS (stream,msgno); } s = mmdf_text_work (stream,elt,&i,flags); INIT (bs,mail_string,s,i); /* set up stringstruct */ return T; /* success */ } /* MMDF mail fetch message text worker routine * Accepts: MAIL stream * message cache element * pointer to returned header text length * option flags */ char *mmdf_text_work (MAILSTREAM *stream,MESSAGECACHE *elt, unsigned long *length,long flags) { FDDATA d; STRING bs; unsigned char c,*s,*t,*tl,tmp[CHUNKSIZE]; /* go to text position */ lseek (LOCAL->fd,elt->private.special.offset + elt->private.msg.text.offset,L_SET); if (flags & FT_INTERNAL) { /* initial data OK? */ if (elt->private.msg.text.text.size > LOCAL->buflen) { fs_give ((void **) &LOCAL->buf); LOCAL->buf = (char *) fs_get ((LOCAL->buflen = elt->private.msg.text.text.size) + 1); } /* read message */ read (LOCAL->fd,LOCAL->buf,elt->private.msg.text.text.size); /* got text, tie off string */ LOCAL->buf[*length = elt->private.msg.text.text.size] = '\0'; /* squeeze out CRs (in case from PC) */ for (s = t = LOCAL->buf,tl = LOCAL->buf + *length; t < tl; t++) if (*t != '\r') *s++ = *t; *s = '\0'; *length = s - LOCAL->buf; /* adjust length */ return (char *) LOCAL->buf; } /* have it cached already? */ if (elt->private.uid != LOCAL->uid) { /* not cached, cache it now */ LOCAL->uid = elt->private.uid; /* is buffer big enough? */ if (elt->rfc822_size > LOCAL->text.size) { /* excessively conservative, but the right thing is too hard to do */ fs_give ((void **) &LOCAL->text.data); LOCAL->text.data = (unsigned char *) fs_get ((LOCAL->text.size = elt->rfc822_size) + 1); } d.fd = LOCAL->fd; /* yes, set up file descriptor */ d.pos = elt->private.special.offset + elt->private.msg.text.offset; d.chunk = tmp; /* initial buffer chunk */ d.chunksize = CHUNKSIZE; /* file chunk size */ INIT (&bs,fd_string,&d,elt->private.msg.text.text.size); for (s = (char *) LOCAL->text.data; SIZE (&bs);) switch (c = SNX (&bs)) { case '\r': /* carriage return seen */ break; case '\n': *s++ = '\r'; /* insert a CR */ default: *s++ = c; /* copy characters */ } *s = '\0'; /* tie off buffer */ /* calculate length of cached data */ LOCAL->textlen = s - LOCAL->text.data; } *length = LOCAL->textlen; /* return from cache */ return (char *) LOCAL->text.data; } /* MMDF per-message modify flag * Accepts: MAIL stream * message cache element */ void mmdf_flagmsg (MAILSTREAM *stream,MESSAGECACHE *elt) { /* only after finishing */ if (elt->valid) elt->private.dirty = LOCAL->dirty = T; } /* MMDF mail ping mailbox * Accepts: MAIL stream * Returns: T if stream alive, else NIL */ long mmdf_ping (MAILSTREAM *stream) { DOTLOCK lock; struct stat sbuf; long reparse; /* big no-op if not readwrite */ if (LOCAL && (LOCAL->ld >= 0) && !stream->lock) { if (stream->rdonly) { /* does he want to give up readwrite? */ /* checkpoint if we changed something */ if (LOCAL->dirty) mmdf_check (stream); flock (LOCAL->ld,LOCK_UN);/* release readwrite lock */ close (LOCAL->ld); /* close the readwrite lock file */ LOCAL->ld = -1; /* no more readwrite lock fd */ unlink (LOCAL->lname); /* delete the readwrite lock file */ } else { /* see if need to reparse */ if (!(reparse = (long) mail_parameters (NIL,GET_NETFSSTATBUG,NIL))) { /* get current mailbox size */ if (LOCAL->fd >= 0) fstat (LOCAL->fd,&sbuf); else if (stat (stream->mailbox,&sbuf)) { sprintf (LOCAL->buf,"Mailbox stat failed, aborted: %s", strerror (errno)); MM_LOG (LOCAL->buf,ERROR); mmdf_abort (stream); return NIL; } reparse = (sbuf.st_size != LOCAL->filesize); } /* parse if mailbox changed */ if ((LOCAL->ddirty || reparse) && mmdf_parse (stream,&lock,LOCK_EX)) { /* force checkpoint if double-dirty */ if (LOCAL->ddirty) mmdf_rewrite (stream,NIL,&lock,NIL); /* unlock mailbox */ else mmdf_unlock (LOCAL->fd,stream,&lock); mail_unlock (stream); /* and stream */ /* done with critical */ MM_NOCRITICAL (stream); } } } return LOCAL ? LONGT : NIL; /* return if still alive */ } /* MMDF mail check mailbox * Accepts: MAIL stream */ void mmdf_check (MAILSTREAM *stream) { DOTLOCK lock; /* parse and lock mailbox */ if (LOCAL && (LOCAL->ld >= 0) && !stream->lock && mmdf_parse (stream,&lock,LOCK_EX)) { /* any unsaved changes? */ if (LOCAL->dirty && mmdf_rewrite (stream,NIL,&lock,NIL)) { if (!stream->silent) MM_LOG ("Checkpoint completed",NIL); } /* no checkpoint needed, just unlock */ else mmdf_unlock (LOCAL->fd,stream,&lock); mail_unlock (stream); /* unlock the stream */ MM_NOCRITICAL (stream); /* done with critical */ } } /* MMDF mail expunge mailbox * Accepts: MAIL stream * sequence to expunge if non-NIL * expunge options * Returns: T, always */ long mmdf_expunge (MAILSTREAM *stream,char *sequence,long options) { long ret; unsigned long i; DOTLOCK lock; char *msg = NIL; if (ret = (sequence ? ((options & EX_UID) ? mail_uid_sequence (stream,sequence) : mail_sequence (stream,sequence)) : LONGT) && LOCAL && (LOCAL->ld >= 0) && !stream->lock && mmdf_parse (stream,&lock,LOCK_EX)) { /* check expunged messages if not dirty */ for (i = 1; !LOCAL->dirty && (i <= stream->nmsgs); i++) { MESSAGECACHE *elt = mail_elt (stream,i); if (mail_elt (stream,i)->deleted) LOCAL->dirty = T; } if (!LOCAL->dirty) { /* not dirty and no expunged messages */ mmdf_unlock (LOCAL->fd,stream,&lock); msg = "No messages deleted, so no update needed"; } else if (mmdf_rewrite (stream,&i,&lock,sequence ? LONGT : NIL)) { if (i) sprintf (msg = LOCAL->buf,"Expunged %lu messages",i); else msg = "Mailbox checkpointed, but no messages expunged"; } /* rewrite failed */ else mmdf_unlock (LOCAL->fd,stream,&lock); mail_unlock (stream); /* unlock the stream */ MM_NOCRITICAL (stream); /* done with critical */ if (msg && !stream->silent) MM_LOG (msg,NIL); } else if (!stream->silent) MM_LOG ("Expunge ignored on readonly mailbox",WARN); return ret; } /* MMDF mail copy message(s) * Accepts: MAIL stream * sequence * destination mailbox * copy options * Returns: T if copy successful, else NIL */ long mmdf_copy (MAILSTREAM *stream,char *sequence,char *mailbox,long options) { struct stat sbuf; int fd; char *s,file[MAILTMPLEN]; DOTLOCK lock; time_t tp[2]; unsigned long i,j; MESSAGECACHE *elt; long ret = T; mailproxycopy_t pc = (mailproxycopy_t) mail_parameters (stream,GET_MAILPROXYCOPY,NIL); copyuid_t cu = (copyuid_t) (mail_parameters (NIL,GET_USERHASNOLIFE,NIL) ? NIL : mail_parameters (NIL,GET_COPYUID,NIL)); SEARCHSET *source = cu ? mail_newsearchset () : NIL; SEARCHSET *dest = cu ? mail_newsearchset () : NIL; MAILSTREAM *tstream = NIL; if (!((options & CP_UID) ? mail_uid_sequence (stream,sequence) : mail_sequence (stream,sequence))) return NIL; /* make sure destination is valid */ if (!(mmdf_valid (mailbox) || !errno)) switch (errno) { case ENOENT: /* no such file? */ if (compare_cstring (mailbox,"INBOX")) { MM_NOTIFY (stream,"[TRYCREATE] Must create mailbox before copy",NIL); return NIL; } if (pc) return (*pc) (stream,sequence,mailbox,options); mmdf_create (NIL,"INBOX");/* create empty INBOX */ case EACCES: /* file protected */ sprintf (LOCAL->buf,"Can't access destination: %.80s",mailbox); MM_LOG (LOCAL->buf,ERROR); return NIL; case EINVAL: if (pc) return (*pc) (stream,sequence,mailbox,options); sprintf (LOCAL->buf,"Invalid MMDF-format mailbox name: %.80s",mailbox); MM_LOG (LOCAL->buf,ERROR); return NIL; default: if (pc) return (*pc) (stream,sequence,mailbox,options); sprintf (LOCAL->buf,"Not a MMDF-format mailbox: %.80s",mailbox); MM_LOG (LOCAL->buf,ERROR); return NIL; } /* try to open rewrite for UIDPLUS */ if ((tstream = mail_open_work (&mmdfdriver,NIL,mailbox, OP_SILENT|OP_NOKOD)) && tstream->rdonly) tstream = mail_close (tstream); if (cu && !tstream) { /* wanted a COPYUID? */ sprintf (LOCAL->buf,"Unable to write-open mailbox for COPYUID: %.80s", mailbox); MM_LOG (LOCAL->buf,WARN); cu = NIL; /* don't try to do COPYUID */ } LOCAL->buf[0] = '\0'; MM_CRITICAL (stream); /* go critical */ if ((fd = mmdf_lock (dummy_file (file,mailbox),O_WRONLY|O_APPEND, (long) mail_parameters (NIL,GET_MBXPROTECTION,NIL), &lock,LOCK_EX)) < 0) { MM_NOCRITICAL (stream); /* done with critical */ sprintf (LOCAL->buf,"Can't open destination mailbox: %s",strerror (errno)); MM_LOG (LOCAL->buf,ERROR); /* log the error */ return NIL; /* failed */ } fstat (fd,&sbuf); /* get current file size */ /* write all requested messages to mailbox */ for (i = 1; ret && (i <= stream->nmsgs); i++) if ((elt = mail_elt (stream,i))->sequence) { lseek (LOCAL->fd,elt->private.special.offset,L_SET); read (LOCAL->fd,LOCAL->buf,elt->private.special.text.size); if (write (fd,LOCAL->buf,elt->private.special.text.size) < 0) ret = NIL; else { /* internal header succeeded */ s = mmdf_header (stream,i,&j,FT_INTERNAL); /* header size, sans trailing newline */ if (j && (s[j - 2] == '\n')) j--; if (write (fd,s,j) < 0) ret = NIL; else { /* message header succeeded */ j = tstream ? /* write UIDPLUS data if have readwrite */ mmdf_xstatus (stream,LOCAL->buf,elt,++(tstream->uid_last),LONGT) : mmdf_xstatus (stream,LOCAL->buf,elt,NIL,NIL); if (write (fd,LOCAL->buf,j) < 0) ret = NIL; else { /* message status succeeded */ s = mmdf_text_work (stream,elt,&j,FT_INTERNAL); if ((write (fd,s,j) < 0) || (write (fd,mmdfhdr,MMDFHDRLEN) < 0)) ret = NIL; else if (cu) { /* need to pass back new UID? */ mail_append_set (source,mail_uid (stream,i)); mail_append_set (dest,tstream->uid_last); } } } } } if (!ret || fsync (fd)) { /* force out the update */ sprintf (LOCAL->buf,"Message copy failed: %s",strerror (errno)); ftruncate (fd,sbuf.st_size); ret = NIL; } /* force UIDVALIDITY assignment now */ if (tstream && !tstream->uid_validity) tstream->uid_validity = time (0); /* return sets if doing COPYUID */ if (cu && ret) (*cu) (stream,mailbox,tstream->uid_validity,source,dest); else { /* flush any sets we may have built */ mail_free_searchset (&source); mail_free_searchset (&dest); } tp[1] = time (0); /* set mtime to now */ if (ret) tp[0] = tp[1] - 1; /* set atime to now-1 if successful copy */ else tp[0] = /* else preserve \Marked status */ ((sbuf.st_ctime > sbuf.st_atime) || (sbuf.st_mtime > sbuf.st_atime)) ? sbuf.st_atime : tp[1]; utime (file,tp); /* set the times */ mmdf_unlock (fd,NIL,&lock); /* unlock and close mailbox */ if (tstream) { /* update last UID if we can */ MMDFLOCAL *local = (MMDFLOCAL *) tstream->local; local->dirty = T; /* do a rewrite */ local->appending = T; /* but not at the cost of marking as old */ tstream = mail_close (tstream); } /* log the error */ if (!ret) MM_LOG (LOCAL->buf,ERROR); /* delete if requested message */ else if (options & CP_MOVE) for (i = 1; i <= stream->nmsgs; i++) if ((elt = mail_elt (stream,i))->sequence) elt->deleted = elt->private.dirty = LOCAL->dirty = T; MM_NOCRITICAL (stream); /* release critical */ return ret; } /* MMDF mail append message from stringstruct * Accepts: MAIL stream * destination mailbox * append callback * data for callback * Returns: T if append successful, else NIL */ #define BUFLEN 8*MAILTMPLEN long mmdf_append (MAILSTREAM *stream,char *mailbox,append_t af,void *data) { struct stat sbuf; int fd; unsigned long i; char *flags,*date,buf[BUFLEN],tmp[MAILTMPLEN],file[MAILTMPLEN]; time_t tp[2]; FILE *sf,*df; MESSAGECACHE elt; DOTLOCK lock; STRING *message; unsigned long uidlocation = 0; appenduid_t au = (appenduid_t) (mail_parameters (NIL,GET_USERHASNOLIFE,NIL) ? NIL : mail_parameters (NIL,GET_APPENDUID,NIL)); SEARCHSET *dst = au ? mail_newsearchset () : NIL; long ret = LONGT; MAILSTREAM *tstream = NIL; /* default stream to prototype */ if (!stream) { /* stream specified? */ stream = &mmdfproto; /* no, default stream to prototype */ for (i = 0; i < NUSERFLAGS && stream->user_flags[i]; ++i) fs_give ((void **) &stream->user_flags[i]); } if (!mmdf_valid (mailbox)) switch (errno) { case ENOENT: /* no such file? */ if (compare_cstring (mailbox,"INBOX")) { MM_NOTIFY (stream,"[TRYCREATE] Must create mailbox before append",NIL); return NIL; } mmdf_create (NIL,"INBOX"); /* create empty INBOX */ case 0: /* merely empty file? */ tstream = stream; break; case EACCES: /* file protected */ sprintf (tmp,"Can't access destination: %.80s",mailbox); MM_LOG (tmp,ERROR); return NIL; case EINVAL: sprintf (tmp,"Invalid MMDF-format mailbox name: %.80s",mailbox); MM_LOG (tmp,ERROR); return NIL; default: sprintf (tmp,"Not a MMDF-format mailbox: %.80s",mailbox); MM_LOG (tmp,ERROR); return NIL; } /* get sniffing stream for keywords */ else if (!(tstream = mail_open (NIL,mailbox, OP_READONLY|OP_SILENT|OP_NOKOD|OP_SNIFF))) { sprintf (tmp,"Unable to examine mailbox for APPEND: %.80s",mailbox); MM_LOG (tmp,ERROR); return NIL; } /* get first message */ if (!MM_APPEND (af) (tstream,data,&flags,&date,&message)) return NIL; if (!(sf = tmpfile ())) { /* must have scratch file */ sprintf (tmp,".%lx.%lx",(unsigned long) time (0),(unsigned long)getpid ()); if (!stat (tmp,&sbuf) || !(sf = fopen (tmp,"wb+"))) { sprintf (tmp,"Unable to create scratch file: %.80s",strerror (errno)); MM_LOG (tmp,ERROR); return NIL; } unlink (tmp); } do { /* parse date */ if (!date) rfc822_date (date = tmp); if (!mail_parse_date (&elt,date)) { sprintf (tmp,"Bad date in append: %.80s",date); MM_LOG (tmp,ERROR); } else { /* user wants to suppress time zones? */ if (mail_parameters (NIL,GET_NOTIMEZONES,NIL)) { time_t when = mail_longdate (&elt); date = ctime (&when); /* use traditional date */ } /* use POSIX-style date */ else date = mail_cdate (tmp,&elt); if (!SIZE (message)) MM_LOG ("Append of zero-length message",ERROR); else if (!mmdf_collect_msg (tstream,sf,flags,date,message)) { sprintf (tmp,"Error writing scratch file: %.80s",strerror (errno)); MM_LOG (tmp,ERROR); } /* get next message */ else if (MM_APPEND (af) (tstream,data,&flags,&date,&message)) continue; } fclose (sf); /* punt scratch file */ return NIL; /* give up */ } while (message); /* until no more messages */ if (fflush (sf)) { sprintf (tmp,"Error finishing scratch file: %.80s",strerror (errno)); MM_LOG (tmp,ERROR); fclose (sf); /* punt scratch file */ return NIL; /* give up */ } i = ftell (sf); /* size of scratch file */ if (tstream != stream) tstream = mail_close (tstream); MM_CRITICAL (stream); /* go critical */ /* try to open readwrite for UIDPLUS */ if ((tstream = mail_open_work (&mmdfdriver,NIL,mailbox, OP_SILENT|OP_NOKOD)) && tstream->rdonly) tstream = mail_close (tstream); if (au && !tstream) { /* wanted an APPENDUID? */ sprintf (tmp,"Unable to re-open mailbox for APPENDUID: %.80s",mailbox); MM_LOG (tmp,WARN); au = NIL; } if (((fd = mmdf_lock (dummy_file (file,mailbox),O_WRONLY|O_APPEND, (long) mail_parameters (NIL,GET_MBXPROTECTION,NIL), &lock,LOCK_EX)) < 0) || !(df = fdopen (fd,"ab"))) { MM_NOCRITICAL (stream); /* done with critical */ sprintf (tmp,"Can't open append mailbox: %s",strerror (errno)); MM_LOG (tmp,ERROR); return NIL; } fstat (fd,&sbuf); /* get current file size */ rewind (sf); tp[1] = time (0); /* set mtime to now */ /* write all messages */ if (!mmdf_append_msgs (tstream,sf,df,au ? dst : NIL) || (fflush (df) == EOF) || fsync (fd)) { sprintf (buf,"Message append failed: %s",strerror (errno)); MM_LOG (buf,ERROR); ftruncate (fd,sbuf.st_size); tp[0] = /* preserve \Marked status */ ((sbuf.st_ctime > sbuf.st_atime) || (sbuf.st_mtime > sbuf.st_atime)) ? sbuf.st_atime : tp[1]; ret = NIL; /* return error */ } else tp[0] = tp[1] - 1; /* set atime to now-1 if successful copy */ utime (file,tp); /* set the times */ fclose (sf); /* done with scratch file */ /* force UIDVALIDITY assignment now */ if (tstream && !tstream->uid_validity) tstream->uid_validity = time (0); /* return sets if doing APPENDUID */ if (au && ret) (*au) (mailbox,tstream->uid_validity,dst); else mail_free_searchset (&dst); mmdf_unlock (fd,NIL,&lock); /* unlock and close mailbox */ fclose (df); if (tstream) { /* update last UID if we can */ MMDFLOCAL *local = (MMDFLOCAL *) tstream->local; local->dirty = T; /* do a rewrite */ local->appending = T; /* but not at the cost of marking as old */ tstream = mail_close (tstream); } MM_NOCRITICAL (stream); /* release critical */ return ret; } /* Collect and write single message to append scratch file * Accepts: MAIL stream * scratch file * flags * date * message stringstruct * Returns: NIL if write error, else T */ int mmdf_collect_msg (MAILSTREAM *stream,FILE *sf,char *flags,char *date, STRING *msg) { unsigned char *s,*t; unsigned long uf; long f = mail_parse_flags (stream,flags,&uf); /* write metadata, note date ends with NL */ if (fprintf (sf,"%ld %lu %s",f,SIZE (msg) + 1,date) < 0) return NIL; while (uf) /* write user flags */ if ((s = stream->user_flags[find_rightmost_bit (&uf)]) && (fprintf (sf," %s",s) < 0)) return NIL; if (putc ('\n',sf) == EOF) return NIL; while (SIZE (msg)) { /* copy text to scratch file */ for (s = (unsigned char *) msg->curpos, t = s + msg->cursize; s < t; ++s) if (!*s) *s = 0x80; /* disallow NUL */ /* write buffered text */ if (fwrite (msg->curpos,1,msg->cursize,sf) == msg->cursize) SETPOS (msg,GETPOS (msg) + msg->cursize); else return NIL; /* failed */ } /* write trailing newline and return */ return (putc ('\n',sf) == EOF) ? NIL : T; } /* Append messages from scratch file to mailbox * Accepts: MAIL stream * source file * destination file * uidset to update if non-NIL * Returns: T if success, NIL if failure */ int mmdf_append_msgs (MAILSTREAM *stream,FILE *sf,FILE *df,SEARCHSET *set) { int c; long f; unsigned long i,j; char *x,tmp[MAILTMPLEN]; int hdrp = T; /* get message metadata line */ while (fgets (tmp,MAILTMPLEN,sf)) { if (!(isdigit (tmp[0]) && strchr (tmp,'\n'))) return NIL; f = strtol (tmp,&x,10); /* get flags */ if (!((*x++ == ' ') && isdigit (*x))) return NIL; i = strtoul (x,&x,10); /* get message size */ if ((*x++ != ' ') || /* build initial header */ (fprintf (df,"%sFrom %s@%s %sStatus: ",mmdfhdr,myusername(), mylocalhost(),x) < 0) || (f&fSEEN && (putc ('R',df) == EOF)) || (fputs ("\nX-Status: ",df) == EOF) || (f&fDELETED && (putc ('D',df) == EOF)) || (f&fFLAGGED && (putc ('F',df) == EOF)) || (f&fANSWERED && (putc ('A',df) == EOF)) || (f&fDRAFT && (putc ('T',df) == EOF)) || (fputs ("\nX-Keywords:",df) == EOF)) return NIL; /* copy keywords */ while ((c = getc (sf)) != '\n') switch (c) { case EOF: return NIL; default: if (putc (c,df) == EOF) return NIL; } if ((putc ('\n',df) == EOF) || (set && (fprintf (df,"X-UID: %lu\n",++(stream->uid_last)) < 0))) return NIL; for (c = '\n'; i && fgets (tmp,MAILTMPLEN,sf); c = tmp[j-1]) { /* get read line length */ if (i < (j = strlen (tmp))) fatal ("mmdf_append_msgs overrun"); i -= j; /* number of bytes left */ /* squish out ^A and CRs (note copies NUL) */ for (x = tmp; x = strpbrk (x,"\01\r"); --j) memmove (x,x+1,j-(x-tmp)); if (!j) continue; /* do nothing if line emptied */ /* start of line? */ if ((c == '\n')) switch (tmp[0]) { case 'S': case 's': /* possible "Status:" */ if (hdrp && (j > 6) && ((tmp[1] == 't') || (tmp[1] == 'T')) && ((tmp[2] == 'a') || (tmp[2] == 'A')) && ((tmp[3] == 't') || (tmp[3] == 'T')) && ((tmp[4] == 'u') || (tmp[4] == 'U')) && ((tmp[5] == 's') || (tmp[5] == 'S')) && (tmp[6] == ':') && (fputs ("X-Original-",df) == EOF)) return NIL; break; case 'X': case 'x': /* possible X-??? header */ if (hdrp && (tmp[1] == '-') && /* possible X-UID: */ (((j > 5) && ((tmp[2] == 'U') || (tmp[2] == 'u')) && ((tmp[3] == 'I') || (tmp[3] == 'i')) && ((tmp[4] == 'D') || (tmp[4] == 'd')) && (tmp[5] == ':')) || /* possible X-IMAP: */ ((j > 6) && ((tmp[2] == 'I') || (tmp[2] == 'i')) && ((tmp[3] == 'M') || (tmp[3] == 'm')) && ((tmp[4] == 'A') || (tmp[4] == 'a')) && ((tmp[5] == 'P') || (tmp[5] == 'p')) && ((tmp[6] == ':') || /* or X-IMAPbase: */ ((j > 10) && ((tmp[6] == 'b') || (tmp[6] == 'B')) && ((tmp[7] == 'a') || (tmp[7] == 'A')) && ((tmp[8] == 's') || (tmp[8] == 'S')) && ((tmp[9] == 'e') || (tmp[9] == 'E')) && (tmp[10] == ':')))) || /* possible X-Status: */ ((j > 8) && ((tmp[2] == 'S') || (tmp[2] == 's')) && ((tmp[3] == 't') || (tmp[3] == 'T')) && ((tmp[4] == 'a') || (tmp[4] == 'A')) && ((tmp[5] == 't') || (tmp[5] == 'T')) && ((tmp[6] == 'u') || (tmp[6] == 'U')) && ((tmp[7] == 's') || (tmp[7] == 'S')) && (tmp[8] == ':')) || /* possible X-Keywords: */ ((j > 10) && ((tmp[2] == 'K') || (tmp[2] == 'k')) && ((tmp[3] == 'e') || (tmp[3] == 'E')) && ((tmp[4] == 'y') || (tmp[4] == 'Y')) && ((tmp[5] == 'w') || (tmp[5] == 'W')) && ((tmp[6] == 'o') || (tmp[6] == 'O')) && ((tmp[7] == 'r') || (tmp[7] == 'R')) && ((tmp[8] == 'd') || (tmp[8] == 'D')) && ((tmp[9] == 's') || (tmp[9] == 'S')) && (tmp[10] == ':'))) && (fputs ("X-Original-",df) == EOF)) return NIL; break; case '\n': /* blank line */ hdrp = NIL; break; default: /* nothing to do */ break; } /* just write the line */ if (fwrite (tmp,1,j,df) != j) return NIL; } /* make sure read entire msg & wrote trailer */ if (i || (fputs (mmdfhdr,df) == EOF)) return NIL; /* update set */ if (stream) mail_append_set (set,stream->uid_last); } return T; } /* Internal routines */ /* MMDF mail abort stream * Accepts: MAIL stream */ void mmdf_abort (MAILSTREAM *stream) { if (LOCAL) { /* only if a file is open */ if (LOCAL->fd >= 0) close (LOCAL->fd); if (LOCAL->ld >= 0) { /* have a mailbox lock? */ flock (LOCAL->ld,LOCK_UN);/* yes, release the lock */ close (LOCAL->ld); /* close the lock file */ unlink (LOCAL->lname); /* and delete it */ } if (LOCAL->lname) fs_give ((void **) &LOCAL->lname); /* free local text buffers */ if (LOCAL->buf) fs_give ((void **) &LOCAL->buf); if (LOCAL->text.data) fs_give ((void **) &LOCAL->text.data); if (LOCAL->linebuf) fs_give ((void **) &LOCAL->linebuf); if (LOCAL->line) fs_give ((void **) &LOCAL->line); /* nuke the local data */ fs_give ((void **) &stream->local); stream->dtb = NIL; /* log out the DTB */ } } /* MMDF open and lock mailbox * Accepts: file name to open/lock * file open mode * destination buffer for lock file name * type of locking operation (LOCK_SH or LOCK_EX) */ int mmdf_lock (char *file,int flags,int mode,DOTLOCK *lock,int op) { int fd; blocknotify_t bn = (blocknotify_t) mail_parameters (NIL,GET_BLOCKNOTIFY,NIL); (*bn) (BLOCK_FILELOCK,NIL); /* try locking the easy way */ if (dotlock_lock (file,lock,-1)) { /* got dotlock file, easy open */ if ((fd = open (file,flags,mode)) >= 0) flock (fd,op); else dotlock_unlock (lock); /* open failed, free the dotlock */ } /* no dot lock file, open file now */ else if ((fd = open (file,flags,mode)) >= 0) { /* try paranoid way to make a dot lock file */ if (dotlock_lock (file,lock,fd)) { close (fd); /* get fresh fd in case of timing race */ if ((fd = open (file,flags,mode)) >= 0) flock (fd,op); /* open failed, free the dotlock */ else dotlock_unlock (lock); } else flock (fd,op); /* paranoid way failed, just flock() it */ } (*bn) (BLOCK_NONE,NIL); return fd; } /* MMDF unlock and close mailbox * Accepts: file descriptor * (optional) mailbox stream to check atime/mtime * (optional) lock file name */ void mmdf_unlock (int fd,MAILSTREAM *stream,DOTLOCK *lock) { if (stream) { /* need to muck with times? */ struct stat sbuf; time_t tp[2]; time_t now = time (0); fstat (fd,&sbuf); /* get file times */ if (LOCAL->ld >= 0) { /* yes, readwrite session? */ tp[0] = now; /* set atime to now */ /* set mtime to (now - 1) if necessary */ tp[1] = (now > sbuf.st_mtime) ? sbuf.st_mtime : now - 1; } else if (stream->recent) { /* readonly with recent messages */ if ((sbuf.st_atime >= sbuf.st_mtime) || (sbuf.st_atime >= sbuf.st_ctime)) /* keep past mtime, whack back atime */ tp[0] = (tp[1] = (sbuf.st_mtime < now) ? sbuf.st_mtime : now) - 1; else now = 0; /* no time change needed */ } /* readonly with no recent messages */ else if ((sbuf.st_atime < sbuf.st_mtime) || (sbuf.st_atime < sbuf.st_ctime)) { tp[0] = now; /* set atime to now */ /* set mtime to (now - 1) if necessary */ tp[1] = (now > sbuf.st_mtime) ? sbuf.st_mtime : now - 1; } else now = 0; /* no time change needed */ /* set the times, note change */ if (now && !utime (stream->mailbox,tp)) LOCAL->filetime = tp[1]; } flock (fd,LOCK_UN); /* release flock'ers */ if (!stream) close (fd); /* close the file if no stream */ dotlock_unlock (lock); /* flush the lock file if any */ } /* MMDF mail parse and lock mailbox * Accepts: MAIL stream * space to write lock file name * type of locking operation * Returns: T if parse OK, critical & mailbox is locked shared; NIL if failure */ int mmdf_parse (MAILSTREAM *stream,DOTLOCK *lock,int op) { int ti,zn,m; unsigned long i,j,k; unsigned char c,*s,*t,*u,tmp[MAILTMPLEN],date[30]; int retain = T; unsigned long nmsgs = stream->nmsgs; unsigned long prevuid = nmsgs ? mail_elt (stream,nmsgs)->private.uid : 0; unsigned long recent = stream->recent; unsigned long oldnmsgs = stream->nmsgs; short silent = stream->silent; short pseudoseen = NIL; struct stat sbuf; STRING bs; FDDATA d; MESSAGECACHE *elt; mail_lock (stream); /* guard against recursion or pingers */ /* toss out previous descriptor */ if (LOCAL->fd >= 0) close (LOCAL->fd); MM_CRITICAL (stream); /* open and lock mailbox (shared OK) */ if ((LOCAL->fd = mmdf_lock (stream->mailbox,(LOCAL->ld >= 0) ? O_RDWR : O_RDONLY, (long)mail_parameters(NIL,GET_MBXPROTECTION,NIL), lock,op)) < 0) { sprintf (tmp,"Mailbox open failed, aborted: %s",strerror (errno)); MM_LOG (tmp,ERROR); mmdf_abort (stream); mail_unlock (stream); MM_NOCRITICAL (stream); /* done with critical */ return NIL; } fstat (LOCAL->fd,&sbuf); /* get status */ /* validate change in size */ if (sbuf.st_size < LOCAL->filesize) { sprintf (tmp,"Mailbox shrank from %lu to %lu bytes, aborted", (unsigned long) LOCAL->filesize,(unsigned long) sbuf.st_size); MM_LOG (tmp,ERROR); /* this is pretty bad */ mmdf_unlock (LOCAL->fd,stream,lock); mmdf_abort (stream); mail_unlock (stream); MM_NOCRITICAL (stream); /* done with critical */ return NIL; } /* new data? */ else if (i = sbuf.st_size - LOCAL->filesize) { d.fd = LOCAL->fd; /* yes, set up file descriptor */ d.pos = LOCAL->filesize; /* get to that position in the file */ d.chunk = LOCAL->buf; /* initial buffer chunk */ d.chunksize = CHUNKSIZE; /* file chunk size */ INIT (&bs,fd_string,&d,i); /* initialize stringstruct */ /* skip leading whitespace for broken MTAs */ while (((c = CHR (&bs)) == '\n') || (c == '\r') || (c == ' ') || (c == '\t')) SNX (&bs); if (SIZE (&bs)) { /* read new data */ /* remember internal header position */ j = LOCAL->filesize + GETPOS (&bs); s = mmdf_mbxline (stream,&bs,&i); stream->silent = T; /* quell main program new message events */ do { /* read MMDF header */ if (!(i && ISMMDF (s))){/* see if valid MMDF header */ sprintf (tmp,"Unexpected changes to mailbox (try restarting): %.20s", (char *) s); /* see if we can back up to a line */ if (i && (j > MMDFHDRLEN)) { SETPOS (&bs,j -= MMDFHDRLEN); /* read previous line */ s = mmdf_mbxline (stream,&bs,&i); /* kill the error if it looks good */ if (i && ISMMDF (s)) tmp[0] = '\0'; } if (tmp[0]) { MM_LOG (tmp,ERROR); mmdf_unlock (LOCAL->fd,stream,lock); mmdf_abort (stream); mail_unlock (stream); MM_NOCRITICAL (stream); return NIL; } } /* instantiate first new message */ mail_exists (stream,++nmsgs); (elt = mail_elt (stream,nmsgs))->valid = T; recent++; /* assume recent by default */ elt->recent = T; /* note position/size of internal header */ elt->private.special.offset = j; elt->private.special.text.size = i; s = mmdf_mbxline (stream,&bs,&i); ti = 0; /* assume not a valid date */ zn = 0,t = NIL; if (i) VALID (s,t,ti,zn); if (ti) { /* generate plausible IMAPish date string */ /* this is also part of header */ elt->private.special.text.size += i; date[2] = date[6] = date[20] = '-'; date[11] = ' '; date[14] = date[17] = ':'; /* dd */ date[0] = t[ti - 2]; date[1] = t[ti - 1]; /* mmm */ date[3] = t[ti - 6]; date[4] = t[ti - 5]; date[5] = t[ti - 4]; /* hh */ date[12] = t[ti + 1]; date[13] = t[ti + 2]; /* mm */ date[15] = t[ti + 4]; date[16] = t[ti + 5]; if (t[ti += 6]==':'){ /* ss */ date[18] = t[++ti]; date[19] = t[++ti]; ti++; /* move to space */ } else date[18] = date[19] = '0'; /* yy -- advance over timezone if necessary */ if (zn == ti) ti += (((t[zn+1] == '+') || (t[zn+1] == '-')) ? 6 : 4); date[7] = t[ti + 1]; date[8] = t[ti + 2]; date[9] = t[ti + 3]; date[10] = t[ti + 4]; /* zzz */ t = zn ? (t + zn + 1) : (unsigned char *) "LCL"; date[21] = *t++; date[22] = *t++; date[23] = *t++; if ((date[21] != '+') && (date[21] != '-')) date[24] = '\0'; else { /* numeric time zone */ date[24] = *t++; date[25] = *t++; date[26] = '\0'; date[20] = ' '; } /* set internal date */ if (!mail_parse_date (elt,date)) { sprintf (tmp,"Unable to parse internal date: %s",(char *) date); MM_LOG (tmp,WARN); } } else { /* make date from file date */ struct tm *tm = gmtime (&sbuf.st_mtime); elt->day = tm->tm_mday; elt->month = tm->tm_mon + 1; elt->year = tm->tm_year + 1900 - BASEYEAR; elt->hours = tm->tm_hour; elt->minutes = tm->tm_min; elt->seconds = tm->tm_sec; elt->zhours = 0; elt->zminutes = 0; t = NIL; /* suppress line read */ } /* header starts here */ elt->private.msg.header.offset = elt->private.special.text.size; do { /* look for message body */ j = GETPOS (&bs); /* note position before line */ if (t) s = t = mmdf_mbxline (stream,&bs,&i); else t = s; /* this line read was suppressed */ if (ISMMDF (s)) { /* found terminator in header? */ SETPOS (&bs,j); /* oops, back up before line */ /* must insert a newline */ elt->private.spare.data++; break; /* punt */ } /* this line is part of header */ elt->private.msg.header.text.size += i; if (i) switch (*s) { /* check header lines */ case 'X': /* possible X-???: line */ if (s[1] == '-') { /* must be immediately followed by hyphen */ /* X-Status: becomes Status: in S case */ if (s[2] == 'S' && s[3] == 't' && s[4] == 'a' && s[5] == 't' && s[6] == 'u' && s[7] == 's' && s[8] == ':') s += 2; /* possible X-Keywords */ else if (s[2] == 'K' && s[3] == 'e' && s[4] == 'y' && s[5] == 'w' && s[6] == 'o' && s[7] == 'r' && s[8] == 'd' && s[9] == 's' && s[10] == ':') { SIZEDTEXT uf; retain = NIL; /* don't retain continuation */ s += 11; /* flush leading whitespace */ while (*s && (*s != '\n') && ((*s != '\r') || (s[1] != '\n'))){ while (*s == ' ') s++; /* find end of keyword */ if (!(u = strpbrk (s," \n\r"))) u = s + strlen (s); /* got a keyword? */ if ((k = (u - s)) && (k <= MAXUSERFLAG)) { uf.data = (unsigned char *) s; uf.size = k; for (j = 0; (j < NUSERFLAGS) && stream->user_flags[j]; ++j) if (!compare_csizedtext (stream->user_flags[j],&uf)) { elt->user_flags |= ((long) 1) << j; break; } } s = u; /* advance to next keyword */ } break; } /* possible X-IMAP */ else if ((s[2] == 'I') && (s[3] == 'M') && (s[4] == 'A') && (s[5] == 'P') && ((m = (s[6] == ':')) || ((s[6] == 'b') && (s[7] == 'a') && (s[8] == 's') && (s[9] == 'e') && (s[10] == ':')))) { retain = NIL; /* don't retain continuation */ if ((nmsgs == 1) && !stream->uid_validity) { /* advance to data */ s += m ? 7 : 11; /* flush whitespace */ while (*s == ' ') s++; j = 0; /* slurp UID validity */ /* found a digit? */ while (isdigit (*s)) { j *= 10; /* yes, add it in */ j += *s++ - '0'; } /* flush whitespace */ while (*s == ' ') s++; /* must have valid UID validity and UID last */ if (j && isdigit (*s)) { /* pseudo-header seen if X-IMAP */ if (m) pseudoseen = LOCAL->pseudo = T; /* save UID validity */ stream->uid_validity = j; j = 0; /* slurp UID last */ while (isdigit (*s)) { j *= 10; /* yes, add it in */ j += *s++ - '0'; } /* save UID last */ stream->uid_last = j; /* process keywords */ for (j = 0; (*s != '\n') && ((*s != '\r')||(s[1] != '\n')); s = u,j++) { /* flush leading whitespace */ while (*s == ' ') s++; u = strpbrk (s," \n\r"); /* got a keyword? */ if ((j < NUSERFLAGS) && (k = (u - s)) && (k <= MAXUSERFLAG)) { if (stream->user_flags[j]) fs_give ((void **) &stream->user_flags[j]); stream->user_flags[j] = (char *) fs_get (k + 1); strncpy (stream->user_flags[j],s,k); stream->user_flags[j][k] = '\0'; } } } } break; } /* possible X-UID */ else if (s[2] == 'U' && s[3] == 'I' && s[4] == 'D' && s[5] == ':') { retain = NIL; /* don't retain continuation */ /* only believe if have a UID validity */ if (stream->uid_validity && ((nmsgs > 1) || !pseudoseen)) { s += 6; /* advance to UID value */ /* flush whitespace */ while (*s == ' ') s++; j = 0; /* found a digit? */ while (isdigit (*s)) { j *= 10; /* yes, add it in */ j += *s++ - '0'; } /* flush remainder of line */ while (*s != '\n') s++; /* make sure not duplicated */ if (elt->private.uid) sprintf (tmp,"Message %lu UID %lu already has UID %lu", pseudoseen ? elt->msgno - 1 : elt->msgno, j,elt->private.uid); /* make sure UID doesn't go backwards */ else if (j <= prevuid) sprintf (tmp,"Message %lu UID %lu less than %lu", pseudoseen ? elt->msgno - 1 : elt->msgno, j,prevuid + 1); #if 0 /* this is currently broken by UIDPLUS */ /* or skip by mailbox's recorded last */ else if (j > stream->uid_last) sprintf (tmp,"Message %lu UID %lu greater than last %lu", pseudoseen ? elt->msgno - 1 : elt->msgno, j,stream->uid_last); #endif else { /* normal UID case */ prevuid = elt->private.uid = j; #if 1 /* temporary kludge for UIDPLUS */ if (prevuid > stream->uid_last) { stream->uid_last = prevuid; LOCAL->ddirty = LOCAL->dirty = T; } #endif break; /* exit this cruft */ } MM_LOG (tmp,WARN); /* invalidate UID validity */ stream->uid_validity = 0; elt->private.uid = 0; } break; } } /* otherwise fall into S case */ case 'S': /* possible Status: line */ if (s[0] == 'S' && s[1] == 't' && s[2] == 'a' && s[3] == 't' && s[4] == 'u' && s[5] == 's' && s[6] == ':') { retain = NIL; /* don't retain continuation */ s += 6; /* advance to status flags */ do switch (*s++) {/* parse flags */ case 'R': /* message read */ elt->seen = T; break; case 'O': /* message old */ if (elt->recent) { elt->recent = NIL; recent--; /* it really wasn't recent */ } break; case 'D': /* message deleted */ elt->deleted = T; break; case 'F': /* message flagged */ elt->flagged = T; break; case 'A': /* message answered */ elt->answered = T; break; case 'T': /* message is a draft */ elt->draft = T; break; default: /* some other crap */ break; } while (*s && (*s != '\n') && ((*s != '\r') || (s[1] != '\n'))); break; /* all done */ } /* otherwise fall into default case */ default: /* ordinary header line */ if ((*s == 'S') || (*s == 's') || (((*s == 'X') || (*s == 'x')) && (s[1] == '-'))) { unsigned char *e,*v; /* must match what mail_filter() does */ for (u = s,v = tmp,e = u + min (i,MAILTMPLEN - 1); (u < e) && ((c = (*u ? *u : (*u = ' '))) != ':') && ((c > ' ') || ((c != ' ') && (c != '\t') && (c != '\r') && (c != '\n'))); *v++ = *u++); *v = '\0'; /* tie off */ /* matches internal header? */ if (!compare_cstring (tmp,"STATUS") || !compare_cstring (tmp,"X-STATUS") || !compare_cstring (tmp,"X-KEYWORDS") || !compare_cstring (tmp,"X-UID") || !compare_cstring (tmp,"X-IMAP") || !compare_cstring (tmp,"X-IMAPBASE")) { char err[MAILTMPLEN]; sprintf (err,"Discarding bogus %s header in message %lu", (char *) tmp,elt->msgno); MM_LOG (err,WARN); retain = NIL; /* don't retain continuation */ break; /* different case or something */ } } /* retain or non-continuation? */ if (retain || ((*s != ' ') && (*s != '\t'))) { retain = T; /* retaining continuation now */ /* line length in LF format newline */ for (j = k = 0; j < i; ++j) if (s[j] != '\r') ++k; /* "internal" header size */ elt->private.spare.data += k; /* message size */ elt->rfc822_size += k + 1; } else { char err[MAILTMPLEN]; sprintf (err,"Discarding bogus continuation in msg %lu: %.80s", elt->msgno,(char *) s); if (u = strpbrk (err,"\r\n")) *u = '\0'; MM_LOG (err,WARN); break; /* different case or something */ } break; } } while (i && (*t != '\n') && ((*t != '\r') || (t[1] != '\n'))); /* "internal" header sans trailing newline */ if (i) elt->private.spare.data--; /* assign a UID if none found */ if (((nmsgs > 1) || !pseudoseen) && !elt->private.uid) { prevuid = elt->private.uid = ++stream->uid_last; elt->private.dirty = T; } else elt->private.dirty = elt->recent; /* note size of header, location of text */ elt->private.msg.header.text.size = (elt->private.msg.text.offset = (LOCAL->filesize + GETPOS (&bs)) - elt->private.special.offset) - elt->private.special.text.size; /* note current position */ j = LOCAL->filesize + GETPOS (&bs); if (i) do { /* look for next message */ s = mmdf_mbxline (stream,&bs,&i); if (i) { /* got new data? */ if (ISMMDF (s)) break; else { /* not a header line, add it to message */ elt->rfc822_size += i; for (j = 0; j < i; ++j) switch (s[j]) { case '\r': /* squeeze out CRs */ elt->rfc822_size -= 1; break; case '\n': /* LF becomes CRLF */ elt->rfc822_size += 1; break; default: break; } /* update current position */ j = LOCAL->filesize + GETPOS (&bs); } } } while (i); /* until found a header */ elt->private.msg.text.text.size = j - (elt->private.special.offset + elt->private.msg.text.offset); if (i) { /* get next header line */ /* remember first internal header position */ j = LOCAL->filesize + GETPOS (&bs); s = mmdf_mbxline (stream,&bs,&i); } /* until end of buffer */ } while (!stream->sniff && i); if (pseudoseen) { /* flush pseudo-message if present */ /* decrement recent count */ if (mail_elt (stream,1)->recent) recent--; /* and the exists count */ mail_exists (stream,nmsgs--); mail_expunged(stream,1);/* fake an expunge of that message */ } /* need to start a new UID validity? */ if (!stream->uid_validity) { stream->uid_validity = time (0); /* in case a whiner with no life */ if (mail_parameters (NIL,GET_USERHASNOLIFE,NIL)) stream->uid_nosticky = T; else if (nmsgs) { /* don't bother if empty file */ /* make dirty to restart UID epoch */ LOCAL->ddirty = LOCAL->dirty = T; /* need to rewrite msg 1 if not pseudo */ if (!LOCAL->pseudo) mail_elt (stream,1)->private.dirty = T; MM_LOG ("Assigning new unique identifiers to all messages",NIL); } } stream->nmsgs = oldnmsgs; /* whack it back down */ stream->silent = silent; /* restore old silent setting */ /* notify upper level of new mailbox sizes */ mail_exists (stream,nmsgs); mail_recent (stream,recent); /* mark dirty so O flags are set */ if (recent) LOCAL->dirty = T; } } /* no change, don't babble if never got time */ else if (LOCAL->filetime && LOCAL->filetime != sbuf.st_mtime) MM_LOG ("New mailbox modification time but apparently no changes",WARN); /* update parsed file size and time */ LOCAL->filesize = sbuf.st_size; LOCAL->filetime = sbuf.st_mtime; return T; /* return the winnage */ } /* MMDF read line from mailbox * Accepts: mail stream * stringstruct * pointer to line size * Returns: pointer to input line */ char *mmdf_mbxline (MAILSTREAM *stream,STRING *bs,unsigned long *size) { unsigned long i,j,k,m; char *s,*t,*te; char *ret = ""; /* flush old buffer */ if (LOCAL->line) fs_give ((void **) &LOCAL->line); /* if buffer needs refreshing */ if (!bs->cursize) SETPOS (bs,GETPOS (bs)); if (SIZE (bs)) { /* find newline */ /* end of fast scan */ te = (t = (s = bs->curpos) + bs->cursize) - 12; while (s < te) if ((*s++ == '\n') || (*s++ == '\n') || (*s++ == '\n') || (*s++ == '\n') || (*s++ == '\n') || (*s++ == '\n') || (*s++ == '\n') || (*s++ == '\n') || (*s++ == '\n') || (*s++ == '\n') || (*s++ == '\n') || (*s++ == '\n')) { --s; /* back up */ break; /* exit loop */ } /* final character-at-a-time scan */ while ((s < t) && (*s != '\n')) ++s; /* difficult case if line spans buffer */ if ((i = s - bs->curpos) == bs->cursize) { /* have space in line buffer? */ if (i > LOCAL->linebuflen) { fs_give ((void **) &LOCAL->linebuf); LOCAL->linebuf = (char *) fs_get (LOCAL->linebuflen = i); } /* remember what we have so far */ memcpy (LOCAL->linebuf,bs->curpos,i); /* load next buffer */ SETPOS (bs,k = GETPOS (bs) + i); /* end of fast scan */ te = (t = (s = bs->curpos) + bs->cursize) - 12; /* fast scan in overlap buffer */ while (s < te) if ((*s++ == '\n') || (*s++ == '\n') || (*s++ == '\n') || (*s++ == '\n') || (*s++ == '\n') || (*s++ == '\n') || (*s++ == '\n') || (*s++ == '\n') || (*s++ == '\n') || (*s++ == '\n') || (*s++ == '\n') || (*s++ == '\n')) { --s; /* back up */ break; /* exit loop */ } /* final character-at-a-time scan */ while ((s < t) && (*s != '\n')) ++s; /* huge line? */ if ((j = s - bs->curpos) == bs->cursize) { SETPOS (bs,GETPOS (bs) + j); /* look for end of line (s-l-o-w!!) */ for (m = SIZE (bs); m && (SNX (bs) != '\n'); --m,++j); SETPOS (bs,k); /* go back to where it started */ } /* got size of data, make buffer for return */ ret = LOCAL->line = (char *) fs_get (i + j + 2); /* copy first chunk */ memcpy (ret,LOCAL->linebuf,i); while (j) { /* copy remainder */ if (!bs->cursize) SETPOS (bs,GETPOS (bs)); memcpy (ret + i,bs->curpos,k = min (j,bs->cursize)); i += k; /* account for this much read in */ j -= k; bs->curpos += k; /* increment new position */ bs->cursize -= k; /* eat that many bytes */ } /* read newline at end */ if (SIZE (bs)) ret[i++] = SNX (bs); ret[i] = '\0'; /* makes debugging easier */ } else { /* this is easy */ ret = bs->curpos; /* string it at this position */ bs->curpos += ++i; /* increment new position */ bs->cursize -= i; /* eat that many bytes */ } *size = i; /* return that to user */ } else *size = 0; /* end of data, return empty */ /* embedded MMDF header at end of line? */ if ((*size > sizeof (MMDFHDRTXT)) && (s = ret + *size - (i = sizeof (MMDFHDRTXT) - 1)) && ISMMDF (s)) { SETPOS (bs,GETPOS (bs) - i);/* back up to start of MMDF header */ *size -= i; /* reduce length of line */ ret[*size - 1] = '\n'; /* force newline at end */ } return ret; } /* MMDF make pseudo-header * Accepts: MAIL stream * buffer to write pseudo-header * Returns: length of pseudo-header */ unsigned long mmdf_pseudo (MAILSTREAM *stream,char *hdr) { int i; char *s,tmp[MAILTMPLEN]; time_t now = time (0); rfc822_fixed_date (tmp); sprintf (hdr,"%sFrom %s %.24s\nDate: %s\nFrom: %s <%s@%.80s>\nSubject: %s\nMessage-ID: <%lu@%.80s>\nX-IMAP: %010lu %010lu", mmdfhdr,pseudo_from,ctime (&now), tmp,pseudo_name,pseudo_from,mylocalhost (),pseudo_subject, (unsigned long) now,mylocalhost (),stream->uid_validity, stream->uid_last); for (s = hdr + strlen (hdr),i = 0; i < NUSERFLAGS; ++i) if (stream->user_flags[i]) sprintf (s += strlen (s)," %s",stream->user_flags[i]); sprintf (s += strlen (s),"\nStatus: RO\n\n%s\n%s",pseudo_msg,mmdfhdr); return strlen (hdr); } /* MMDF make status string * Accepts: MAIL stream * destination string to write * message cache entry * UID to write if non-zero (else use elt->private.uid) * non-zero flag to write UID (.LT. 0 to write UID base info too) * Returns: length of string */ unsigned long mmdf_xstatus (MAILSTREAM *stream,char *status,MESSAGECACHE *elt, unsigned long uid,long flag) { char *t,stack[64]; char *s = status; unsigned long n; int pad = 50; int sticky = uid ? T : !stream->uid_nosticky; /* This used to use sprintf(), but thanks to certain cretinous C libraries with horribly slow implementations of sprintf() I had to change it to this mess. At least it should be fast. */ if ((flag < 0) && sticky) { /* need to write X-IMAPbase: header? */ *s++ = 'X'; *s++ = '-'; *s++ = 'I'; *s++ = 'M'; *s++ = 'A'; *s++ = 'P'; *s++ = 'b'; *s++ = 'a'; *s++ = 's'; *s++ = 'e'; *s++ = ':'; *s++ = ' '; t = stack; n = stream->uid_validity; /* push UID validity digits on the stack */ do *t++ = (char) (n % 10) + '0'; while (n /= 10); /* pop UID validity digits from stack */ while (t > stack) *s++ = *--t; *s++ = ' '; n = stream->uid_last; /* push UID last digits on the stack */ do *t++ = (char) (n % 10) + '0'; while (n /= 10); /* pop UID last digits from stack */ while (t > stack) *s++ = *--t; for (n = 0; n < NUSERFLAGS; ++n) if (t = stream->user_flags[n]) for (*s++ = ' '; *t; *s++ = *t++); *s++ = '\n'; pad += 30; /* increased padding if have IMAPbase */ } *s++ = 'S'; *s++ = 't'; *s++ = 'a'; *s++ = 't'; *s++ = 'u'; *s++ = 's'; *s++ = ':'; *s++ = ' '; if (elt->seen) *s++ = 'R'; /* only write O if have a UID */ if (flag && (!elt->recent || !LOCAL->appending)) *s++ = 'O'; *s++ = '\n'; *s++ = 'X'; *s++ = '-'; *s++ = 'S'; *s++ = 't'; *s++ = 'a'; *s++ = 't'; *s++ = 'u'; *s++ = 's'; *s++ = ':'; *s++ = ' '; if (elt->deleted) *s++ = 'D'; if (elt->flagged) *s++ = 'F'; if (elt->answered) *s++ = 'A'; if (elt->draft) *s++ = 'T'; *s++ = '\n'; if (sticky) { /* only do this if UIDs sticky */ *s++ = 'X'; *s++ = '-'; *s++ = 'K'; *s++ = 'e'; *s++ = 'y'; *s++ = 'w'; *s++ = 'o'; *s++ = 'r'; *s++ = 'd'; *s++ = 's'; *s++ = ':'; if (n = elt->user_flags) do { *s++ = ' '; for (t = stream->user_flags[find_rightmost_bit (&n)]; *t; *s++ = *t++); } while (n); n = s - status; /* get size of stuff so far */ /* pad X-Keywords to make size constant */ if (n < pad) for (n = pad - n; n > 0; --n) *s++ = ' '; *s++ = '\n'; if (flag) { /* want to include UID? */ t = stack; /* push UID digits on the stack */ n = uid ? uid : elt->private.uid; do *t++ = (char) (n % 10) + '0'; while (n /= 10); *s++ = 'X'; *s++ = '-'; *s++ = 'U'; *s++ = 'I'; *s++ = 'D'; *s++ = ':'; *s++ = ' '; /* pop UID from stack */ while (t > stack) *s++ = *--t; *s++ = '\n'; } } *s++ = '\n'; *s = '\0'; /* end of extended message status */ return s - status; /* return size of resulting string */ } /* Rewrite mailbox file * Accepts: MAIL stream, must be critical and locked * return pointer to number of expunged messages if want expunge * lock file name * expunge sequence, not deleted flag * Returns: T if success and mailbox unlocked, NIL if failure */ #define OVERFLOWBUFLEN 8192 /* initial overflow buffer length */ long mmdf_rewrite (MAILSTREAM *stream,unsigned long *nexp,DOTLOCK *lock, long flags) { MESSAGECACHE *elt; MMDFFILE f; char *s; time_t tp[2]; long ret,flag; unsigned long i,j; unsigned long recent = stream->recent; unsigned long size = LOCAL->pseudo ? mmdf_pseudo (stream,LOCAL->buf) : 0; if (nexp) *nexp = 0; /* initially nothing expunged */ /* calculate size of mailbox after rewrite */ for (i = 1,flag = LOCAL->pseudo ? 1 : -1; i <= stream->nmsgs; i++) { elt = mail_elt (stream,i); /* get cache */ if (!(nexp && elt->deleted && (flags ? elt->sequence : T))) { /* add RFC822 size of this message */ size += elt->private.special.text.size + elt->private.spare.data + mmdf_xstatus (stream,LOCAL->buf,elt,NIL,flag) + elt->private.msg.text.text.size + MMDFHDRLEN; flag = 1; /* only count X-IMAPbase once */ } } /* no messages, has a life, and no pseudo */ if (!size && !mail_parameters (NIL,GET_USERHASNOLIFE,NIL)) { LOCAL->pseudo = T; /* so make a pseudo-message now */ size = mmdf_pseudo (stream,LOCAL->buf); } /* extend the file as necessary */ if (ret = mmdf_extend (stream,size)) { /* Set up buffered I/O file structure * curpos current position being written through buffering * filepos current position being written physically to the disk * bufpos current position being written in the buffer * protect current maximum position that can be written to the disk * before buffering is forced * The code tries to buffer so that that disk is written in multiples of * OVERBLOWBUFLEN bytes. */ f.stream = stream; /* note mail stream */ f.curpos = f.filepos = 0; /* start of file */ f.protect = stream->nmsgs ? /* initial protection pointer */ mail_elt (stream,1)->private.special.offset : 8192; f.bufpos = f.buf = (char *) fs_get (f.buflen = OVERFLOWBUFLEN); if (LOCAL->pseudo) /* update pseudo-header */ mmdf_write (&f,LOCAL->buf,mmdf_pseudo (stream,LOCAL->buf)); /* loop through all messages */ for (i = 1,flag = LOCAL->pseudo ? 1 : -1; i <= stream->nmsgs;) { elt = mail_elt (stream,i);/* get cache */ /* expunge this message? */ if (nexp && elt->deleted && (flags ? elt->sequence : T)) { /* one less recent message */ if (elt->recent) --recent; mail_expunged(stream,i);/* notify upper levels */ ++*nexp; /* count up one more expunged message */ } else { /* preserve this message */ i++; /* advance to next message */ if ((flag < 0) || /* need to rewrite message? */ elt->private.dirty || (f.curpos != elt->private.special.offset) || (elt->private.msg.header.text.size != (elt->private.spare.data + mmdf_xstatus (stream,LOCAL->buf,elt,NIL,flag)))) { unsigned long newoffset = f.curpos; /* yes, seek to internal header */ lseek (LOCAL->fd,elt->private.special.offset,L_SET); read (LOCAL->fd,LOCAL->buf,elt->private.special.text.size); /* see if need to squeeze out a CR */ if (LOCAL->buf[elt->private.special.text.size - 2] == '\r') { LOCAL->buf[--elt->private.special.text.size - 1] = '\n'; --size; /* squeezed out a CR from PC */ } /* protection pointer moves to RFC822 header */ f.protect = elt->private.special.offset + elt->private.msg.header.offset; /* write internal header */ mmdf_write (&f,LOCAL->buf,elt->private.special.text.size); /* get RFC822 header */ s = mmdf_header (stream,elt->msgno,&j,FT_INTERNAL); /* in case this got decremented */ elt->private.msg.header.offset = elt->private.special.text.size; /* header size, sans trailing newline */ if ((j < 2) || (s[j - 2] == '\n')) j--; /* this can happen if CRs were squeezed */ if (j < elt->private.spare.data) { /* so fix up counts */ size -= elt->private.spare.data - j; elt->private.spare.data = j; } else if (j != elt->private.spare.data) fatal ("header size inconsistent"); /* protection pointer moves to RFC822 text */ f.protect = elt->private.special.offset + elt->private.msg.text.offset; mmdf_write (&f,s,j); /* write RFC822 header */ /* write status and UID */ mmdf_write (&f,LOCAL->buf, j = mmdf_xstatus (stream,LOCAL->buf,elt,NIL,flag)); flag = 1; /* only write X-IMAPbase once */ /* new file header size */ elt->private.msg.header.text.size = elt->private.spare.data + j; /* did text move? */ if (f.curpos != f.protect) { /* get message text */ s = mmdf_text_work (stream,elt,&j,FT_INTERNAL); /* this can happen if CRs were squeezed */ if (j < elt->private.msg.text.text.size) { /* so fix up counts */ size -= elt->private.msg.text.text.size - j; elt->private.msg.text.text.size = j; } /* can't happen it says here */ else if (j > elt->private.msg.text.text.size) fatal ("text size inconsistent"); /* new text offset, status/UID may change it */ elt->private.msg.text.offset = f.curpos - newoffset; /* protection pointer moves to next message */ f.protect = (i <= stream->nmsgs) ? mail_elt (stream,i)->private.special.offset : (f.curpos + j + MMDFHDRLEN); mmdf_write (&f,s,j);/* write text */ /* write trailing newline */ mmdf_write (&f,mmdfhdr,MMDFHDRLEN); } else { /* tie off header and status */ mmdf_write (&f,NIL,NIL); f.curpos = f.protect =/* restart everything at end of message */ f.filepos += elt->private.msg.text.text.size + MMDFHDRLEN; } /* new internal header offset */ elt->private.special.offset = newoffset; elt->private.dirty =NIL;/* message is now clean */ } else { /* no need to rewrite this message */ /* tie off previous message if needed */ mmdf_write (&f,NIL,NIL); f.curpos = f.protect =/* restart everything at end of message */ f.filepos += elt->private.special.text.size + elt->private.msg.header.text.size + elt->private.msg.text.text.size + MMDFHDRLEN; } } } mmdf_write (&f,NIL,NIL); /* tie off final message */ if (size != f.filepos) fatal ("file size inconsistent"); fs_give ((void **) &f.buf); /* free buffer */ /* make sure tied off */ ftruncate (LOCAL->fd,LOCAL->filesize = size); fsync (LOCAL->fd); /* make sure the updates take */ if (size && (flag < 0)) fatal ("lost UID base information"); /* no longer dirty */ LOCAL->ddirty = LOCAL->dirty = NIL; /* notify upper level of new mailbox sizes */ mail_exists (stream,stream->nmsgs); mail_recent (stream,recent); /* set atime to now, mtime a second earlier */ tp[1] = (tp[0] = time (0)) - 1; /* set the times, note change */ if (!utime (stream->mailbox,tp)) LOCAL->filetime = tp[1]; close (LOCAL->fd); /* close and reopen file */ if ((LOCAL->fd = open (stream->mailbox,O_RDWR, (long) mail_parameters (NIL,GET_MBXPROTECTION,NIL))) < 0) { sprintf (LOCAL->buf,"Mailbox open failed, aborted: %s",strerror (errno)); MM_LOG (LOCAL->buf,ERROR); mmdf_abort (stream); } dotlock_unlock (lock); /* flush the lock file */ } return ret; /* return state from algorithm */ } /* Extend MMDF mailbox file * Accepts: MAIL stream * new desired size * Return: T if success, else NIL */ long mmdf_extend (MAILSTREAM *stream,unsigned long size) { unsigned long i = (size > LOCAL->filesize) ? size - LOCAL->filesize : 0; if (i) { /* does the mailbox need to grow? */ if (i > LOCAL->buflen) { /* make sure have enough space */ /* this user won the lottery all right */ fs_give ((void **) &LOCAL->buf); LOCAL->buf = (char *) fs_get ((LOCAL->buflen = i) + 1); } memset (LOCAL->buf,'\0',i); /* get a block of nulls */ while (T) { /* until write successful or punt */ lseek (LOCAL->fd,LOCAL->filesize,L_SET); if ((write (LOCAL->fd,LOCAL->buf,i) >= 0) && !fsync (LOCAL->fd)) break; else { long e = errno; /* note error before doing ftruncate */ ftruncate (LOCAL->fd,LOCAL->filesize); if (MM_DISKERROR (stream,e,NIL)) { fsync (LOCAL->fd); /* user chose to punt */ sprintf (LOCAL->buf,"Unable to extend mailbox: %s",strerror (e)); if (!stream->silent) MM_LOG (LOCAL->buf,ERROR); return NIL; } } } } return LONGT; } /* Write data to buffered file * Accepts: buffered file pointer * file data or NIL to indicate "flush buffer" * date size (ignored for "flush buffer") * Does not return until success */ void mmdf_write (MMDFFILE *f,char *buf,unsigned long size) { unsigned long i,j,k; if (buf) { /* doing buffered write? */ i = f->bufpos - f->buf; /* yes, get size of current buffer data */ /* yes, have space in current buffer chunk? */ if (j = i ? ((f->buflen - i) % OVERFLOWBUFLEN) : f->buflen) { /* yes, fill up buffer as much as we can */ memcpy (f->bufpos,buf,k = min (j,size)); f->bufpos += k; /* new buffer position */ f->curpos += k; /* new current position */ if (j -= k) return; /* all done if still have buffer free space */ buf += k; /* full, get new unwritten data pointer */ size -= k; /* new data size */ i += k; /* new buffer data size */ } /* This chunk of the buffer is full. See if can make some space by * writing to the disk, if there's enough unprotected space to do so. * Try to fill out any unaligned chunk, along with any subsequent full * chunks that will fit in unprotected space. */ /* any unprotected space we can write to? */ if (j = min (i,f->protect - f->filepos)) { /* yes, filepos not at chunk boundary? */ if ((k = f->filepos % OVERFLOWBUFLEN) && ((k = OVERFLOWBUFLEN - k) < j)) j -= k; /* yes, and can write out partial chunk */ else k = 0; /* no partial chunk to write */ /* if at least a chunk free, write that too */ if (j > OVERFLOWBUFLEN) k += j - (j % OVERFLOWBUFLEN); if (k) { /* write data if there is anything we can */ mmdf_phys_write (f,f->buf,k); /* slide buffer */ if (i -= k) memmove (f->buf,f->buf + k,i); f->bufpos = f->buf + i; /* new end of buffer */ } } /* Have flushed the buffer as best as possible. All done if no more * data to write. Otherwise, if the buffer is empty AND if the unwritten * data is larger than a chunk AND the unprotected space is also larger * than a chunk, then write as many chunks as we can directly from the * data. Buffer the rest, expanding the buffer as needed. */ if (size) { /* have more data that we need to buffer? */ /* can write any of it to disk instead? */ if ((f->bufpos == f->buf) && ((j = min (f->protect - f->filepos,size)) > OVERFLOWBUFLEN)) { /* write as much as we can right now */ mmdf_phys_write (f,buf,j -= (j % OVERFLOWBUFLEN)); buf += j; /* new data pointer */ size -= j; /* new data size */ f->curpos += j; /* advance current pointer */ } if (size) { /* still have data that we need to buffer? */ /* yes, need to expand the buffer? */ if ((i = ((f->bufpos + size) - f->buf)) > f->buflen) { /* note current position in buffer */ j = f->bufpos - f->buf; i += OVERFLOWBUFLEN; /* yes, grow another chunk */ fs_resize ((void **) &f->buf,f->buflen = i - (i % OVERFLOWBUFLEN)); /* in case buffer relocated */ f->bufpos = f->buf + j; } /* buffer remaining data */ memcpy (f->bufpos,buf,size); f->bufpos += size; /* new end of buffer */ f->curpos += size; /* advance current pointer */ } } } else { /* flush buffer to disk */ mmdf_phys_write (f,f->buf,i = f->bufpos - f->buf); f->bufpos = f->buf; /* reset buffer */ /* update positions */ f->curpos = f->protect = f->filepos; } } /* Physical disk write * Accepts: buffered file pointer * buffer address * buffer size * Does not return until success */ void mmdf_phys_write (MMDFFILE *f,char *buf,size_t size) { MAILSTREAM *stream = f->stream; /* write data at desired position */ while (size && ((lseek (LOCAL->fd,f->filepos,L_SET) < 0) || (write (LOCAL->fd,buf,size) < 0))) { int e; char tmp[MAILTMPLEN]; sprintf (tmp,"Unable to write to mailbox: %s",strerror (e = errno)); MM_LOG (tmp,ERROR); MM_DISKERROR (NIL,e,T); /* serious problem, must retry */ } f->filepos += size; /* update file position */ } alpine-2.10+dfsg/imap/src/osdep/unix/os_dyn.c0000600000175000017500000000303211512502123022602 0ustar paulproteuspaulproteus/* ======================================================================== * Copyright 1988-2007 University of Washington * * Licensed under the Apache License, Version 2.0 (the "License"); * you may not use this file except in compliance with the License. * You may obtain a copy of the License at * * http://www.apache.org/licenses/LICENSE-2.0 * * * ======================================================================== */ /* * Program: Operating-system dependent routines -- Dynix version * * Author: Mark Crispin * Networks and Distributed Computing * Computing & Communications * University of Washington * Administration Building, AG-44 * Seattle, WA 98195 * * Date: 11 May 1989 * Last Edited: 16 August 2007 */ #include "tcp_unix.h" /* must be before osdep includes tcp.h */ #include "mail.h" #include "osdep.h" #include #include #include #include #include #include #include #include #include extern int errno; /* just in case */ #include #include "misc.h" extern int sys_nerr; extern char *sys_errlist[]; #define toint(c) ((c)-'0') #define isodigit(c) (((unsigned)(c)>=060)&((unsigned)(c)<=067)) #include "fs_unix.c" #include "ftl_unix.c" #include "nl_unix.c" #include "env_unix.c" #define fork vfork #include "tcp_unix.c" #include "gr_wait.c" #include "memmove.c" #include "strerror.c" #include "strpbrk.c" #include "strstr.c" #include "strtoul.c" #include "strtok.c" #include "tz_nul.c" alpine-2.10+dfsg/imap/src/osdep/unix/os_sv4.h0000600000175000017500000000345611512502123022543 0ustar paulproteuspaulproteus/* ======================================================================== * Copyright 1988-2006 University of Washington * * Licensed under the Apache License, Version 2.0 (the "License"); * you may not use this file except in compliance with the License. * You may obtain a copy of the License at * * http://www.apache.org/licenses/LICENSE-2.0 * * * ======================================================================== */ /* * Program: Operating-system dependent routines -- SVR4 version * * Author: Mark Crispin * Networks and Distributed Computing * Computing & Communications * University of Washington * Administration Building, AG-44 * Seattle, WA 98195 * Internet: MRC@CAC.Washington.EDU * * Date: 10 April 1992 * Last Edited: 20 December 2006 */ #include #include #include #include #include #include #include #include #include #include #include /* Many versions of SysV get this wrong */ #define setpgrp(a,b) Setpgrp(a,b) int Setpgrp (int pid,int gid); /* Different names, equivalent things in BSD and SysV */ /* L_SET is defined for some strange reason in on SVR4. */ #ifndef L_SET #define L_SET SEEK_SET #endif #define L_INCR SEEK_CUR #define L_XTND SEEK_END #define direct dirent #define random lrand48 #define utime portable_utime int portable_utime (char *file,time_t timep[2]); long gethostid (void); typedef int (*select_t) (struct direct *name); typedef int (*compar_t) (void *d1,void *d2); int scandir (char *dirname,struct direct ***namelist,select_t select, compar_t compar); int alphasort (void *d1,void *d2); #include "env_unix.h" #include "fs.h" #include "ftl.h" #include "nl.h" #include "tcp.h" #include "flocksim.h" alpine-2.10+dfsg/imap/src/osdep/unix/strerror.c0000600000175000017500000000172511512502123023200 0ustar paulproteuspaulproteus/* ======================================================================== * Copyright 1988-2006 University of Washington * * Licensed under the Apache License, Version 2.0 (the "License"); * you may not use this file except in compliance with the License. * You may obtain a copy of the License at * * http://www.apache.org/licenses/LICENSE-2.0 * * * ======================================================================== */ /* * Program: Error number to string * * Author: Mark Crispin * Networks and Distributed Computing * Computing & Communications * University of Washington * Administration Building, AG-44 * Seattle, WA 98195 * Internet: MRC@CAC.Washington.EDU * * Date: 1 August 1988 * Last Edited: 30 August 2006 */ /* Return implementation-defined string corresponding to error * Accepts: error number * Returns: string for that error */ char *strerror (int n) { return (n >= 0 && n < sys_nerr) ? sys_errlist[n] : NIL; } alpine-2.10+dfsg/imap/src/osdep/unix/fdstring.h0000600000175000017500000000205711512502123023142 0ustar paulproteuspaulproteus/* ======================================================================== * Copyright 1988-2006 University of Washington * * Licensed under the Apache License, Version 2.0 (the "License"); * you may not use this file except in compliance with the License. * You may obtain a copy of the License at * * http://www.apache.org/licenses/LICENSE-2.0 * * * ======================================================================== */ /* * Program: File descriptor string routines * * Author: Mark Crispin * Networks and Distributed Computing * Computing & Communications * University of Washington * Administration Building, AG-44 * Seattle, WA 98195 * Internet: MRC@CAC.Washington.EDU * * Date: 15 April 1997 * Last Edited: 30 August 2006 */ /* Driver-dependent data passed to init method */ typedef struct fd_data { int fd; /* file descriptor */ unsigned long pos; /* initial position */ char *chunk; /* I/O buffer chunk */ unsigned long chunksize; /* I/O buffer chunk length */ } FDDATA; extern STRINGDRIVER fd_string; alpine-2.10+dfsg/imap/src/osdep/unix/getspnam.c0000600000175000017500000000305711512502123023134 0ustar paulproteuspaulproteus/* ======================================================================== * Copyright 1988-2006 University of Washington * * Licensed under the Apache License, Version 2.0 (the "License"); * you may not use this file except in compliance with the License. * You may obtain a copy of the License at * * http://www.apache.org/licenses/LICENSE-2.0 * * * ======================================================================== */ /* * Program: 64-bit getsockname()/getpeername() emulator * * Author: Mark Crispin from code contributed by Chris Ross * Networks and Distributed Computing * Computing & Communications * University of Washington * Administration Building, AG-44 * Seattle, WA 98195 * Internet: MRC@CAC.Washington.EDU * * Date: 5 November 2004 * Last Edited: 30 August 2006 */ /* Jacket into getpeername() * Accepts: socket * pointer to socket address * void pointer to len * Returns: 0 if success, -1 if error */ int Getpeername (int s,struct sockaddr *name,size_t *namelen) { int ret; socklen_t len = (socklen_t) *namelen; ret = getpeername (s,name,&len); *namelen = (size_t) len; return ret; } /* Jacket into getsockname() * Accepts: socket * pointer to socket address * void pointer to len * Returns: 0 if success, -1 if error */ int Getsockname (int s,struct sockaddr *name,size_t *namelen) { int ret; socklen_t len = (socklen_t) *namelen; ret = getsockname (s,name,&len); *namelen = (size_t) len; return ret; } #define getpeername Getpeername #define getsockname Getsockname alpine-2.10+dfsg/imap/src/osdep/unix/os_lyn.c0000600000175000017500000000251311512502123022615 0ustar paulproteuspaulproteus/* ======================================================================== * Copyright 1988-2006 University of Washington * * Licensed under the Apache License, Version 2.0 (the "License"); * you may not use this file except in compliance with the License. * You may obtain a copy of the License at * * http://www.apache.org/licenses/LICENSE-2.0 * * * ======================================================================== */ /* * Program: Operating-system dependent routines -- LynxOS version * * Author: Mark Crispin * Networks and Distributed Computing * Computing & Communications * University of Washington * Administration Building, AG-44 * Seattle, WA 98195 * Internet: MRC@CAC.Washington.EDU * * Date: 1 August 1988 * Last Edited: 30 August 2006 */ #include "tcp_unix.h" /* must be before osdep includes tcp.h */ #include "mail.h" #include "osdep.h" #include #include #include #include #include #include #include #include #include extern int errno; /* just in case */ #include #include "misc.h" char *crypt (char *key,char *salt); #include "fs_unix.c" #include "ftl_unix.c" #include "nl_unix.c" #include "env_unix.c" #include "tcp_unix.c" #include "gr_waitp.c" #include "tz_nul.c" alpine-2.10+dfsg/imap/src/osdep/unix/dummy.h0000600000175000017500000000276411512502123022462 0ustar paulproteuspaulproteus/* ======================================================================== * Copyright 1988-2006 University of Washington * * Licensed under the Apache License, Version 2.0 (the "License"); * you may not use this file except in compliance with the License. * You may obtain a copy of the License at * * http://www.apache.org/licenses/LICENSE-2.0 * * * ======================================================================== */ /* * Program: Dummy routines * * Author: Mark Crispin * Networks and Distributed Computing * Computing & Communications * University of Washington * Administration Building, AG-44 * Seattle, WA 98195 * Internet: MRC@CAC.Washington.EDU * * Date: 9 May 1991 * Last Edited: 30 August 2006 */ /* Exported function prototypes */ void dummy_scan (MAILSTREAM *stream,char *ref,char *pat,char *contents); void dummy_list (MAILSTREAM *stream,char *ref,char *pat); void dummy_lsub (MAILSTREAM *stream,char *ref,char *pat); long scan_contents (DRIVER *dtb,char *name,char *contents, unsigned long csiz,unsigned long fsiz); long dummy_scan_contents (char *name,char *contents,unsigned long csiz, unsigned long fsiz); long dummy_create (MAILSTREAM *stream,char *mailbox); long dummy_create_path (MAILSTREAM *stream,char *path,long dirmode); long dummy_delete (MAILSTREAM *stream,char *mailbox); long dummy_rename (MAILSTREAM *stream,char *old,char *newname); char *dummy_file (char *dst,char *name); long dummy_canonicalize (char *tmp,char *ref,char *pat); alpine-2.10+dfsg/imap/src/osdep/unix/os_sv4.c0000600000175000017500000000315311512502123022530 0ustar paulproteuspaulproteus/* ======================================================================== * Copyright 1988-2006 University of Washington * * Licensed under the Apache License, Version 2.0 (the "License"); * you may not use this file except in compliance with the License. * You may obtain a copy of the License at * * http://www.apache.org/licenses/LICENSE-2.0 * * * ======================================================================== */ /* * Program: Operating-system dependent routines -- SVR4 version * * Author: Mark Crispin * Networks and Distributed Computing * Computing & Communications * University of Washington * Administration Building, AG-44 * Seattle, WA 98195 * Internet: MRC@CAC.Washington.EDU * * Date: 10 April 1992 * Last Edited: 30 August 2006 */ #include "tcp_unix.h" /* must be before osdep includes tcp.h */ #include "mail.h" #include "osdep.h" #include #include #include #include #include #include #include #include #include #include #include #include #include #include "misc.h" extern int sys_nerr; extern char *sys_errlist[]; #define DIR_SIZE(d) d->d_reclen #define toint(c) ((c)-'0') #define isodigit(c) (((unsigned)(c)>=060)&((unsigned)(c)<=067)) #include "fs_unix.c" #include "ftl_unix.c" #include "nl_unix.c" #include "env_unix.c" #include "tcp_unix.c" #include "gr_waitp.c" #include "flocksim.c" #include "scandir.c" #include "tz_sv4.c" #include "gethstid.c" #undef setpgrp #include "setpgrp.c" #include "utime.c" alpine-2.10+dfsg/imap/src/osdep/unix/os_lnx.h0000600000175000017500000000271111512502123022621 0ustar paulproteuspaulproteus/* ======================================================================== * Copyright 1988-2006 University of Washington * * Licensed under the Apache License, Version 2.0 (the "License"); * you may not use this file except in compliance with the License. * You may obtain a copy of the License at * * http://www.apache.org/licenses/LICENSE-2.0 * * * ======================================================================== */ /* * Program: Operating-system dependent routines -- Linux version * * Author: Mark Crispin * Networks and Distributed Computing * Computing & Communications * University of Washington * Administration Building, AG-44 * Seattle, WA 98195 * Internet: MRC@CAC.Washington.EDU * * Date: 10 September 1993 * Last Edited: 30 August 2006 */ /* *** These lines are claimed to be necessary to build on Debian Linux on an *** Alpha. */ #ifndef _XOPEN_SOURCE #define _XOPEN_SOURCE 1 #endif /* _XOPEN_SOURCE */ #ifndef _BSD_SOURCE #define _BSD_SOURCE 1 #endif /* _BSD_SOURCE */ /* end Debian Linux on Alpha strangeness */ #include #include #include #include #include #include /* for struct tm */ #include #include #include /* Linux gets this wrong */ #define setpgrp setpgid #define direct dirent #define flock safe_flock #include "env_unix.h" #include "fs.h" #include "ftl.h" #include "nl.h" #include "tcp.h" alpine-2.10+dfsg/imap/src/osdep/unix/os_s40.c0000600000175000017500000000312711512502123022423 0ustar paulproteuspaulproteus/* ======================================================================== * Copyright 1988-2007 University of Washington * * Licensed under the Apache License, Version 2.0 (the "License"); * you may not use this file except in compliance with the License. * You may obtain a copy of the License at * * http://www.apache.org/licenses/LICENSE-2.0 * * * ======================================================================== */ /* * Program: Operating-system dependent routines -- SUN-OS 4.0 version * * Author: Mark Crispin * Networks and Distributed Computing * Computing & Communications * University of Washington * Administration Building, AG-44 * Seattle, WA 98195 * Internet: MRC@CAC.Washington.EDU * * Date: 11 May 1989 * Last Edited: 16 August 2007 */ #include "tcp_unix.h" /* must be before osdep includes tcp.h */ #include "mail.h" #include "osdep.h" #include #include #include #include #include #include #include #include #include extern int errno; /* just in case */ #include #include "misc.h" extern int sys_nerr; extern char *sys_errlist[]; #define toint(c) ((c)-'0') #define isodigit(c) (((unsigned)(c)>=060)&((unsigned)(c)<=067)) #include "fs_unix.c" #include "ftl_unix.c" #include "nl_unix.c" #include "env_unix.c" #define fork vfork #include "tcp_unix.c" #include "gr_wait4.c" #include "memmove.c" #include "strerror.c" #define strstr Strstr /* override SUN's broken version */ #include "strstr.c" #include "strtoul.c" #include "tz_bsd.c" alpine-2.10+dfsg/imap/src/osdep/unix/os_sco.c0000600000175000017500000000317011512502123022577 0ustar paulproteuspaulproteus/* ======================================================================== * Copyright 1988-2006 University of Washington * * Licensed under the Apache License, Version 2.0 (the "License"); * you may not use this file except in compliance with the License. * You may obtain a copy of the License at * * http://www.apache.org/licenses/LICENSE-2.0 * * * ======================================================================== */ /* * Program: Operating-system dependent routines -- SCO Unix version * * Author: Mark Crispin * Networks and Distributed Computing * Computing & Communications * University of Washington * Administration Building, AG-44 * Seattle, WA 98195 * Internet: MRC@CAC.Washington.EDU * * Date: 1 August 1988 * Last Edited: 30 August 2006 */ #include "tcp_unix.h" /* must be before osdep includes tcp.h */ #include /* must be before osdep.h */ #include "mail.h" #include #include "osdep.h" #include #include #include #include #include #include #include #include "misc.h" #define SecureWare /* protected subsystem */ #include #include #include #include char *bigcrypt (char *key,char *salt); #define DIR_SIZE(d) d->d_reclen #include "fs_unix.c" #include "ftl_unix.c" #include "nl_unix.c" #include "env_unix.c" #include "tcp_unix.c" #include "gr_waitp.c" #include "flocksim.c" #include "scandir.c" #include "tz_sv4.c" #include "gethstid.c" #include "fsync.c" #undef setpgrp #include "setpgrp.c" #include "rename.c" #include "utime.c" alpine-2.10+dfsg/imap/src/osdep/unix/os_isc.h0000600000175000017500000000327211512502123022601 0ustar paulproteuspaulproteus/* ======================================================================== * Copyright 1988-2006 University of Washington * * Licensed under the Apache License, Version 2.0 (the "License"); * you may not use this file except in compliance with the License. * You may obtain a copy of the License at * * http://www.apache.org/licenses/LICENSE-2.0 * * * ======================================================================== */ /* * Program: Operating-system dependent routines -- ISC version * * Author: Mark Crispin * Networks and Distributed Computing * Computing & Communications * University of Washington * Administration Building, AG-44 * Seattle, WA 98195 * Internet: MRC@CAC.Washington.EDU * * Date: 10 April 1992 * Last Edited: 15 September 2006 */ #include #include #include #include #include #include #include #include #include #include #include /* Different names, equivalent things in BSD and SysV */ /* L_SET is defined for some strange reason in on SVR4. */ #ifndef L_SET #define L_SET SEEK_SET #endif #define L_INCR SEEK_CUR #define L_XTND SEEK_END #define direct dirent #define ftruncate chsize #define random lrand48 long gethostid (void); void *memmove (void *s,void *ct,size_t n); typedef int (*select_t) (struct direct *name); typedef int (*compar_t) (void *d1,void *d2); int scandir (char *dirname,struct direct ***namelist,select_t select, compar_t compar); int alphasort (void *d1,void *d2); #include "env_unix.h" #include "fs.h" #include "ftl.h" #include "nl.h" #include "tcp.h" #include "flocksim.h" alpine-2.10+dfsg/imap/src/osdep/unix/gr_wait.c0000600000175000017500000000242411512502123022747 0ustar paulproteuspaulproteus/* ======================================================================== * Copyright 1988-2006 University of Washington * * Licensed under the Apache License, Version 2.0 (the "License"); * you may not use this file except in compliance with the License. * You may obtain a copy of the License at * * http://www.apache.org/licenses/LICENSE-2.0 * * * ======================================================================== */ /* * Program: UNIX Grim PID Reaper -- wait() version * * Author: Mark Crispin * Networks and Distributed Computing * Computing & Communications * University of Washington * Administration Building, AG-44 * Seattle, WA 98195 * Internet: MRC@CAC.Washington.EDU * * Date: 30 November 1993 * Last Edited: 30 August 2006 */ /* Grim PID reaper * Accepts: process ID * kill request flag * status return value */ void grim_pid_reap_status (int pid,int killreq,void *status) { int r; if (killreq) { kill (pid,SIGHUP); /* kill if not already dead */ alarm (10); /* in case we get hosed */ while (((r = wait (NIL)) != pid) && ((r > 0) || ((errno != ECHILD) && (errno != EINTR)))); alarm (0); /* cancel the alarm */ } else while (((r = wait (status)) != pid) && ((r > 0) || (errno != ECHILD))); } alpine-2.10+dfsg/imap/src/osdep/unix/os_sc5.c0000600000175000017500000000307411512502123022510 0ustar paulproteuspaulproteus/* ======================================================================== * Copyright 1988-2006 University of Washington * * Licensed under the Apache License, Version 2.0 (the "License"); * you may not use this file except in compliance with the License. * You may obtain a copy of the License at * * http://www.apache.org/licenses/LICENSE-2.0 * * * ======================================================================== */ /* * Program: Operating-system dependent routines -- SCO Unix version * * Author: Mark Crispin * Networks and Distributed Computing * Computing & Communications * University of Washington * Administration Building, AG-44 * Seattle, WA 98195 * Internet: MRC@CAC.Washington.EDU * * Date: 1 August 1988 * Last Edited: 30 August 2006 */ #include "tcp_unix.h" /* must be before osdep includes tcp.h */ #include /* must be before osdep.h */ #include "mail.h" #include #include "osdep.h" #include #include #include #include #include #include #include #include "misc.h" #define SecureWare /* protected subsystem */ #include #include #include #include #define DIR_SIZE(d) d->d_reclen #include "fs_unix.c" #include "ftl_unix.c" #include "nl_unix.c" #include "env_unix.c" #include "tcp_unix.c" #include "gr_waitp.c" #include "flocksim.c" #include "scandir.c" #include "tz_sv4.c" #include "gethstid.c" #undef setpgrp #include "setpgrp.c" #include "rename.c" #include "utime.c" alpine-2.10+dfsg/imap/src/osdep/unix/os_vu2.h0000600000175000017500000000453411512502123022541 0ustar paulproteuspaulproteus/* ======================================================================== * Copyright 1988-2006 University of Washington * * Licensed under the Apache License, Version 2.0 (the "License"); * you may not use this file except in compliance with the License. * You may obtain a copy of the License at * * http://www.apache.org/licenses/LICENSE-2.0 * * * ======================================================================== */ /* * Program: Operating-system dependent routines -- VAX Ultrix 2.3 version * * Author: Mark Crispin * Networks and Distributed Computing * Computing & Communications * University of Washington * Administration Building, AG-44 * Seattle, WA 98195 * Internet: MRC@CAC.Washington.EDU * * Date: 11 May 1989 * Last Edited: 30 August 2006 */ #include #include #include #include #include #include #include /* syslog() emulation */ #define LOG_MAIL (2<<3) /* mail system */ #define LOG_DAEMON (3<<3) /* system daemons */ #define LOG_AUTH (4<<3) /* security/authorization messages */ #define LOG_EMERG 0 /* system is unusable */ #define LOG_ALERT 1 /* action must be taken immediately */ #define LOG_CRIT 2 /* critical conditions */ #define LOG_ERR 3 /* error conditions */ #define LOG_WARNING 4 /* warning conditions */ #define LOG_NOTICE 5 /* normal but signification condition */ #define LOG_INFO 6 /* informational */ #define LOG_DEBUG 7 /* debug-level messages */ #define LOG_PID 0x01 /* log the pid with each message */ #define LOG_CONS 0x02 /* log on the console if errors in sending */ #define LOG_ODELAY 0x04 /* delay open until syslog() is called */ #define LOG_NDELAY 0x08 /* don't delay open */ #define LOG_NOWAIT 0x10 /* if forking to log on console, don't wait() */ #define isodigit(c) (((unsigned)(c)>=060)&((unsigned)(c)<=067)) #define toint(c) ((c)-'0') extern int sys_nerr; extern char *sys_errlist[]; char *getenv (char *name); char *strstr (char *cs,char *ct); char *strerror (int n); void *memmove (void *s,void *ct,size_t n); unsigned long strtoul (char *s,char **endp,int base); void *malloc (size_t byteSize); void free (void *ptr); void *realloc (void *oldptr,size_t newsize); u_long portable_inet_addr (char *hostname); #include "env_unix.h" #include "fs.h" #include "ftl.h" #include "nl.h" #include "tcp.h" alpine-2.10+dfsg/imap/src/osdep/unix/ckp_sv4.c0000600000175000017500000000625511512502123022672 0ustar paulproteuspaulproteus/* ======================================================================== * Copyright 1988-2006 University of Washington * * Licensed under the Apache License, Version 2.0 (the "License"); * you may not use this file except in compliance with the License. * You may obtain a copy of the License at * * http://www.apache.org/licenses/LICENSE-2.0 * * * ======================================================================== */ /* * Program: SVR4 check password * * Author: Mark Crispin * Networks and Distributed Computing * Computing & Communications * University of Washington * Administration Building, AG-44 * Seattle, WA 98195 * Internet: MRC@CAC.Washington.EDU * * Date: 1 August 1988 * Last Edited: 30 August 2006 */ /* Check password * Accepts: login passwd struct * password string * argument count * argument vector * Returns: passwd struct if password validated, NIL otherwise */ struct passwd *checkpw (struct passwd *pw,char *pass,int argc,char *argv[]) { char tmp[MAILTMPLEN]; struct spwd *sp = NIL; time_t left; time_t now = time (0); struct tm *t = gmtime (&now); int zone = t->tm_hour * 60 + t->tm_min; int julian = t->tm_yday; t = localtime (&now); /* get local time now */ /* minus UTC minutes since midnight */ zone = t->tm_hour * 60 + t->tm_min - zone; /* julian can be one of: * 36x local time is December 31, UTC is January 1, offset -24 hours * 1 local time is 1 day ahead of UTC, offset +24 hours * 0 local time is same day as UTC, no offset * -1 local time is 1 day behind UTC, offset -24 hours * -36x local time is January 1, UTC is December 31, offset +24 hours */ if (julian = t->tm_yday -julian) zone += ((julian < 0) == (abs (julian) == 1)) ? -24*60 : 24*60; /* days since 1/1/1970 local time */ now = ((now /60) + zone) / (60*24); /* non-shadow authentication */ if (!pw->pw_passwd || !pw->pw_passwd[0] || !pw->pw_passwd[1] || strcmp (pw->pw_passwd,(char *) crypt (pass,pw->pw_passwd))) { /* As far as I've been able to determine, here is how the expiration * fields in the shadow authentication data work: * lstchg last password change date if non-negative. If zero, the * user can not log in without changing password. * max number of days a password is valid if positive * warn number of days of password expiration warning * The expiration day is the *last* day that the password is valid. */ /* shadow authentication */ if ((sp = getspnam (pw->pw_name)) && sp->sp_lstchg && ((sp->sp_lstchg < 0) || (sp->sp_max <= 0) || ((sp->sp_lstchg + sp->sp_max) >= now)) && sp->sp_pwdp && sp->sp_pwdp[0] && sp->sp_pwdp[1] && !strcmp (sp->sp_pwdp,(char *) crypt (pass,sp->sp_pwdp))) { if ((sp->sp_lstchg > 0) && (sp->sp_max > 0) && ((left = (sp->sp_lstchg + sp->sp_max) - now) <= sp->sp_warn)) { if (left) { sprintf (tmp,"[ALERT] Password expires in %ld day(s)",(long) left); mm_notify (NIL,tmp,NIL); } else mm_notify (NIL,"[ALERT] Password expires today!",WARN); } endspent (); /* don't need shadow password data any more */ } else pw = NIL; /* password failed */ } return pw; } alpine-2.10+dfsg/imap/src/osdep/unix/gr_wait4.c0000600000175000017500000000207111512502123023031 0ustar paulproteuspaulproteus/* ======================================================================== * Copyright 1988-2006 University of Washington * * Licensed under the Apache License, Version 2.0 (the "License"); * you may not use this file except in compliance with the License. * You may obtain a copy of the License at * * http://www.apache.org/licenses/LICENSE-2.0 * * * ======================================================================== */ /* * Program: UNIX Grim PID Reaper -- wait4() version * * Author: Mark Crispin * Networks and Distributed Computing * Computing & Communications * University of Washington * Administration Building, AG-44 * Seattle, WA 98195 * Internet: MRC@CAC.Washington.EDU * * Date: 30 November 1993 * Last Edited: 30 August 2006 */ /* Grim PID reaper * Accepts: process ID * kill request flag * status return value */ void grim_pid_reap_status (int pid,int killreq,void *status) { if (killreq) kill(pid,SIGHUP);/* kill if not already dead */ while ((wait4 (pid,status,NIL,NIL) < 0) && (errno != ECHILD)); } alpine-2.10+dfsg/imap/src/osdep/unix/os_slx.h0000600000175000017500000000271111512502123022626 0ustar paulproteuspaulproteus/* ======================================================================== * Copyright 1988-2006 University of Washington * * Licensed under the Apache License, Version 2.0 (the "License"); * you may not use this file except in compliance with the License. * You may obtain a copy of the License at * * http://www.apache.org/licenses/LICENSE-2.0 * * * ======================================================================== */ /* * Program: Operating-system dependent routines -- Linux version * * Author: Mark Crispin * Networks and Distributed Computing * Computing & Communications * University of Washington * Administration Building, AG-44 * Seattle, WA 98195 * Internet: MRC@CAC.Washington.EDU * * Date: 10 September 1993 * Last Edited: 30 August 2006 */ /* *** These lines are claimed to be necessary to build on Debian Linux on an *** Alpha. */ #ifndef _XOPEN_SOURCE #define _XOPEN_SOURCE 1 #endif /* _XOPEN_SOURCE */ #ifndef _BSD_SOURCE #define _BSD_SOURCE 1 #endif /* _BSD_SOURCE */ /* end Debian Linux on Alpha strangeness */ #include #include #include #include #include #include /* for struct tm */ #include #include #include /* Linux gets this wrong */ #define setpgrp setpgid #define direct dirent #define flock safe_flock #include "env_unix.h" #include "fs.h" #include "ftl.h" #include "nl.h" #include "tcp.h" alpine-2.10+dfsg/imap/src/osdep/unix/os_aix.h0000600000175000017500000000214211512502123022577 0ustar paulproteuspaulproteus/* ======================================================================== * Copyright 1988-2006 University of Washington * * Licensed under the Apache License, Version 2.0 (the "License"); * you may not use this file except in compliance with the License. * You may obtain a copy of the License at * * http://www.apache.org/licenses/LICENSE-2.0 * * * ======================================================================== */ /* * Program: Operating-system dependent routines -- AIX version * * Author: Mark Crispin * Networks and Distributed Computing * Computing & Communications * University of Washington * Administration Building, AG-44 * Seattle, WA 98195 * Internet: MRC@CAC.Washington.EDU * * Date: 1 August 1988 * Last Edited: 30 August 2006 */ #include #include #include #include #include #include #include #define direct dirent char *strerror (int n); void *memmove (void *s,void *ct,size_t n); #include "env_unix.h" #include "fs.h" #include "ftl.h" #include "nl.h" #include "tcp.h" alpine-2.10+dfsg/imap/src/osdep/unix/flocklnx.c0000600000175000017500000000441611512502123023136 0ustar paulproteuspaulproteus/* ======================================================================== * Copyright 1988-2006 University of Washington * * Licensed under the Apache License, Version 2.0 (the "License"); * you may not use this file except in compliance with the License. * You may obtain a copy of the License at * * http://www.apache.org/licenses/LICENSE-2.0 * * * ======================================================================== */ /* * Program: Safe File Lock for Linux * * Author: Mark Crispin * Networks and Distributed Computing * Computing & Communications * University of Washington * Administration Building, AG-44 * Seattle, WA 98195 * Internet: MRC@CAC.Washington.EDU * * Date: 20 April 2005 * Last Edited: 30 August 2006 */ #undef flock #include #ifndef NFS_SUPER_MAGIC #define NFS_SUPER_MAGIC 0x6969 #endif int safe_flock (int fd,int op) { struct statfs sfbuf; char tmp[MAILTMPLEN]; int e; int logged = 0; /* Check for NFS because Linux 2.6 broke flock() on NFS. Instead of being * a no-op, flock() on NFS now returns ENOLCK. Read * https://bugzilla.redhat.com/bugzilla/show_bug.cgi?id=123415 * for the gruesome details. */ /* check filesystem type */ while ((e = fstatfs (fd,&sfbuf)) && (errno == EINTR)); if (!e) switch (sfbuf.f_type) { case NFS_SUPER_MAGIC: /* always a fast no-op on NFS */ break; default: /* allow on other filesystem types */ /* do the lock */ while (flock (fd,op)) switch (errno) { case EINTR: /* interrupt */ break; case ENOLCK: /* lock table is full */ sprintf (tmp,"File locking failure: %s",strerror (errno)); mm_log (tmp,WARN); /* give the user a warning of what happened */ if (!logged++) syslog (LOG_ERR,tmp); /* return failure if non-blocking lock */ if (op & LOCK_NB) return -1; sleep (5); /* slow down in case it loops */ break; case EWOULDBLOCK: /* file is locked, LOCK_NB should be set */ if (op & LOCK_NB) return -1; case EBADF: /* not valid open file descriptor */ case EINVAL: /* invalid operator */ default: /* other error code? */ sprintf (tmp,"Unexpected file locking failure: %s",strerror (errno)); fatal (tmp); } break; } return 0; /* success */ } alpine-2.10+dfsg/imap/src/osdep/unix/phile.c0000600000175000017500000004043711512502123022422 0ustar paulproteuspaulproteus/* ======================================================================== * Copyright 1988-2006 University of Washington * * Licensed under the Apache License, Version 2.0 (the "License"); * you may not use this file except in compliance with the License. * You may obtain a copy of the License at * * http://www.apache.org/licenses/LICENSE-2.0 * * * ======================================================================== */ /* * Program: File routines * * Author: Mark Crispin * Networks and Distributed Computing * Computing & Communications * University of Washington * Administration Building, AG-44 * Seattle, WA 98195 * Internet: MRC@CAC.Washington.EDU * * Date: 25 August 1993 * Last Edited: 9 May 2006 */ #include #include #include extern int errno; /* just in case */ #include #include "mail.h" #include "osdep.h" #include #include #include #include "rfc822.h" #include "misc.h" #include "dummy.h" /* Types returned from phile_type() */ #define PTYPEBINARY 0 /* binary data */ #define PTYPETEXT 1 /* textual data */ #define PTYPECRTEXT 2 /* textual data with CR */ #define PTYPE8 4 /* textual 8bit data */ #define PTYPEISO2022JP 8 /* textual Japanese */ #define PTYPEISO2022KR 16 /* textual Korean */ #define PTYPEISO2022CN 32 /* textual Chinese */ /* PHILE I/O stream local data */ typedef struct phile_local { ENVELOPE *env; /* file envelope */ BODY *body; /* file body */ char tmp[MAILTMPLEN]; /* temporary buffer */ } PHILELOCAL; /* Convenient access to local data */ #define LOCAL ((PHILELOCAL *) stream->local) /* Function prototypes */ DRIVER *phile_valid (char *name); int phile_isvalid (char *name,char *tmp); void *phile_parameters (long function,void *value); void phile_scan (MAILSTREAM *stream,char *ref,char *pat,char *contents); void phile_list (MAILSTREAM *stream,char *ref,char *pat); void phile_lsub (MAILSTREAM *stream,char *ref,char *pat); long phile_create (MAILSTREAM *stream,char *mailbox); long phile_delete (MAILSTREAM *stream,char *mailbox); long phile_rename (MAILSTREAM *stream,char *old,char *newname); long phile_status (MAILSTREAM *stream,char *mbx,long flags); MAILSTREAM *phile_open (MAILSTREAM *stream); int phile_type (unsigned char *s,unsigned long i,unsigned long *j); void phile_close (MAILSTREAM *stream,long options); ENVELOPE *phile_structure (MAILSTREAM *stream,unsigned long msgno,BODY **body, long flags); char *phile_header (MAILSTREAM *stream,unsigned long msgno, unsigned long *length,long flags); long phile_text (MAILSTREAM *stream,unsigned long msgno,STRING *bs,long flags); long phile_ping (MAILSTREAM *stream); void phile_check (MAILSTREAM *stream); long phile_expunge (MAILSTREAM *stream,char *sequence,long options); long phile_copy (MAILSTREAM *stream,char *sequence,char *mailbox,long options); long phile_append (MAILSTREAM *stream,char *mailbox,append_t af,void *data); /* File routines */ /* Driver dispatch used by MAIL */ DRIVER philedriver = { "phile", /* driver name */ /* driver flags */ DR_LOCAL|DR_READONLY|DR_NOSTICKY, (DRIVER *) NIL, /* next driver */ phile_valid, /* mailbox is valid for us */ phile_parameters, /* manipulate parameters */ phile_scan, /* scan mailboxes */ phile_list, /* list mailboxes */ phile_lsub, /* list subscribed mailboxes */ NIL, /* subscribe to mailbox */ NIL, /* unsubscribe from mailbox */ dummy_create, /* create mailbox */ dummy_delete, /* delete mailbox */ dummy_rename, /* rename mailbox */ phile_status, /* status of mailbox */ phile_open, /* open mailbox */ phile_close, /* close mailbox */ NIL, /* fetch message "fast" attributes */ NIL, /* fetch message flags */ NIL, /* fetch overview */ phile_structure, /* fetch message envelopes */ phile_header, /* fetch message header only */ phile_text, /* fetch message body only */ NIL, /* fetch partial message text */ NIL, /* unique identifier */ NIL, /* message number */ NIL, /* modify flags */ NIL, /* per-message modify flags */ NIL, /* search for message based on criteria */ NIL, /* sort messages */ NIL, /* thread messages */ phile_ping, /* ping mailbox to see if still alive */ phile_check, /* check for new messages */ phile_expunge, /* expunge deleted messages */ phile_copy, /* copy messages to another mailbox */ phile_append, /* append string message to mailbox */ NIL /* garbage collect stream */ }; /* prototype stream */ MAILSTREAM phileproto = {&philedriver}; /* File validate mailbox * Accepts: mailbox name * Returns: our driver if name is valid, NIL otherwise */ DRIVER *phile_valid (char *name) { char tmp[MAILTMPLEN]; return phile_isvalid (name,tmp) ? &philedriver : NIL; } /* File test for valid mailbox * Accepts: mailbox name * Returns: T if valid, NIL otherwise */ int phile_isvalid (char *name,char *tmp) { struct stat sbuf; char *s; /* INBOX never accepted, any other name is */ return ((s = mailboxfile (tmp,name)) && *s && !stat (s,&sbuf) && !(sbuf.st_mode & S_IFDIR) && /* only allow empty files if no empty proto or if #ftp */ (sbuf.st_size || !default_proto (T) || ((*name == '#') && ((name[1] == 'f') || (name[1] == 'F')) && ((name[2] == 't') || (name[2] == 'T')) && ((name[3] == 'p') || (name[3] == 'P')) && (name[4] == '/')))); } /* File manipulate driver parameters * Accepts: function code * function-dependent value * Returns: function-dependent return value */ void *phile_parameters (long function,void *value) { return NIL; } /* File mail scan mailboxes * Accepts: mail stream * reference * pattern to search * string to scan */ void phile_scan (MAILSTREAM *stream,char *ref,char *pat,char *contents) { if (stream) dummy_scan (NIL,ref,pat,contents); } /* File list mailboxes * Accepts: mail stream * reference * pattern to search */ void phile_list (MAILSTREAM *stream,char *ref,char *pat) { if (stream) dummy_list (NIL,ref,pat); } /* File list subscribed mailboxes * Accepts: mail stream * reference * pattern to search */ void phile_lsub (MAILSTREAM *stream,char *ref,char *pat) { if (stream) dummy_lsub (NIL,ref,pat); } /* File status * Accepts: mail stream * mailbox name * status flags * Returns: T on success, NIL on failure */ long phile_status (MAILSTREAM *stream,char *mbx,long flags) { char *s,tmp[MAILTMPLEN]; MAILSTATUS status; struct stat sbuf; long ret = NIL; if ((s = mailboxfile (tmp,mbx)) && *s && !stat (s,&sbuf)) { status.flags = flags; /* return status values */ status.unseen = (stream && mail_elt (stream,1)->seen) ? 0 : 1; status.messages = status.recent = status.uidnext = 1; status.uidvalidity = sbuf.st_mtime; /* pass status to main program */ mm_status (stream,mbx,&status); ret = LONGT; /* success */ } return ret; } /* File open * Accepts: Stream to open * Returns: Stream on success, NIL on failure */ MAILSTREAM *phile_open (MAILSTREAM *stream) { int i,k,fd; unsigned long j,m; char *s,tmp[MAILTMPLEN]; struct passwd *pw; struct stat sbuf; struct tm *t; MESSAGECACHE *elt; SIZEDTEXT *buf; /* return prototype for OP_PROTOTYPE call */ if (!stream) return &phileproto; if (stream->local) fatal ("phile recycle stream"); /* open associated file */ if (!mailboxfile (tmp,stream->mailbox) || !tmp[0] || stat (tmp,&sbuf) || (fd = open (tmp,O_RDONLY,NIL)) < 0) { sprintf (tmp,"Unable to open file %s",stream->mailbox); mm_log (tmp,ERROR); return NIL; } fs_give ((void **) &stream->mailbox); stream->mailbox = cpystr (tmp); stream->local = fs_get (sizeof (PHILELOCAL)); mail_exists (stream,1); /* make sure upper level knows */ mail_recent (stream,1); elt = mail_elt (stream,1); /* instantiate cache element */ elt->valid = elt->recent = T; /* mark valid flags */ stream->sequence++; /* bump sequence number */ stream->rdonly = T; /* make sure upper level knows readonly */ /* instantiate a new envelope and body */ LOCAL->env = mail_newenvelope (); LOCAL->body = mail_newbody (); t = gmtime (&sbuf.st_mtime); /* get UTC time and Julian day */ i = t->tm_hour * 60 + t->tm_min; k = t->tm_yday; t = localtime(&sbuf.st_mtime);/* get local time */ /* calculate time delta */ i = t->tm_hour * 60 + t->tm_min - i; if (k = t->tm_yday - k) i += ((k < 0) == (abs (k) == 1)) ? -24*60 : 24*60; k = abs (i); /* time from UTC either way */ elt->hours = t->tm_hour; elt->minutes = t->tm_min; elt->seconds = t->tm_sec; elt->day = t->tm_mday; elt->month = t->tm_mon + 1; elt->year = t->tm_year - (BASEYEAR - 1900); elt->zoccident = (k == i) ? 0 : 1; elt->zhours = k/60; elt->zminutes = k % 60; sprintf (tmp,"%s, %d %s %d %02d:%02d:%02d %c%02d%02d", days[t->tm_wday],t->tm_mday,months[t->tm_mon],t->tm_year+1900, t->tm_hour,t->tm_min,t->tm_sec,elt->zoccident ? '-' : '+', elt->zhours,elt->zminutes); /* set up Date field */ LOCAL->env->date = cpystr (tmp); /* fill in From field from file owner */ LOCAL->env->from = mail_newaddr (); if (pw = getpwuid (sbuf.st_uid)) strcpy (tmp,pw->pw_name); else sprintf (tmp,"User-Number-%ld",(long) sbuf.st_uid); LOCAL->env->from->mailbox = cpystr (tmp); LOCAL->env->from->host = cpystr (mylocalhost ()); /* set subject to be mailbox name */ LOCAL->env->subject = cpystr (stream->mailbox); /* slurp the data */ (buf = &elt->private.special.text)->size = sbuf.st_size; read (fd,buf->data = (unsigned char *) fs_get (buf->size + 1),buf->size); buf->data[buf->size] = '\0'; close (fd); /* close the file */ /* analyze data type */ if (i = phile_type (buf->data,buf->size,&j)) { LOCAL->body->type = TYPETEXT; LOCAL->body->subtype = cpystr ("PLAIN"); if (!(i & PTYPECRTEXT)) { /* change Internet newline format as needed */ s = (char *) buf->data; /* make copy of UNIX-format string */ buf->data = NIL; /* zap the buffer */ buf->size = strcrlfcpy (&buf->data,&m,s,buf->size); fs_give ((void **) &s); /* flush original UNIX-format string */ } LOCAL->body->parameter = mail_newbody_parameter (); LOCAL->body->parameter->attribute = cpystr ("charset"); LOCAL->body->parameter->value = cpystr ((i & PTYPEISO2022JP) ? "ISO-2022-JP" : (i & PTYPEISO2022KR) ? "ISO-2022-KR" : (i & PTYPEISO2022CN) ? "ISO-2022-CN" : (i & PTYPE8) ? "X-UNKNOWN" : "US-ASCII"); LOCAL->body->encoding = (i & PTYPE8) ? ENC8BIT : ENC7BIT; LOCAL->body->size.lines = j; } else { /* binary data */ LOCAL->body->type = TYPEAPPLICATION; LOCAL->body->subtype = cpystr ("OCTET-STREAM"); LOCAL->body->parameter = mail_newbody_parameter (); LOCAL->body->parameter->attribute = cpystr ("name"); LOCAL->body->parameter->value = cpystr ((s = (strrchr (stream->mailbox,'/'))) ? s+1 : stream->mailbox); LOCAL->body->encoding = ENCBASE64; buf->data = rfc822_binary (s = (char *) buf->data,buf->size,&buf->size); fs_give ((void **) &s); /* flush originary binary contents */ } phile_header (stream,1,&j,NIL); LOCAL->body->size.bytes = LOCAL->body->contents.text.size = buf->size; elt->rfc822_size = j + buf->size; /* only one message ever... */ stream->uid_validity = sbuf.st_mtime; stream->uid_last = elt->private.uid = 1; return stream; /* return stream alive to caller */ } /* File determine data type * Accepts: data to examine * size of data * pointer to line count return * Returns: PTYPE mask of data type */ int phile_type (unsigned char *s,unsigned long i,unsigned long *j) { int ret = PTYPETEXT; char *charvec = "bbbbbbbaaalaacaabbbbbbbbbbbebbbbaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaabAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA"; *j = 0; /* no lines */ /* check type of every character */ while (i--) switch (charvec[*s++]) { case 'A': ret |= PTYPE8; /* 8bit character */ break; case 'a': break; /* ASCII character */ case 'b': return PTYPEBINARY; /* binary byte seen, stop immediately */ case 'c': ret |= PTYPECRTEXT; /* CR indicates Internet text */ break; case 'e': /* ESC */ if (*s == '$') { /* ISO-2022 sequence? */ switch (s[1]) { case 'B': case '@': ret |= PTYPEISO2022JP; break; case ')': switch (s[2]) { case 'A': case 'E': case 'G': ret |= PTYPEISO2022CN; break; case 'C': ret |= PTYPEISO2022KR; break; } case '*': switch (s[2]) { case 'H': ret |= PTYPEISO2022CN; break; } case '+': switch (s[2]) { case 'I': case 'J': case 'K': case 'L': case 'M': ret |= PTYPEISO2022CN; break; } } } break; case 'l': /* newline */ (*j)++; break; } return ret; /* return type of data */ } /* File close * Accepts: MAIL stream * close options */ void phile_close (MAILSTREAM *stream,long options) { if (LOCAL) { /* only if a file is open */ fs_give ((void **) &mail_elt (stream,1)->private.special.text.data); /* nuke the local data */ fs_give ((void **) &stream->local); stream->dtb = NIL; /* log out the DTB */ } } /* File fetch structure * Accepts: MAIL stream * message # to fetch * pointer to return body * option flags * Returns: envelope of this message, body returned in body value * * Fetches the "fast" information as well */ ENVELOPE *phile_structure (MAILSTREAM *stream,unsigned long msgno,BODY **body, long flags) { if (body) *body = LOCAL->body; return LOCAL->env; /* return the envelope */ } /* File fetch message header * Accepts: MAIL stream * message # to fetch * pointer to returned header text length * option flags * Returns: message header in RFC822 format */ char *phile_header (MAILSTREAM *stream,unsigned long msgno, unsigned long *length,long flags) { rfc822_header (LOCAL->tmp,LOCAL->env,LOCAL->body); *length = strlen (LOCAL->tmp); return LOCAL->tmp; } /* File fetch message text (body only) * Accepts: MAIL stream * message # to fetch * pointer to returned stringstruct * option flags * Returns: T, always */ long phile_text (MAILSTREAM *stream,unsigned long msgno,STRING *bs,long flags) { SIZEDTEXT *buf = &mail_elt (stream,msgno)->private.special.text; if (!(flags &FT_PEEK)) { /* mark message as seen */ mail_elt (stream,msgno)->seen = T; mm_flags (stream,msgno); } INIT (bs,mail_string,buf->data,buf->size); return T; } /* File ping mailbox * Accepts: MAIL stream * Returns: T if stream alive, else NIL * No-op for readonly files, since read/writer can expunge it from under us! */ long phile_ping (MAILSTREAM *stream) { return T; } /* File check mailbox * Accepts: MAIL stream * No-op for readonly files, since read/writer can expunge it from under us! */ void phile_check (MAILSTREAM *stream) { mm_log ("Check completed",NIL); } /* File expunge mailbox * Accepts: MAIL stream * sequence to expunge if non-NIL * expunge options * Returns: T if success, NIL if failure */ long phile_expunge (MAILSTREAM *stream,char *sequence,long options) { if (!stream->silent) mm_log ("Expunge ignored on readonly mailbox",NIL); return LONGT; } /* File copy message(s) * Accepts: MAIL stream * sequence * destination mailbox * copy options * Returns: T if copy successful, else NIL */ long phile_copy (MAILSTREAM *stream,char *sequence,char *mailbox,long options) { char tmp[MAILTMPLEN]; mailproxycopy_t pc = (mailproxycopy_t) mail_parameters (stream,GET_MAILPROXYCOPY,NIL); if (pc) return (*pc) (stream,sequence,mailbox,options); sprintf (tmp,"Can't copy - file \"%s\" is not in valid mailbox format", stream->mailbox); mm_log (tmp,ERROR); return NIL; } /* File append message from stringstruct * Accepts: MAIL stream * destination mailbox * append callback function * data for callback * Returns: T if append successful, else NIL */ long phile_append (MAILSTREAM *stream,char *mailbox,append_t af,void *data) { char tmp[MAILTMPLEN],file[MAILTMPLEN]; char *s = mailboxfile (file,mailbox); if (s && *s) sprintf (tmp,"Can't append - not in valid mailbox format: %.80s",s); else sprintf (tmp,"Can't append - invalid name: %.80s",mailbox); mm_log (tmp,ERROR); return NIL; } alpine-2.10+dfsg/imap/src/osdep/unix/os_aux.c0000600000175000017500000000301311512502123022604 0ustar paulproteuspaulproteus/* ======================================================================== * Copyright 1988-2006 University of Washington * * Licensed under the Apache License, Version 2.0 (the "License"); * you may not use this file except in compliance with the License. * You may obtain a copy of the License at * * http://www.apache.org/licenses/LICENSE-2.0 * * * ======================================================================== */ /* * Program: Operating-system dependent routines -- A/UX version * * Author: Mark Crispin * Networks and Distributed Computing * Computing & Communications * University of Washington * Administration Building, AG-44 * Seattle, WA 98195 * * Date: 11 May 1989 * Last Edited: 30 August 2006 */ #include "tcp_unix.h" /* must be before osdep includes tcp.h */ #include "mail.h" #include "osdep.h" #include #include #include #include #include #include #include #include #include #include #include #include "misc.h" #define isodigit(c) (((unsigned)(c)>=060)&((unsigned)(c)<=067)) #define toint(c) ((c)-'0') extern char *sys_errlist[]; extern int sys_nerr; #include "fs_unix.c" #include "ftl_unix.c" #include "nl_unix.c" #include "env_unix.c" #include "tcp_unix.c" #include "gr_wait.c" #include "flocksim.c" #include "strerror.c" #include "strtoul.c" #include "strpbrk.c" /* the A/UX version is bogus! */ #include "memmove.c" #include "tz_sv4.c" alpine-2.10+dfsg/imap/src/osdep/unix/log_cyg.c0000600000175000017500000000236411512502123022741 0ustar paulproteuspaulproteus/* ======================================================================== * Copyright 1988-2006 University of Washington * * Licensed under the Apache License, Version 2.0 (the "License"); * you may not use this file except in compliance with the License. * You may obtain a copy of the License at * * http://www.apache.org/licenses/LICENSE-2.0 * * * ======================================================================== */ /* * Program: Cygwin login * * Author: Mark Crispin * Networks and Distributed Computing * Computing & Communications * University of Washington * Administration Building, AG-44 * Seattle, WA 98195 * Internet: MRC@CAC.Washington.EDU * * Date: 1 August 1988 * Last Edited: 30 August 2006 */ /* Log in * Accepts: login passwd struct * argument count * argument vector * Returns: T if success, NIL otherwise */ long loginpw (struct passwd *pw,int argc,char *argv[]) { uid_t uid = pw->pw_uid; /* must be same user name as last checkpw() */ if (!(cyg_user && !strcmp (pw->pw_name,cyg_user))) return NIL; /* do the ImpersonateLoggedOnUser() */ cygwin_set_impersonation_token (cyg_hdl); return !(setgid (pw->pw_gid) || initgroups (cyg_user,pw->pw_gid) || setuid (uid)); } alpine-2.10+dfsg/imap/src/osdep/unix/os_pyr.c0000600000175000017500000000276211512502123022633 0ustar paulproteuspaulproteus/* ======================================================================== * Copyright 1988-2006 University of Washington * * Licensed under the Apache License, Version 2.0 (the "License"); * you may not use this file except in compliance with the License. * You may obtain a copy of the License at * * http://www.apache.org/licenses/LICENSE-2.0 * * * ======================================================================== */ /* * Program: Operating-system dependent routines -- Pyramid OSx 4.4c version * * Author: Mark Crispin * Networks and Distributed Computing * Computing & Communications * University of Washington * Administration Building, AG-44 * Seattle, WA 98195 * * Date: 11 May 1989 * Last Edited: 30 August 2006 */ #define isodigit(c) (((unsigned)(c)>=060)&((unsigned)(c)<=067)) #define toint(c) ((c)-'0') #include "tcp_unix.h" /* must be before osdep includes tcp.h */ #include "mail.h" #include "osdep.h" #include #include #include #include #include #include #include #include #include extern int errno; /* just in case */ #include #include "misc.h" #include "fs_unix.c" #include "ftl_unix.c" #include "nl_unix.c" #include "env_unix.c" #include "tcp_unix.c" #include "gr_wait.c" #include "memmove.c" #include "memset.c" #include "strerror.c" #include "strpbrk.c" #include "strstr.c" #include "strtok.c" #include "tz_nul.c" alpine-2.10+dfsg/imap/src/osdep/unix/log_old.c0000600000175000017500000000201111512502123022722 0ustar paulproteuspaulproteus/* ======================================================================== * Copyright 1988-2006 University of Washington * * Licensed under the Apache License, Version 2.0 (the "License"); * you may not use this file except in compliance with the License. * You may obtain a copy of the License at * * http://www.apache.org/licenses/LICENSE-2.0 * * * ======================================================================== */ /* * Program: Standard login for very old UNIX systems * * Author: Mark Crispin * Networks and Distributed Computing * Computing & Communications * University of Washington * Administration Building, AG-44 * Seattle, WA 98195 * Internet: MRC@CAC.Washington.EDU * * Date: 1 August 1988 * Last Edited: 30 August 2006 */ /* Log in * Accepts: login passwd struct * argument count * argument vector * Returns: T if success, NIL otherwise */ long loginpw (struct passwd *pw,int argc,char *argv[]) { return !(setgid (pw->pw_gid) || setuid (pw->pw_uid)); } alpine-2.10+dfsg/imap/src/osdep/unix/kerb_mit.c0000600000175000017500000000600111512502123023102 0ustar paulproteuspaulproteus/* ======================================================================== * Copyright 1988-2006 University of Washington * * Licensed under the Apache License, Version 2.0 (the "License"); * you may not use this file except in compliance with the License. * You may obtain a copy of the License at * * http://www.apache.org/licenses/LICENSE-2.0 * * * ======================================================================== */ /* * Program: MIT Kerberos routines * * Author: Mark Crispin * Networks and Distributed Computing * Computing & Communications * University of Washington * Administration Building, AG-44 * Seattle, WA 98195 * Internet: MRC@CAC.Washington.EDU * * Date: 4 March 2003 * Last Edited: 30 August 2006 */ #define PROTOTYPE(x) x #include #include long kerberos_server_valid (void); long kerberos_try_kinit (OM_uint32 error); char *kerberos_login (char *user,char *authuser,int argc,char *argv[]); /* Kerberos server valid check * Returns: T if have keytab, NIL otherwise * * Note that this routine will probably return T only if the process is root. * This is alright since the server is probably still root at this point. */ long kerberos_server_valid () { krb5_context ctx; krb5_keytab kt; krb5_kt_cursor csr; long ret = NIL; /* make a context */ if (!krb5_init_context (&ctx)) { /* get default keytab */ if (!krb5_kt_default (ctx,&kt)) { /* can do server if have good keytab */ if (!krb5_kt_start_seq_get (ctx,kt,&csr) && !krb5_kt_end_seq_get (ctx,kt,&csr)) ret = LONGT; krb5_kt_close (ctx,kt); /* finished with keytab */ } krb5_free_context (ctx); /* finished with context */ } return ret; } /* Kerberos check for missing or expired credentials * Returns: T if should suggest running kinit, NIL otherwise */ long kerberos_try_kinit (OM_uint32 error) { switch (error) { case KRB5KRB_AP_ERR_TKT_EXPIRED: case KRB5_FCC_NOFILE: /* MIT */ case KRB5_CC_NOTFOUND: /* Heimdal */ return LONGT; } return NIL; } /* Kerberos server log in * Accepts: authorization ID as user name * authentication ID as Kerberos principal * argument count * argument vector * Returns: logged in user name if logged in, NIL otherwise */ char *kerberos_login (char *user,char *authuser,int argc,char *argv[]) { krb5_context ctx; krb5_principal prnc; char kuser[NETMAXUSER]; char *ret = NIL; /* make a context */ if (!krb5_init_context (&ctx)) { /* build principal */ if (!krb5_parse_name (ctx,authuser,&prnc)) { /* can get local name for this principal? */ if (!krb5_aname_to_localname (ctx,prnc,NETMAXUSER-1,kuser)) { /* yes, local name permitted login as user? */ if (authserver_login (user,kuser,argc,argv) || authserver_login (lcase (user),kuser,argc,argv)) ret = myusername (); /* yes, return user name */ } krb5_free_principal (ctx,prnc); } krb5_free_context (ctx); /* finished with context */ } return ret; } alpine-2.10+dfsg/imap/src/osdep/unix/os_a52.c0000600000175000017500000000310511512502123022400 0ustar paulproteuspaulproteus/* ======================================================================== * Copyright 1988-2006 University of Washington * * Licensed under the Apache License, Version 2.0 (the "License"); * you may not use this file except in compliance with the License. * You may obtain a copy of the License at * * http://www.apache.org/licenses/LICENSE-2.0 * * * ======================================================================== */ /* * Program: Operating-system dependent routines -- AIX 4.1 on RS 6000 * * Author: Mark Crispin * Networks and Distributed Computing * Computing & Communications * University of Washington * Administration Building, AG-44 * Seattle, WA 98195 * Internet: MRC@CAC.Washington.EDU * * Date: 1 August 1988 * Last Edited: 30 August 2006 */ #include "tcp_unix.h" /* must be before osdep includes tcp.h */ #include "mail.h" #include "osdep.h" #include #include #include #include #include #include #include #include #include extern int errno; /* just in case */ #include #include "misc.h" #include #include /* needed for authenticate() */ int authenticate (char *UserName,char *Response,int *Reenter,char **Message); extern int sys_nerr; extern char *sys_errlist[]; #include "fs_unix.c" #include "ftl_unix.c" #include "nl_unix.c" #include "env_unix.c" #include "tcp_unix.c" #include "gr_waitp.c" #include "tz_sv4.c" #include "flocksim.c" #undef setpgrp #include "setpgrp.c" #include "utime.c" alpine-2.10+dfsg/imap/src/osdep/unix/os_sv2.c0000600000175000017500000000551411512502123022531 0ustar paulproteuspaulproteus/* ======================================================================== * Copyright 1988-2006 University of Washington * * Licensed under the Apache License, Version 2.0 (the "License"); * you may not use this file except in compliance with the License. * You may obtain a copy of the License at * * http://www.apache.org/licenses/LICENSE-2.0 * * * ======================================================================== */ /* * Program: Operating-system dependent routines -- SVR2 version * * Author: Mark Crispin * Networks and Distributed Computing * Computing & Communications * University of Washington * Administration Building, AG-44 * Seattle, WA 98195 * Internet: MRC@CAC.Washington.EDU * * Date: 10 April 1992 * Last Edited: 30 August 2006 */ #include "tcp_unix.h" /* must be before osdep includes tcp.h */ #include "mail.h" #include "osdep.h" #include #include #include #include #include #include #include extern int errno; #include #include #include #define KERNEL #include #undef KERNEL #include "misc.h" #define DIR_SIZE(d) sizeof (DIR) extern int sys_nerr; extern char *sys_errlist[]; #define toint(c) ((c)-'0') #define isodigit(c) (((unsigned)(c)>=060)&((unsigned)(c)<=067)) #define NBBY 8 /* number of bits in a byte */ #define FD_SETSIZE 256 typedef long fd_mask; #define NFDBITS (sizeof(fd_mask) * NBBY) /* bits per mask */ #define howmany(x, y) (((x)+((y)-1))/(y)) typedef struct fd_set { fd_mask fds_bits[howmany(FD_SETSIZE, NFDBITS)]; } fd_set; #define FD_SET(n, p) ((p)->fds_bits[(n)/NFDBITS] |= \ (1 << ((n) % NFDBITS))) #define FD_CLR(n, p) ((p)->fds_bits[(n)/NFDBITS] &= \ ~(1 << ((n) % NFDBITS))) #define FD_ISSET(n, p) ((p)->fds_bits[(n)/NFDBITS] & \ (1 << ((n) % NFDBITS))) #define FD_ZERO(p) bzero((char *)(p), sizeof(*(p))) #include "fs_unix.c" #include "ftl_unix.c" #include "nl_unix.c" #include "env_unix.c" #include "tcp_unix.c" #include "gr_wait.c" #include "flocksim.c" #include "opendir.c" #include "scandir.c" #include "memmove2.c" #include "strstr.c" #include "strerror.c" #include "strtoul.c" #include "tz_sv4.c" #include "gethstid.c" #include "fsync.c" #undef setpgrp #include "setpgrp.c" /* Emulator for BSD syslog() routine * Accepts: priority * message * parameters */ int syslog (int priority,char *message,char *parameters) { /* nothing here for now */ } /* Emulator for BSD openlog() routine * Accepts: identity * options * facility */ int openlog (char *ident,int logopt,int facility) { /* nothing here for now */ } /* Emulator for BSD ftruncate() routine * Accepts: file descriptor * length */ int ftruncate (int fd,unsigned long length) { return -1; /* gotta figure out how to do this */ } alpine-2.10+dfsg/imap/src/osdep/unix/os_aos.h0000600000175000017500000000241411512502123022602 0ustar paulproteuspaulproteus/* ======================================================================== * Copyright 1988-2006 University of Washington * * Licensed under the Apache License, Version 2.0 (the "License"); * you may not use this file except in compliance with the License. * You may obtain a copy of the License at * * http://www.apache.org/licenses/LICENSE-2.0 * * * ======================================================================== */ /* * Program: Operating-system dependent routines -- AOS version * * Author: Mark Crispin * Networks and Distributed Computing * Computing & Communications * University of Washington * Administration Building, AG-44 * Seattle, WA 98195 * Internet: MRC@CAC.Washington.EDU * * Date: 11 May 1989 * Last Edited: 30 August 2006 */ #include #include #include #include #include #include char *getenv (char *name); char *strstr (char *cs,char *ct); char *strerror (int n); void *memmove (void *s,void *ct,size_t n); unsigned long strtoul (char *s,char **endp,int base); void *malloc (size_t byteSize); void free (void *ptr); void *realloc (void *oldptr,size_t newsize); #include "env_unix.h" #include "fs.h" #include "ftl.h" #include "nl.h" #include "tcp.h" alpine-2.10+dfsg/imap/src/osdep/unix/ckp_gss.c0000600000175000017500000000601211512502123022741 0ustar paulproteuspaulproteus/* ======================================================================== * Copyright 1988-2007 University of Washington * * Licensed under the Apache License, Version 2.0 (the "License"); * you may not use this file except in compliance with the License. * You may obtain a copy of the License at * * http://www.apache.org/licenses/LICENSE-2.0 * * * ======================================================================== */ /* * Program: Kerberos 5 check password * * Author: Mark Crispin * Networks and Distributed Computing * Computing & Communications * University of Washington * Administration Building, AG-44 * Seattle, WA 98195 * Internet: MRC@CAC.Washington.EDU * * Date: 1 August 1988 * Last Edited: 11 October 2007 */ /* Check password * Accepts: login passwd struct * password string * argument count * argument vector * Returns: passwd struct if password validated, NIL otherwise */ struct passwd *checkpw (struct passwd *pw,char *pass,int argc,char *argv[]) { char svrnam[MAILTMPLEN],cltnam[MAILTMPLEN]; krb5_context ctx; krb5_timestamp now; krb5_principal service; krb5_ccache ccache; krb5_error_code code; krb5_creds *crd = (krb5_creds *) memset (fs_get (sizeof (krb5_creds)),0, sizeof (krb5_creds)); struct passwd *ret = NIL; if (*pass) { /* only if password non-empty */ /* make service name */ sprintf (svrnam,"%.80s@%.512s", (char *) mail_parameters (NIL,GET_SERVICENAME,NIL), tcp_serverhost ()); /* make client name with principal */ sprintf (cltnam,"%.80s/%.80s",pw->pw_name, (char *) mail_parameters (NIL,GET_SERVICENAME,NIL)); /* get a context */ if (!krb5_init_context (&ctx)) { /* get time, client and server principals */ if (!krb5_timeofday (ctx,&now) && /* Normally, kerb_cp_svr_name (defined/set in env_unix.c) is NIL, so * only the user name is used as a client principal. A few sites want * to have separate client principals for different services, but many * other sites vehemently object... */ !krb5_parse_name (ctx,kerb_cp_svr_name ? cltnam : pw->pw_name, &crd->client) && !krb5_parse_name (ctx,svrnam,&service) && !krb5_build_principal_ext(ctx,&crd->server, krb5_princ_realm (ctx,crd->client)->length, krb5_princ_realm (ctx,crd->client)->data, KRB5_TGS_NAME_SIZE,KRB5_TGS_NAME, krb5_princ_realm (ctx,crd->client)->length, krb5_princ_realm (ctx,crd->client)->data, 0)) { /* expire in 3 minutes */ crd->times.endtime = now + (3 * 60); if (krb5_cc_resolve (ctx,"MEMORY:pwk",&ccache) || krb5_cc_initialize (ctx,ccache,crd->client)) ccache = 0; if (!krb5_get_in_tkt_with_password (ctx,NIL,NIL,NIL,NIL,pass,ccache, crd,0) && !krb5_verify_init_creds (ctx,crd,service,0,ccache ? &ccache : 0,0)) ret = pw; krb5_free_creds (ctx,crd);/* flush creds and service principal */ krb5_free_principal (ctx,service); } krb5_free_context (ctx); /* don't need context any more */ } } return ret; } alpine-2.10+dfsg/imap/src/osdep/unix/ckp_dce.c0000600000175000017500000000507511512502123022710 0ustar paulproteuspaulproteus/* ======================================================================== * Copyright 1988-2006 University of Washington * * Licensed under the Apache License, Version 2.0 (the "License"); * you may not use this file except in compliance with the License. * You may obtain a copy of the License at * * http://www.apache.org/licenses/LICENSE-2.0 * * * ======================================================================== */ /* * Program: DCE check password * * Author: Mark Crispin * Networks and Distributed Computing * Computing & Communications * University of Washington * Administration Building, AG-44 * Seattle, WA 98195 * Internet: MRC@CAC.Washington.EDU * * Date: 1 August 1988 * Last Edited: 30 August 2006 */ /* Check password * Accepts: login passwd struct * password string * argument count * argument vector * Returns: passwd struct if password validated, NIL otherwise */ #include #include struct passwd *checkpw (struct passwd *pw,char *pass,int argc,char *argv[]) { sec_passwd_rec_t pwr; sec_login_handle_t lhdl; boolean32 rstpwd; sec_login_auth_src_t asrc; error_status_t status; FILE *fd; /* easy case */ if (pw->pw_passwd && pw->pw_passwd[0] && pw->pw_passwd[1] && !strcmp (pw->pw_passwd,(char *) crypt (pass,pw->pw_passwd))) return pw; /* try DCE password cache file */ if (fd = fopen (PASSWD_OVERRIDE,"r")) { char *usr = cpystr (pw->pw_name); while ((pw = fgetpwent (fd)) && strcmp (usr,pw->pw_name)); fclose (fd); /* finished with cache file */ /* validate cached password */ if (pw && pw->pw_passwd && pw->pw_passwd[0] && pw->pw_passwd[1] && !strcmp (pw->pw_passwd,(char *) crypt (pass,pw->pw_passwd))) { fs_give ((void **) &usr); return pw; } if (!pw) pw = getpwnam (usr); fs_give ((void **) &usr); } if (pw) { /* try S-L-O-W DCE... */ sec_login_setup_identity ((unsigned_char_p_t) pw->pw_name, sec_login_no_flags,&lhdl,&status); if (status == error_status_ok) { pwr.key.tagged_union.plain = (idl_char *) pass; pwr.key.key_type = sec_passwd_plain; pwr.pepper = NIL; pwr.version_number = sec_passwd_c_version_none; /* validate password with login context */ sec_login_validate_identity (lhdl,&pwr,&rstpwd,&asrc,&status); if (!rstpwd && (asrc == sec_login_auth_src_network) && (status == error_status_ok)) { sec_login_purge_context (&lhdl,&status); if (status == error_status_ok) return pw; } } } return NIL; /* password validation failed */ } alpine-2.10+dfsg/imap/src/osdep/unix/tenex.c0000600000175000017500000014130511512502123022440 0ustar paulproteuspaulproteus/* ======================================================================== * Copyright 1988-2007 University of Washington * * Licensed under the Apache License, Version 2.0 (the "License"); * you may not use this file except in compliance with the License. * You may obtain a copy of the License at * * http://www.apache.org/licenses/LICENSE-2.0 * * * ======================================================================== */ /* * Program: Tenex mail routines * * Author: Mark Crispin * Networks and Distributed Computing * Computing & Communications * University of Washington * Administration Building, AG-44 * Seattle, WA 98195 * Internet: MRC@CAC.Washington.EDU * * Date: 22 May 1990 * Last Edited: 11 October 2007 */ /* FILE TIME SEMANTICS * * The atime is the last read time of the file. * The mtime is the last flags update time of the file. * The ctime is the last write time of the file. * * TEXT SIZE SEMANTICS * * Most of the text sizes are in internal (LF-only) form, except for the * msg.text size. Beware. */ #include #include #include extern int errno; /* just in case */ #include "mail.h" #include "osdep.h" #include #include "misc.h" #include "dummy.h" /* TENEX I/O stream local data */ typedef struct tenex_local { unsigned int shouldcheck: 1; /* if ping should do a check instead */ unsigned int mustcheck: 1; /* if ping must do a check instead */ int fd; /* file descriptor for I/O */ off_t filesize; /* file size parsed */ time_t filetime; /* last file time */ time_t lastsnarf; /* local snarf time */ unsigned char *buf; /* temporary buffer */ unsigned long buflen; /* current size of temporary buffer */ unsigned long uid; /* current text uid */ SIZEDTEXT text; /* current text */ } TENEXLOCAL; /* Convenient access to local data */ #define LOCAL ((TENEXLOCAL *) stream->local) /* Function prototypes */ DRIVER *tenex_valid (char *name); int tenex_isvalid (char *name,char *tmp); void *tenex_parameters (long function,void *value); void tenex_scan (MAILSTREAM *stream,char *ref,char *pat,char *contents); void tenex_list (MAILSTREAM *stream,char *ref,char *pat); void tenex_lsub (MAILSTREAM *stream,char *ref,char *pat); long tenex_create (MAILSTREAM *stream,char *mailbox); long tenex_delete (MAILSTREAM *stream,char *mailbox); long tenex_rename (MAILSTREAM *stream,char *old,char *newname); long tenex_status (MAILSTREAM *stream,char *mbx,long flags); MAILSTREAM *tenex_open (MAILSTREAM *stream); void tenex_close (MAILSTREAM *stream,long options); void tenex_fast (MAILSTREAM *stream,char *sequence,long flags); void tenex_flags (MAILSTREAM *stream,char *sequence,long flags); char *tenex_header (MAILSTREAM *stream,unsigned long msgno, unsigned long *length,long flags); long tenex_text (MAILSTREAM *stream,unsigned long msgno,STRING *bs,long flags); void tenex_flag (MAILSTREAM *stream,char *sequence,char *flag,long flags); void tenex_flagmsg (MAILSTREAM *stream,MESSAGECACHE *elt); long tenex_ping (MAILSTREAM *stream); void tenex_check (MAILSTREAM *stream); void tenex_snarf (MAILSTREAM *stream); long tenex_expunge (MAILSTREAM *stream,char *sequence,long options); long tenex_copy (MAILSTREAM *stream,char *sequence,char *mailbox,long options); long tenex_append (MAILSTREAM *stream,char *mailbox,append_t af,void *data); unsigned long tenex_size (MAILSTREAM *stream,unsigned long m); char *tenex_file (char *dst,char *name); long tenex_parse (MAILSTREAM *stream); MESSAGECACHE *tenex_elt (MAILSTREAM *stream,unsigned long msgno); void tenex_read_flags (MAILSTREAM *stream,MESSAGECACHE *elt); void tenex_update_status (MAILSTREAM *stream,unsigned long msgno, long syncflag); unsigned long tenex_hdrpos (MAILSTREAM *stream,unsigned long msgno, unsigned long *size); /* Tenex mail routines */ /* Driver dispatch used by MAIL */ DRIVER tenexdriver = { "tenex", /* driver name */ DR_LOCAL|DR_MAIL|DR_NOSTICKY|DR_LOCKING, /* driver flags */ (DRIVER *) NIL, /* next driver */ tenex_valid, /* mailbox is valid for us */ tenex_parameters, /* manipulate parameters */ tenex_scan, /* scan mailboxes */ tenex_list, /* list mailboxes */ tenex_lsub, /* list subscribed mailboxes */ NIL, /* subscribe to mailbox */ NIL, /* unsubscribe from mailbox */ dummy_create, /* create mailbox */ tenex_delete, /* delete mailbox */ tenex_rename, /* rename mailbox */ tenex_status, /* status of mailbox */ tenex_open, /* open mailbox */ tenex_close, /* close mailbox */ tenex_fast, /* fetch message "fast" attributes */ tenex_flags, /* fetch message flags */ NIL, /* fetch overview */ NIL, /* fetch message envelopes */ tenex_header, /* fetch message header */ tenex_text, /* fetch message body */ NIL, /* fetch partial message text */ NIL, /* unique identifier */ NIL, /* message number */ tenex_flag, /* modify flags */ tenex_flagmsg, /* per-message modify flags */ NIL, /* search for message based on criteria */ NIL, /* sort messages */ NIL, /* thread messages */ tenex_ping, /* ping mailbox to see if still alive */ tenex_check, /* check for new messages */ tenex_expunge, /* expunge deleted messages */ tenex_copy, /* copy messages to another mailbox */ tenex_append, /* append string message to mailbox */ NIL /* garbage collect stream */ }; /* prototype stream */ MAILSTREAM tenexproto = {&tenexdriver}; /* Tenex mail validate mailbox * Accepts: mailbox name * Returns: our driver if name is valid, NIL otherwise */ DRIVER *tenex_valid (char *name) { char tmp[MAILTMPLEN]; return tenex_isvalid (name,tmp) ? &tenexdriver : NIL; } /* Tenex mail test for valid mailbox * Accepts: mailbox name * Returns: T if valid, NIL otherwise */ int tenex_isvalid (char *name,char *tmp) { int fd; int ret = NIL; char *s,file[MAILTMPLEN]; struct stat sbuf; time_t tp[2]; errno = EINVAL; /* assume invalid argument */ /* if file, get its status */ if ((s = tenex_file (file,name)) && !stat (s,&sbuf)) { if (!sbuf.st_size) { /* allow empty file if INBOX */ if ((s = mailboxfile (tmp,name)) && !*s) ret = T; else errno = 0; /* empty file */ } else if ((fd = open (file,O_RDONLY,NIL)) >= 0) { memset (tmp,'\0',MAILTMPLEN); if ((read (fd,tmp,64) >= 0) && (s = strchr (tmp,'\012')) && (s[-1] != '\015')) { /* valid format? */ *s = '\0'; /* tie off header */ /* must begin with dd-mmm-yy" */ ret = (((tmp[2] == '-' && tmp[6] == '-') || (tmp[1] == '-' && tmp[5] == '-')) && (s = strchr (tmp+18,',')) && strchr (s+2,';')) ? T : NIL; } else errno = -1; /* bogus format */ close (fd); /* close the file */ /* \Marked status? */ if (sbuf.st_ctime > sbuf.st_atime) { tp[0] = sbuf.st_atime; /* preserve atime and mtime */ tp[1] = sbuf.st_mtime; utime (file,tp); /* set the times */ } } } /* in case INBOX but not tenex format */ else if ((errno == ENOENT) && !compare_cstring (name,"INBOX")) errno = -1; return ret; /* return what we should */ } /* Tenex manipulate driver parameters * Accepts: function code * function-dependent value * Returns: function-dependent return value */ void *tenex_parameters (long function,void *value) { void *ret = NIL; switch ((int) function) { case GET_INBOXPATH: if (value) ret = tenex_file ((char *) value,"INBOX"); break; } return ret; } /* Tenex mail scan mailboxes * Accepts: mail stream * reference * pattern to search * string to scan */ void tenex_scan (MAILSTREAM *stream,char *ref,char *pat,char *contents) { if (stream) dummy_scan (NIL,ref,pat,contents); } /* Tenex mail list mailboxes * Accepts: mail stream * reference * pattern to search */ void tenex_list (MAILSTREAM *stream,char *ref,char *pat) { if (stream) dummy_list (NIL,ref,pat); } /* Tenex mail list subscribed mailboxes * Accepts: mail stream * reference * pattern to search */ void tenex_lsub (MAILSTREAM *stream,char *ref,char *pat) { if (stream) dummy_lsub (NIL,ref,pat); } /* Tenex mail delete mailbox * Accepts: MAIL stream * mailbox name to delete * Returns: T on success, NIL on failure */ long tenex_delete (MAILSTREAM *stream,char *mailbox) { return tenex_rename (stream,mailbox,NIL); } /* Tenex mail rename mailbox * Accepts: MAIL stream * old mailbox name * new mailbox name (or NIL for delete) * Returns: T on success, NIL on failure */ long tenex_rename (MAILSTREAM *stream,char *old,char *newname) { long ret = T; char c,*s,tmp[MAILTMPLEN],file[MAILTMPLEN],lock[MAILTMPLEN]; int fd,ld; struct stat sbuf; if (!tenex_file (file,old) || (newname && (!((s = mailboxfile (tmp,newname)) && *s) || ((s = strrchr (tmp,'/')) && !s[1])))) { sprintf (tmp,newname ? "Can't rename mailbox %.80s to %.80s: invalid name" : "Can't delete mailbox %.80s: invalid name", old,newname); MM_LOG (tmp,ERROR); return NIL; } else if ((fd = open (file,O_RDWR,NIL)) < 0) { sprintf (tmp,"Can't open mailbox %.80s: %s",old,strerror (errno)); MM_LOG (tmp,ERROR); return NIL; } /* get exclusive parse/append permission */ if ((ld = lockfd (fd,lock,LOCK_EX)) < 0) { MM_LOG ("Unable to lock rename mailbox",ERROR); return NIL; } /* lock out other users */ if (flock (fd,LOCK_EX|LOCK_NB)) { close (fd); /* couldn't lock, give up on it then */ sprintf (tmp,"Mailbox %.80s is in use by another process",old); MM_LOG (tmp,ERROR); unlockfd (ld,lock); /* release exclusive parse/append permission */ return NIL; } if (newname) { /* want rename? */ if (s = strrchr (tmp,'/')) {/* found superior to destination name? */ c = *++s; /* remember first character of inferior */ *s = '\0'; /* tie off to get just superior */ /* name doesn't exist, create it */ if ((stat (tmp,&sbuf) || ((sbuf.st_mode & S_IFMT) != S_IFDIR)) && !dummy_create_path (stream,tmp,get_dir_protection (newname))) ret = NIL; else *s = c; /* restore full name */ } /* rename the file */ if (ret && rename (file,tmp)) { sprintf (tmp,"Can't rename mailbox %.80s to %.80s: %s",old,newname, strerror (errno)); MM_LOG (tmp,ERROR); ret = NIL; /* set failure */ } } else if (unlink (file)) { sprintf (tmp,"Can't delete mailbox %.80s: %s",old,strerror (errno)); MM_LOG (tmp,ERROR); ret = NIL; /* set failure */ } flock (fd,LOCK_UN); /* release lock on the file */ close (fd); /* close the file */ unlockfd (ld,lock); /* release exclusive parse/append permission */ /* recreate file if renamed INBOX */ if (ret && !compare_cstring (old,"INBOX")) dummy_create (NIL,"mail.txt"); return ret; /* return success */ } /* Tenex Mail status * Accepts: mail stream * mailbox name * status flags * Returns: T on success, NIL on failure */ long tenex_status (MAILSTREAM *stream,char *mbx,long flags) { MAILSTATUS status; unsigned long i; MAILSTREAM *tstream = NIL; MAILSTREAM *systream = NIL; /* make temporary stream (unless this mbx) */ if (!stream && !(stream = tstream = mail_open (NIL,mbx,OP_READONLY|OP_SILENT))) return NIL; status.flags = flags; /* return status values */ status.messages = stream->nmsgs; status.recent = stream->recent; if (flags & SA_UNSEEN) /* must search to get unseen messages */ for (i = 1,status.unseen = 0; i <= stream->nmsgs; i++) if (!mail_elt (stream,i)->seen) status.unseen++; status.uidnext = stream->uid_last + 1; status.uidvalidity = stream->uid_validity; /* calculate post-snarf results */ if (!status.recent && stream->inbox && (systream = mail_open (NIL,sysinbox (),OP_READONLY|OP_SILENT))) { status.messages += systream->nmsgs; status.recent += systream->recent; if (flags & SA_UNSEEN) /* must search to get unseen messages */ for (i = 1; i <= systream->nmsgs; i++) if (!mail_elt (systream,i)->seen) status.unseen++; /* kludge but probably good enough */ status.uidnext += systream->nmsgs; } MM_STATUS(stream,mbx,&status);/* pass status to main program */ if (tstream) mail_close (tstream); if (systream) mail_close (systream); return T; /* success */ } /* Tenex mail open * Accepts: stream to open * Returns: stream on success, NIL on failure */ MAILSTREAM *tenex_open (MAILSTREAM *stream) { int fd,ld; char tmp[MAILTMPLEN]; blocknotify_t bn = (blocknotify_t) mail_parameters (NIL,GET_BLOCKNOTIFY,NIL); /* return prototype for OP_PROTOTYPE call */ if (!stream) return user_flags (&tenexproto); if (stream->local) fatal ("tenex recycle stream"); user_flags (stream); /* set up user flags */ /* canonicalize the mailbox name */ if (!tenex_file (tmp,stream->mailbox)) { sprintf (tmp,"Can't open - invalid name: %.80s",stream->mailbox); MM_LOG (tmp,ERROR); } if (stream->rdonly || (fd = open (tmp,O_RDWR,NIL)) < 0) { if ((fd = open (tmp,O_RDONLY,NIL)) < 0) { sprintf (tmp,"Can't open mailbox: %s",strerror (errno)); MM_LOG (tmp,ERROR); return NIL; } else if (!stream->rdonly) { /* got it, but readonly */ MM_LOG ("Can't get write access to mailbox, access is readonly",WARN); stream->rdonly = T; } } stream->local = fs_get (sizeof (TENEXLOCAL)); LOCAL->buf = (char *) fs_get (CHUNKSIZE); LOCAL->buflen = CHUNKSIZE - 1; LOCAL->text.data = (unsigned char *) fs_get (CHUNKSIZE); LOCAL->text.size = CHUNKSIZE - 1; /* note if an INBOX or not */ stream->inbox = !compare_cstring (stream->mailbox,"INBOX"); LOCAL->fd = fd; /* bind the file */ /* flush old name */ fs_give ((void **) &stream->mailbox); /* save canonical name */ stream->mailbox = cpystr (tmp); /* get shared parse permission */ if ((ld = lockfd (fd,tmp,LOCK_SH)) < 0) { MM_LOG ("Unable to lock open mailbox",ERROR); return NIL; } (*bn) (BLOCK_FILELOCK,NIL); flock (LOCAL->fd,LOCK_SH); /* lock the file */ (*bn) (BLOCK_NONE,NIL); unlockfd (ld,tmp); /* release shared parse permission */ LOCAL->filesize = 0; /* initialize parsed file size */ /* time not set up yet */ LOCAL->lastsnarf = LOCAL->filetime = 0; LOCAL->mustcheck = LOCAL->shouldcheck = NIL; stream->sequence++; /* bump sequence number */ /* parse mailbox */ stream->nmsgs = stream->recent = 0; if (tenex_ping (stream) && !stream->nmsgs) MM_LOG ("Mailbox is empty",(long) NIL); if (!LOCAL) return NIL; /* failure if stream died */ stream->perm_seen = stream->perm_deleted = stream->perm_flagged = stream->perm_answered = stream->perm_draft = stream->rdonly ? NIL : T; stream->perm_user_flags = stream->rdonly ? NIL : 0xffffffff; return stream; /* return stream to caller */ } /* Tenex mail close * Accepts: MAIL stream * close options */ void tenex_close (MAILSTREAM *stream,long options) { if (stream && LOCAL) { /* only if a file is open */ int silent = stream->silent; stream->silent = T; /* note this stream is dying */ if (options & CL_EXPUNGE) tenex_expunge (stream,NIL,NIL); stream->silent = silent; /* restore previous status */ flock (LOCAL->fd,LOCK_UN); /* unlock local file */ close (LOCAL->fd); /* close the local file */ /* free local text buffer */ if (LOCAL->buf) fs_give ((void **) &LOCAL->buf); if (LOCAL->text.data) fs_give ((void **) &LOCAL->text.data); /* nuke the local data */ fs_give ((void **) &stream->local); stream->dtb = NIL; /* log out the DTB */ } } /* Tenex mail fetch fast data * Accepts: MAIL stream * sequence * option flags */ void tenex_fast (MAILSTREAM *stream,char *sequence,long flags) { STRING bs; MESSAGECACHE *elt; unsigned long i; if (stream && LOCAL && ((flags & FT_UID) ? mail_uid_sequence (stream,sequence) : mail_sequence (stream,sequence))) for (i = 1; i <= stream->nmsgs; i++) if ((elt = mail_elt (stream,i))->sequence) { if (!elt->rfc822_size) { /* have header size yet? */ lseek (LOCAL->fd,elt->private.special.offset + elt->private.special.text.size,L_SET); /* resize bigbuf if necessary */ if (LOCAL->buflen < elt->private.msg.full.text.size) { fs_give ((void **) &LOCAL->buf); LOCAL->buflen = elt->private.msg.full.text.size; LOCAL->buf = (char *) fs_get (LOCAL->buflen + 1); } /* tie off string */ LOCAL->buf[elt->private.msg.full.text.size] = '\0'; /* read in the message */ read (LOCAL->fd,LOCAL->buf,elt->private.msg.full.text.size); INIT (&bs,mail_string,(void *) LOCAL->buf, elt->private.msg.full.text.size); /* calculate its CRLF size */ elt->rfc822_size = strcrlflen (&bs); } tenex_elt (stream,i); /* get current flags from file */ } } /* Tenex mail fetch flags * Accepts: MAIL stream * sequence * option flags * Sniffs at file to get flags */ void tenex_flags (MAILSTREAM *stream,char *sequence,long flags) { unsigned long i; if (stream && LOCAL && ((flags & FT_UID) ? mail_uid_sequence (stream,sequence) : mail_sequence (stream,sequence))) for (i = 1; i <= stream->nmsgs; i++) if (mail_elt (stream,i)->sequence) tenex_elt (stream,i); } /* TENEX mail fetch message header * Accepts: MAIL stream * message # to fetch * pointer to returned header text length * option flags * Returns: message header in RFC822 format */ char *tenex_header (MAILSTREAM *stream,unsigned long msgno, unsigned long *length,long flags) { char *s; unsigned long i; *length = 0; /* default to empty */ if (flags & FT_UID) return "";/* UID call "impossible" */ /* get to header position */ lseek (LOCAL->fd,tenex_hdrpos (stream,msgno,&i),L_SET); if (flags & FT_INTERNAL) { if (i > LOCAL->buflen) { /* resize if not enough space */ fs_give ((void **) &LOCAL->buf); LOCAL->buf = (char *) fs_get (LOCAL->buflen = i + 1); } /* slurp the data */ read (LOCAL->fd,LOCAL->buf,*length = i); } else { s = (char *) fs_get (i + 1);/* get readin buffer */ s[i] = '\0'; /* tie off string */ read (LOCAL->fd,s,i); /* slurp the data */ /* make CRLF copy of string */ *length = strcrlfcpy (&LOCAL->buf,&LOCAL->buflen,s,i); fs_give ((void **) &s); /* free readin buffer */ } return (char *) LOCAL->buf; } /* TENEX mail fetch message text (body only) * Accepts: MAIL stream * message # to fetch * pointer to returned stringstruct * option flags * Returns: T, always */ long tenex_text (MAILSTREAM *stream,unsigned long msgno,STRING *bs,long flags) { char *s; unsigned long i,j; MESSAGECACHE *elt; /* UID call "impossible" */ if (flags & FT_UID) return NIL; /* get message status */ elt = tenex_elt (stream,msgno); /* if message not seen */ if (!(flags & FT_PEEK) && !elt->seen) { elt->seen = T; /* mark message as seen */ /* recalculate status */ tenex_update_status (stream,msgno,T); MM_FLAGS (stream,msgno); } if (flags & FT_INTERNAL) { /* if internal representation wanted */ /* find header position */ i = tenex_hdrpos (stream,msgno,&j); if (i > LOCAL->buflen) { /* resize if not enough space */ fs_give ((void **) &LOCAL->buf); LOCAL->buf = (char *) fs_get (LOCAL->buflen = i + 1); } /* go to text position */ lseek (LOCAL->fd,i + j,L_SET); /* slurp the data */ read (LOCAL->fd,LOCAL->buf,i); /* set up stringstruct for internal */ INIT (bs,mail_string,LOCAL->buf,i); } else { /* normal form, previous text cached? */ if (elt->private.uid == LOCAL->uid) i = elt->private.msg.text.text.size; else { /* not cached, cache it now */ LOCAL->uid = elt->private.uid; /* find header position */ i = tenex_hdrpos (stream,msgno,&j); /* go to text position */ lseek (LOCAL->fd,i + j,L_SET); s = (char *) fs_get ((i = tenex_size (stream,msgno) - j) + 1); s[i] = '\0'; /* tie off string */ read (LOCAL->fd,s,i); /* slurp the data */ /* make CRLF copy of string */ i = elt->private.msg.text.text.size = strcrlfcpy (&LOCAL->text.data,&LOCAL->text.size,s,i); fs_give ((void **) &s); /* free readin buffer */ } /* set up stringstruct */ INIT (bs,mail_string,LOCAL->text.data,i); } return T; /* success */ } /* Tenex mail modify flags * Accepts: MAIL stream * sequence * flag(s) * option flags */ void tenex_flag (MAILSTREAM *stream,char *sequence,char *flag,long flags) { time_t tp[2]; struct stat sbuf; if (!stream->rdonly) { /* make sure the update takes */ fsync (LOCAL->fd); fstat (LOCAL->fd,&sbuf); /* get current write time */ tp[1] = LOCAL->filetime = sbuf.st_mtime; tp[0] = time (0); /* make sure read comes after all that */ utime (stream->mailbox,tp); } } /* Tenex mail per-message modify flags * Accepts: MAIL stream * message cache element */ void tenex_flagmsg (MAILSTREAM *stream,MESSAGECACHE *elt) { struct stat sbuf; /* maybe need to do a checkpoint? */ if (LOCAL->filetime && !LOCAL->shouldcheck) { fstat (LOCAL->fd,&sbuf); /* get current write time */ if (LOCAL->filetime < sbuf.st_mtime) LOCAL->shouldcheck = T; LOCAL->filetime = 0; /* don't do this test for any other messages */ } /* recalculate status */ tenex_update_status (stream,elt->msgno,NIL); } /* Tenex mail ping mailbox * Accepts: MAIL stream * Returns: T if stream still alive, NIL if not */ long tenex_ping (MAILSTREAM *stream) { unsigned long i = 1; long r = T; int ld; char lock[MAILTMPLEN]; struct stat sbuf; if (stream && LOCAL) { /* only if stream already open */ fstat (LOCAL->fd,&sbuf); /* get current file poop */ if (LOCAL->filetime && !(LOCAL->mustcheck || LOCAL->shouldcheck) && (LOCAL->filetime < sbuf.st_mtime)) LOCAL->shouldcheck = T; /* check for changed message status */ if (LOCAL->mustcheck || LOCAL->shouldcheck) { LOCAL->filetime = sbuf.st_mtime; if (LOCAL->shouldcheck) /* babble when we do this unilaterally */ MM_NOTIFY (stream,"[CHECK] Checking for flag updates",NIL); while (i <= stream->nmsgs) tenex_elt (stream,i++); LOCAL->mustcheck = LOCAL->shouldcheck = NIL; } /* get shared parse/append permission */ if ((sbuf.st_size != LOCAL->filesize) && ((ld = lockfd (LOCAL->fd,lock,LOCK_SH)) >= 0)) { /* parse resulting mailbox */ r = (tenex_parse (stream)) ? T : NIL; unlockfd (ld,lock); /* release shared parse/append permission */ } if (LOCAL) { /* stream must still be alive */ /* snarf if this is a read-write inbox */ if (stream->inbox && !stream->rdonly) { tenex_snarf (stream); fstat (LOCAL->fd,&sbuf);/* see if file changed now */ if ((sbuf.st_size != LOCAL->filesize) && ((ld = lockfd (LOCAL->fd,lock,LOCK_SH)) >= 0)) { /* parse resulting mailbox */ r = (tenex_parse (stream)) ? T : NIL; unlockfd (ld,lock); /* release shared parse/append permission */ } } } } return r; /* return result of the parse */ } /* Tenex mail check mailbox (reparses status too) * Accepts: MAIL stream */ void tenex_check (MAILSTREAM *stream) { /* mark that a check is desired */ if (LOCAL) LOCAL->mustcheck = T; if (tenex_ping (stream)) MM_LOG ("Check completed",(long) NIL); } /* Tenex mail snarf messages from system inbox * Accepts: MAIL stream */ void tenex_snarf (MAILSTREAM *stream) { unsigned long i = 0; unsigned long j,r,hdrlen,txtlen; struct stat sbuf; char *hdr,*txt,lock[MAILTMPLEN],tmp[MAILTMPLEN]; MESSAGECACHE *elt; MAILSTREAM *sysibx = NIL; int ld; /* give up if can't get exclusive permission */ if ((time (0) >= (LOCAL->lastsnarf + (long) mail_parameters (NIL,GET_SNARFINTERVAL,NIL))) && strcmp (sysinbox (),stream->mailbox) && ((ld = lockfd (LOCAL->fd,lock,LOCK_EX)) >= 0)) { MM_CRITICAL (stream); /* go critical */ /* sizes match and anything in sysinbox? */ if (!stat (sysinbox (),&sbuf) && sbuf.st_size && !fstat (LOCAL->fd,&sbuf) && (sbuf.st_size == LOCAL->filesize) && (sysibx = mail_open (sysibx,sysinbox (),OP_SILENT)) && (!sysibx->rdonly) && (r = sysibx->nmsgs)) { /* yes, go to end of file in our mailbox */ lseek (LOCAL->fd,sbuf.st_size,L_SET); /* for each message in sysibx mailbox */ while (r && (++i <= sysibx->nmsgs)) { /* snarf message from system INBOX */ hdr = cpystr (mail_fetchheader_full(sysibx,i,NIL,&hdrlen,FT_INTERNAL)); txt = mail_fetchtext_full (sysibx,i,&txtlen,FT_INTERNAL|FT_PEEK); /* if have a message */ if (j = hdrlen + txtlen) { /* calculate header line */ mail_date (LOCAL->buf,elt = mail_elt (sysibx,i)); sprintf (LOCAL->buf + strlen (LOCAL->buf), ",%lu;0000000000%02o\n",j,(unsigned) ((fSEEN * elt->seen) + (fDELETED * elt->deleted) + (fFLAGGED * elt->flagged) + (fANSWERED * elt->answered) + (fDRAFT * elt->draft))); /* copy message */ if ((write (LOCAL->fd,LOCAL->buf,strlen (LOCAL->buf)) < 0) || (write (LOCAL->fd,hdr,hdrlen) < 0) || (write (LOCAL->fd,txt,txtlen) < 0)) r = 0; } fs_give ((void **) &hdr); } /* make sure all the updates take */ if (fsync (LOCAL->fd)) r = 0; if (r) { /* delete all the messages we copied */ if (r == 1) strcpy (tmp,"1"); else sprintf (tmp,"1:%lu",r); mail_flag (sysibx,tmp,"\\Deleted",ST_SET); mail_expunge (sysibx); /* now expunge all those messages */ } else { sprintf (LOCAL->buf,"Can't copy new mail: %s",strerror (errno)); MM_LOG (LOCAL->buf,WARN); ftruncate (LOCAL->fd,sbuf.st_size); } fstat (LOCAL->fd,&sbuf); /* yes, get current file size */ LOCAL->filetime = sbuf.st_mtime; } if (sysibx) mail_close (sysibx); MM_NOCRITICAL (stream); /* release critical */ unlockfd (ld,lock); /* release exclusive parse/append permission */ LOCAL->lastsnarf = time (0);/* note time of last snarf */ } } /* Tenex mail expunge mailbox * Accepts: MAIL stream * sequence to expunge if non-NIL * expunge options * Returns: T, always */ long tenex_expunge (MAILSTREAM *stream,char *sequence,long options) { long ret; time_t tp[2]; struct stat sbuf; off_t pos = 0; int ld; unsigned long i = 1; unsigned long j,k,m,recent; unsigned long n = 0; unsigned long delta = 0; char lock[MAILTMPLEN]; MESSAGECACHE *elt; blocknotify_t bn = (blocknotify_t) mail_parameters (NIL,GET_BLOCKNOTIFY,NIL); if (!(ret = (sequence ? ((options & EX_UID) ? mail_uid_sequence (stream,sequence) : mail_sequence (stream,sequence)) : LONGT) && tenex_ping (stream))); /* parse sequence if given, ping stream */ else if (stream->rdonly) MM_LOG ("Expunge ignored on readonly mailbox",WARN); else { if (LOCAL->filetime && !LOCAL->shouldcheck) { fstat (LOCAL->fd,&sbuf); /* get current write time */ if (LOCAL->filetime < sbuf.st_mtime) LOCAL->shouldcheck = T; } /* The cretins who designed flock() created a window of vulnerability in * upgrading locks from shared to exclusive or downgrading from exclusive * to shared. Rather than maintain the lock at shared status at a minimum, * flock() actually *releases* the former lock. Obviously they never talked * to any database guys. Fortunately, we have the parse/append permission * lock. If we require this lock before going exclusive on the mailbox, * another process can not sneak in and steal the exclusive mailbox lock on * us, because it will block on trying to get parse/append permission first. */ /* get exclusive parse/append permission */ if ((ld = lockfd (LOCAL->fd,lock,LOCK_EX)) < 0) MM_LOG ("Unable to lock expunge mailbox",ERROR); /* make sure see any newly-arrived messages */ else if (!tenex_parse (stream)); /* get exclusive access */ else if (flock (LOCAL->fd,LOCK_EX|LOCK_NB)) { (*bn) (BLOCK_FILELOCK,NIL); flock (LOCAL->fd,LOCK_SH);/* recover previous lock */ (*bn) (BLOCK_NONE,NIL); MM_LOG ("Can't expunge because mailbox is in use by another process", ERROR); unlockfd (ld,lock); /* release exclusive parse/append permission */ } else { MM_CRITICAL (stream); /* go critical */ recent = stream->recent; /* get recent now that pinged and locked */ /* for each message */ while (i <= stream->nmsgs) { /* get cache element */ elt = tenex_elt (stream,i); /* number of bytes to smash or preserve */ k = elt->private.special.text.size + tenex_size (stream,i); /* if need to expunge this message */ if (elt->deleted && (sequence ? elt->sequence : T)) { /* if recent, note one less recent message */ if (elt->recent) --recent; delta += k; /* number of bytes to delete */ /* notify upper levels */ mail_expunged (stream,i); n++; /* count up one more expunged message */ } else if (i++ && delta) {/* preserved message */ /* first byte to preserve */ j = elt->private.special.offset; do { /* read from source position */ m = min (k,LOCAL->buflen); lseek (LOCAL->fd,j,L_SET); read (LOCAL->fd,LOCAL->buf,m); pos = j - delta; /* write to destination position */ lseek (LOCAL->fd,pos,L_SET); while (T) { lseek (LOCAL->fd,pos,L_SET); if (write (LOCAL->fd,LOCAL->buf,m) > 0) break; MM_NOTIFY (stream,strerror (errno),WARN); MM_DISKERROR (stream,errno,T); } pos += m; /* new position */ j += m; /* next chunk, perhaps */ } while (k -= m); /* until done */ /* note the new address of this text */ elt->private.special.offset -= delta; } /* preserved but no deleted messages */ else pos = elt->private.special.offset + k; } if (n) { /* truncate file after last message */ if (pos != (LOCAL->filesize -= delta)) { sprintf (LOCAL->buf, "Calculated size mismatch %lu != %lu, delta = %lu", (unsigned long) pos,(unsigned long) LOCAL->filesize,delta); MM_LOG (LOCAL->buf,WARN); LOCAL->filesize = pos;/* fix it then */ } ftruncate (LOCAL->fd,LOCAL->filesize); sprintf (LOCAL->buf,"Expunged %lu messages",n); /* output the news */ MM_LOG (LOCAL->buf,(long) NIL); } else MM_LOG ("No messages deleted, so no update needed",(long) NIL); fsync (LOCAL->fd); /* force disk update */ fstat (LOCAL->fd,&sbuf); /* get new write time */ tp[1] = LOCAL->filetime = sbuf.st_mtime; tp[0] = time (0); /* reset atime to now */ utime (stream->mailbox,tp); MM_NOCRITICAL (stream); /* release critical */ /* notify upper level of new mailbox size */ mail_exists (stream,stream->nmsgs); mail_recent (stream,recent); (*bn) (BLOCK_FILELOCK,NIL); flock (LOCAL->fd,LOCK_SH);/* allow sharers again */ (*bn) (BLOCK_NONE,NIL); unlockfd (ld,lock); /* release exclusive parse/append permission */ } } return LONGT; } /* Tenex mail copy message(s) * Accepts: MAIL stream * sequence * destination mailbox * copy options * Returns: T if success, NIL if failed */ long tenex_copy (MAILSTREAM *stream,char *sequence,char *mailbox,long options) { struct stat sbuf; time_t tp[2]; MESSAGECACHE *elt; unsigned long i,j,k; long ret = LONGT; int fd,ld; char file[MAILTMPLEN],lock[MAILTMPLEN]; mailproxycopy_t pc = (mailproxycopy_t) mail_parameters (stream,GET_MAILPROXYCOPY,NIL); /* make sure valid mailbox */ if (!tenex_isvalid (mailbox,LOCAL->buf)) switch (errno) { case ENOENT: /* no such file? */ MM_NOTIFY (stream,"[TRYCREATE] Must create mailbox before copy",NIL); return NIL; case 0: /* merely empty file? */ break; case EACCES: /* file protected */ sprintf (LOCAL->buf,"Can't access destination: %.80s",mailbox); MM_LOG (LOCAL->buf,ERROR); return NIL; case EINVAL: if (pc) return (*pc) (stream,sequence,mailbox,options); sprintf (LOCAL->buf,"Invalid Tenex-format mailbox name: %.80s",mailbox); MM_LOG (LOCAL->buf,ERROR); return NIL; default: if (pc) return (*pc) (stream,sequence,mailbox,options); sprintf (LOCAL->buf,"Not a Tenex-format mailbox: %.80s",mailbox); MM_LOG (LOCAL->buf,ERROR); return NIL; } if (!((options & CP_UID) ? mail_uid_sequence (stream,sequence) : mail_sequence (stream,sequence))) return NIL; /* got file? */ if ((fd = open (tenex_file(file,mailbox),O_RDWR,NIL)) < 0) { sprintf (LOCAL->buf,"Unable to open copy mailbox: %s",strerror (errno)); MM_LOG (LOCAL->buf,ERROR); return NIL; } MM_CRITICAL (stream); /* go critical */ /* get exclusive parse/append permission */ if (flock (fd,LOCK_SH) || ((ld = lockfd (fd,lock,LOCK_EX)) < 0)) { MM_LOG ("Unable to lock copy mailbox",ERROR); MM_NOCRITICAL (stream); return NIL; } fstat (fd,&sbuf); /* get current file size */ lseek (fd,sbuf.st_size,L_SET);/* move to end of file */ /* for each requested message */ for (i = 1; ret && (i <= stream->nmsgs); i++) if ((elt = mail_elt (stream,i))->sequence) { lseek (LOCAL->fd,elt->private.special.offset,L_SET); /* number of bytes to copy */ k = elt->private.special.text.size + tenex_size (stream,i); do { /* read from source position */ j = min (k,LOCAL->buflen); read (LOCAL->fd,LOCAL->buf,j); if (write (fd,LOCAL->buf,j) < 0) ret = NIL; } while (ret && (k -= j));/* until done */ } /* make sure all the updates take */ if (!(ret && (ret = !fsync (fd)))) { sprintf (LOCAL->buf,"Unable to write message: %s",strerror (errno)); MM_LOG (LOCAL->buf,ERROR); ftruncate (fd,sbuf.st_size); } if (ret) tp[0] = time (0) - 1;/* set atime to now-1 if successful copy */ /* else preserve \Marked status */ else tp[0] = (sbuf.st_ctime > sbuf.st_atime) ? sbuf.st_atime : time(0); tp[1] = sbuf.st_mtime; /* preserve mtime */ utime (file,tp); /* set the times */ close (fd); /* close the file */ unlockfd (ld,lock); /* release exclusive parse/append permission */ MM_NOCRITICAL (stream); /* release critical */ /* delete all requested messages */ if (ret && (options & CP_MOVE)) { for (i = 1; i <= stream->nmsgs; i++) if ((elt = tenex_elt (stream,i))->sequence) { elt->deleted = T; /* mark message deleted */ /* recalculate status */ tenex_update_status (stream,i,NIL); } if (!stream->rdonly) { /* make sure the update takes */ fsync (LOCAL->fd); fstat (LOCAL->fd,&sbuf); /* get current write time */ tp[1] = LOCAL->filetime = sbuf.st_mtime; tp[0] = time (0); /* make sure atime remains greater */ utime (stream->mailbox,tp); } } if (ret && mail_parameters (NIL,GET_COPYUID,NIL)) MM_LOG ("Can not return meaningful COPYUID with this mailbox format",WARN); return ret; } /* Tenex mail append message from stringstruct * Accepts: MAIL stream * destination mailbox * append callback * data for callback * Returns: T if append successful, else NIL */ long tenex_append (MAILSTREAM *stream,char *mailbox,append_t af,void *data) { struct stat sbuf; int fd,ld,c; char *flags,*date,tmp[MAILTMPLEN],file[MAILTMPLEN],lock[MAILTMPLEN]; time_t tp[2]; FILE *df; MESSAGECACHE elt; long f; unsigned long i,j,uf,size; STRING *message; long ret = LONGT; /* default stream to prototype */ if (!stream) stream = user_flags (&tenexproto); /* make sure valid mailbox */ if (!tenex_isvalid (mailbox,tmp)) switch (errno) { case ENOENT: /* no such file? */ if (!compare_cstring (mailbox,"INBOX")) dummy_create (NIL,"mail.txt"); else { MM_NOTIFY (stream,"[TRYCREATE] Must create mailbox before append",NIL); return NIL; } /* falls through */ case 0: /* merely empty file? */ break; case EACCES: /* file protected */ sprintf (tmp,"Can't access destination: %.80s",mailbox); MM_LOG (tmp,ERROR); return NIL; case EINVAL: sprintf (tmp,"Invalid TENEX-format mailbox name: %.80s",mailbox); MM_LOG (tmp,ERROR); return NIL; default: sprintf (tmp,"Not a TENEX-format mailbox: %.80s",mailbox); MM_LOG (tmp,ERROR); return NIL; } /* get first message */ if (!MM_APPEND (af) (stream,data,&flags,&date,&message)) return NIL; /* open destination mailbox */ if (((fd = open (tenex_file (file,mailbox),O_WRONLY|O_APPEND,NIL)) < 0) || !(df = fdopen (fd,"ab"))) { sprintf (tmp,"Can't open append mailbox: %s",strerror (errno)); MM_LOG (tmp,ERROR); return NIL; } /* get parse/append permission */ if (flock (fd,LOCK_SH) || ((ld = lockfd (fd,lock,LOCK_EX)) < 0)) { MM_LOG ("Unable to lock append mailbox",ERROR); close (fd); return NIL; } MM_CRITICAL (stream); /* go critical */ fstat (fd,&sbuf); /* get current file size */ errno = 0; do { /* parse flags */ if (!SIZE (message)) { /* guard against zero-length */ MM_LOG ("Append of zero-length message",ERROR); ret = NIL; break; } f = mail_parse_flags (stream,flags,&i); /* reverse bits (dontcha wish we had CIRC?) */ for (uf = 0; i; uf |= 1 << (29 - find_rightmost_bit (&i))); if (date) { /* parse date if given */ if (!mail_parse_date (&elt,date)) { sprintf (tmp,"Bad date in append: %.80s",date); MM_LOG (tmp,ERROR); ret = NIL; /* mark failure */ break; } mail_date (tmp,&elt); /* write preseved date */ } else internal_date (tmp); /* get current date in IMAP format */ i = GETPOS (message); /* remember current position */ for (j = SIZE (message), size = 0; j; --j) if (SNX (message) != '\015') ++size; SETPOS (message,i); /* restore position */ /* write header */ if (fprintf (df,"%s,%lu;%010lo%02lo\n",tmp,size,uf,(unsigned long) f) < 0) ret = NIL; else { /* write message */ while (size) if ((c = 0xff & SNX (message)) != '\015') { if (putc (c,df) != EOF) --size; else break; } /* get next message */ if (size || !MM_APPEND (af) (stream,data,&flags,&date,&message)) ret = NIL; } } while (ret && message); /* if error... */ if (!ret || (fflush (df) == EOF)) { ftruncate (fd,sbuf.st_size);/* revert file */ close (fd); /* make sure fclose() doesn't corrupt us */ if (errno) { sprintf (tmp,"Message append failed: %s",strerror (errno)); MM_LOG (tmp,ERROR); } ret = NIL; } if (ret) tp[0] = time (0) - 1;/* set atime to now-1 if successful copy */ /* else preserve \Marked status */ else tp[0] = (sbuf.st_ctime > sbuf.st_atime) ? sbuf.st_atime : time(0); tp[1] = sbuf.st_mtime; /* preserve mtime */ utime (file,tp); /* set the times */ fclose (df); /* close the file */ unlockfd (ld,lock); /* release exclusive parse/append permission */ MM_NOCRITICAL (stream); /* release critical */ if (ret && mail_parameters (NIL,GET_APPENDUID,NIL)) MM_LOG ("Can not return meaningful APPENDUID with this mailbox format", WARN); return ret; } /* Internal routines */ /* Tenex mail return internal message size in bytes * Accepts: MAIL stream * message # * Returns: internal size of message */ unsigned long tenex_size (MAILSTREAM *stream,unsigned long m) { MESSAGECACHE *elt = mail_elt (stream,m); return ((m < stream->nmsgs) ? mail_elt (stream,m+1)->private.special.offset : LOCAL->filesize) - (elt->private.special.offset + elt->private.special.text.size); } /* Tenex mail generate file string * Accepts: temporary buffer to write into * mailbox name string * Returns: local file string or NIL if failure */ char *tenex_file (char *dst,char *name) { char tmp[MAILTMPLEN]; char *s = mailboxfile (dst,name); /* return our standard inbox */ return (s && !*s) ? mailboxfile (dst,tenex_isvalid ("~/INBOX",tmp) ? "~/INBOX" : "mail.txt") : s; } /* Tenex mail parse mailbox * Accepts: MAIL stream * Returns: T if parse OK * NIL if failure, stream aborted */ long tenex_parse (MAILSTREAM *stream) { struct stat sbuf; MESSAGECACHE *elt = NIL; unsigned char c,*s,*t,*x; char tmp[MAILTMPLEN]; unsigned long i,j; long curpos = LOCAL->filesize; long nmsgs = stream->nmsgs; long recent = stream->recent; short added = NIL; short silent = stream->silent; fstat (LOCAL->fd,&sbuf); /* get status */ if (sbuf.st_size < curpos) { /* sanity check */ sprintf (tmp,"Mailbox shrank from %lu to %lu!", (unsigned long) curpos,(unsigned long) sbuf.st_size); MM_LOG (tmp,ERROR); tenex_close (stream,NIL); return NIL; } stream->silent = T; /* don't pass up exists events yet */ while (sbuf.st_size - curpos){/* while there is stuff to parse */ /* get to that position in the file */ lseek (LOCAL->fd,curpos,L_SET); if ((i = read (LOCAL->fd,LOCAL->buf,64)) <= 0) { sprintf (tmp,"Unable to read internal header at %lu, size = %lu: %s", (unsigned long) curpos,(unsigned long) sbuf.st_size, i ? strerror (errno) : "no data read"); MM_LOG (tmp,ERROR); tenex_close (stream,NIL); return NIL; } LOCAL->buf[i] = '\0'; /* tie off buffer just in case */ if (!(s = strchr (LOCAL->buf,'\012'))) { sprintf (tmp,"Unable to find newline at %lu in %lu bytes, text: %s", (unsigned long) curpos,i,(char *) LOCAL->buf); MM_LOG (tmp,ERROR); tenex_close (stream,NIL); return NIL; } *s = '\0'; /* tie off header line */ i = (s + 1) - LOCAL->buf; /* note start of text offset */ if (!((s = strchr (LOCAL->buf,',')) && (t = strchr (s+1,';')))) { sprintf (tmp,"Unable to parse internal header at %lu: %s", (unsigned long) curpos,(char *) LOCAL->buf); MM_LOG (tmp,ERROR); tenex_close (stream,NIL); return NIL; } *s++ = '\0'; *t++ = '\0'; /* tie off fields */ added = T; /* note that a new message was added */ /* swell the cache */ mail_exists (stream,++nmsgs); /* instantiate an elt for this message */ (elt = mail_elt (stream,nmsgs))->valid = T; elt->private.uid = ++stream->uid_last; /* note file offset of header */ elt->private.special.offset = curpos; /* in case error */ elt->private.special.text.size = 0; /* header size not known yet */ elt->private.msg.header.text.size = 0; x = s; /* parse the header components */ if (mail_parse_date (elt,LOCAL->buf) && (elt->private.msg.full.text.size = strtoul (s,(char **) &s,10)) && (!(s && *s)) && isdigit (t[0]) && isdigit (t[1]) && isdigit (t[2]) && isdigit (t[3]) && isdigit (t[4]) && isdigit (t[5]) && isdigit (t[6]) && isdigit (t[7]) && isdigit (t[8]) && isdigit (t[9]) && isdigit (t[10]) && isdigit (t[11]) && !t[12]) elt->private.special.text.size = i; else { /* oops */ sprintf (tmp,"Unable to parse internal header elements at %ld: %s,%s;%s", curpos,(char *) LOCAL->buf,(char *) x,(char *) t); MM_LOG (tmp,ERROR); tenex_close (stream,NIL); return NIL; } /* make sure didn't run off end of file */ if ((curpos += (elt->private.msg.full.text.size + i)) > sbuf.st_size) { sprintf (tmp,"Last message (at %lu) runs past end of file (%lu > %lu)", elt->private.special.offset,(unsigned long) curpos, (unsigned long) sbuf.st_size); MM_LOG (tmp,ERROR); tenex_close (stream,NIL); return NIL; } c = t[10]; /* remember first system flags byte */ t[10] = '\0'; /* tie off flags */ j = strtoul (t,NIL,8); /* get user flags value */ t[10] = c; /* restore first system flags byte */ /* set up all valid user flags (reversed!) */ while (j) if (((i = 29 - find_rightmost_bit (&j)) < NUSERFLAGS) && stream->user_flags[i]) elt->user_flags |= 1 << i; /* calculate system flags */ if ((j = ((t[10]-'0') * 8) + t[11]-'0') & fSEEN) elt->seen = T; if (j & fDELETED) elt->deleted = T; if (j & fFLAGGED) elt->flagged = T; if (j & fANSWERED) elt->answered = T; if (j & fDRAFT) elt->draft = T; if (!(j & fOLD)) { /* newly arrived message? */ elt->recent = T; recent++; /* count up a new recent message */ /* mark it as old */ tenex_update_status (stream,nmsgs,NIL); } } fsync (LOCAL->fd); /* make sure all the fOLD flags take */ /* update parsed file size and time */ LOCAL->filesize = sbuf.st_size; fstat (LOCAL->fd,&sbuf); /* get status again to ensure time is right */ LOCAL->filetime = sbuf.st_mtime; if (added && !stream->rdonly){/* make sure atime updated */ time_t tp[2]; tp[0] = time (0); tp[1] = LOCAL->filetime; utime (stream->mailbox,tp); } stream->silent = silent; /* can pass up events now */ mail_exists (stream,nmsgs); /* notify upper level of new mailbox size */ mail_recent (stream,recent); /* and of change in recent messages */ return LONGT; /* return the winnage */ } /* Tenex get cache element with status updating from file * Accepts: MAIL stream * message number * Returns: cache element */ MESSAGECACHE *tenex_elt (MAILSTREAM *stream,unsigned long msgno) { MESSAGECACHE *elt = mail_elt (stream,msgno); struct { /* old flags */ unsigned int seen : 1; unsigned int deleted : 1; unsigned int flagged : 1; unsigned int answered : 1; unsigned int draft : 1; unsigned long user_flags; } old; old.seen = elt->seen; old.deleted = elt->deleted; old.flagged = elt->flagged; old.answered = elt->answered; old.draft = elt->draft; old.user_flags = elt->user_flags; tenex_read_flags (stream,elt); if ((old.seen != elt->seen) || (old.deleted != elt->deleted) || (old.flagged != elt->flagged) || (old.answered != elt->answered) || (old.draft != elt->draft) || (old.user_flags != elt->user_flags)) MM_FLAGS (stream,msgno); /* let top level know */ return elt; } /* Tenex read flags from file * Accepts: MAIL stream * Returns: cache element */ void tenex_read_flags (MAILSTREAM *stream,MESSAGECACHE *elt) { unsigned long i,j; /* noop if readonly and have valid flags */ if (stream->rdonly && elt->valid) return; /* set the seek pointer */ lseek (LOCAL->fd,(off_t) elt->private.special.offset + elt->private.special.text.size - 13,L_SET); /* read the new flags */ if (read (LOCAL->fd,LOCAL->buf,12) < 0) { sprintf (LOCAL->buf,"Unable to read new status: %s",strerror (errno)); fatal (LOCAL->buf); } /* calculate system flags */ i = (((LOCAL->buf[10]-'0') * 8) + LOCAL->buf[11]-'0'); elt->seen = i & fSEEN ? T : NIL; elt->deleted = i & fDELETED ? T : NIL; elt->flagged = i & fFLAGGED ? T : NIL; elt->answered = i & fANSWERED ? T : NIL; elt->draft = i & fDRAFT ? T : NIL; LOCAL->buf[10] = '\0'; /* tie off flags */ j = strtoul(LOCAL->buf,NIL,8);/* get user flags value */ /* set up all valid user flags (reversed!) */ while (j) if (((i = 29 - find_rightmost_bit (&j)) < NUSERFLAGS) && stream->user_flags[i]) elt->user_flags |= 1 << i; elt->valid = T; /* have valid flags now */ } /* Tenex update status string * Accepts: MAIL stream * message number * flag saying whether or not to sync */ void tenex_update_status (MAILSTREAM *stream,unsigned long msgno,long syncflag) { time_t tp[2]; struct stat sbuf; MESSAGECACHE *elt = mail_elt (stream,msgno); unsigned long j,k = 0; /* readonly */ if (stream->rdonly || !elt->valid) tenex_read_flags (stream,elt); else { /* readwrite */ j = elt->user_flags; /* get user flags */ /* reverse bits (dontcha wish we had CIRC?) */ while (j) k |= 1 << (29 - find_rightmost_bit (&j)); /* print new flag string */ sprintf (LOCAL->buf,"%010lo%02o",k,(unsigned) (fOLD + (fSEEN * elt->seen) + (fDELETED * elt->deleted) + (fFLAGGED * elt->flagged) + (fANSWERED * elt->answered) + (fDRAFT * elt->draft))); /* get to that place in the file */ lseek (LOCAL->fd,(off_t) elt->private.special.offset + elt->private.special.text.size - 13,L_SET); /* write new flags */ write (LOCAL->fd,LOCAL->buf,12); if (syncflag) { /* sync if requested */ fsync (LOCAL->fd); fstat (LOCAL->fd,&sbuf); /* get new write time */ tp[1] = LOCAL->filetime = sbuf.st_mtime; tp[0] = time (0); /* make sure read is later */ utime (stream->mailbox,tp); } } } /* Tenex locate header for a message * Accepts: MAIL stream * message number * pointer to returned header size * Returns: position of header in file */ unsigned long tenex_hdrpos (MAILSTREAM *stream,unsigned long msgno, unsigned long *size) { unsigned long siz; long i = 0; char c = '\0'; char *s = NIL; MESSAGECACHE *elt = tenex_elt (stream,msgno); unsigned long ret = elt->private.special.offset + elt->private.special.text.size; unsigned long msiz = tenex_size (stream,msgno); /* is header size known? */ if (!(*size = elt->private.msg.header.text.size)) { lseek (LOCAL->fd,ret,L_SET);/* get to header position */ /* search message for LF LF */ for (siz = 0; siz < msiz; siz++) { if (--i <= 0) /* read another buffer as necessary */ read (LOCAL->fd,s = LOCAL->buf,i = min (msiz-siz,(long) MAILTMPLEN)); /* two newline sequence? */ if ((c == '\012') && (*s == '\012')) { /* yes, note for later */ elt->private.msg.header.text.size = (*size = siz + 1); return ret; /* return to caller */ } else c = *s++; /* next character */ } /* header consumes entire message */ elt->private.msg.header.text.size = *size = msiz; } return ret; } alpine-2.10+dfsg/imap/src/osdep/unix/log_sec.c0000600000175000017500000000222111512502123022721 0ustar paulproteuspaulproteus/* ======================================================================== * Copyright 1988-2006 University of Washington * * Licensed under the Apache License, Version 2.0 (the "License"); * you may not use this file except in compliance with the License. * You may obtain a copy of the License at * * http://www.apache.org/licenses/LICENSE-2.0 * * * ======================================================================== */ /* * Program: SecureWare login * * Author: Mark Crispin * Networks and Distributed Computing * Computing & Communications * University of Washington * Administration Building, AG-44 * Seattle, WA 98195 * Internet: MRC@CAC.Washington.EDU * * Date: 1 August 1988 * Last Edited: 30 August 2006 */ /* Log in * Accepts: login passwd struct * argument count * argument vector * Returns: T if success, NIL otherwise */ long loginpw (struct passwd *pw,int argc,char *argv[]) { uid_t uid = pw->pw_uid; char *name = cpystr (pw->pw_name); long ret = !(setluid (uid) || setgid (pw->pw_gid) || initgroups (name,pw->pw_gid) || setuid (uid)); fs_give ((void **) &name); return ret; } alpine-2.10+dfsg/imap/src/osdep/unix/mh.c0000600000175000017500000011726311512502123021727 0ustar paulproteuspaulproteus/* ======================================================================== * Copyright 1988-2007 University of Washington * * Licensed under the Apache License, Version 2.0 (the "License"); * you may not use this file except in compliance with the License. * You may obtain a copy of the License at * * http://www.apache.org/licenses/LICENSE-2.0 * * * ======================================================================== */ /* * Program: MH mail routines * * Author(s): Mark Crispin * Networks and Distributed Computing * Computing & Communications * University of Washington * Administration Building, AG-44 * Seattle, WA 98195 * Internet: MRC@CAC.Washington.EDU * * Date: 23 February 1992 * Last Edited: 11 October 2007 */ #include #include #include extern int errno; /* just in case */ #include "mail.h" #include "osdep.h" #include #include #include #include "misc.h" #include "dummy.h" #include "fdstring.h" /* Build parameters */ #define MHINBOX "#mhinbox" /* corresponds to namespace in env_unix.c */ #define MHINBOXDIR "inbox" #define MHPROFILE ".mh_profile" #define MHCOMMA ',' #define MHSEQUENCE ".mh_sequence" #define MHSEQUENCES ".mh_sequences" #define MHPATH "Mail" /* mh_load_message() flags */ #define MLM_HEADER 0x1 /* load message text */ #define MLM_TEXT 0x2 /* load message text */ /* MH I/O stream local data */ typedef struct mh_local { char *dir; /* spool directory name */ unsigned char buf[CHUNKSIZE]; /* temporary buffer */ unsigned long cachedtexts; /* total size of all cached texts */ time_t scantime; /* last time directory scanned */ } MHLOCAL; /* Convenient access to local data */ #define LOCAL ((MHLOCAL *) stream->local) /* Function prototypes */ DRIVER *mh_valid (char *name); int mh_isvalid (char *name,char *tmp,long synonly); int mh_namevalid (char *name); char *mh_path (char *tmp); void *mh_parameters (long function,void *value); long mh_dirfmttest (char *name); void mh_scan (MAILSTREAM *stream,char *ref,char *pat,char *contents); void mh_list (MAILSTREAM *stream,char *ref,char *pat); void mh_lsub (MAILSTREAM *stream,char *ref,char *pat); void mh_list_work (MAILSTREAM *stream,char *dir,char *pat,long level); long mh_subscribe (MAILSTREAM *stream,char *mailbox); long mh_unsubscribe (MAILSTREAM *stream,char *mailbox); long mh_create (MAILSTREAM *stream,char *mailbox); long mh_delete (MAILSTREAM *stream,char *mailbox); long mh_rename (MAILSTREAM *stream,char *old,char *newname); MAILSTREAM *mh_open (MAILSTREAM *stream); void mh_close (MAILSTREAM *stream,long options); void mh_fast (MAILSTREAM *stream,char *sequence,long flags); void mh_load_message (MAILSTREAM *stream,unsigned long msgno,long flags); char *mh_header (MAILSTREAM *stream,unsigned long msgno,unsigned long *length, long flags); long mh_text (MAILSTREAM *stream,unsigned long msgno,STRING *bs,long flags); long mh_ping (MAILSTREAM *stream); void mh_check (MAILSTREAM *stream); long mh_expunge (MAILSTREAM *stream,char *sequence,long options); long mh_copy (MAILSTREAM *stream,char *sequence,char *mailbox, long options); long mh_append (MAILSTREAM *stream,char *mailbox,append_t af,void *data); int mh_select (struct direct *name); int mh_numsort (const void *d1,const void *d2); char *mh_file (char *dst,char *name); long mh_canonicalize (char *pattern,char *ref,char *pat); void mh_setdate (char *file,MESSAGECACHE *elt); /* MH mail routines */ /* Driver dispatch used by MAIL */ DRIVER mhdriver = { "mh", /* driver name */ /* driver flags */ DR_MAIL|DR_LOCAL|DR_NOFAST|DR_NAMESPACE|DR_NOSTICKY|DR_DIRFMT, (DRIVER *) NIL, /* next driver */ mh_valid, /* mailbox is valid for us */ mh_parameters, /* manipulate parameters */ mh_scan, /* scan mailboxes */ mh_list, /* find mailboxes */ mh_lsub, /* find subscribed mailboxes */ mh_subscribe, /* subscribe to mailbox */ mh_unsubscribe, /* unsubscribe from mailbox */ mh_create, /* create mailbox */ mh_delete, /* delete mailbox */ mh_rename, /* rename mailbox */ mail_status_default, /* status of mailbox */ mh_open, /* open mailbox */ mh_close, /* close mailbox */ mh_fast, /* fetch message "fast" attributes */ NIL, /* fetch message flags */ NIL, /* fetch overview */ NIL, /* fetch message envelopes */ mh_header, /* fetch message header */ mh_text, /* fetch message body */ NIL, /* fetch partial message text */ NIL, /* unique identifier */ NIL, /* message number */ NIL, /* modify flags */ NIL, /* per-message modify flags */ NIL, /* search for message based on criteria */ NIL, /* sort messages */ NIL, /* thread messages */ mh_ping, /* ping mailbox to see if still alive */ mh_check, /* check for new messages */ mh_expunge, /* expunge deleted messages */ mh_copy, /* copy messages to another mailbox */ mh_append, /* append string message to mailbox */ NIL /* garbage collect stream */ }; /* prototype stream */ MAILSTREAM mhproto = {&mhdriver}; static char *mh_profile = NIL; /* holds MH profile */ static char *mh_pathname = NIL; /* holds MH path name */ static long mh_once = 0; /* already snarled once */ static long mh_allow_inbox =NIL;/* allow INBOX as well as MHINBOX */ /* MH mail validate mailbox * Accepts: mailbox name * Returns: our driver if name is valid, NIL otherwise */ DRIVER *mh_valid (char *name) { char tmp[MAILTMPLEN]; return mh_isvalid (name,tmp,T) ? &mhdriver : NIL; } /* MH mail test for valid mailbox * Accepts: mailbox name * temporary buffer to use * syntax only test flag * Returns: T if valid, NIL otherwise */ int mh_isvalid (char *name,char *tmp,long synonly) { struct stat sbuf; char *s,*t,altname[MAILTMPLEN]; unsigned long i; int ret = NIL; errno = NIL; /* zap any error condition */ /* mh name? */ if ((mh_allow_inbox && !compare_cstring (name,"INBOX")) || !compare_cstring (name,MHINBOX) || ((name[0] == '#') && ((name[1] == 'm') || (name[1] == 'M')) && ((name[2] == 'h') || (name[2] == 'H')) && (name[3] == '/') && name[4])){ if (mh_path (tmp)) /* validate name if INBOX or not synonly */ ret = (synonly && compare_cstring (name,"INBOX")) ? T : ((stat (mh_file (tmp,name),&sbuf) == 0) && (sbuf.st_mode & S_IFMT) == S_IFDIR); else if (!mh_once++) { /* only report error once */ sprintf (tmp,"%.900s not found, mh format names disabled",mh_profile); mm_log (tmp,WARN); } } /* see if non-NS name within mh hierarchy */ else if ((name[0] != '#') && (s = mh_path (tmp)) && (i = strlen (s)) && (t = mailboxfile (tmp,name)) && !strncmp (t,s,i) && (tmp[i] == '/') && tmp[i+1]) { sprintf (altname,"#mh%.900s",tmp+i); /* can't do synonly here! */ ret = mh_isvalid (altname,tmp,NIL); } else errno = EINVAL; /* bogus name */ return ret; } /* MH mail test for valid mailbox * Accepts: mailbox name * Returns: T if valid, NIL otherwise */ int mh_namevalid (char *name) { char *s; if (name[0] == '#' && (name[1] == 'm' || name[1] == 'M') && (name[2] == 'h' || name[2] == 'H') && name[3] == '/') for (s = name; s && *s;) { /* make sure no all-digit nodes */ if (isdigit (*s)) s++; /* digit, check this node further... */ else if (*s == '/') break;/* all digit node, barf */ /* non-digit, skip to next node or return */ else if (!((s = strchr (s+1,'/')) && *++s)) return T; } return NIL; /* all numeric or empty node */ } /* Return MH path * Accepts: temporary buffer * Returns: MH path or NIL if MH disabled */ char *mh_path (char *tmp) { char *s,*t,*v,*r; int fd; struct stat sbuf; if (!mh_profile) { /* build mh_profile and mh_pathname now */ sprintf (tmp,"%s/%s",myhomedir (),MHPROFILE); if ((fd = open (mh_profile = cpystr (tmp),O_RDONLY,NIL)) >= 0) { fstat (fd,&sbuf); /* yes, get size and read file */ read (fd,(t = (char *) fs_get (sbuf.st_size + 1)),sbuf.st_size); close (fd); /* don't need the file any more */ t[sbuf.st_size] = '\0'; /* tie it off */ /* parse profile file */ for (s = strtok_r (t,"\r\n",&r); s && *s; s = strtok_r (NIL,"\r\n",&r)) { /* found space in line? */ if (v = strpbrk (s," \t")) { *v++ = '\0'; /* tie off, is keyword "Path:"? */ if (!compare_cstring (s,"Path:")) { /* skip whitespace */ while ((*v == ' ') || (*v == '\t')) ++v; /* absolute path? */ if (*v == '/') s = v; else sprintf (s = tmp,"%s/%s",myhomedir (),v); /* copy name */ mh_pathname = cpystr (s); break; /* don't need to look at rest of file */ } } } fs_give ((void **) &t); /* flush profile text */ if (!mh_pathname) { /* default path if not in the profile */ sprintf (tmp,"%s/%s",myhomedir (),MHPATH); mh_pathname = cpystr (tmp); } } } return mh_pathname; } /* MH manipulate driver parameters * Accepts: function code * function-dependent value * Returns: function-dependent return value */ void *mh_parameters (long function,void *value) { void *ret = NIL; switch ((int) function) { case GET_INBOXPATH: if (value) ret = mh_file ((char *) value,"INBOX"); break; case GET_DIRFMTTEST: ret = (void *) mh_dirfmttest; break; case SET_MHPROFILE: if (mh_profile) fs_give ((void **) &mh_profile); mh_profile = cpystr ((char *) value); case GET_MHPROFILE: ret = (void *) mh_profile; break; case SET_MHPATH: if (mh_pathname) fs_give ((void **) &mh_pathname); mh_pathname = cpystr ((char *) value); case GET_MHPATH: ret = (void *) mh_pathname; break; case SET_MHALLOWINBOX: mh_allow_inbox = value ? T : NIL; case GET_MHALLOWINBOX: ret = (void *) (mh_allow_inbox ? VOIDT : NIL); } return ret; } /* MH test for directory format internal node * Accepts: candidate node name * Returns: T if internal name, NIL otherwise */ long mh_dirfmttest (char *s) { int c; /* sequence(s) file is an internal name */ if (strcmp (s,MHSEQUENCE) && strcmp (s,MHSEQUENCES)) { if (*s == MHCOMMA) ++s; /* else comma + all numeric name */ /* success if all-numeric */ while (c = *s++) if (!isdigit (c)) return NIL; } return LONGT; } /* MH scan mailboxes * Accepts: mail stream * reference * pattern to search * string to scan */ void mh_scan (MAILSTREAM *stream,char *ref,char *pat,char *contents) { char *s,test[MAILTMPLEN],file[MAILTMPLEN]; long i = 0; if (!pat || !*pat) { /* empty pattern? */ if (mh_canonicalize (test,ref,"*")) { /* tie off name at root */ if (s = strchr (test,'/')) *++s = '\0'; else test[0] = '\0'; mm_list (stream,'/',test,LATT_NOSELECT); } } /* get canonical form of name */ else if (mh_canonicalize (test,ref,pat)) { if (contents) { /* maybe I'll implement this someday */ mm_log ("Scan not valid for mh mailboxes",ERROR); return; } if (test[3] == '/') { /* looking down levels? */ /* yes, found any wildcards? */ if (s = strpbrk (test,"%*")) { /* yes, copy name up to that point */ strncpy (file,test+4,i = s - (test+4)); file[i] = '\0'; /* tie off */ } else strcpy (file,test+4);/* use just that name then */ /* find directory name */ if (s = strrchr (file,'/')) { *s = '\0'; /* found, tie off at that point */ s = file; } /* do the work */ mh_list_work (stream,s,test,0); } /* always an INBOX */ if (!compare_cstring (test,MHINBOX)) mm_list (stream,NIL,MHINBOX,LATT_NOINFERIORS); } } /* MH list mailboxes * Accepts: mail stream * reference * pattern to search */ void mh_list (MAILSTREAM *stream,char *ref,char *pat) { mh_scan (stream,ref,pat,NIL); } /* MH list subscribed mailboxes * Accepts: mail stream * reference * pattern to search */ void mh_lsub (MAILSTREAM *stream,char *ref,char *pat) { void *sdb = NIL; char *s,test[MAILTMPLEN]; /* get canonical form of name */ if (mh_canonicalize (test,ref,pat) && (s = sm_read (&sdb))) { do if (pmatch_full (s,test,'/')) mm_lsub (stream,'/',s,NIL); while (s = sm_read (&sdb)); /* until no more subscriptions */ } } /* MH list mailboxes worker routine * Accepts: mail stream * directory name to search * search pattern * search level */ void mh_list_work (MAILSTREAM *stream,char *dir,char *pat,long level) { DIR *dp; struct direct *d; struct stat sbuf; char *cp,*np,curdir[MAILTMPLEN],name[MAILTMPLEN]; /* build MH name to search */ if (dir) sprintf (name,"#mh/%s/",dir); else strcpy (name,"#mh/"); /* make directory name, punt if bogus */ if (!mh_file (curdir,name)) return; cp = curdir + strlen (curdir);/* end of directory name */ np = name + strlen (name); /* end of MH name */ if (dp = opendir (curdir)) { /* open directory */ while (d = readdir (dp)) /* scan, ignore . and numeric names */ if ((d->d_name[0] != '.') && !mh_select (d)) { strcpy (cp,d->d_name); /* make directory name */ if (!stat (curdir,&sbuf) && ((sbuf.st_mode & S_IFMT) == S_IFDIR)) { strcpy (np,d->d_name);/* make mh name of directory name */ /* yes, an MH name if full match */ if (pmatch_full (name,pat,'/')) mm_list (stream,'/',name,NIL); /* check if should recurse */ if (dmatch (name,pat,'/') && (level < (long) mail_parameters (NIL,GET_LISTMAXLEVEL,NIL))) mh_list_work (stream,name+4,pat,level+1); } } closedir (dp); /* all done, flush directory */ } } /* MH mail subscribe to mailbox * Accepts: mail stream * mailbox to add to subscription list * Returns: T on success, NIL on failure */ long mh_subscribe (MAILSTREAM *stream,char *mailbox) { return sm_subscribe (mailbox); } /* MH mail unsubscribe to mailbox * Accepts: mail stream * mailbox to delete from subscription list * Returns: T on success, NIL on failure */ long mh_unsubscribe (MAILSTREAM *stream,char *mailbox) { return sm_unsubscribe (mailbox); } /* MH mail create mailbox * Accepts: mail stream * mailbox name to create * Returns: T on success, NIL on failure */ long mh_create (MAILSTREAM *stream,char *mailbox) { char tmp[MAILTMPLEN]; if (!mh_namevalid (mailbox)) /* validate name */ sprintf (tmp,"Can't create mailbox %.80s: invalid MH-format name",mailbox); /* must not already exist */ else if (mh_isvalid (mailbox,tmp,NIL)) sprintf (tmp,"Can't create mailbox %.80s: mailbox already exists",mailbox); else if (!mh_path (tmp)) return NIL; /* try to make it */ else if (!(mh_file (tmp,mailbox) && dummy_create_path (stream,strcat (tmp,"/"), get_dir_protection (mailbox)))) sprintf (tmp,"Can't create mailbox %.80s: %s",mailbox,strerror (errno)); else return LONGT; /* success */ mm_log (tmp,ERROR); return NIL; } /* MH mail delete mailbox * mailbox name to delete * Returns: T on success, NIL on failure */ long mh_delete (MAILSTREAM *stream,char *mailbox) { DIR *dirp; struct direct *d; int i; char tmp[MAILTMPLEN]; /* is mailbox valid? */ if (!mh_isvalid (mailbox,tmp,NIL)) { sprintf (tmp,"Can't delete mailbox %.80s: no such mailbox",mailbox); mm_log (tmp,ERROR); return NIL; } /* get name of directory */ i = strlen (mh_file (tmp,mailbox)); if (dirp = opendir (tmp)) { /* open directory */ tmp[i++] = '/'; /* now apply trailing delimiter */ /* massacre all mh owned files */ while (d = readdir (dirp)) if (mh_dirfmttest (d->d_name)) { strcpy (tmp + i,d->d_name); unlink (tmp); /* sayonara */ } closedir (dirp); /* flush directory */ } /* try to remove the directory */ if (rmdir (mh_file (tmp,mailbox))) { sprintf (tmp,"Can't delete mailbox %.80s: %s",mailbox,strerror (errno)); mm_log (tmp,WARN); } return T; /* return success */ } /* MH mail rename mailbox * Accepts: MH mail stream * old mailbox name * new mailbox name * Returns: T on success, NIL on failure */ long mh_rename (MAILSTREAM *stream,char *old,char *newname) { char c,*s,tmp[MAILTMPLEN],tmp1[MAILTMPLEN]; struct stat sbuf; /* old mailbox name must be valid */ if (!mh_isvalid (old,tmp,NIL)) sprintf (tmp,"Can't rename mailbox %.80s: no such mailbox",old); else if (!mh_namevalid (newname)) sprintf (tmp,"Can't rename to mailbox %.80s: invalid MH-format name", newname); /* new mailbox name must not be valid */ else if (mh_isvalid (newname,tmp,NIL)) sprintf (tmp,"Can't rename to mailbox %.80s: destination already exists", newname); /* success if can rename the directory */ else { /* found superior to destination name? */ if (s = strrchr (mh_file (tmp1,newname),'/')) { c = *++s; /* remember first character of inferior */ *s = '\0'; /* tie off to get just superior */ /* name doesn't exist, create it */ if ((stat (tmp1,&sbuf) || ((sbuf.st_mode & S_IFMT) != S_IFDIR)) && !dummy_create_path (stream,tmp1,get_dir_protection (newname))) return NIL; *s = c; /* restore full name */ } if (!rename (mh_file (tmp,old),tmp1)) return T; sprintf (tmp,"Can't rename mailbox %.80s to %.80s: %s", old,newname,strerror (errno)); } mm_log (tmp,ERROR); /* something failed */ return NIL; } /* MH mail open * Accepts: stream to open * Returns: stream on success, NIL on failure */ MAILSTREAM *mh_open (MAILSTREAM *stream) { char tmp[MAILTMPLEN]; if (!stream) return &mhproto; /* return prototype for OP_PROTOTYPE call */ if (stream->local) fatal ("mh recycle stream"); stream->local = fs_get (sizeof (MHLOCAL)); /* INBOXness is one of the following: * #mhinbox (case-independent) * #mh/inbox (mh is case-independent, inbox is case-dependent) * INBOX (case-independent */ stream->inbox = /* note if an INBOX or not */ (!compare_cstring (stream->mailbox,MHINBOX) || ((stream->mailbox[0] == '#') && ((stream->mailbox[1] == 'm') || (stream->mailbox[1] == 'M')) && ((stream->mailbox[2] == 'h') || (stream->mailbox[2] == 'H')) && (stream->mailbox[3] == '/') && !strcmp (stream->mailbox+4,MHINBOXDIR)) || !compare_cstring (stream->mailbox,"INBOX")) ? T : NIL; mh_file (tmp,stream->mailbox);/* get directory name */ LOCAL->dir = cpystr (tmp); /* copy directory name for later */ LOCAL->scantime = 0; /* not scanned yet */ LOCAL->cachedtexts = 0; /* no cached texts */ stream->sequence++; /* bump sequence number */ /* parse mailbox */ stream->nmsgs = stream->recent = 0; if (!mh_ping (stream)) return NIL; if (!(stream->nmsgs || stream->silent)) mm_log ("Mailbox is empty",(long) NIL); return stream; /* return stream to caller */ } /* MH mail close * Accepts: MAIL stream * close options */ void mh_close (MAILSTREAM *stream,long options) { if (LOCAL) { /* only if a file is open */ int silent = stream->silent; stream->silent = T; /* note this stream is dying */ if (options & CL_EXPUNGE) mh_expunge (stream,NIL,NIL); if (LOCAL->dir) fs_give ((void **) &LOCAL->dir); /* nuke the local data */ fs_give ((void **) &stream->local); stream->dtb = NIL; /* log out the DTB */ stream->silent = silent; /* reset silent state */ } } /* MH mail fetch fast information * Accepts: MAIL stream * sequence * option flags */ void mh_fast (MAILSTREAM *stream,char *sequence,long flags) { MESSAGECACHE *elt; unsigned long i; /* set up metadata for all messages */ if (stream && LOCAL && ((flags & FT_UID) ? mail_uid_sequence (stream,sequence) : mail_sequence (stream,sequence))) for (i = 1; i <= stream->nmsgs; i++) if ((elt = mail_elt (stream,i))->sequence && !(elt->day && elt->rfc822_size)) mh_load_message (stream,i,NIL); } /* MH load message into cache * Accepts: MAIL stream * message # * option flags */ void mh_load_message (MAILSTREAM *stream,unsigned long msgno,long flags) { unsigned long i,j,nlseen; int fd; unsigned char c,*t; struct stat sbuf; MESSAGECACHE *elt; FDDATA d; STRING bs; elt = mail_elt (stream,msgno);/* get elt */ /* build message file name */ sprintf (LOCAL->buf,"%s/%lu",LOCAL->dir,elt->private.uid); /* anything we need not currently cached? */ if ((!elt->day || !elt->rfc822_size || ((flags & MLM_HEADER) && !elt->private.msg.header.text.data) || ((flags & MLM_TEXT) && !elt->private.msg.text.text.data)) && ((fd = open (LOCAL->buf,O_RDONLY,NIL)) >= 0)) { fstat (fd,&sbuf); /* get file metadata */ d.fd = fd; /* set up file descriptor */ d.pos = 0; /* start of file */ d.chunk = LOCAL->buf; d.chunksize = CHUNKSIZE; INIT (&bs,fd_string,&d,sbuf.st_size); if (!elt->day) { /* set internaldate to file date */ struct tm *tm = gmtime (&sbuf.st_mtime); elt->day = tm->tm_mday; elt->month = tm->tm_mon + 1; elt->year = tm->tm_year + 1900 - BASEYEAR; elt->hours = tm->tm_hour; elt->minutes = tm->tm_min; elt->seconds = tm->tm_sec; elt->zhours = 0; elt->zminutes = 0; } if (!elt->rfc822_size) { /* know message size yet? */ for (i = 0, j = SIZE (&bs), nlseen = 0; j--; ) switch (SNX (&bs)) { case '\015': /* unlikely carriage return */ if (!j || (CHR (&bs) != '\012')) { i++; /* ugh, raw CR */ nlseen = NIL; break; } SNX (&bs); /* eat the line feed, drop in */ --j; case '\012': /* line feed? */ i += 2; /* count a CRLF */ /* header size known yet? */ if (!elt->private.msg.header.text.size && nlseen) { /* note position in file */ elt->private.special.text.size = GETPOS (&bs); /* and CRLF-adjusted size */ elt->private.msg.header.text.size = i; } nlseen = T; /* note newline seen */ break; default: /* ordinary chararacter */ i++; nlseen = NIL; break; } SETPOS (&bs,0); /* restore old position */ elt->rfc822_size = i; /* note that we have size now */ /* header is entire message if no delimiter */ if (!elt->private.msg.header.text.size) elt->private.msg.header.text.size = elt->rfc822_size; /* text is remainder of message */ elt->private.msg.text.text.size = elt->rfc822_size - elt->private.msg.header.text.size; } /* need to load cache with message data? */ if (((flags & MLM_HEADER) && !elt->private.msg.header.text.data) || ((flags & MLM_TEXT) && !elt->private.msg.text.text.data)) { /* purge cache if too big */ if (LOCAL->cachedtexts > max (stream->nmsgs * 4096,2097152)) { /* just can't keep that much */ mail_gc (stream,GC_TEXTS); LOCAL->cachedtexts = 0; } if ((flags & MLM_HEADER) && !elt->private.msg.header.text.data) { t = elt->private.msg.header.text.data = (unsigned char *) fs_get (elt->private.msg.header.text.size + 1); LOCAL->cachedtexts += elt->private.msg.header.text.size; /* read in message header */ for (i = 0; i < elt->private.msg.header.text.size; i++) switch (c = SNX (&bs)) { case '\015': /* unlikely carriage return */ *t++ = c; if ((CHR (&bs) == '\012')) { *t++ = SNX (&bs); i++; } break; case '\012': /* line feed? */ *t++ = '\015'; i++; default: *t++ = c; break; } *t = '\0'; /* tie off string */ if ((t - elt->private.msg.header.text.data) != elt->private.msg.header.text.size) fatal ("mh hdr size mismatch"); } if ((flags & MLM_TEXT) && !elt->private.msg.text.text.data) { t = elt->private.msg.text.text.data = (unsigned char *) fs_get (elt->private.msg.text.text.size + 1); SETPOS (&bs,elt->private.special.text.size); LOCAL->cachedtexts += elt->private.msg.text.text.size; /* read in message text */ for (i = 0; i < elt->private.msg.text.text.size; i++) switch (c = SNX (&bs)) { case '\015': /* unlikely carriage return */ *t++ = c; if ((CHR (&bs) == '\012')) { *t++ = SNX (&bs); i++; } break; case '\012': /* line feed? */ *t++ = '\015'; i++; default: *t++ = c; break; } *t = '\0'; /* tie off string */ if ((t - elt->private.msg.text.text.data) != elt->private.msg.text.text.size) fatal ("mh txt size mismatch"); } } close (fd); /* flush message file */ } } /* MH mail fetch message header * Accepts: MAIL stream * message # to fetch * pointer to returned header text length * option flags * Returns: message header in RFC822 format */ char *mh_header (MAILSTREAM *stream,unsigned long msgno,unsigned long *length, long flags) { MESSAGECACHE *elt; *length = 0; /* default to empty */ if (flags & FT_UID) return "";/* UID call "impossible" */ elt = mail_elt (stream,msgno);/* get elt */ if (!elt->private.msg.header.text.data) mh_load_message (stream,msgno,MLM_HEADER); *length = elt->private.msg.header.text.size; return (char *) elt->private.msg.header.text.data; } /* MH mail fetch message text (body only) * Accepts: MAIL stream * message # to fetch * pointer to returned stringstruct * option flags * Returns: T on success, NIL on failure */ long mh_text (MAILSTREAM *stream,unsigned long msgno,STRING *bs,long flags) { MESSAGECACHE *elt; /* UID call "impossible" */ if (flags & FT_UID) return NIL; elt = mail_elt (stream,msgno);/* get elt */ /* snarf message if don't have it yet */ if (!elt->private.msg.text.text.data) { mh_load_message (stream,msgno,MLM_TEXT); if (!elt->private.msg.text.text.data) return NIL; } if (!(flags & FT_PEEK)) { /* mark as seen */ mail_elt (stream,msgno)->seen = T; mm_flags (stream,msgno); } INIT (bs,mail_string,elt->private.msg.text.text.data, elt->private.msg.text.text.size); return T; } /* MH mail ping mailbox * Accepts: MAIL stream * Returns: T if stream alive, else NIL */ long mh_ping (MAILSTREAM *stream) { MAILSTREAM *sysibx = NIL; MESSAGECACHE *elt,*selt; struct stat sbuf; char *s,tmp[MAILTMPLEN]; int fd; unsigned long i,j,r; unsigned long old = stream->uid_last; long nmsgs = stream->nmsgs; long recent = stream->recent; int silent = stream->silent; if (stat (LOCAL->dir,&sbuf)) {/* directory exists? */ if (stream->inbox && /* no, create if INBOX */ dummy_create_path (stream,strcat (mh_file (tmp,MHINBOX),"/"), get_dir_protection ("INBOX"))) return T; sprintf (tmp,"Can't open mailbox %.80s: no such mailbox",stream->mailbox); mm_log (tmp,ERROR); return NIL; } stream->silent = T; /* don't pass up mm_exists() events yet */ if (sbuf.st_ctime != LOCAL->scantime) { struct direct **names = NIL; long nfiles = scandir (LOCAL->dir,&names,mh_select,mh_numsort); if (nfiles < 0) nfiles = 0; /* in case error */ /* note scanned now */ LOCAL->scantime = sbuf.st_ctime; /* scan directory */ for (i = 0; i < nfiles; ++i) { /* if newly seen, add to list */ if ((j = atoi (names[i]->d_name)) > old) { mail_exists (stream,++nmsgs); stream->uid_last = (elt = mail_elt (stream,nmsgs))->private.uid = j; elt->valid = T; /* note valid flags */ if (old) { /* other than the first pass? */ elt->recent = T; /* yup, mark as recent */ recent++; /* bump recent count */ } else { /* see if already read */ sprintf (tmp,"%s/%s",LOCAL->dir,names[i]->d_name); if (!stat (tmp,&sbuf) && (sbuf.st_atime > sbuf.st_mtime)) elt->seen = T; } } fs_give ((void **) &names[i]); } /* free directory */ if (s = (void *) names) fs_give ((void **) &s); } /* if INBOX, snarf from system INBOX */ if (stream->inbox && strcmp (sysinbox (),stream->mailbox)) { old = stream->uid_last; mm_critical (stream); /* go critical */ /* see if anything in system inbox */ if (!stat (sysinbox (),&sbuf) && sbuf.st_size && (sysibx = mail_open (sysibx,sysinbox (),OP_SILENT)) && !sysibx->rdonly && (r = sysibx->nmsgs)) { for (i = 1; i <= r; ++i) {/* for each message in sysinbox mailbox */ /* build file name we will use */ sprintf (LOCAL->buf,"%s/%lu",LOCAL->dir,++old); /* snarf message from Berkeley mailbox */ selt = mail_elt (sysibx,i); if (((fd = open (LOCAL->buf,O_WRONLY|O_CREAT|O_EXCL, (long) mail_parameters (NIL,GET_MBXPROTECTION,NIL))) >= 0) && (s = mail_fetchheader_full (sysibx,i,NIL,&j,FT_INTERNAL)) && (write (fd,s,j) == j) && (s = mail_fetchtext_full (sysibx,i,&j,FT_INTERNAL|FT_PEEK)) && (write (fd,s,j) == j) && !fsync (fd) && !close (fd)) { /* swell the cache */ mail_exists (stream,++nmsgs); stream->uid_last = /* create new elt, note its file number */ (elt = mail_elt (stream,nmsgs))->private.uid = old; recent++; /* bump recent count */ /* set up initial flags and date */ elt->valid = elt->recent = T; elt->seen = selt->seen; elt->deleted = selt->deleted; elt->flagged = selt->flagged; elt->answered = selt->answered; elt->draft = selt->draft; elt->day = selt->day;elt->month = selt->month;elt->year = selt->year; elt->hours = selt->hours;elt->minutes = selt->minutes; elt->seconds = selt->seconds; elt->zhours = selt->zhours; elt->zminutes = selt->zminutes; elt->zoccident = selt->zoccident; mh_setdate (LOCAL->buf,elt); sprintf (tmp,"%lu",i);/* delete it from the sysinbox */ mail_flag (sysibx,tmp,"\\Deleted",ST_SET); } else { /* failed to snarf */ if (fd) { /* did it ever get opened? */ close (fd); /* close descriptor */ unlink (LOCAL->buf);/* flush this file */ } sprintf (tmp,"Message copy to MH mailbox failed: %.80s", s,strerror (errno)); mm_log (tmp,ERROR); r = 0; /* stop the snarf in its tracks */ } } /* update scan time */ if (!stat (LOCAL->dir,&sbuf)) LOCAL->scantime = sbuf.st_ctime; mail_expunge (sysibx); /* now expunge all those messages */ } if (sysibx) mail_close (sysibx); mm_nocritical (stream); /* release critical */ } stream->silent = silent; /* can pass up events now */ mail_exists (stream,nmsgs); /* notify upper level of mailbox size */ mail_recent (stream,recent); return T; /* return that we are alive */ } /* MH mail check mailbox * Accepts: MAIL stream */ void mh_check (MAILSTREAM *stream) { /* Perhaps in the future this will preserve flags */ if (mh_ping (stream)) mm_log ("Check completed",(long) NIL); } /* MH mail expunge mailbox * Accepts: MAIL stream * sequence to expunge if non-NIL * expunge options * Returns: T, always */ long mh_expunge (MAILSTREAM *stream,char *sequence,long options) { long ret; MESSAGECACHE *elt; unsigned long i = 1; unsigned long n = 0; unsigned long recent = stream->recent; if (ret = sequence ? ((options & EX_UID) ? mail_uid_sequence (stream,sequence) : mail_sequence (stream,sequence)) : LONGT) { mm_critical (stream); /* go critical */ while (i <= stream->nmsgs) {/* for each message */ elt = mail_elt (stream,i);/* if deleted, need to trash it */ if (elt->deleted && (sequence ? elt->sequence : T)) { sprintf (LOCAL->buf,"%s/%lu",LOCAL->dir,elt->private.uid); if (unlink (LOCAL->buf)) {/* try to delete the message */ sprintf (LOCAL->buf,"Expunge of message %lu failed, aborted: %s",i, strerror (errno)); mm_log (LOCAL->buf,(long) NIL); break; } /* note uncached */ LOCAL->cachedtexts -= ((elt->private.msg.header.text.data ? elt->private.msg.header.text.size : 0) + (elt->private.msg.text.text.data ? elt->private.msg.text.text.size : 0)); mail_gc_msg (&elt->private.msg,GC_ENV | GC_TEXTS); /* if recent, note one less recent message */ if (elt->recent) --recent; /* notify upper levels */ mail_expunged (stream,i); n++; /* count up one more expunged message */ } else i++; /* otherwise try next message */ } if (n) { /* output the news if any expunged */ sprintf (LOCAL->buf,"Expunged %lu messages",n); mm_log (LOCAL->buf,(long) NIL); } else mm_log ("No messages deleted, so no update needed",(long) NIL); mm_nocritical (stream); /* release critical */ /* notify upper level of new mailbox size */ mail_exists (stream,stream->nmsgs); mail_recent (stream,recent); } return ret; } /* MH mail copy message(s) * Accepts: MAIL stream * sequence * destination mailbox * copy options * Returns: T if copy successful, else NIL */ long mh_copy (MAILSTREAM *stream,char *sequence,char *mailbox,long options) { FDDATA d; STRING st; MESSAGECACHE *elt; struct stat sbuf; int fd; unsigned long i; char flags[MAILTMPLEN],date[MAILTMPLEN]; appenduid_t au = (appenduid_t) mail_parameters (NIL,GET_APPENDUID,NIL); long ret = NIL; /* copy the messages */ if ((options & CP_UID) ? mail_uid_sequence (stream,sequence) : mail_sequence (stream,sequence)) for (i = 1; i <= stream->nmsgs; i++) if ((elt = mail_elt (stream,i))->sequence) { sprintf (LOCAL->buf,"%s/%lu",LOCAL->dir,elt->private.uid); if ((fd = open (LOCAL->buf,O_RDONLY,NIL)) < 0) return NIL; fstat (fd,&sbuf); /* get size of message */ if (!elt->day) { /* set internaldate to file date if needed */ struct tm *tm = gmtime (&sbuf.st_mtime); elt->day = tm->tm_mday; elt->month = tm->tm_mon + 1; elt->year = tm->tm_year + 1900 - BASEYEAR; elt->hours = tm->tm_hour; elt->minutes = tm->tm_min; elt->seconds = tm->tm_sec; elt->zhours = 0; elt->zminutes = 0; } d.fd = fd; /* set up file descriptor */ d.pos = 0; /* start of file */ d.chunk = LOCAL->buf; d.chunksize = CHUNKSIZE; /* kludge; mh_append would just strip CRs */ INIT (&st,fd_string,&d,sbuf.st_size); /* init flag string */ flags[0] = flags[1] = '\0'; if (elt->seen) strcat (flags," \\Seen"); if (elt->deleted) strcat (flags," \\Deleted"); if (elt->flagged) strcat (flags," \\Flagged"); if (elt->answered) strcat (flags," \\Answered"); if (elt->draft) strcat (flags," \\Draft"); flags[0] = '('; /* open list */ strcat (flags,")"); /* close list */ mail_date (date,elt); /* generate internal date */ if (au) mail_parameters (NIL,SET_APPENDUID,NIL); if ((ret = mail_append_full (NIL,mailbox,flags,date,&st)) && (options & CP_MOVE)) elt->deleted = T; if (au) mail_parameters (NIL,SET_APPENDUID,(void *) au); close (fd); } if (ret && mail_parameters (NIL,GET_COPYUID,NIL)) mm_log ("Can not return meaningful COPYUID with this mailbox format",WARN); return ret; /* return success */ } /* MH mail append message from stringstruct * Accepts: MAIL stream * destination mailbox * append callback * data for callback * Returns: T if append successful, else NIL */ long mh_append (MAILSTREAM *stream,char *mailbox,append_t af,void *data) { struct direct **names = NIL; int fd; char c,*flags,*date,*s,tmp[MAILTMPLEN]; STRING *message; MESSAGECACHE elt; FILE *df; long i,size,last,nfiles; long ret = LONGT; /* default stream to prototype */ if (!stream) stream = &mhproto; /* make sure valid mailbox */ if (!mh_isvalid (mailbox,tmp,NIL)) switch (errno) { case ENOENT: /* no such file? */ if (!((!compare_cstring (mailbox,MHINBOX) || !compare_cstring (mailbox,"INBOX")) && (mh_file (tmp,MHINBOX) && dummy_create_path (stream,strcat (tmp,"/"), get_dir_protection (mailbox))))) { mm_notify (stream,"[TRYCREATE] Must create mailbox before append",NIL); return NIL; } /* falls through */ case 0: /* merely empty file? */ break; case EINVAL: sprintf (tmp,"Invalid MH-format mailbox name: %.80s",mailbox); mm_log (tmp,ERROR); return NIL; default: sprintf (tmp,"Not a MH-format mailbox: %.80s",mailbox); mm_log (tmp,ERROR); return NIL; } /* get first message */ if (!(*af) (stream,data,&flags,&date,&message)) return NIL; if ((nfiles = scandir (tmp,&names,mh_select,mh_numsort)) > 0) { /* largest number */ last = atoi (names[nfiles-1]->d_name); for (i = 0; i < nfiles; ++i) /* free directory */ fs_give ((void **) &names[i]); } else last = 0; /* no messages here yet */ if (s = (void *) names) fs_give ((void **) &s); mm_critical (stream); /* go critical */ do { if (!SIZE (message)) { /* guard against zero-length */ mm_log ("Append of zero-length message",ERROR); ret = NIL; break; } if (date) { /* want to preserve date? */ /* yes, parse date into an elt */ if (!mail_parse_date (&elt,date)) { sprintf (tmp,"Bad date in append: %.80s",date); mm_log (tmp,ERROR); ret = NIL; break; } } mh_file (tmp,mailbox); /* build file name we will use */ sprintf (tmp + strlen (tmp),"/%ld",++last); if (((fd = open (tmp,O_WRONLY|O_CREAT|O_EXCL, (long)mail_parameters (NIL,GET_MBXPROTECTION,NIL))) < 0)|| !(df = fdopen (fd,"ab"))) { sprintf (tmp,"Can't open append message: %s",strerror (errno)); mm_log (tmp,ERROR); ret = NIL; break; } /* copy the data w/o CR's */ for (size = 0,i = SIZE (message); i && ret; --i) if (((c = SNX (message)) != '\015') && (putc (c,df) == EOF)) ret = NIL; /* close the file */ if (!ret || fclose (df)) { unlink (tmp); /* delete message */ sprintf (tmp,"Message append failed: %s",strerror (errno)); mm_log (tmp,ERROR); ret = NIL; } if (ret) { /* set the date for this message */ if (date) mh_setdate (tmp,&elt); /* get next message */ if (!(*af) (stream,data,&flags,&date,&message)) ret = NIL; } } while (ret && message); mm_nocritical (stream); /* release critical */ if (ret && mail_parameters (NIL,GET_APPENDUID,NIL)) mm_log ("Can not return meaningful APPENDUID with this mailbox format", WARN); return ret; } /* Internal routines */ /* MH file name selection test * Accepts: candidate directory entry * Returns: T to use file name, NIL to skip it */ int mh_select (struct direct *name) { char c; char *s = name->d_name; while (c = *s++) if (!isdigit (c)) return NIL; return T; } /* MH file name comparision * Accepts: first candidate directory entry * second candidate directory entry * Returns: negative if d1 < d2, 0 if d1 == d2, postive if d1 > d2 */ int mh_numsort (const void *d1,const void *d2) { return atoi ((*(struct direct **) d1)->d_name) - atoi ((*(struct direct **) d2)->d_name); } /* MH mail build file name * Accepts: destination string * source * Returns: destination */ char *mh_file (char *dst,char *name) { char *s; char *path = mh_path (dst); if (!path) fatal ("No mh path in mh_file()!"); /* INBOX becomes "inbox" in the MH path */ if (!compare_cstring (name,MHINBOX) || !compare_cstring (name,"INBOX")) sprintf (dst,"%.900s/%.80s",path,MHINBOXDIR); /* #mh names skip past prefix */ else if (*name == '#') sprintf (dst,"%.100s/%.900s",path,name + 4); else mailboxfile (dst,name); /* all other names */ /* tie off unnecessary trailing / */ if ((s = strrchr (dst,'/')) && !s[1] && (s[-1] == '/')) *s = '\0'; return dst; } /* MH canonicalize name * Accepts: buffer to write name * reference * pattern * Returns: T if success, NIL if failure */ long mh_canonicalize (char *pattern,char *ref,char *pat) { unsigned long i; char *s,tmp[MAILTMPLEN]; if (ref && *ref) { /* have a reference */ strcpy (pattern,ref); /* copy reference to pattern */ /* # overrides mailbox field in reference */ if (*pat == '#') strcpy (pattern,pat); /* pattern starts, reference ends, with / */ else if ((*pat == '/') && (pattern[strlen (pattern) - 1] == '/')) strcat (pattern,pat + 1); /* append, omitting one of the period */ else strcat (pattern,pat); /* anything else is just appended */ } else strcpy (pattern,pat); /* just have basic name */ if (mh_isvalid (pattern,tmp,T)) { /* count wildcards */ for (i = 0, s = pattern; *s; *s++) if ((*s == '*') || (*s == '%')) ++i; /* success if not too many */ if (i <= MAXWILDCARDS) return LONGT; mm_log ("Excessive wildcards in LIST/LSUB",ERROR); } return NIL; } /* Set date for message * Accepts: file name * elt containing date */ void mh_setdate (char *file,MESSAGECACHE *elt) { time_t tp[2]; tp[0] = time (0); /* atime is now */ tp[1] = mail_longdate (elt); /* modification time */ utime (file,tp); /* set the times */ } alpine-2.10+dfsg/imap/src/osdep/unix/ckp_pam.c0000600000175000017500000000776111512502123022736 0ustar paulproteuspaulproteus/* ======================================================================== * Copyright 1988-2006 University of Washington * * Licensed under the Apache License, Version 2.0 (the "License"); * you may not use this file except in compliance with the License. * You may obtain a copy of the License at * * http://www.apache.org/licenses/LICENSE-2.0 * * * ======================================================================== */ /* * Program: Pluggable Authentication Modules login services * * Author: Mark Crispin * Networks and Distributed Computing * Computing & Communications * University of Washington * Administration Building, AG-44 * Seattle, WA 98195 * Internet: MRC@CAC.Washington.EDU * * Date: 1 August 1988 * Last Edited: 31 August 2006 */ #ifdef MAC_OSX_KLUDGE /* why can't Apple be compatible? */ #include #else #include #endif struct checkpw_cred { char *uname; /* user name */ char *pass; /* password */ }; /* PAM conversation function * Accepts: number of messages * vector of messages * pointer to response return * application data * Returns: PAM_SUCCESS if OK, response vector filled in, else PAM_CONV_ERR */ static int checkpw_conv (int num_msg,const struct pam_message **msg, struct pam_response **resp,void *appdata_ptr) { int i; struct checkpw_cred *cred = (struct checkpw_cred *) appdata_ptr; struct pam_response *reply = fs_get (sizeof (struct pam_response) * num_msg); for (i = 0; i < num_msg; i++) switch (msg[i]->msg_style) { case PAM_PROMPT_ECHO_ON: /* assume want user name */ reply[i].resp_retcode = PAM_SUCCESS; reply[i].resp = cpystr (cred->uname); break; case PAM_PROMPT_ECHO_OFF: /* assume want password */ reply[i].resp_retcode = PAM_SUCCESS; reply[i].resp = cpystr (cred->pass); break; case PAM_TEXT_INFO: case PAM_ERROR_MSG: reply[i].resp_retcode = PAM_SUCCESS; reply[i].resp = NULL; break; default: /* unknown message style */ fs_give ((void **) &reply); return PAM_CONV_ERR; } *resp = reply; return PAM_SUCCESS; } /* PAM cleanup * Accepts: handle */ static void checkpw_cleanup (pam_handle_t *hdl) { #if 0 /* see checkpw() for why this is #if 0 */ pam_close_session (hdl,NIL); /* close session [uw]tmp */ #endif pam_setcred (hdl,PAM_DELETE_CRED); pam_end (hdl,PAM_SUCCESS); } /* Server log in * Accepts: user name string * password string * Returns: T if password validated, NIL otherwise */ struct passwd *checkpw (struct passwd *pw,char *pass,int argc,char *argv[]) { pam_handle_t *hdl; struct pam_conv conv; struct checkpw_cred cred; char *name = cpystr (pw->pw_name); conv.conv = &checkpw_conv; conv.appdata_ptr = &cred; cred.uname = name; cred.pass = pass; if (pw = ((pam_start ((char *) mail_parameters (NIL,GET_SERVICENAME,NIL), pw->pw_name,&conv,&hdl) == PAM_SUCCESS) && (pam_set_item (hdl,PAM_RHOST,tcp_clientaddr ()) == PAM_SUCCESS) && (pam_authenticate (hdl,NIL) == PAM_SUCCESS) && (pam_acct_mgmt (hdl,NIL) == PAM_SUCCESS) && (pam_setcred (hdl,PAM_ESTABLISH_CRED) == PAM_SUCCESS)) ? getpwnam (name) : NIL) { #if 0 /* * Some people have reported that this causes a SEGV in strncpy() from * pam_unix.so.1 */ /* * This pam_open_session() call is inconsistant with how we handle other * platforms, where we don't write [uw]tmp records. However, unlike our * code on other platforms, pam_acct_mgmt() will check those records for * inactivity and deny the authentication. */ pam_open_session (hdl,NIL); /* make sure account doesn't go inactive */ #endif /* arm hook to delete credentials */ mail_parameters (NIL,SET_LOGOUTHOOK,(void *) checkpw_cleanup); mail_parameters (NIL,SET_LOGOUTDATA,(void *) hdl); } else checkpw_cleanup (hdl); /* clean up */ fs_give ((void **) &name); /* reset log facility in case PAM broke it */ if (myServerName) openlog (myServerName,LOG_PID,syslog_facility); return pw; } alpine-2.10+dfsg/imap/src/osdep/unix/log_std.c0000600000175000017500000000217611512502123022752 0ustar paulproteuspaulproteus/* ======================================================================== * Copyright 1988-2006 University of Washington * * Licensed under the Apache License, Version 2.0 (the "License"); * you may not use this file except in compliance with the License. * You may obtain a copy of the License at * * http://www.apache.org/licenses/LICENSE-2.0 * * * ======================================================================== */ /* * Program: Standard login * * Author: Mark Crispin * Networks and Distributed Computing * Computing & Communications * University of Washington * Administration Building, AG-44 * Seattle, WA 98195 * Internet: MRC@CAC.Washington.EDU * * Date: 1 August 1988 * Last Edited: 30 August 2006 */ /* Log in * Accepts: login passwd struct * argument count * argument vector * Returns: T if success, NIL otherwise */ long loginpw (struct passwd *pw,int argc,char *argv[]) { uid_t uid = pw->pw_uid; char *name = cpystr (pw->pw_name); long ret = !(setgid (pw->pw_gid) || initgroups (name,pw->pw_gid) || setuid (uid)); fs_give ((void **) &name); return ret; } alpine-2.10+dfsg/imap/src/osdep/unix/Makefile0000600000175000017500000007574211512502123022624 0ustar paulproteuspaulproteus# ======================================================================== # Copyright 1988-2007 University of Washington # # Licensed under the Apache License, Version 2.0 (the "License"); # you may not use this file except in compliance with the License. # You may obtain a copy of the License at # # http://www.apache.org/licenses/LICENSE-2.0 # # # ======================================================================== # Program: C client makefile # # Author: Mark Crispin # Networks and Distributed Computing # Computing & Communications # University of Washington # Administration Building, AG-44 # Seattle, WA 98195 # Internet: MRC@CAC.Washington.EDU # # Date: 11 May 1989 # Last Edited: 17 December 2007 # Command line build parameters EXTRAAUTHENTICATORS= EXTRADRIVERS=mbox PASSWDTYPE=std SSLTYPE=nopwd IP=4 # The optimization level here for GCC ports is set here for a reason. It's # to get you to read this text. # The general concensus seems to be that -O2 is the one to use. # Over the years, I've been told to use many different settings, including -O6. # In recent versions of GCC [as of 2/2005], -O6 generates bad code that, among # other ill effects, causes infinite loops. # -O3 seems to be safe, but empirical observation from our local expert # indicates that in some (many?) cases -O3 code runs slower than -O2. GCCOPTLEVEL= -O2 # Try to have some consistency in GCC builds. We want optimization, but we # also want to be able to debug. GCCCFLAGS= -g $(GCCOPTLEVEL) -pipe -fno-omit-frame-pointer GCC4CFLAGS= $(GCCCFLAGS) -Wno-pointer-sign # Extended flags needed for SSL. You may need to modify. SSLDIR=/usr/local/ssl SSLCERTS=$(SSLDIR)/certs SSLKEYS=$(SSLCERTS) SSLINCLUDE=$(SSLDIR)/include SSLLIB=$(SSLDIR)/lib SSLCRYPTO=-lcrypto # Older versions of MIT Kerberos also have a libcrypto. If so, you may need # to use this instead #SSLCRYPTO=$(SSLLIB)/libcrypto.a # RSA Security Inc. released the RSA public key encryption algorithm into # the public domain on September 6, 2000. There is no longer any need to # use RSAREF. SSLRSA= # -lRSAglue -lrsaref SSLCFLAGS= -I$(SSLINCLUDE) -I$(SSLINCLUDE)/openssl\ -DSSL_CERT_DIRECTORY=\"$(SSLCERTS)\" -DSSL_KEY_DIRECTORY=\"$(SSLKEYS)\" SSLLDFLAGS= -L$(SSLLIB) -lssl $(SSLCRYPTO) $(SSLRSA) # Extended flags needed for non-standard passwd types. You may need to modify. AFSDIR=/usr/afsws AFSCFLAGS=-I$(AFSDIR)/include AFSLIB=$(AFSDIR)/lib AFSLDFLAGS=-L$(AFSLIB)/afs -L$(AFSLIB) -L$(AFSDIR)/domestic/lib\ -lkauth -lprot -lubik -lauth -lrxkad -lrx -llwp -ldes -lcom_err\ $(AFSLIB)/afs/util.a -laudit -lsys # AFSLDFLAGS may also need -L/usr/ucblib -lucb DCECFLAGS= -DDCE_MINIMAL -DPASSWD_OVERRIDE=\"/opt/pop3/passwd/passwd\" DCELDFLAGS= -ldce PAMLDFLAGS= -lpam -ldl # Build parameters normally set by the individual port CHECKPW=std LOGINPW=std SIGTYPE=bsd CRXTYPE=std ACTIVEFILE=/usr/lib/news/active SPOOLDIR=/usr/spool MAILSPOOL=$(SPOOLDIR)/mail NEWSSPOOL=$(SPOOLDIR)/news RSHPATH=/usr/ucb/rsh MD5PWD=/etc/cram-md5.pwd # Tries one of the test alternatives below if not specified. LOCKPGM= # Test alternatives if LOCKPGM not specified LOCKPGM1=/usr/libexec/mlock LOCKPGM2=/usr/sbin/mlock LOCKPGM3=/etc/mlock # Default formats for creating new mailboxes and for empty mailboxes in the # default namespace; must be set to the associated driver's prototype. # # The CREATEPROTO is the default format for new mailbox creation. # The EMPTYPROTO is the default format for handling zero-byte files. # # Normally, this is set by the individual port. # # NOTE: namespace formats (e.g. mh and news) can not be set as a default format # since they do not exist in the default namespace. Also, it is meaningless to # set certain other formats (e.g. mbx, mx, and mix) as the EMPTYPROTO since # these formats can never be empty files. CREATEPROTO=unixproto EMPTYPROTO=unixproto # Commands possibly overriden by the individual port ARRC=ar rc CC=cc LN=ln -s RANLIB=ranlib # Standard distribution build parameters DEFAULTAUTHENTICATORS=ext md5 pla log # # mh needs to be after any other directory format drivers (such as mx or mix) # since otherwise mh will seize any directory that is under the mh path. # However, mh needs to be before any sysinbox formats (such as mmdf or unix) # since otherwise INBOX won't work correctly when mh_allow_inbox is set. # DEFAULTDRIVERS=imap nntp pop3 mix mx mbx tenex mtx mh mmdf unix news phile CHUNKSIZE=65536 # Normally no need to change any of these ARCHIVE=c-client.a BINARIES=osdep.o mail.o misc.o newsrc.o smanager.o utf8.o utf8aux.o siglocal.o \ dummy.o pseudo.o netmsg.o flstring.o fdstring.o \ rfc822.o nntp.o smtp.o imap4r1.o pop3.o \ unix.o mbx.o mmdf.o tenex.o mtx.o news.o phile.o mh.o mx.o mix.o CFLAGS=-g CAT=cat MAKE=make MV=mv RM=rm -rf SH=sh # Primary build command BUILD=$(MAKE) build EXTRACFLAGS='$(EXTRACFLAGS)'\ EXTRALDFLAGS='$(EXTRALDFLAGS)'\ EXTRADRIVERS='$(EXTRADRIVERS)' EXTRAAUTHENTICATORS='$(EXTRAAUTHENTICATORS)'\ PASSWDTYPE=$(PASSWDTYPE) SSLTYPE=$(SSLTYPE) IP=$(IP) # Here if no make argument established missing: osdep.h $(MAKE) all `$(CAT) SPECIALS` osdep.h: @echo You must specify what type of system @false # Current ports a32: # AIX 3.2 for RS/6000 $(BUILD) `$(CAT) SPECIALS` OS=$@ \ SIGTYPE=psx CRXTYPE=nfs \ SPOOLDIR=/var/spool \ RSHPATH=/usr/bin/rsh \ BASECFLAGS="-g -Dunix=1 -D_BSD" \ BASELDFLAGS="-lbsd" a41: # AIX 4.1 for RS/6000 $(BUILD) `$(CAT) SPECIALS` OS=$@ \ SIGTYPE=psx CHECKPW=a41 CRXTYPE=nfs \ SPOOLDIR=/var/spool \ RSHPATH=/usr/bin/rsh \ BASECFLAGS="-g -Dunix=1 -D_BSD -qro -qroconst" \ BASELDFLAGS="-ls" a52: # Attempt at AIX 5.2 $(BUILD) `$(CAT) SPECIALS` OS=$@ \ SIGTYPE=psx CHECKPW=a41 CRXTYPE=nfs \ SPOOLDIR=/var/spool \ RSHPATH=/usr/bin/rsh \ BASECFLAGS="-g -Dunix=1 -D_BSD -qro -qroconst" \ BASELDFLAGS="-ls" aix: # AIX/370 @echo You are building for AIX on an S/370 class machine @echo If you want AIX on an RS/6000 you need to use a32 or a41 instead! $(BUILD) `$(CAT) SPECIALS` OS=$@ \ CRXTYPE=nfs \ BASECFLAGS="-g" \ BASELDFLAGS="-lbsd" aos: # AOS for RT $(BUILD) `$(CAT) SPECIALS` OS=$@ \ CRXTYPE=nfs \ BASECFLAGS="-g -Dconst=" art: # AIX 2.2.1 for RT $(BUILD) `$(CAT) SPECIALS` OS=$@ \ SIGTYPE=sv4 \ SPOOLDIR=/var \ ACTIVEFILE=/usr/local/news/control/active \ RSHPATH=/bin/rsh \ BASECFLAGS="-g -Dconst= -Dvoid=char" \ RANLIB=true asv: # Altos SVR4 $(BUILD) `$(CAT) SPECIALS` OS=$@ \ SIGTYPE=sv4 LOGINPW=old \ ACTIVEFILE=/usr/spool/news/active \ RSHPATH=/usr/bin/rcmd \ BASECFLAGS="-Dconst= -DSIGSTOP=SIGKILL" \ BASELDFLAGS="-lsocket -lrpc -lgen -lcrypt -lxenix" \ RANLIB=true aux: # A/UX $(BUILD) `$(CAT) SPECIALS` OS=$@ \ CRXTYPE=nfs \ MAILSPOOL=/usr/mail \ BASECFLAGS="-g -B/usr/lib/big/ -Dvoid=char -Dconst=" \ RANLIB=true ARRC="ar -rc" bs3: # BSD/i386 3.0 or higher $(BUILD) `$(CAT) SPECIALS` OS=bsi \ CHECKPW=bsi LOGINPW=bsi CRXTYPE=nfs \ SPOOLDIR=/var NEWSSPOOL=/var/news/spool \ ACTIVEFILE=/var/news/etc/active \ RSHPATH=/usr/bin/rsh \ BASECFLAGS="$(GCCCFLAGS)" CC=shlicc bsd: # BSD UNIX $(BUILD) `$(CAT) SPECIALS` OS=$@ \ CRXTYPE=nfs \ BASECFLAGS="-g -Dconst=" bsf: # FreeBSD $(BUILD) `$(CAT) SPECIALS` OS=$@ \ SIGTYPE=psx CRXTYPE=nfs \ SPOOLDIR=/var \ ACTIVEFILE=/usr/local/news/lib/active \ RSHPATH=/usr/bin/rsh \ BASECFLAGS="$(GCCCFLAGS)" \ BASELDFLAGS="-lcrypt" bsi: # BSD/i386 $(BUILD) `$(CAT) SPECIALS` OS=$@ \ CRXTYPE=nfs \ SPOOLDIR=/var NEWSSPOOL=/var/news/spool \ ACTIVEFILE=/var/news/etc/active \ RSHPATH=/usr/bin/rsh \ BASECFLAGS="$(GCCCFLAGS)" bso: # OpenBSD $(BUILD) `$(CAT) SPECIALS` OS=bsi \ SIGTYPE=psx CRXTYPE=nfs \ SPOOLDIR=/var \ ACTIVEFILE=/usr/local/news/lib/active \ RSHPATH=/usr/bin/rsh \ BASECFLAGS="$(GCCCFLAGS)" cvx: # Convex $(BUILD) `$(CAT) SPECIALS` OS=$@ \ CRXTYPE=nfs \ BASECFLAGS="-O -ext -Dconst=" cyg: # Cygwin - note that most local file drivers don't work!! $(BUILD) `$(CAT) SPECIALS` OS=$@ \ DEFAULTDRIVERS="imap nntp pop3 mbx unix phile" \ SIGTYPE=psx CHECKPW=cyg LOGINPW=cyg CRXTYPE=std \ SPOOLDIR=/var \ ACTIVEFILE=/usr/local/news/lib/active \ RSHPATH=/usr/bin/rsh \ BASECFLAGS="$(GCCCFLAGS)" \ BASELDFLAGS="-lcrypt" \ CC=gcc d-g: # Data General DG/UX $(BUILD) `$(CAT) SPECIALS` OS=$@ \ SIGTYPE=sv4 CRXTYPE=nfs \ SPOOLDIR=/var/spool MAILSPOOL=/var/mail \ ACTIVEFILE=/local/news/active \ RSHPATH=/usr/bin/remsh \ BASECFLAGS="-g -Dconst=" \ BASELDFLAGS="-lnsl -lsocket" \ RANLIB=true d54: # Data General DG/UX 5.4 $(BUILD) `$(CAT) SPECIALS` OS=d-g \ SIGTYPE=sv4 CRXTYPE=nfs \ SPOOLDIR=/var/spool MAILSPOOL=/var/mail \ ACTIVEFILE=/local/news/active \ RSHPATH=/usr/bin/remsh \ BASECFLAGS="-g -Dconst=" \ BASELDFLAGS="-lnsl -lsocket" \ RANLIB=true dpx: # Bull DPX/2 $(BUILD) `$(CAT) SPECIALS` OS=sv4 \ SIGTYPE=sv4 CHECKPW=sv4 LOGINPW=sv4 \ RSHPATH=/usr/bin/remsh \ BASECFLAGS="-Dconst= -DSYSTEM5 -DSHORT_IDENT" \ BASELDFLAGS="-linet" \ RANLIB=true LN=ln drs: # ICL DRS/NX $(BUILD) `$(CAT) SPECIALS` OS=$@ \ SIGTYPE=sv4 CHECKPW=sv4 LOGINPW=sv4 CRXTYPE=nfs \ SPOOLDIR=/var/spool MAILSPOOL=/var/mail \ ACTIVEFILE=/var/lib/news/active \ RSHPATH=/usr/bin/rsh \ BASECFLAGS="-O" \ BASELDFLAGS="-lsocket -lgen" \ RANLIB=true do4: # Apollo Domain/OS sr10.4 $(BUILD) `$(CAT) SPECIALS` OS=$@ \ CRXTYPE=nfs \ BASECFLAGS="-A systype,bsd4.3 -D_APOLLO_SOURCE" \ RANLIB=true dyn: # Dynix $(BUILD) `$(CAT) SPECIALS` OS=$@ \ CRXTYPE=nfs \ BASECFLAGS="-g -Dconst=" epx: # EP/IX $(BUILD) `$(CAT) SPECIALS` OS=sv4 \ SIGTYPE=sv4 CHECKPW=sv4 LOGINPW=sv4 \ SPOOLDIR=/var/spool MAILSPOOL=/var/mail \ ACTIVEFILE=/usr/share/news/active \ RSHPATH=/usr/net/rsh \ BASECFLAGS="-g -systype svr4" \ BASELDFLAGS="-lsocket -lnsl -lgen" \ RANLIB=true ga4: # GCC AIX 4.1 for RS/6000 $(BUILD) `$(CAT) SPECIALS` OS=a41 \ SIGTYPE=psx CHECKPW=a41 CRXTYPE=nfs \ SPOOLDIR=/var/spool \ RSHPATH=/usr/bin/rsh \ BASECFLAGS="-g -Dunix=1 -D_BSD" \ BASELDFLAGS="-ls" gas: # GCC Altos SVR4 $(BUILD) `$(CAT) SPECIALS` OS=asv \ SIGTYPE=sv4 LOGINPW=old \ ACTIVEFILE=/usr/spool/news/active \ RSHPATH=/usr/bin/rcmd \ BASECFLAGS="-g -O -DALTOS_SYSTEM_V -DSIGSTOP=SIGKILL" \ BASELDFLAGS="-lsocket -lrpc -lgen -lcrypt -lxenix" \ RANLIB=true CC=gcc gh9: # GCC HP-UX 9.x $(BUILD) `$(CAT) SPECIALS` OS=hpp \ SIGTYPE=psx CRXTYPE=nfs \ MAILSPOOL=/usr/mail \ RSHPATH=/usr/bin/remsh \ BASECFLAGS="$(GCCCFLAGS)" \ RANLIB=true CC=gcc ghp: # GCC HP-UX 10.x $(BUILD) `$(CAT) SPECIALS` OS=hpp \ SIGTYPE=psx CRXTYPE=nfs \ SPOOLDIR=/var \ ACTIVEFILE=/var/news/active \ RSHPATH=/usr/bin/remsh \ BASECFLAGS="$(GCCCFLAGS)" \ RANLIB=true CC=gcc ghs: # GCC HP-UX with Trusted Computer Base $(BUILD) `$(CAT) SPECIALS` OS=shp \ SIGTYPE=psx CHECKPW=sec CRXTYPE=nfs \ SPOOLDIR=/var \ ACTIVEFILE=/var/news/active \ RSHPATH=/usr/bin/remsh \ BASECFLAGS="$(GCCCFLAGS)" \ BASELDFLAGS="-lnet -lV3 -lsec" \ RANLIB=true CC=gcc go5: # GCC 2.7.1 (95q4) SCO Open Server 5.0.x $(BUILD) `$(CAT) SPECIALS` OS=sc5 \ SIGTYPE=psx CHECKPW=sec LOGINPW=sec \ CREATEPROTO=mmdfproto EMPTYPROTO=mmdfproto \ SPOOLDIR=/var/spool \ ACTIVEFILE=/var/lib/news/active \ RSHPATH=/usr/bin/rcmd \ BASECFLAGS="$(GCCCFLAGS) -I/usr/include -L/lib" \ BASELDFLAGS="-lsocket -lprot -lx -ltinfo -lm" \ RANLIB=true CC=gcc gsc: # Santa Cruz Operation $(BUILD) `$(CAT) SPECIALS` OS=sco \ SIGTYPE=sv4 CHECKPW=sec LOGINPW=sec \ CREATEPROTO=mmdfproto EMPTYPROTO=mmdfproto \ RSHPATH=/usr/bin/rcmd \ BASECFLAGS="$(GCCCFLAGS)" \ BASELDFLAGS="-lsocket -lprot -lcrypt_i -lx -los" \ RANLIB=true LN=ln CC=gcc gsg: # GCC Silicon Graphics $(BUILD) `$(CAT) SPECIALS` OS=sgi \ SIGTYPE=sv4 CRXTYPE=nfs \ MAILSPOOL=/usr/mail \ RSHPATH=/usr/bsd/rsh \ BASECFLAGS="$(GCCCFLAGS)" \ RANLIB=true CC=gcc gso: os_sol.h # GCC Solaris $(BUILD) `$(CAT) SPECIALS` OS=sol \ SIGTYPE=psx CHECKPW=psx CRXTYPE=nfs \ SPOOLDIR=/var/spool MAILSPOOL=/var/mail \ ACTIVEFILE=/usr/share/news/active \ RSHPATH=/usr/bin/rsh \ BASECFLAGS="$(GCCCFLAGS)" \ BASELDFLAGS="-lsocket -lnsl -lgen" \ RANLIB=true CC=gcc gsu: # GCC SUN-OS $(BUILD) `$(CAT) SPECIALS` OS=sun \ CRXTYPE=nfs \ BASECFLAGS="$(GCCCFLAGS)" \ BASELDFLAGS="-ldl" \ CC=gcc gul: # GCC Ultrix $(BUILD) `$(CAT) SPECIALS` OS=ult \ SIGTYPE=psx CHECKPW=ult CRXTYPE=nfs \ BASECFLAGS="$(GCCCFLAGS)" \ BASELDFLAGS="-lauth -lc" \ CC=gcc h11: # HP-UX 11i $(BUILD) `$(CAT) SPECIALS` OS=hpp \ SIGTYPE=psx CRXTYPE=nfs \ SPOOLDIR=/var \ ACTIVEFILE=/var/news/active \ RSHPATH=/usr/bin/remsh \ BASECFLAGS="-g -Ae" \ RANLIB=true hpp: # HP-UX 9.x $(BUILD) `$(CAT) SPECIALS` OS=$@ \ SIGTYPE=psx CRXTYPE=nfs \ MAILSPOOL=/usr/mail \ RSHPATH=/usr/bin/remsh \ BASECFLAGS="-g -Aa -D_HPUX_SOURCE" \ BASELDFLAGS="-lnet -lV3" \ RANLIB=true hpx: # HP-UX 10.x $(BUILD) `$(CAT) SPECIALS` OS=hpp \ SIGTYPE=psx CRXTYPE=nfs \ SPOOLDIR=/var \ ACTIVEFILE=/var/news/active \ RSHPATH=/usr/bin/remsh \ BASECFLAGS="-g -Ae" \ BASELDFLAGS="-lnet -lV3" \ RANLIB=true isc: # Interactive $(BUILD) `$(CAT) SPECIALS` OS=$@ \ SIGTYPE=sv4 CHECKPW=sv4 LOGINPW=sv4 \ SPOOLDIR=/var/spool MAILSPOOL=/var/mail \ ACTIVEFILE=/var/spool/news/active \ BASECFLAGS="-Xp -D_SYSV3" \ BASELDFLAGS="-linet -lnsl_s -lgen -lx -lsec -liberty" \ RANLIB=true lnp: # Linux Pluggable Authentication modules $(BUILD) `$(CAT) SPECIALS` OS=slx \ SIGTYPE=psx CHECKPW=pam CRXTYPE=nfs \ SPOOLDIR=/var/spool \ ACTIVEFILE=/var/lib/news/active \ RSHPATH=/usr/bin/rsh \ BASECFLAGS="$(GCCCFLAGS)" \ BASELDFLAGS="$(PAMLDFLAGS)" lnx: # Linux non-shadow passwords @echo You are building for traditional Linux *without* shadow @echo passwords and with the crypt function in the C library. @echo If your system has shadow passwords, or if crypt is not @echo in the C library, you must use slx, sl4, or sl5 instead! $(BUILD) `$(CAT) SPECIALS` OS=$@ \ SIGTYPE=psx CRXTYPE=nfs \ SPOOLDIR=/var/spool \ ACTIVEFILE=/var/lib/news/active \ RSHPATH=/usr/bin/rsh \ BASECFLAGS="$(GCCCFLAGS)" lyn: # LynxOS $(BUILD) `$(CAT) SPECIALS` OS=$@ \ CRXTYPE=nfs \ RSHPATH=/bin/rsh \ BASECFLAGS="$(GCCCFLAGS)" \ BASELDFLAGS=-lbsd \ CC=gcc mct: # MachTen - CRXTYPE=nfs doesn't work (at least not on 2.2) $(BUILD) `$(CAT) SPECIALS` OS=$@ \ SPOOLDIR=/var/spool \ BASECFLAGS="$(GCCCFLAGS)" mnt: # Mint $(BUILD) `$(CAT) SPECIALS` OS=$@ \ SIGTYPE=psx CRXTYPE=nfs \ SPOOLDIR=/var/spool \ ACTIVEFILE=/var/lib/news/active \ RSHPATH=/usr/bin/rsh \ BASECFLAGS="$(GCCCFLAGS)" neb: # NetBSD $(BUILD) `$(CAT) SPECIALS` OS=bsi \ CRXTYPE=nfs \ SPOOLDIR=/var \ ACTIVEFILE=/var/db/news/active \ RSHPATH=/usr/bin/rsh \ BASECFLAGS="$(GCCCFLAGS)" \ BASELDFLAGS="-lcrypt" nec: # NEC UX $(BUILD) `$(CAT) SPECIALS` OS=sv4 \ SIGTYPE=sv4 CHECKPW=sv4 \ SPOOLDIR=/var/spool MAILSPOOL=/var/mail \ ACTIVEFILE=/var/news/lib/active \ RSHPATH=/usr/bin/rsh \ BASECFLAGS="-g -Kopt=2 -KOlimit=2000" \ BASELDFLAGS="-lsocket -lnsl -lgen" \ RANLIB=true CC=/usr/abiccs/bin/cc nto: # QNX Neutrino RTP $(BUILD) `$(CAT) SPECIALS` OS=$@ \ CRXTYPE=nfs \ SPOOLDIR=/var/spool \ ACTIVEFILE=/var/lib/news/active \ RSHPATH=/usr/bin/rsh \ BASECFLAGS="-g -O" nxt: # NEXTSTEP $(BUILD) `$(CAT) SPECIALS` OS=$@ \ CRXTYPE=nfs \ BASECFLAGS="$(GCCCFLAGS)" nx3: # NEXTSTEP 3.0 single threaded $(BUILD) `$(CAT) SPECIALS` OS=nxt \ CRXTYPE=nfs \ BASECFLAGS="$(GCCCFLAGS)" echo "void malloc_singlethreaded (void);" >> linkage.h echo " malloc_singlethreaded ();" >> linkage.c osf: # OSF/1 $(BUILD) `$(CAT) SPECIALS` OS=$@ \ SIGTYPE=psx CRXTYPE=nfs \ SPOOLDIR=/var/spool \ BASECFLAGS="-g3 -w -O2 -Olimit 1500" # Note: sia_become_user() used by LOGINPW=os4 doesn't seem to work right. The # user doesn't get proper file access, and the process can't be killed. os4: # OSF/1 (Digital UNIX) 4 $(BUILD) `$(CAT) SPECIALS` OS=$@ \ SIGTYPE=psx CHECKPW=os4 LOGINPW=os4 CRXTYPE=nfs \ SPOOLDIR=/var/spool \ BASECFLAGS="-g3 -w -std0 -O2" osx: # Mac OS X $(BUILD) `$(CAT) SPECIALS` OS=$@ \ CRXTYPE=nfs \ SPOOLDIR=/var/spool MAILSPOOL=/var/mail \ RSHPATH=/usr/bin/rsh \ BASECFLAGS="$(GCC4CFLAGS)" ptx: # PTX $(BUILD) `$(CAT) SPECIALS` OS=$@ \ SIGTYPE=psx CHECKPW=svo LOGINPW=sv4 CRXTYPE=nfs \ MAILSPOOL=/usr/mail \ RSHPATH=/usr/bin/resh \ BASECFLAGS="-Wc,-O3 -Wc,-seq -Dprivate=PRIVATE" \ BASELDFLAGS="-lseq -lsec -lsocket -linet -lnsl -lgen" \ RANLIB=true pyr: # Pyramid $(BUILD) `$(CAT) SPECIALS` OS=$@ \ CRXTYPE=nfs \ BASECFLAGS="-g -Dconst=" qnx: # QNX $(BUILD) `$(CAT) SPECIALS` OS=$@ \ CHECKPW=psx LOGINPW=old \ RSHPATH=/usr/ucb/rsh \ BASECFLAGS="-Otax -g -Dunix=1 -D_POSIX_SOURCE" \ BASELDFLAGS="-g -N128k -llogin -lsocket -lunix" s40: # SUN-OS 4.0 $(BUILD) `$(CAT) SPECIALS` OS=$@ \ CRXTYPE=nfs \ BASECFLAGS="-g -Dconst=" sc5: # SCO Open Server 5.0 $(BUILD) `$(CAT) SPECIALS` OS=$@ \ SIGTYPE=psx CHECKPW=sec LOGINPW=sec \ CREATEPROTO=mmdfproto EMPTYPROTO=mmdfproto \ SPOOLDIR=/var/spool \ ACTIVEFILE=/var/lib/news/active \ RSHPATH=/usr/bin/rcmd \ BASECFLAGS="-O3 -s -belf" \ BASELDFLAGS="-lsocket -lprot -lx -ltinfo -lm" \ RANLIB=true sco: # Santa Cruz Operation $(BUILD) `$(CAT) SPECIALS` OS=$@ \ SIGTYPE=sv4 CHECKPW=sec LOGINPW=sec \ CREATEPROTO=mmdfproto EMPTYPROTO=mmdfproto \ RSHPATH=/usr/bin/rcmd \ BASECFLAGS="-O3" \ BASELDFLAGS="-lsocket -lprot -lcrypt_i -lx -los" \ RANLIB=true LN=ln # Note: setting _POSIX_SOURCE doesn't seem to build it as of SGI IRIX 5.3 sgi: # Silicon Graphics $(BUILD) `$(CAT) SPECIALS` OS=$@ \ SIGTYPE=sv4 CRXTYPE=nfs \ MAILSPOOL=/usr/mail \ RSHPATH=/usr/bsd/rsh \ BASECFLAGS="-g3 -O2 -Olimit 8192" \ RANLIB=true sg6: # Silicon Graphics, IRIX 6.5 MAKEFLAGS= $(BUILD) `$(CAT) SPECIALS` OS=sgi \ SIGTYPE=sv4 CRXTYPE=nfs \ MAILSPOOL=/usr/mail \ RSHPATH=/usr/bsd/rsh \ BASECFLAGS="-g3 -O2 -OPT:Olimit=0 -woff 1110,1116" \ RANLIB=true # Note: Mark Kaesling says that setluid() isn't in HP-UX with SecureWare. shp: # HP-UX with Trusted Computer Base $(BUILD) `$(CAT) SPECIALS` OS=$@ \ SIGTYPE=psx CHECKPW=sec CRXTYPE=nfs \ SPOOLDIR=/var \ ACTIVEFILE=/var/news/active \ RSHPATH=/usr/bin/remsh \ BASECFLAGS="-g -Ae" \ BASELDFLAGS="-lnet -lV3 -lsec" \ RANLIB=true slx: # Secure Linux @echo You are building for libc6/glibc versions of Secure Linux @echo If you want libc5 versions you must use sl5 instead! @echo If you want libc4 versions you must use sl4 instead! $(BUILD) `$(CAT) SPECIALS` OS=$@ \ SIGTYPE=psx CHECKPW=psx CRXTYPE=nfs \ SPOOLDIR=/var/spool \ ACTIVEFILE=/var/lib/news/active \ RSHPATH=/usr/bin/rsh \ BASECFLAGS="$(GCCCFLAGS)" \ BASELDFLAGS="-lcrypt" sl4: # Secure Linux using libc4 @echo You are building for libc4 versions of Secure Linux @echo If you want libc6/glibc versions you must use slx instead! @echo If you want libc5 versions you must use sl5 instead! $(BUILD) `$(CAT) SPECIALS` OS=slx \ SIGTYPE=psx CHECKPW=psx CRXTYPE=nfs \ SPOOLDIR=/var/spool \ ACTIVEFILE=/var/lib/news/active \ RSHPATH=/usr/bin/rsh \ BASECFLAGS="$(GCCCFLAGS)" \ BASELDFLAGS="-lshadow" sl5: # Secure Linux using libc5 @echo You are building for libc5 versions of Secure Linux @echo If you want libc6/glibc versions you must use slx instead! @echo If you want libc4 versions you must use sl4 instead! $(BUILD) `$(CAT) SPECIALS` OS=slx \ SIGTYPE=psx CHECKPW=psx CRXTYPE=nfs \ SPOOLDIR=/var/spool \ ACTIVEFILE=/var/lib/news/active \ RSHPATH=/usr/bin/rsh \ BASECFLAGS="$(GCCCFLAGS)" snx: # Siemens Nixdorf SINIX and Reliant UNIX $(BUILD) `$(CAT) SPECIALS` OS=sv4 \ SIGTYPE=psx CHECKPW=sv4 \ SPOOLDIR=/var/spool MAILSPOOL=/var/mail \ ACTIVEFILE=/usr/share/news/active \ RSHPATH=/usr/bin/rsh \ BASECFLAGS="-g -D_SYS_CLOCK_H -Dconst=" \ BASELDFLAGS="-lsocket -lnsl -lgen" \ RANLIB=true # Sorry about the -w, but the cretinous SUN Workshop Pro C compiler barfs on # implicit casts between char and unsigned char. soc: os_sol.h # Solaris with cc $(BUILD) `$(CAT) SPECIALS` OS=sol \ SIGTYPE=psx CHECKPW=psx CRXTYPE=nfs \ SPOOLDIR=/var/spool MAILSPOOL=/var/mail \ ACTIVEFILE=/usr/share/news/active \ RSHPATH=/usr/bin/rsh \ BASECFLAGS="-g -O -w" \ BASELDFLAGS="-lsocket -lnsl -lgen" \ RANLIB=true CC=/opt/SUNWspro/bin/cc # Note: It is a long and disgusting story about why cc is set to ucbcc. You # need to invoke the C compiler so that it links with the SVR4 libraries and # not the BSD libraries, otherwise readdir() will return the wrong information. # Of all the names in the most common path, ucbcc is the only name to be found # (on /usr/ccs/bin) that points to a suitable compiler. cc is likely to be # /usr/ucb/cc which is absolutely not the compiler that you want. The real # SVR4 cc is probably something like /opt/SUNWspro/bin/cc which is rarely in # anyone's path. # # ucbcc is probably a link to acc, e.g. /opt/SUNWspro/SC4.0/bin/acc, and is # the UCB C compiler using the SVR4 libraries. # # If ucbcc isn't on your system, then punt on the SUN C compiler and use gcc # instead (the gso port instead of the sol port). # # If, in spite of all the above warnings, you choose to use the "soc" port # instead of the "sol" port, be sure to check the behavior of the LIST command # in imapd. Also, note that the "soc" port uses -O. If you want to use the # real SVR4 compiler, you must use -O. If it works to compile with -O2, then # cc is probably using the UCB compiler with BSD libraries, and will not build # a good binary # # To recap: # 1) The sol port is designed to be built using the UCB compiler using the # SVR4 libraries. This compiler is "ucbcc", which is lunk to acc. You # use -O2 as one of the CFLAGS. # 2) If you build the sol port with the UCB compiler using the BSD libraries, # you will get no error messages but you will get bad binaries (the most # obvious symptom is dropping the first two characters return filenames # from the imapd LIST command. This compiler also uses -O2, and is very # often what the user gets from "cc". BEWARE!!! # 3) If you build the sol port with the real SVR4 compiler, which is often # hidden away or unavailable on many systems, then you will get errors # from -O2 and you need to change that to -O. But you will get a good # binary. However, you should try it with -O2 first, to make sure that # you got this compiler and not the UCB compiler using BSD libraries. sol: os_sol.h # Solaris $(BUILD) `$(CAT) SPECIALS` OS=$@ \ SIGTYPE=psx CHECKPW=psx CRXTYPE=nfs \ SPOOLDIR=/var/spool MAILSPOOL=/var/mail \ ACTIVEFILE=/usr/share/news/active \ RSHPATH=/usr/bin/rsh \ BASECFLAGS="-g -O2" \ BASELDFLAGS="-lsocket -lnsl -lgen" \ RANLIB=true CC=ucbcc sos: # Secure OSF/1 $(BUILD) `$(CAT) SPECIALS` OS=$@ \ SIGTYPE=psx CHECKPW=sce LOGINPW=sec CRXTYPE=nfs \ BASECFLAGS="-g3 -w -O2 -Olimit 1500" \ BASELDFLAGS="-lsecurity -laud" ssn: # Secure SUN-OS $(BUILD) `$(CAT) SPECIALS` OS=sun \ CHECKPW=ssn CRXTYPE=nfs \ BASECFLAGS="-g -Dconst=" \ BASELDFLAGS="-ldl" sua: # Windows Vista Subsystem for UNIX Applications $(BUILD) `$(CAT) SPECIALS` OS=sua \ SIGTYPE=psx CRXTYPE=nfs LOGINPW=old \ SPOOLDIR=/var/spool MAILSPOOL=/var/mail \ ACTIVEFILE=/var/lib/news/active \ RSHPATH=/usr/bin/rsh \ BASECFLAGS="-g -O2" \ BASELDFLAGS="-lcrypt" sun: # SUN-OS $(BUILD) `$(CAT) SPECIALS` OS=$@ \ CRXTYPE=nfs \ BASECFLAGS="-g -Dconst=" \ BASELDFLAGS="-ldl" sv2: # SVR2 @echo You are being *very* optimistic! $(BUILD) `$(CAT) SPECIALS` OS=$@ \ SIGTYPE=sv4 LOGINPW=old \ MAILSPOOL=/usr/mail \ RSHPATH=/usr/bin/remsh \ BASECFLAGS="-Dconst= -DSYSTEM5 -DSHORT_IDENT -I/usr/ethernet/include" \ BASELDFLAGS="-lnet" \ RANLIB=true LN=ln sv4: # SVR4 $(BUILD) `$(CAT) SPECIALS` OS=$@ \ SIGTYPE=sv4 CHECKPW=sv4 LOGINPW=sv4 \ SPOOLDIR=/var/spool MAILSPOOL=/var/mail \ ACTIVEFILE=/usr/share/news/active \ RSHPATH=/usr/bin/resh \ BASECFLAGS="-g -Dconst=" \ BASELDFLAGS="-lsocket -lnsl -lgen" \ RANLIB=true ult: # Ultrix $(BUILD) `$(CAT) SPECIALS` OS=$@ \ SIGTYPE=psx CHECKPW=ult CRXTYPE=nfs \ BASECFLAGS="-g3 -O2 -Olimit 1500 -Dconst=" \ BASELDFLAGS="-lauth -lc" uw2: # UnixWare SVR4.2 $(BUILD) `$(CAT) SPECIALS` OS=sv4 \ SIGTYPE=sv4 CHECKPW=sv4 \ SPOOLDIR=/var/spool MAILSPOOL=/var/mail \ ACTIVEFILE=/var/news/lib/active \ RSHPATH=/usr/bin/rsh \ BASECFLAGS="-g" \ BASELDFLAGS="-lsocket -lnsl -lgen" \ RANLIB=true vul: # VAX Ultrix $(BUILD) `$(CAT) SPECIALS` OS=ult \ SIGTYPE=psx CHECKPW=ult CRXTYPE=nfs \ BASECFLAGS="-O2 -Dconst=" \ BASELDFLAGS="-lauth -lc" vu2: # VAX Ultrix 2.3, etc. $(BUILD) `$(CAT) SPECIALS` OS=$@ \ CRXTYPE=nfs \ BASECFLAGS="-O2 -Dconst= -Dvoid=char" # Build it! build: clean once $(ARCHIVE) all: $(ARCHIVE) $(ARCHIVE): $(BINARIES) sh -c '$(RM) $(ARCHIVE) || true' @$(CAT) ARCHIVE @$(SH) ARCHIVE .c.o: `$(CAT) CCTYPE` -c `$(CAT) CFLAGS` $*.c # Cleanup clean: sh -c '$(RM) auths.c crexcl.c ip_unix.c linkage.[ch] siglocal.c osdep*.[ch] *.o ARCHIVE *FLAGS *TYPE $(ARCHIVE) || true' # Dependencies dummy.o: mail.h misc.h osdep.h dummy.h fdstring.o: mail.h misc.h osdep.h fdstring.h flstring.o: mail.h misc.h osdep.h flstring.h imap4r1.o: mail.h misc.h osdep.h imap4r1.h rfc822.h mail.o: mail.h misc.h osdep.h rfc822.h linkage.h mbx.o: mail.h misc.h osdep.h dummy.h mh.o: mail.h misc.h osdep.h dummy.h mix.o: mail.h misc.h osdep.h dummy.h mx.o: mail.h misc.h osdep.h dummy.h misc.o: mail.h misc.h osdep.h mmdf.o: mail.h misc.h osdep.h pseudo.h dummy.h mtx.o: mail.h misc.h osdep.h dummy.h netmsg.o: mail.h misc.h osdep.h netmsg.h news.o: mail.h misc.h osdep.h newsrc.o: mail.h misc.h osdep.h newsrc.h nntp.o: mail.h misc.h osdep.h netmsg.h smtp.h nntp.h rfc822.h phile.o: mail.h misc.h osdep.h rfc822.h dummy.h pseudo.o: pseudo.h pop3.o: mail.h misc.h osdep.h rfc822.h smanager.o: mail.h misc.h osdep.h smtp.o: mail.h misc.h osdep.h smtp.h rfc822.h rfc822.o: mail.h misc.h osdep.h rfc822.h tenex.o: mail.h misc.h osdep.h dummy.h unix.o: mail.h misc.h osdep.h unix.h pseudo.h dummy.h utf8.o: mail.h misc.h osdep.h utf8.h tmap.c widths.c utf8aux.o: mail.h misc.h osdep.h utf8.h # OS-dependent osdep.o:mail.h misc.h env.h fs.h ftl.h nl.h tcp.h \ osdep.h env_unix.h tcp_unix.h \ osdep.c env_unix.c fs_unix.c ftl_unix.c nl_unix.c tcp_unix.c ip_unix.c\ auths.c crexcl.c flockcyg.c flocklnx.c flocksim.c fsync.c \ gethstid.c getspnam.c \ gr_wait.c gr_wait4.c gr_waitp.c \ kerb_mit.c \ auth_ext.c auth_gss.c auth_log.c auth_md5.c auth_pla.c \ pmatch.c scandir.c setpgrp.c strerror.c truncate.c write.c \ memmove.c memmove2.c memset.c \ tz_bsd.c tz_nul.c tz_sv4.c \ write.c sslstdio.c \ strerror.c strpbrk.c strstr.c strtok.c strtoul.c \ OSCFLAGS @echo Building OS-dependent module @echo If you get No such file error messages for files x509.h, ssl.h, @echo pem.h, buffer.h, bio.h, and crypto.h, that means that OpenSSL @echo is not installed on your system. Either install OpenSSL first @echo or build with command: make `$(CAT) OSTYPE` SSLTYPE=none `$(CAT) CCTYPE` -c `$(CAT) CFLAGS` `$(CAT) OSCFLAGS` -c osdep.c osdep.c: osdepbas.c osdepckp.c osdeplog.c osdepssl.c $(CAT) osdepbas.c osdepckp.c osdeplog.c osdepssl.c > osdep.c osdepbas.c: @echo osdepbas.c not found...try make clean and new make @false osdepckp.c: @echo osdepckp.c not found...try make clean and new make @false osdeplog.c: @echo osdeplog.c not found...try make clean and new make @false osdepssl.c: @echo osdepssl.c not found...try make clean and new make @false siglocal.c: @echo siglocal.c not found...try make clean and new make @false crexcl.c: @echo crexcl.c not found...do make clean and new make @false ip_unix.c: @echo ip_unix.c not found...do make clean and new make @false os_sol.h: sh -c 'if [ -f /lib/libc.a ]; then (strings /lib/libc.a | grep getpassphrase > /dev/null) && $(LN) os_soln.h os_sol.h || $(LN) os_solo.h os_sol.h ; else $(LN) os_soln.h os_sol.h ; fi' # Once-only environment setup once: onceenv ckp$(PASSWDTYPE) ssl$(SSLTYPE) osdep.c onceenv: @echo Once-only environment setup... echo $(CC) > CCTYPE echo $(BASECFLAGS) '$(EXTRACFLAGS)' -DCHUNKSIZE=$(CHUNKSIZE) > CFLAGS echo -DCREATEPROTO=$(CREATEPROTO) -DEMPTYPROTO=$(EMPTYPROTO) \ -DMD5ENABLE=\"$(MD5PWD)\" -DMAILSPOOL=\"$(MAILSPOOL)\" \ -DANONYMOUSHOME=\"$(MAILSPOOL)/anonymous\" \ -DACTIVEFILE=\"$(ACTIVEFILE)\" -DNEWSSPOOL=\"$(NEWSSPOOL)\" \ -DRSHPATH=\"$(RSHPATH)\" -DLOCKPGM=\"$(LOCKPGM)\" \ -DLOCKPGM1=\"$(LOCKPGM1)\" -DLOCKPGM2=\"$(LOCKPGM2)\" \ -DLOCKPGM3=\"$(LOCKPGM3)\" > OSCFLAGS echo $(BASELDFLAGS) $(EXTRALDFLAGS) > LDFLAGS echo "$(ARRC) $(ARCHIVE) $(BINARIES);$(RANLIB) $(ARCHIVE)" > ARCHIVE echo $(OS) > OSTYPE ./drivers $(EXTRADRIVERS) $(DEFAULTDRIVERS) dummy ./mkauths $(EXTRAAUTHENTICATORS) $(DEFAULTAUTHENTICATORS) echo " mail_versioncheck (CCLIENTVERSION);" >> linkage.c $(LN) os_$(OS).h osdep.h $(LN) os_$(OS).c osdepbas.c $(LN) log_$(LOGINPW).c osdeplog.c $(LN) sig_$(SIGTYPE).c siglocal.c $(LN) crx_$(CRXTYPE).c crexcl.c $(LN) ip$(IP)_unix.c ip_unix.c sh -c '(test $(OS) = sc5 -o $(OS) = sco -o ! -f /usr/include/sys/statvfs.h) && echo -DNOFSTATVFS >> OSCFLAGS || fgrep statvfs64 /usr/include/sys/statvfs.h > /dev/null || echo -DNOFSTATVFS64 >> OSCFLAGS' # Password checkers ckpafs: # AFS @echo AFS password authentication echo $(AFSCFLAGS) >> OSCFLAGS # echo $(AFSLDFLAGS) >> LDFLAGS # Note: Steve Roseman says that AFS libraries have to be lunk before SSL echo $(AFSLDFLAGS) `$(CAT) LDFLAGS` > LDFLAGS.tmp mv LDFLAGS.tmp LDFLAGS $(LN) ckp_afs.c osdepckp.c ckpdce: # DCE @echo DCE password authentication echo $(DCECFLAGS) >> OSCFLAGS echo $(DCELDFLAGS) >> LDFLAGS $(LN) ckp_dce.c osdepckp.c ckpgss: # Kerberos V (must have gss EXTRAAUTHENTICATOR as well) @echo Kerberos V password authentication $(LN) ckp_gss.c osdepckp.c ckpnul: # NUL authenticator (disables all plaintext authentication) @echo Plaintext authentication prohibited echo " mail_parameters (NIL,SET_DISABLEPLAINTEXT,(void *) 1);" >> linkage.c $(LN) ckp_nul.c osdepckp.c ckppam: # Pluggable Authentication Modules authenticator @echo PAM password authentication echo $(PAMLDFLAGS) >> LDFLAGS $(LN) ckp_pam.c osdepckp.c ckppmb: # Broken (e.g. SUN) Pluggable Authentication Modules authenticator @echo Broken PAM password authentication echo $(PAMLDFLAGS) >> LDFLAGS $(LN) ckp_pmb.c osdepckp.c ckpstd: # Port standard @echo Standard password authentication $(LN) ckp_$(CHECKPW).c osdepckp.c ckptwo: # Something plus standard @echo $(CHECKPWALT) password authentication first, then standard $(CAT) ckp_1st.c ckp_$(CHECKPWALT).c ckp_2nd.c ckp_$(CHECKPW).c \ ckp_3rd.c > osdepckp.c # SSL support sslnone:# No SSL @echo Building without SSL support $(LN) ssl_none.c osdepssl.c sslnopwd: sslunix snopwd sslunix.nopwd: sslnopwd sslsco.nopwd: sslsco snopwd sslunix: sbasic sldunix sslsco: sbasic sldsco sbasic: # UNIX OpenSSL @echo Building with SSL $(LN) ssl_unix.c osdepssl.c echo $(SSLCFLAGS) >> OSCFLAGS echo " ssl_onceonlyinit ();" >> linkage.c snopwd: # Plaintext disable @echo Building with SSL and plaintext passwords disabled unless SSL/TLS echo " mail_parameters (NIL,SET_DISABLEPLAINTEXT,(void *) 2);" >> linkage.c sldunix:# Normal UNIX SSL load flags echo $(SSLLDFLAGS) >> LDFLAGS sldsco: # SCO SSL load flags # Note: Tim Rice says that SSL has to be lunk before other libraries on SCO. echo $(SSLLDFLAGS) `cat LDFLAGS` > LDFLAGS.tmp mv LDFLAGS.tmp LDFLAGS # A monument to a hack of long ago and far away... love: @echo not war? alpine-2.10+dfsg/imap/src/osdep/unix/ssl_unix.c0000600000175000017500000006377112074110156023200 0ustar paulproteuspaulproteus/* ======================================================================== * Copyright 1988-2008 University of Washington * * Licensed under the Apache License, Version 2.0 (the "License"); * you may not use this file except in compliance with the License. * You may obtain a copy of the License at * * http://www.apache.org/licenses/LICENSE-2.0 * * * ======================================================================== */ /* * Program: SSL authentication/encryption module * * Author: Mark Crispin * Networks and Distributed Computing * Computing & Communications * University of Washington * Administration Building, AG-44 * Seattle, WA 98195 * Internet: MRC@CAC.Washington.EDU * * Date: 22 September 1998 * Last Edited: 13 January 2007 */ #define crypt ssl_private_crypt #include #include #include #include #include #include #include #include #undef crypt #define SSLBUFLEN 8192 #define SSLCIPHERLIST "ALL:!LOW" /* SSL I/O stream */ typedef struct ssl_stream { TCPSTREAM *tcpstream; /* TCP stream */ SSL_CTX *context; /* SSL context */ SSL *con; /* SSL connection */ int ictr; /* input counter */ char *iptr; /* input pointer */ char ibuf[SSLBUFLEN]; /* input buffer */ } SSLSTREAM; #include "sslio.h" /* Function prototypes */ static SSLSTREAM *ssl_start(TCPSTREAM *tstream,char *host,unsigned long flags); static char *ssl_start_work (SSLSTREAM *stream,char *host,unsigned long flags); static int ssl_open_verify (int ok,X509_STORE_CTX *ctx); static char *ssl_validate_cert (X509 *cert,char *host); static long ssl_compare_hostnames (unsigned char *s,unsigned char *pat); static char *ssl_getline_work (SSLSTREAM *stream,unsigned long *size, long *contd); static long ssl_abort (SSLSTREAM *stream); static RSA *ssl_genkey (SSL *con,int export,int keylength); /* Secure Sockets Layer network driver dispatch */ static struct ssl_driver ssldriver = { ssl_open, /* open connection */ ssl_aopen, /* open preauthenticated connection */ ssl_getline, /* get a line */ ssl_getbuffer, /* get a buffer */ ssl_soutr, /* output pushed data */ ssl_sout, /* output string */ ssl_close, /* close connection */ ssl_host, /* return host name */ ssl_remotehost, /* return remote host name */ ssl_port, /* return port number */ ssl_localhost /* return local host name */ }; /* non-NIL if doing SSL primary I/O */ static SSLSTDIOSTREAM *sslstdio = NIL; static char *start_tls = NIL; /* non-NIL if start TLS requested */ /* One-time SSL initialization */ static int sslonceonly = 0; void ssl_onceonlyinit (void) { if (!sslonceonly++) { /* only need to call it once */ int fd; char tmp[MAILTMPLEN]; struct stat sbuf; /* if system doesn't have /dev/urandom */ if (stat ("/dev/urandom",&sbuf)) { while ((fd = open (tmpnam (tmp),O_WRONLY|O_CREAT|O_EXCL,0600)) < 0) sleep (1); unlink (tmp); /* don't need the file */ fstat (fd,&sbuf); /* get information about the file */ close (fd); /* flush descriptor */ /* not great but it'll have to do */ sprintf (tmp + strlen (tmp),"%.80s%lx%.80s%lx%lx%lx%lx%lx", tcp_serveraddr (),(unsigned long) tcp_serverport (), tcp_clientaddr (),(unsigned long) tcp_clientport (), (unsigned long) sbuf.st_ino,(unsigned long) time (0), (unsigned long) gethostid (),(unsigned long) getpid ()); RAND_seed (tmp,strlen (tmp)); } /* apply runtime linkage */ mail_parameters (NIL,SET_SSLDRIVER,(void *) &ssldriver); mail_parameters (NIL,SET_SSLSTART,(void *) ssl_start); SSL_library_init (); /* add all algorithms */ } } /* SSL open * Accepts: host name * contact service name * contact port number * Returns: SSL stream if success else NIL */ SSLSTREAM *ssl_open (char *host,char *service,unsigned long port) { TCPSTREAM *stream = tcp_open (host,service,port); return stream ? ssl_start (stream,host,port) : NIL; } /* SSL authenticated open * Accepts: host name * service name * returned user name buffer * Returns: SSL stream if success else NIL */ SSLSTREAM *ssl_aopen (NETMBX *mb,char *service,char *usrbuf) { return NIL; /* don't use this mechanism with SSL */ } /* Start SSL/TLS negotiations * Accepts: open TCP stream of session * user's host name * flags * Returns: SSL stream if success else NIL */ static SSLSTREAM *ssl_start (TCPSTREAM *tstream,char *host,unsigned long flags) { char *reason,tmp[MAILTMPLEN]; sslfailure_t sf = (sslfailure_t) mail_parameters (NIL,GET_SSLFAILURE,NIL); blocknotify_t bn = (blocknotify_t) mail_parameters (NIL,GET_BLOCKNOTIFY,NIL); void *data = (*bn) (BLOCK_SENSITIVE,NIL); SSLSTREAM *stream = (SSLSTREAM *) memset (fs_get (sizeof (SSLSTREAM)),0, sizeof (SSLSTREAM)); stream->tcpstream = tstream; /* bind TCP stream */ /* do the work */ reason = ssl_start_work (stream,host,flags); (*bn) (BLOCK_NONSENSITIVE,data); if (reason) { /* failed? */ ssl_close (stream); /* failed to do SSL */ stream = NIL; /* no stream returned */ switch (*reason) { /* analyze reason */ case '*': /* certificate failure */ ++reason; /* skip over certificate failure indication */ /* pass to error callback */ if (sf) (*sf) (host,reason,flags); else { /* no error callback, build error message */ sprintf (tmp,"Certificate failure for %.80s: %.512s",host,reason); mm_log (tmp,ERROR); } case '\0': /* user answered no to certificate callback */ if (flags & NET_TRYSSL) /* return dummy stream to stop tryssl */ stream = (SSLSTREAM *) memset (fs_get (sizeof (SSLSTREAM)),0, sizeof (SSLSTREAM)); break; default: /* non-certificate failure */ if (flags & NET_TRYSSL); /* no error output if tryssl */ /* pass to error callback */ else if (sf) (*sf) (host,reason,flags); else { /* no error callback, build error message */ sprintf (tmp,"TLS/SSL failure for %.80s: %.512s",host,reason); mm_log (tmp,ERROR); } break; } } return stream; } /* Start SSL/TLS negotiations worker routine * Accepts: SSL stream * user's host name * flags * Returns: NIL if success, else error reason */ /* evil but I had no choice */ static char *ssl_last_error = NIL; static char *ssl_last_host = NIL; static char *ssl_start_work (SSLSTREAM *stream,char *host,unsigned long flags) { BIO *bio; X509 *cert; unsigned long sl,tl; char *s,*t,*err,tmp[MAILTMPLEN]; sslcertificatequery_t scq = (sslcertificatequery_t) mail_parameters (NIL,GET_SSLCERTIFICATEQUERY,NIL); sslclientcert_t scc = (sslclientcert_t) mail_parameters (NIL,GET_SSLCLIENTCERT,NIL); sslclientkey_t sck = (sslclientkey_t) mail_parameters (NIL,GET_SSLCLIENTKEY,NIL); if (ssl_last_error) fs_give ((void **) &ssl_last_error); ssl_last_host = host; if (!(stream->context = SSL_CTX_new ((flags & NET_TLSCLIENT) ? TLSv1_client_method () : SSLv23_client_method ()))) return "SSL context failed"; SSL_CTX_set_options (stream->context,0); /* disable certificate validation? */ if (flags & NET_NOVALIDATECERT) SSL_CTX_set_verify (stream->context,SSL_VERIFY_NONE,NIL); else SSL_CTX_set_verify (stream->context,SSL_VERIFY_PEER,ssl_open_verify); /* set default paths to CAs... */ SSL_CTX_set_default_verify_paths (stream->context); /* ...unless a non-standard path desired */ if (s = (char *) mail_parameters (NIL,GET_SSLCAPATH,NIL)) SSL_CTX_load_verify_locations (stream->context,NIL,s); /* want to send client certificate? */ if (scc && (s = (*scc) ()) && (sl = strlen (s))) { if (cert = PEM_read_bio_X509 (bio = BIO_new_mem_buf (s,sl),NIL,NIL,NIL)) { SSL_CTX_use_certificate (stream->context,cert); X509_free (cert); } BIO_free (bio); if (!cert) return "SSL client certificate failed"; /* want to supply private key? */ if ((t = (sck ? (*sck) () : s)) && (tl = strlen (t))) { EVP_PKEY *key; if (key = PEM_read_bio_PrivateKey (bio = BIO_new_mem_buf (t,tl), NIL,NIL,"")) { SSL_CTX_use_PrivateKey (stream->context,key); EVP_PKEY_free (key); } BIO_free (bio); memset (t,0,tl); /* erase key */ } if (s != t) memset (s,0,sl);/* erase certificate if different from key */ } /* create connection */ if (!(stream->con = (SSL *) SSL_new (stream->context))) return "SSL connection failed"; bio = BIO_new_socket (stream->tcpstream->tcpsi,BIO_NOCLOSE); SSL_set_bio (stream->con,bio,bio); SSL_set_connect_state (stream->con); if (SSL_in_init (stream->con)) SSL_total_renegotiations (stream->con); /* now negotiate SSL */ if (SSL_write (stream->con,"",0) < 0) return ssl_last_error ? ssl_last_error : "SSL negotiation failed"; /* need to validate host names? */ if (!(flags & NET_NOVALIDATECERT) && (err = ssl_validate_cert (cert = SSL_get_peer_certificate (stream->con), host))) { /* application callback */ if (scq) return (*scq) (err,host,cert ? cert->name : "???") ? NIL : ""; /* error message to return via mm_log() */ sprintf (tmp,"*%.128s: %.255s",err,cert ? cert->name : "???"); return ssl_last_error = cpystr (tmp); } return NIL; } /* SSL certificate verification callback * Accepts: error flag * X509 context * Returns: error flag */ static int ssl_open_verify (int ok,X509_STORE_CTX *ctx) { char *err,cert[256],tmp[MAILTMPLEN]; sslcertificatequery_t scq = (sslcertificatequery_t) mail_parameters (NIL,GET_SSLCERTIFICATEQUERY,NIL); if (!ok) { /* in case failure */ err = (char *) X509_verify_cert_error_string (X509_STORE_CTX_get_error (ctx)); X509_NAME_oneline (X509_get_subject_name (X509_STORE_CTX_get_current_cert (ctx)),cert,255); if (!scq) { /* mm_log() error message if no callback */ sprintf (tmp,"*%.128s: %.255s",err,cert); ssl_last_error = cpystr (tmp); } /* ignore error if application says to */ else if ((*scq) (err,ssl_last_host,cert)) ok = T; /* application wants punt */ else ssl_last_error = cpystr (""); } return ok; } /* SSL validate certificate * Accepts: certificate * host to validate against * Returns: NIL if validated, else string of error message */ static char *ssl_validate_cert (X509 *cert,char *host) { int i,n; char *s,*t,*ret; void *ext; GENERAL_NAME *name; /* make sure have a certificate */ if (!cert) ret = "No certificate from server"; /* and that it has a name */ else if (!cert->name) ret = "No name in certificate"; /* locate CN */ else if (s = strstr (cert->name,"/CN=")) { if (t = strchr (s += 4,'/')) *t = '\0'; /* host name matches pattern? */ ret = ssl_compare_hostnames (host,s) ? NIL : "Server name does not match certificate"; if (t) *t = '/'; /* restore smashed delimiter */ /* if mismatch, see if in extensions */ if (ret && (ext = X509_get_ext_d2i (cert,NID_subject_alt_name,NIL,NIL)) && (n = sk_GENERAL_NAME_num (ext))) /* older versions of OpenSSL use "ia5" instead of dNSName */ for (i = 0; ret && (i < n); i++) if ((name = sk_GENERAL_NAME_value (ext,i)) && (name->type = GEN_DNS) && (s = name->d.ia5->data) && ssl_compare_hostnames (host,s)) ret = NIL; } else ret = "Unable to locate common name in certificate"; return ret; } /* Case-independent wildcard pattern match * Accepts: base string * pattern string * Returns: T if pattern matches base, else NIL */ static long ssl_compare_hostnames (unsigned char *s,unsigned char *pat) { long ret = NIL; switch (*pat) { case '*': /* wildcard */ if (pat[1]) { /* there must be a pattern suffix */ /* there is, scan base against it */ do if (ssl_compare_hostnames (s,pat+1)) ret = LONGT; while (!ret && (*s != '.') && *s++); } break; case '\0': /* end of pattern */ if (!*s) ret = LONGT; /* success if base is also at end */ break; default: /* non-wildcard, recurse if match */ if (!compare_uchar (*pat,*s)) ret = ssl_compare_hostnames (s+1,pat+1); break; } return ret; } /* SSL receive line * Accepts: SSL stream * Returns: text line string or NIL if failure */ char *ssl_getline (SSLSTREAM *stream) { unsigned long n,contd; char *ret = ssl_getline_work (stream,&n,&contd); if (ret && contd) { /* got a line needing continuation? */ STRINGLIST *stl = mail_newstringlist (); STRINGLIST *stc = stl; do { /* collect additional lines */ stc->text.data = (unsigned char *) ret; stc->text.size = n; stc = stc->next = mail_newstringlist (); ret = ssl_getline_work (stream,&n,&contd); } while (ret && contd); if (ret) { /* stash final part of line on list */ stc->text.data = (unsigned char *) ret; stc->text.size = n; /* determine how large a buffer we need */ for (n = 0, stc = stl; stc; stc = stc->next) n += stc->text.size; ret = fs_get (n + 1); /* copy parts into buffer */ for (n = 0, stc = stl; stc; n += stc->text.size, stc = stc->next) memcpy (ret + n,stc->text.data,stc->text.size); ret[n] = '\0'; } mail_free_stringlist (&stl);/* either way, done with list */ } return ret; } /* SSL receive line or partial line * Accepts: SSL stream * pointer to return size * pointer to return continuation flag * Returns: text line string, size and continuation flag, or NIL if failure */ static char *ssl_getline_work (SSLSTREAM *stream,unsigned long *size, long *contd) { unsigned long n; char *s,*ret,c,d; *contd = NIL; /* assume no continuation */ /* make sure have data */ if (!ssl_getdata (stream)) return NIL; for (s = stream->iptr, n = 0, c = '\0'; stream->ictr--; n++, c = d) { d = *stream->iptr++; /* slurp another character */ if ((c == '\015') && (d == '\012')) { ret = (char *) fs_get (n--); memcpy (ret,s,*size = n); /* copy into a free storage string */ ret[n] = '\0'; /* tie off string with null */ return ret; } } /* copy partial string from buffer */ memcpy ((ret = (char *) fs_get (n)),s,*size = n); /* get more data from the net */ if (!ssl_getdata (stream)) fs_give ((void **) &ret); /* special case of newline broken by buffer */ else if ((c == '\015') && (*stream->iptr == '\012')) { stream->iptr++; /* eat the line feed */ stream->ictr--; ret[*size = --n] = '\0'; /* tie off string with null */ } else *contd = LONGT; /* continuation needed */ return ret; } /* SSL receive buffer * Accepts: SSL stream * size in bytes * buffer to read into * Returns: T if success, NIL otherwise */ long ssl_getbuffer (SSLSTREAM *stream,unsigned long size,char *buffer) { unsigned long n; while (size > 0) { /* until request satisfied */ if (!ssl_getdata (stream)) return NIL; n = min (size,stream->ictr);/* number of bytes to transfer */ /* do the copy */ memcpy (buffer,stream->iptr,n); buffer += n; /* update pointer */ stream->iptr += n; size -= n; /* update # of bytes to do */ stream->ictr -= n; } buffer[0] = '\0'; /* tie off string */ return T; } /* SSL receive data * Accepts: TCP/IP stream * Returns: T if success, NIL otherwise */ long ssl_getdata (SSLSTREAM *stream) { int i,sock; fd_set fds,efds; struct timeval tmo; tcptimeout_t tmoh = (tcptimeout_t) mail_parameters (NIL,GET_TIMEOUT,NIL); long ttmo_read = (long) mail_parameters (NIL,GET_READTIMEOUT,NIL); time_t t = time (0); blocknotify_t bn = (blocknotify_t) mail_parameters (NIL,GET_BLOCKNOTIFY,NIL); if (!stream->con || ((sock = SSL_get_fd (stream->con)) < 0)) return NIL; /* tcp_unix should have prevented this */ if (sock >= FD_SETSIZE) fatal ("unselectable socket in ssl_getdata()"); (*bn) (BLOCK_TCPREAD,NIL); while (stream->ictr < 1) { /* if nothing in the buffer */ time_t tl = time (0); /* start of request */ time_t now = tl; int ti = ttmo_read ? now + ttmo_read : 0; if (SSL_pending (stream->con)) i = 1; else { if (tcpdebug) mm_log ("Reading SSL data",TCPDEBUG); tmo.tv_usec = 0; FD_ZERO (&fds); /* initialize selection vector */ FD_ZERO (&efds); /* handle errors too */ FD_SET (sock,&fds); /* set bit in selection vector */ FD_SET (sock,&efds); /* set bit in error selection vector */ errno = NIL; /* block and read */ do { /* block under timeout */ tmo.tv_sec = ti ? ti - now : 0; i = select (sock+1,&fds,0,&efds,ti ? &tmo : 0); now = time (0); /* fake timeout if interrupt & time expired */ if ((i < 0) && (errno == EINTR) && ti && (ti <= now)) i = 0; } while ((i < 0) && (errno == EINTR)); } if (i) { /* non-timeout result from select? */ errno = 0; /* just in case */ if (i > 0) /* read what we can */ while (((i = SSL_read (stream->con,stream->ibuf,SSLBUFLEN)) < 0) && ((errno == EINTR) || (SSL_get_error (stream->con,i) == SSL_ERROR_WANT_READ))); if (i <= 0) { /* error seen? */ if (tcpdebug) { char *s,tmp[MAILTMPLEN]; if (i) sprintf (s = tmp,"SSL data read I/O error %d SSL error %d", errno,SSL_get_error (stream->con,i)); else s = "SSL data read end of file"; mm_log (s,TCPDEBUG); } return ssl_abort (stream); } stream->iptr = stream->ibuf;/* point at TCP buffer */ stream->ictr = i; /* set new byte count */ if (tcpdebug) mm_log ("Successfully read SSL data",TCPDEBUG); } /* timeout, punt unless told not to */ else if (!tmoh || !(*tmoh) (now - t,now - tl, stream->tcpstream->host)) { if (tcpdebug) mm_log ("SSL data read timeout",TCPDEBUG); return ssl_abort (stream); } } (*bn) (BLOCK_NONE,NIL); return T; } /* SSL send string as record * Accepts: SSL stream * string pointer * Returns: T if success else NIL */ long ssl_soutr (SSLSTREAM *stream,char *string) { return ssl_sout (stream,string,(unsigned long) strlen (string)); } /* SSL send string * Accepts: SSL stream * string pointer * byte count * Returns: T if success else NIL */ long ssl_sout (SSLSTREAM *stream,char *string,unsigned long size) { long i; blocknotify_t bn = (blocknotify_t) mail_parameters (NIL,GET_BLOCKNOTIFY,NIL); if (!stream->con) return NIL; (*bn) (BLOCK_TCPWRITE,NIL); if (tcpdebug) mm_log ("Writing to SSL",TCPDEBUG); /* until request satisfied */ for (i = 0; size > 0; string += i,size -= i) /* write as much as we can */ if ((i = SSL_write (stream->con,string,(int) min (SSLBUFLEN,size))) < 0) { if (tcpdebug) { char tmp[MAILTMPLEN]; sprintf (tmp,"SSL data write I/O error %d SSL error %d", errno,SSL_get_error (stream->con,i)); mm_log (tmp,TCPDEBUG); } return ssl_abort (stream);/* write failed */ } if (tcpdebug) mm_log ("successfully wrote to TCP",TCPDEBUG); (*bn) (BLOCK_NONE,NIL); return LONGT; /* all done */ } /* SSL close * Accepts: SSL stream */ void ssl_close (SSLSTREAM *stream) { ssl_abort (stream); /* nuke the stream */ fs_give ((void **) &stream); /* flush the stream */ } /* SSL abort stream * Accepts: SSL stream * Returns: NIL always */ static long ssl_abort (SSLSTREAM *stream) { blocknotify_t bn = (blocknotify_t) mail_parameters (NIL,GET_BLOCKNOTIFY,NIL); if (stream->con) { /* close SSL connection */ SSL_shutdown (stream->con); SSL_free (stream->con); stream->con = NIL; } if (stream->context) { /* clean up context */ SSL_CTX_free (stream->context); stream->context = NIL; } if (stream->tcpstream) { /* close TCP stream */ tcp_close (stream->tcpstream); stream->tcpstream = NIL; } (*bn) (BLOCK_NONE,NIL); return NIL; } /* SSL get host name * Accepts: SSL stream * Returns: host name for this stream */ char *ssl_host (SSLSTREAM *stream) { return tcp_host (stream->tcpstream); } /* SSL get remote host name * Accepts: SSL stream * Returns: host name for this stream */ char *ssl_remotehost (SSLSTREAM *stream) { return tcp_remotehost (stream->tcpstream); } /* SSL return port for this stream * Accepts: SSL stream * Returns: port number for this stream */ unsigned long ssl_port (SSLSTREAM *stream) { return tcp_port (stream->tcpstream); } /* SSL get local host name * Accepts: SSL stream * Returns: local host name */ char *ssl_localhost (SSLSTREAM *stream) { return tcp_localhost (stream->tcpstream); } /* Start TLS * Accepts: /etc/services service name * Returns: cpystr'd error string if TLS failed, else NIL for success */ char *ssl_start_tls (char *server) { char tmp[MAILTMPLEN]; struct stat sbuf; if (sslstdio) return cpystr ("Already in an SSL session"); if (start_tls) return cpystr ("TLS already started"); if (server) { /* build specific certificate/key file name */ sprintf (tmp,"%s/%s-%s.pem",SSL_CERT_DIRECTORY,server,tcp_serveraddr ()); if (stat (tmp,&sbuf)) { /* use non-specific name if no specific file */ sprintf (tmp,"%s/%s.pem",SSL_CERT_DIRECTORY,server); if (stat (tmp,&sbuf)) return cpystr ("Server certificate not installed"); } start_tls = server; /* switch to STARTTLS mode */ } return NIL; } /* Init server for SSL * Accepts: server name */ void ssl_server_init (char *server) { char cert[MAILTMPLEN],key[MAILTMPLEN]; unsigned long i; struct stat sbuf; SSLSTREAM *stream = (SSLSTREAM *) memset (fs_get (sizeof (SSLSTREAM)),0, sizeof (SSLSTREAM)); ssl_onceonlyinit (); /* make sure algorithms added */ ERR_load_crypto_strings (); SSL_load_error_strings (); /* build specific certificate/key file names */ sprintf (cert,"%s/%s-%s.pem",SSL_CERT_DIRECTORY,server,tcp_serveraddr ()); sprintf (key,"%s/%s-%s.pem",SSL_KEY_DIRECTORY,server,tcp_serveraddr ()); /* use non-specific name if no specific cert */ if (stat (cert,&sbuf)) sprintf (cert,"%s/%s.pem",SSL_CERT_DIRECTORY,server); if (stat (key,&sbuf)) { /* use non-specific name if no specific key */ sprintf (key,"%s/%s.pem",SSL_KEY_DIRECTORY,server); /* use cert file as fallback for key */ if (stat (key,&sbuf)) strcpy (key,cert); } /* create context */ if (!(stream->context = SSL_CTX_new (start_tls ? TLSv1_server_method () : SSLv23_server_method ()))) syslog (LOG_ALERT,"Unable to create SSL context, host=%.80s", tcp_clienthost ()); else { /* set context options */ SSL_CTX_set_options (stream->context,SSL_OP_ALL); /* set cipher list */ if (!SSL_CTX_set_cipher_list (stream->context,SSLCIPHERLIST)) syslog (LOG_ALERT,"Unable to set cipher list %.80s, host=%.80s", SSLCIPHERLIST,tcp_clienthost ()); /* load certificate */ else if (!SSL_CTX_use_certificate_chain_file (stream->context,cert)) syslog (LOG_ALERT,"Unable to load certificate from %.80s, host=%.80s", cert,tcp_clienthost ()); /* load key */ else if (!(SSL_CTX_use_RSAPrivateKey_file (stream->context,key, SSL_FILETYPE_PEM))) syslog (LOG_ALERT,"Unable to load private key from %.80s, host=%.80s", key,tcp_clienthost ()); else { /* generate key if needed */ if (SSL_CTX_need_tmp_RSA (stream->context)) SSL_CTX_set_tmp_rsa_callback (stream->context,ssl_genkey); /* create new SSL connection */ if (!(stream->con = SSL_new (stream->context))) syslog (LOG_ALERT,"Unable to create SSL connection, host=%.80s", tcp_clienthost ()); else { /* set file descriptor */ SSL_set_fd (stream->con,0); /* all OK if accepted */ if (SSL_accept (stream->con) < 0) syslog (LOG_INFO,"Unable to accept SSL connection, host=%.80s", tcp_clienthost ()); else { /* server set up */ sslstdio = (SSLSTDIOSTREAM *) memset (fs_get (sizeof(SSLSTDIOSTREAM)),0,sizeof (SSLSTDIOSTREAM)); sslstdio->sslstream = stream; /* available space in output buffer */ sslstdio->octr = SSLBUFLEN; /* current output buffer pointer */ sslstdio->optr = sslstdio->obuf; /* allow plaintext if disable value was 2 */ if ((long) mail_parameters (NIL,GET_DISABLEPLAINTEXT,NIL) > 1) mail_parameters (NIL,SET_DISABLEPLAINTEXT,NIL); /* unhide PLAIN SASL authenticator */ mail_parameters (NIL,UNHIDE_AUTHENTICATOR,"PLAIN"); mail_parameters (NIL,UNHIDE_AUTHENTICATOR,"LOGIN"); return; } } } } while (i = ERR_get_error ()) /* SSL failure */ syslog (LOG_ERR,"SSL error status: %.80s",ERR_error_string (i,NIL)); ssl_close (stream); /* punt stream */ exit (1); /* punt this program too */ } /* Generate one-time key for server * Accepts: SSL connection * export flag * keylength * Returns: generated key, always */ static RSA *ssl_genkey (SSL *con,int export,int keylength) { unsigned long i; static RSA *key = NIL; if (!key) { /* if don't have a key already */ /* generate key */ if (!(key = RSA_generate_key (export ? keylength : 1024,RSA_F4,NIL,NIL))) { syslog (LOG_ALERT,"Unable to generate temp key, host=%.80s", tcp_clienthost ()); while (i = ERR_get_error ()) syslog (LOG_ALERT,"SSL error status: %s",ERR_error_string (i,NIL)); exit (1); } } return key; } /* Wait for stdin input * Accepts: timeout in seconds * Returns: T if have input on stdin, else NIL */ long ssl_server_input_wait (long seconds) { int i,sock; fd_set fds,efd; struct timeval tmo; SSLSTREAM *stream; if (!sslstdio) return server_input_wait (seconds); /* input available in buffer */ if (((stream = sslstdio->sslstream)->ictr > 0) || !stream->con || ((sock = SSL_get_fd (stream->con)) < 0)) return LONGT; /* sock ought to be 0 always */ if (sock >= FD_SETSIZE) fatal ("unselectable socket in ssl_getdata()"); /* input available from SSL */ if (SSL_pending (stream->con) && ((i = SSL_read (stream->con,stream->ibuf,SSLBUFLEN)) > 0)) { stream->iptr = stream->ibuf;/* point at TCP buffer */ stream->ictr = i; /* set new byte count */ return LONGT; } FD_ZERO (&fds); /* initialize selection vector */ FD_ZERO (&efd); /* initialize selection vector */ FD_SET (sock,&fds); /* set bit in selection vector */ FD_SET (sock,&efd); /* set bit in selection vector */ tmo.tv_sec = seconds; tmo.tv_usec = 0; /* see if input available from the socket */ return select (sock+1,&fds,0,&efd,&tmo) ? LONGT : NIL; } #include "sslstdio.c" alpine-2.10+dfsg/imap/src/osdep/unix/os_a32.h0000600000175000017500000000231611512502123022406 0ustar paulproteuspaulproteus/* ======================================================================== * Copyright 1988-2006 University of Washington * * Licensed under the Apache License, Version 2.0 (the "License"); * you may not use this file except in compliance with the License. * You may obtain a copy of the License at * * http://www.apache.org/licenses/LICENSE-2.0 * * * ======================================================================== */ /* * Program: Operating-system dependent routines -- AIX on RS6000 * * Author: Mark Crispin * Networks and Distributed Computing * Computing & Communications * University of Washington * Administration Building, AG-44 * Seattle, WA 98195 * Internet: MRC@CAC.Washington.EDU * * Date: 1 August 1988 * Last Edited: 30 August 2006 */ #include #include #include #include #include /* for struct tm */ #include #include #include #include #include #include #define utime portable_utime int portable_utime (char *file,time_t timep[2]); #include "env_unix.h" #include "fs.h" #include "ftl.h" #include "nl.h" #include "tcp.h" #include "flocksim.h" alpine-2.10+dfsg/imap/src/osdep/unix/os_drs.c0000600000175000017500000000262211512502123022604 0ustar paulproteuspaulproteus/* ======================================================================== * Copyright 1988-2006 University of Washington * * Licensed under the Apache License, Version 2.0 (the "License"); * you may not use this file except in compliance with the License. * You may obtain a copy of the License at * * http://www.apache.org/licenses/LICENSE-2.0 * * * ======================================================================== */ /* * Program: Operating-system dependent routines -- ICL DRS/NX * * Author: Mark Crispin * Networks and Distributed Computing * Computing & Communications * University of Washington * Administration Building, AG-44 * Seattle, WA 98195 * Internet: MRC@CAC.Washington.EDU * * Date: 1 August 1988 * Last Edited: 30 August 2006 */ #include "tcp_unix.h" /* must be before osdep includes tcp.h */ #include "mail.h" #include "osdep.h" #include #include #include #include #include #include #include #include #include extern int errno; /* just in case */ #include #include "misc.h" char *crypt (char *key,char *salt); #define DIR_SIZE(d) d->d_reclen #include "fs_unix.c" #include "ftl_unix.c" #include "nl_unix.c" #include "env_unix.c" #include "tcp_unix.c" #include "gr_waitp.c" #include "tz_sv4.c" #include "flocksim.c" #include "scandir.c" alpine-2.10+dfsg/imap/src/osdep/unix/pseudo.c0000600000175000017500000000236611512502123022617 0ustar paulproteuspaulproteus/* ======================================================================== * Copyright 1988-2006 University of Washington * * Licensed under the Apache License, Version 2.0 (the "License"); * you may not use this file except in compliance with the License. * You may obtain a copy of the License at * * http://www.apache.org/licenses/LICENSE-2.0 * * * ======================================================================== */ /* * Program: Pseudo Header Strings * * Author: Mark Crispin * Networks and Distributed Computing * Computing & Communications * University of Washington * Administration Building, AG-44 * Seattle, WA 98195 * Internet: MRC@CAC.Washington.EDU * * Date: 26 September 1996 * Last Edited: 30 August 2006 */ /* Local sites may wish to alter this text */ char *pseudo_from = "MAILER-DAEMON"; char *pseudo_name = "Mail System Internal Data"; char *pseudo_subject = "DON'T DELETE THIS MESSAGE -- FOLDER INTERNAL DATA"; char *pseudo_msg = "This text is part of the internal format of your mail folder, and is not\na real message. It is created automatically by the mail system software.\nIf deleted, important folder data will be lost, and it will be re-created\nwith the data reset to initial values." ; alpine-2.10+dfsg/imap/src/osdep/unix/os_shp.c0000600000175000017500000000367611512502123022620 0ustar paulproteuspaulproteus/* ======================================================================== * Copyright 1988-2007 University of Washington * * Licensed under the Apache License, Version 2.0 (the "License"); * you may not use this file except in compliance with the License. * You may obtain a copy of the License at * * http://www.apache.org/licenses/LICENSE-2.0 * * * ======================================================================== */ /* * Program: Operating-system dependent routines -- HP/UX version * * Author: Mark Crispin * Networks and Distributed Computing * Computing & Communications * University of Washington * Administration Building, AG-44 * Seattle, WA 98195 * Internet: MRC@CAC.Washington.EDU * * Date: 11 May 1989 * Last Edited: 16 August 2007 */ #define isodigit(c) (((unsigned)(c)>=060)&((unsigned)(c)<=067)) #define toint(c) ((c)-'0') #include #include "tcp_unix.h" /* must be before osdep includes tcp.h */ #include "mail.h" #include "osdep.h" #include #include #include #include #include #include #include #include #include #include extern int errno; /* just in case */ extern char *sys_errlist[]; extern int sys_nerr; #include #include #include #include "misc.h" #include "fs_unix.c" #include "ftl_unix.c" #include "nl_unix.c" #include "env_unix.c" #define fork vfork #include "tcp_unix.c" #include "gr_waitp.c" #include "flocksim.c" #include "tz_sv4.c" #undef setpgrp #include "setpgrp.c" #include "utime.c" /* Emulator for BSD gethostid() call * Returns: a unique identifier for the system. * Even though HP/UX has an undocumented gethostid() system call, * it does not work (at least for non-privileged users). */ long gethostid (void) { struct utsname udata; return (uname (&udata)) ? 0xfeedface : atol (udata.__idnumber); } alpine-2.10+dfsg/imap/src/osdep/unix/os_osx.h0000600000175000017500000000241611512502123022633 0ustar paulproteuspaulproteus/* ======================================================================== * Copyright 1988-2006 University of Washington * * Licensed under the Apache License, Version 2.0 (the "License"); * you may not use this file except in compliance with the License. * You may obtain a copy of the License at * * http://www.apache.org/licenses/LICENSE-2.0 * * * ======================================================================== */ /* * Program: Operating-system dependent routines -- Mac OS X version * * Author: Mark Crispin * Networks and Distributed Computing * Computing & Communications * University of Washington * Administration Building, AG-44 * Seattle, WA 98195 * Internet: MRC@CAC.Washington.EDU * * Date: 1 August 1988 * Last Edited: 26 October 2007 */ #include #include #include #include #include #include #include #include /* Mac OS X gets this wrong as of Leopard */ #define setpgrp setpgid #define unix 1 /* Mac OS X security framework also has checkpw, and this causes * multiple-definition problems when building Alpine. */ #define checkpw Checkpw #include "env_unix.h" #include "fs.h" #include "ftl.h" #include "nl.h" #include "tcp.h" alpine-2.10+dfsg/imap/src/osdep/unix/os_cyg.c0000600000175000017500000000316311512502123022577 0ustar paulproteuspaulproteus/* ======================================================================== * Copyright 1988-2006 University of Washington * * Licensed under the Apache License, Version 2.0 (the "License"); * you may not use this file except in compliance with the License. * You may obtain a copy of the License at * * http://www.apache.org/licenses/LICENSE-2.0 * * * ======================================================================== */ /* * Program: Operating-system dependent routines -- Cygwin version * * Author: Mark Crispin * Networks and Distributed Computing * Computing & Communications * University of Washington * Administration Building, AG-44 * Seattle, WA 98195 * Internet: MRC@CAC.Washington.EDU * * Date: 1 August 1988 * Last Edited: 30 August 2006 */ #include "tcp_unix.h" /* must be before osdep includes tcp.h */ #include "mail.h" #include "osdep.h" #include #include #include #include #include #include #include #include #include extern int errno; /* just in case */ #include #include #include "misc.h" #define isodigit(c) (((unsigned)(c)>=060)&((unsigned)(c)<=067)) #define toint(c) ((c)-'0') #include "fs_unix.c" #include "ftl_unix.c" #include "nl_unix.c" #include "env_unix.c" #include "tcp_unix.c" #include "gr_wait.c" #include "tz_nul.c" #include "flockcyg.c" #include "gethstid.c" /* Emulator for geteuid() call * Returns: effective UID */ #undef geteuid uid_t Geteuid (void) { uid_t ret = geteuid (); return (ret == SYSTEMUID) ? 0 : ret; } alpine-2.10+dfsg/imap/src/osdep/unix/os_hpp.h0000600000175000017500000000256011512502123022611 0ustar paulproteuspaulproteus/* ======================================================================== * Copyright 1988-2006 University of Washington * * Licensed under the Apache License, Version 2.0 (the "License"); * you may not use this file except in compliance with the License. * You may obtain a copy of the License at * * http://www.apache.org/licenses/LICENSE-2.0 * * * ======================================================================== */ /* * Program: Operating-system dependent routines -- HP/UX version * * Author: Mark Crispin * Networks and Distributed Computing * Computing & Communications * University of Washington * Administration Building, AG-44 * Seattle, WA 98195 * Internet: MRC@CAC.Washington.EDU * * Date: 11 May 1989 * Last Edited: 20 December 2006 */ #include #include #include #include #include #include #include #include #include #include #include #define direct dirent #define random lrand48 /* Many versions of SysV get this wrong */ #define setpgrp(a,b) Setpgrp(a,b) int Setpgrp (int pid,int gid); #define utime portable_utime int portable_utime (char *file,time_t timep[2]); long gethostid (void); #include "env_unix.h" #include "fs.h" #include "ftl.h" #include "nl.h" #include "tcp.h" #include "flocksim.h" alpine-2.10+dfsg/imap/src/osdep/unix/os_os4.c0000600000175000017500000000261111512502123022517 0ustar paulproteuspaulproteus/* ======================================================================== * Copyright 1988-2006 University of Washington * * Licensed under the Apache License, Version 2.0 (the "License"); * you may not use this file except in compliance with the License. * You may obtain a copy of the License at * * http://www.apache.org/licenses/LICENSE-2.0 * * * ======================================================================== */ /* * Program: Operating-system dependent routines -- OSF/Digital UNIX/Tru64 4 * * Author: Mark Crispin * Networks and Distributed Computing * Computing & Communications * University of Washington * Administration Building, AG-44 * Seattle, WA 98195 * Internet: MRC@CAC.Washington.EDU * * Date: 1 August 1988 * Last Edited: 30 August 2006 */ #include "tcp_unix.h" /* must be before osdep includes tcp.h */ #include "mail.h" #include "osdep.h" #include #include #include #include #include #include #include #include #include extern int errno; /* just in case */ #include #include "misc.h" #include #include #include #include "fs_unix.c" #include "ftl_unix.c" #include "nl_unix.c" #include "env_unix.c" #include "gr_waitp.c" #include "tcp_unix.c" #include "tz_bsd.c" #undef flock #include "flocksim.c" alpine-2.10+dfsg/imap/src/osdep/unix/mbx.c0000600000175000017500000017366511512502123022121 0ustar paulproteuspaulproteus/* ======================================================================== * Copyright 1988-2007 University of Washington * * Licensed under the Apache License, Version 2.0 (the "License"); * you may not use this file except in compliance with the License. * You may obtain a copy of the License at * * http://www.apache.org/licenses/LICENSE-2.0 * * * ======================================================================== */ /* * Program: MBX mail routines * * Author: Mark Crispin * Networks and Distributed Computing * Computing & Communications * University of Washington * Administration Building, AG-44 * Seattle, WA 98195 * Internet: MRC@CAC.Washington.EDU * * Date: 3 October 1995 * Last Edited: 11 October 2007 */ /* FILE TIME SEMANTICS * * The atime is the last read time of the file. * The mtime is the last flags update time of the file. * The ctime is the last write time of the file. */ #include #include #include extern int errno; /* just in case */ #include "mail.h" #include "osdep.h" #include #include #include #include "misc.h" #include "dummy.h" #include "fdstring.h" /* Build parameters */ #define HDRSIZE 2048 /* Kludge to make Cygwin happy */ #ifndef O_BINARY #define O_BINARY 0 #endif /* MBX I/O stream local data */ typedef struct mbx_local { unsigned int flagcheck: 1; /* if ping should sweep for flags */ unsigned int expok: 1; /* if expunging OK in ping */ unsigned int expunged : 1; /* if one or more expunged messages */ int fd; /* file descriptor for I/O */ int ld; /* lock file descriptor */ int ffuserflag; /* first free user flag */ off_t filesize; /* file size parsed */ time_t filetime; /* last file time */ time_t lastsnarf; /* last snarf time */ unsigned long lastpid; /* PID of last writer */ unsigned char *buf; /* temporary buffer */ unsigned long buflen; /* current size of temporary buffer */ char lock[MAILTMPLEN]; /* buffer to write lock name */ } MBXLOCAL; /* Convenient access to local data */ #define LOCAL ((MBXLOCAL *) stream->local) /* Function prototypes */ DRIVER *mbx_valid (char *name); int mbx_isvalid (MAILSTREAM **stream,char *name,char *tmp,int *ld,char *lock, long flags); void *mbx_parameters (long function,void *value); void mbx_scan (MAILSTREAM *stream,char *ref,char *pat,char *contents); void mbx_list (MAILSTREAM *stream,char *ref,char *pat); void mbx_lsub (MAILSTREAM *stream,char *ref,char *pat); long mbx_create (MAILSTREAM *stream,char *mailbox); long mbx_delete (MAILSTREAM *stream,char *mailbox); long mbx_rename (MAILSTREAM *stream,char *old,char *newname); long mbx_status (MAILSTREAM *stream,char *mbx,long flags); MAILSTREAM *mbx_open (MAILSTREAM *stream); void mbx_close (MAILSTREAM *stream,long options); void mbx_abort (MAILSTREAM *stream); void mbx_flags (MAILSTREAM *stream,char *sequence,long flags); char *mbx_header (MAILSTREAM *stream,unsigned long msgno,unsigned long *length, long flags); long mbx_text (MAILSTREAM *stream,unsigned long msgno,STRING *bs,long flags); void mbx_flag (MAILSTREAM *stream,char *sequence,char *flag,long flags); void mbx_flagmsg (MAILSTREAM *stream,MESSAGECACHE *elt); long mbx_ping (MAILSTREAM *stream); void mbx_check (MAILSTREAM *stream); long mbx_expunge (MAILSTREAM *stream,char *sequence,long options); void mbx_snarf (MAILSTREAM *stream); long mbx_copy (MAILSTREAM *stream,char *sequence,char *mailbox,long options); long mbx_append (MAILSTREAM *stream,char *mailbox,append_t af,void *data); char *mbx_file (char *dst,char *name); long mbx_parse (MAILSTREAM *stream); MESSAGECACHE *mbx_elt (MAILSTREAM *stream,unsigned long msgno,long expok); unsigned long mbx_read_flags (MAILSTREAM *stream,MESSAGECACHE *elt); void mbx_update_header (MAILSTREAM *stream); void mbx_update_status (MAILSTREAM *stream,unsigned long msgno,long flags); unsigned long mbx_hdrpos (MAILSTREAM *stream,unsigned long msgno, unsigned long *size,char **hdr); unsigned long mbx_rewrite (MAILSTREAM *stream,unsigned long *reclaimed, long flags); long mbx_flaglock (MAILSTREAM *stream); /* MBX mail routines */ /* Driver dispatch used by MAIL */ DRIVER mbxdriver = { "mbx", /* driver name */ DR_LOCAL|DR_MAIL|DR_CRLF|DR_LOCKING, /* driver flags */ (DRIVER *) NIL, /* next driver */ mbx_valid, /* mailbox is valid for us */ mbx_parameters, /* manipulate parameters */ mbx_scan, /* scan mailboxes */ mbx_list, /* list mailboxes */ mbx_lsub, /* list subscribed mailboxes */ NIL, /* subscribe to mailbox */ NIL, /* unsubscribe from mailbox */ mbx_create, /* create mailbox */ mbx_delete, /* delete mailbox */ mbx_rename, /* rename mailbox */ mbx_status, /* status of mailbox */ mbx_open, /* open mailbox */ mbx_close, /* close mailbox */ mbx_flags, /* fetch message "fast" attributes */ mbx_flags, /* fetch message flags */ NIL, /* fetch overview */ NIL, /* fetch message envelopes */ mbx_header, /* fetch message header */ mbx_text, /* fetch message body */ NIL, /* fetch partial message text */ NIL, /* unique identifier */ NIL, /* message number */ mbx_flag, /* modify flags */ mbx_flagmsg, /* per-message modify flags */ NIL, /* search for message based on criteria */ NIL, /* sort messages */ NIL, /* thread messages */ mbx_ping, /* ping mailbox to see if still alive */ mbx_check, /* check for new messages */ mbx_expunge, /* expunge deleted messages */ mbx_copy, /* copy messages to another mailbox */ mbx_append, /* append string message to mailbox */ NIL /* garbage collect stream */ }; /* prototype stream */ MAILSTREAM mbxproto = {&mbxdriver}; /* MBX mail validate mailbox * Accepts: mailbox name * Returns: our driver if name is valid, NIL otherwise */ DRIVER *mbx_valid (char *name) { char tmp[MAILTMPLEN]; int fd = mbx_isvalid (NIL,name,tmp,NIL,NIL,NIL); if (fd < 0) return NIL; close (fd); /* don't need the fd now */ return &mbxdriver; } /* MBX mail test for valid mailbox * Accepts: returned stream with valid mailbox keywords * mailbox name * scratch buffer * returned lock fd * returned lock name * RW flags or NIL for readonly * Returns: file descriptor if valid, NIL otherwise */ #define MBXISVALIDNOUID 0x1 /* RW, don't do UID action */ #define MBXISVALIDUID 0x2 /* RW, do UID action */ int mbx_isvalid (MAILSTREAM **stream,char *name,char *tmp,int *ld,char *lock, long flags) { int fd,upd; int ret = -1; unsigned long i; long j,k; off_t pos; char c,*s,*t,hdr[HDRSIZE]; struct stat sbuf; time_t tp[2]; int error = EINVAL; /* assume invalid argument */ if (ld) *ld = -1; /* initially no lock */ if ((s = mbx_file (tmp,name)) && !stat (s,&sbuf) && ((fd = open (tmp,(flags ? O_RDWR : O_RDONLY)|O_BINARY,NIL)) >= 0)) { error = -1; /* bogus format */ /* I love cretinous C compilers -- don't you? */ if (read (fd,hdr,HDRSIZE) == HDRSIZE) if ((hdr[0] == '*') && (hdr[1] == 'm') && (hdr[2] == 'b') && (hdr[3] == 'x') && (hdr[4] == '*') && (hdr[5] == '\015') && (hdr[6] == '\012') && isxdigit (hdr[7]) && isxdigit (hdr[8])) if (isxdigit (hdr[9]) && isxdigit (hdr[10]) && isxdigit (hdr[11]) && isxdigit (hdr[12]) && isxdigit (hdr[13]) && isxdigit (hdr[14]) && isxdigit (c = hdr[15]) && isxdigit (hdr[16])) if (isxdigit (hdr[17]) && isxdigit (hdr[18]) && isxdigit (hdr[19]) && isxdigit (hdr[20]) && isxdigit (hdr[21]) && isxdigit (hdr[22]) && (hdr[23] == '\015') && (hdr[24] == '\012')) { ret = fd; /* mbx format */ if (stream) { /* lock if making mini-stream */ if (flock (fd,LOCK_SH) || (flags && ((*ld = lockfd (fd,lock,LOCK_EX)) < 0))) ret = -1; /* reread data now that locked */ else if (lseek (fd,0,L_SET) || (read (fd,hdr,HDRSIZE) != HDRSIZE)) ret = -1; else { *stream = (MAILSTREAM *) memset (fs_get (sizeof (MAILSTREAM)), 0,sizeof (MAILSTREAM)); hdr[15] = '\0'; /* tie off UIDVALIDITY */ (*stream)->uid_validity = strtoul (hdr+7,NIL,16); hdr[15] = c; /* now get UIDLAST */ (*stream)->uid_last = strtoul (hdr+15,NIL,16); /* parse user flags */ for (i = 0, s = hdr + 25; (i < NUSERFLAGS) && (t = strchr (s,'\015')) && (t - s); i++, s = t + 2) { *t = '\0'; /* tie off flag */ if (strlen (s) <= MAXUSERFLAG) (*stream)->user_flags[i] = cpystr (s); } /* make sure have true UIDLAST */ if (flags & MBXISVALIDUID) { for (upd = NIL,pos = 2048, k = 0; pos < sbuf.st_size; pos += (j + k)) { /* read header for this message */ lseek (fd,pos,L_SET); if ((j = read (fd,hdr,64)) >= 0) { hdr[j] = '\0'; if ((s = strchr (hdr,'\015')) && (s[1] == '\012')) { *s = '\0'; k = s + 2 - hdr; if ((s = strchr (hdr,',')) && (j = strtol (s+1,&s,10)) && (*s == ';') && (s = strchr (s+1,'-'))) { /* get UID if there is any */ i = strtoul (++s,&t,16); if (!*t && (t == (s + 8)) && (i <= (*stream)->uid_last)) { if (!i) { lseek (fd,pos + s - hdr,L_SET); sprintf (hdr,"%08lx",++(*stream)->uid_last); write (fd,hdr,8); upd = T; } continue; } } } ret = -1; /* error, give up */ *stream = mail_close (*stream); pos = sbuf.st_size + 1; j = k = 0; } } if (upd) { /* need to update hdr with new UIDLAST? */ lseek (fd,15,L_SET); sprintf (hdr,"%08lx",(*stream)->uid_last); write (fd,hdr,8); } } } } } if (ret != fd) close (fd); /* close the file */ else lseek (fd,0,L_SET); /* else rewind to start */ /* \Marked status? */ if (sbuf.st_ctime > sbuf.st_atime) { tp[0] = sbuf.st_atime; /* preserve atime and mtime */ tp[1] = sbuf.st_mtime; utime (tmp,tp); /* set the times */ } } /* in case INBOX but not mbx format */ else if (((error = errno) == ENOENT) && !compare_cstring (name,"INBOX")) error = -1; if ((ret < 0) && ld && (*ld >= 0)) { unlockfd (*ld,lock); *ld = -1; } errno = error; /* return as last error */ return ret; /* return what we should */ } /* MBX manipulate driver parameters * Accepts: function code * function-dependent value * Returns: function-dependent return value */ void *mbx_parameters (long function,void *value) { void *ret = NIL; switch ((int) function) { case GET_INBOXPATH: if (value) ret = mbx_file ((char *) value,"INBOX"); break; case SET_ONETIMEEXPUNGEATPING: if (value) ((MBXLOCAL *) ((MAILSTREAM *) value)->local)->expok = T; case GET_ONETIMEEXPUNGEATPING: if (value) ret = (void *) (((MBXLOCAL *) ((MAILSTREAM *) value)->local)->expok ? VOIDT : NIL); break; } return ret; } /* MBX mail scan mailboxes * Accepts: mail stream * reference * pattern to search * string to scan */ void mbx_scan (MAILSTREAM *stream,char *ref,char *pat,char *contents) { if (stream) dummy_scan (NIL,ref,pat,contents); } /* MBX mail list mailboxes * Accepts: mail stream * reference * pattern to search */ void mbx_list (MAILSTREAM *stream,char *ref,char *pat) { if (stream) dummy_list (NIL,ref,pat); } /* MBX mail list subscribed mailboxes * Accepts: mail stream * reference * pattern to search */ void mbx_lsub (MAILSTREAM *stream,char *ref,char *pat) { if (stream) dummy_lsub (NIL,ref,pat); } /* MBX mail create mailbox * Accepts: MAIL stream * mailbox name to create * Returns: T on success, NIL on failure */ long mbx_create (MAILSTREAM *stream,char *mailbox) { char *s,*t,mbx[MAILTMPLEN],tmp[HDRSIZE]; long ret = NIL; int i,fd; if (!(s = mbx_file (mbx,mailbox))) { sprintf (mbx,"Can't create %.80s: invalid name",mailbox); MM_LOG (mbx,ERROR); } /* create underlying file */ else if (dummy_create_path (stream,s,get_dir_protection (mailbox))) { /* done if made directory */ if ((s = strrchr (s,'/')) && !s[1]) return T; if ((fd = open (mbx,O_WRONLY|O_BINARY,NIL)) < 0) { sprintf (tmp,"Can't reopen mailbox node %.80s: %s",mbx,strerror (errno)); MM_LOG (tmp,ERROR); unlink (mbx); /* delete the file */ } else { memset (tmp,'\0',HDRSIZE);/* initialize header */ sprintf (s = tmp,"*mbx*\015\012%08lx00000000\015\012", (unsigned long) time (0)); for (i = 0; i < NUSERFLAGS; ++i) { t = (stream && stream->user_flags[i]) ? stream->user_flags[i] : ((t = default_user_flag (i)) ? t : ""); sprintf (s += strlen (s),"%s\015\012",t); } if (write (fd,tmp,HDRSIZE) != HDRSIZE) { sprintf (tmp,"Can't initialize mailbox node %.80s: %s", mbx,strerror (errno)); MM_LOG (tmp,ERROR); unlink (mbx); /* delete the file */ } else ret = T; /* success */ close (fd); /* close file */ } } /* set proper protections */ return ret ? set_mbx_protections (mailbox,mbx) : NIL; } /* MBX mail delete mailbox * Accepts: MAIL stream * mailbox name to delete * Returns: T on success, NIL on failure */ long mbx_delete (MAILSTREAM *stream,char *mailbox) { return mbx_rename (stream,mailbox,NIL); } /* MBX mail rename mailbox * Accepts: MAIL stream * old mailbox name * new mailbox name (or NIL for delete) * Returns: T on success, NIL on failure */ long mbx_rename (MAILSTREAM *stream,char *old,char *newname) { long ret = LONGT; char c,*s,tmp[MAILTMPLEN],file[MAILTMPLEN],lock[MAILTMPLEN]; int fd,ld; struct stat sbuf; if (!mbx_file (file,old) || (newname && (!((s = mailboxfile (tmp,newname)) && *s) || ((s = strrchr (tmp,'/')) && !s[1])))) { sprintf (tmp,newname ? "Can't rename mailbox %.80s to %.80s: invalid name" : "Can't delete mailbox %.80s: invalid name", old,newname); MM_LOG (tmp,ERROR); return NIL; } else if ((fd = open (file,O_RDWR|O_BINARY,NIL)) < 0) { sprintf (tmp,"Can't open mailbox %.80s: %s",old,strerror (errno)); MM_LOG (tmp,ERROR); return NIL; } /* get parse/append permission */ if ((ld = lockfd (fd,lock,LOCK_EX)) < 0) { MM_LOG ("Unable to lock rename mailbox",ERROR); return NIL; } /* lock out other users */ if (flock (fd,LOCK_EX|LOCK_NB)) { close (fd); /* couldn't lock, give up on it then */ sprintf (tmp,"Mailbox %.80s is in use by another process",old); MM_LOG (tmp,ERROR); unlockfd (ld,lock); /* release exclusive parse/append permission */ return NIL; } if (newname) { /* want rename? */ /* found superior to destination name? */ if (s = strrchr (tmp,'/')) { c = *++s; /* remember first character of inferior */ *s = '\0'; /* tie off to get just superior */ /* superior name doesn't exist, create it */ if ((stat (tmp,&sbuf) || ((sbuf.st_mode & S_IFMT) != S_IFDIR)) && !dummy_create_path (stream,tmp,get_dir_protection (newname))) ret = NIL; else *s = c; /* restore full name */ } /* rename the file */ if (ret && rename (file,tmp)) { sprintf (tmp,"Can't rename mailbox %.80s to %.80s: %s",old,newname, strerror (errno)); MM_LOG (tmp,ERROR); ret = NIL; /* set failure */ } } else if (unlink (file)) { sprintf (tmp,"Can't delete mailbox %.80s: %s",old,strerror (errno)); MM_LOG (tmp,ERROR); ret = NIL; /* set failure */ } flock (fd,LOCK_UN); /* release lock on the file */ unlockfd (ld,lock); /* release exclusive parse/append permission */ close (fd); /* close the file */ /* recreate file if renamed INBOX */ if (ret && !compare_cstring (old,"INBOX")) mbx_create (NIL,"INBOX"); return ret; /* return success */ } /* MBX Mail status * Accepts: mail stream * mailbox name * status flags * Returns: T on success, NIL on failure */ long mbx_status (MAILSTREAM *stream,char *mbx,long flags) { MAILSTATUS status; unsigned long i; MAILSTREAM *tstream = NIL; MAILSTREAM *systream = NIL; /* make temporary stream (unless this mbx) */ if (!stream && !(stream = tstream = mail_open (NIL,mbx,OP_READONLY|OP_SILENT))) return NIL; status.flags = flags; /* return status values */ status.messages = stream->nmsgs; status.recent = stream->recent; if (flags & SA_UNSEEN) /* must search to get unseen messages */ for (i = 1,status.unseen = 0; i <= stream->nmsgs; i++) if (!mail_elt (stream,i)->seen) status.unseen++; status.uidnext = stream->uid_last + 1; status.uidvalidity = stream->uid_validity; /* calculate post-snarf results */ if (!status.recent && stream->inbox && (systream = mail_open (NIL,sysinbox (),OP_READONLY|OP_SILENT))) { status.messages += systream->nmsgs; status.recent += systream->recent; if (flags & SA_UNSEEN) /* must search to get unseen messages */ for (i = 1; i <= systream->nmsgs; i++) if (!mail_elt (systream,i)->seen) status.unseen++; /* kludge but probably good enough */ status.uidnext += systream->nmsgs; } MM_STATUS(stream,mbx,&status);/* pass status to main program */ if (tstream) mail_close (tstream); if (systream) mail_close (systream); return T; /* success */ } /* MBX mail open * Accepts: stream to open * Returns: stream on success, NIL on failure */ MAILSTREAM *mbx_open (MAILSTREAM *stream) { int fd,ld; short silent; char tmp[MAILTMPLEN]; blocknotify_t bn = (blocknotify_t) mail_parameters (NIL,GET_BLOCKNOTIFY,NIL); /* return prototype for OP_PROTOTYPE call */ if (!stream) return user_flags (&mbxproto); if (stream->local) fatal ("mbx recycle stream"); /* canonicalize the mailbox name */ if (!mbx_file (tmp,stream->mailbox)) { sprintf (tmp,"Can't open - invalid name: %.80s",stream->mailbox); MM_LOG (tmp,ERROR); } if (stream->rdonly || (fd = open (tmp,O_RDWR|O_BINARY,NIL)) < 0) { if ((fd = open (tmp,O_RDONLY|O_BINARY,NIL)) < 0) { sprintf (tmp,"Can't open mailbox: %s",strerror (errno)); MM_LOG (tmp,ERROR); return NIL; } else if (!stream->rdonly) { /* got it, but readonly */ MM_LOG ("Can't get write access to mailbox, access is readonly",WARN); stream->rdonly = T; } } stream->local = memset (fs_get (sizeof (MBXLOCAL)),NIL,sizeof (MBXLOCAL)); LOCAL->fd = fd; /* bind the file */ LOCAL->ld = -1; /* no flaglock */ LOCAL->buf = (char *) fs_get (CHUNKSIZE); LOCAL->buflen = CHUNKSIZE - 1; /* note if an INBOX or not */ stream->inbox = !compare_cstring (stream->mailbox,"INBOX"); fs_give ((void **) &stream->mailbox); stream->mailbox = cpystr (tmp); /* get parse/append permission */ if ((ld = lockfd (LOCAL->fd,tmp,LOCK_EX)) < 0) { MM_LOG ("Unable to lock open mailbox",ERROR); return NIL; } (*bn) (BLOCK_FILELOCK,NIL); flock (LOCAL->fd,LOCK_SH); /* lock the file */ (*bn) (BLOCK_NONE,NIL); unlockfd (ld,tmp); /* release shared parse permission */ LOCAL->filesize = HDRSIZE; /* initialize parsed file size */ /* time not set up yet */ LOCAL->lastsnarf = LOCAL->filetime = 0; LOCAL->expok = LOCAL->flagcheck = NIL; stream->sequence++; /* bump sequence number */ /* parse mailbox */ stream->nmsgs = stream->recent = 0; silent = stream->silent; /* defer events */ stream->silent = T; if (mbx_ping (stream) && !stream->nmsgs) MM_LOG ("Mailbox is empty",(long) NIL); stream->silent = silent; /* now notify upper level */ mail_exists (stream,stream->nmsgs); mail_recent (stream,stream->recent); if (!LOCAL) return NIL; /* failure if stream died */ stream->perm_seen = stream->perm_deleted = stream->perm_flagged = stream->perm_answered = stream->perm_draft = stream->rdonly ? NIL : T; stream->perm_user_flags = stream->rdonly ? NIL : 0xffffffff; stream->kwd_create = (stream->user_flags[NUSERFLAGS-1] || stream->rdonly) ? NIL : T; /* can we create new user flags? */ return stream; /* return stream to caller */ } /* MBX mail close * Accepts: MAIL stream * close options */ void mbx_close (MAILSTREAM *stream,long options) { if (stream && LOCAL) { /* only if a file is open */ int silent = stream->silent; stream->silent = T; /* note this stream is dying */ /* do an expunge if requested */ if (options & CL_EXPUNGE) mbx_expunge (stream,NIL,NIL); else { /* otherwise do a checkpoint to purge */ LOCAL->expok = T; /* possible expunged messages */ mbx_ping (stream); } stream->silent = silent; /* restore previous status */ mbx_abort (stream); } } /* MBX mail abort stream * Accepts: MAIL stream */ void mbx_abort (MAILSTREAM *stream) { if (stream && LOCAL) { /* only if a file is open */ flock (LOCAL->fd,LOCK_UN); /* unlock local file */ close (LOCAL->fd); /* close the local file */ /* free local text buffer */ if (LOCAL->buf) fs_give ((void **) &LOCAL->buf); /* nuke the local data */ fs_give ((void **) &stream->local); stream->dtb = NIL; /* log out the DTB */ } } /* MBX mail fetch flags * Accepts: MAIL stream * sequence * option flags * Sniffs at file to see if some other process changed the flags */ void mbx_flags (MAILSTREAM *stream,char *sequence,long flags) { MESSAGECACHE *elt; unsigned long i; if (mbx_ping (stream) && /* ping mailbox, get new status for messages */ ((flags & FT_UID) ? mail_uid_sequence (stream,sequence) : mail_sequence (stream,sequence))) for (i = 1; i <= stream->nmsgs; i++) if ((elt = mail_elt (stream,i))->sequence && !elt->valid) mbx_elt (stream,i,NIL); } /* MBX mail fetch message header * Accepts: MAIL stream * message # to fetch * pointer to returned header text length * option flags * Returns: message header in RFC822 format */ char *mbx_header (MAILSTREAM *stream,unsigned long msgno,unsigned long *length, long flags) { unsigned long i; char *s; *length = 0; /* default to empty */ if (flags & FT_UID) return "";/* UID call "impossible" */ /* get header position, possibly header */ i = mbx_hdrpos (stream,msgno,length,&s); if (!s) { /* mbx_hdrpos() returned header? */ lseek (LOCAL->fd,i,L_SET); /* no, get to header position */ /* is buffer big enough? */ if (*length > LOCAL->buflen) { fs_give ((void **) &LOCAL->buf); LOCAL->buf = (char *) fs_get ((LOCAL->buflen = *length) + 1); } /* slurp the data */ read (LOCAL->fd,s = LOCAL->buf,*length); } s[*length] = '\0'; /* tie off string */ return s; } /* MBX mail fetch message text (body only) * Accepts: MAIL stream * message # to fetch * pointer to returned header text length * option flags * Returns: T on success, NIL on failure */ long mbx_text (MAILSTREAM *stream,unsigned long msgno,STRING *bs,long flags) { FDDATA d; unsigned long i,j; MESSAGECACHE *elt; /* UID call "impossible" */ if (flags & FT_UID) return NIL; /* get message status */ elt = mbx_elt (stream,msgno,NIL); /* if message not seen */ if (!(flags & FT_PEEK) && !elt->seen && mbx_flaglock (stream)) { elt->seen = T; /* mark message as seen */ /* recalculate status */ mbx_update_status (stream,msgno,NIL); MM_FLAGS (stream,msgno); /* update flags */ mbx_flag (stream,NIL,NIL,NIL); } if (!LOCAL) return NIL; /* mbx_flaglock() could have aborted */ /* find header position */ i = mbx_hdrpos (stream,msgno,&j,NIL); d.fd = LOCAL->fd; /* set up file descriptor */ d.pos = i + j; d.chunk = LOCAL->buf; /* initial buffer chunk */ d.chunksize = CHUNKSIZE; INIT (bs,fd_string,&d,elt->rfc822_size - j); return LONGT; /* success */ } /* MBX mail modify flags * Accepts: MAIL stream * sequence * flag(s) * option flags * Unlocks flag lock */ void mbx_flag (MAILSTREAM *stream,char *sequence,char *flag,long flags) { time_t tp[2]; struct stat sbuf; unsigned long oldpid = LOCAL->lastpid; /* make sure the update takes */ if (!stream->rdonly && LOCAL && (LOCAL->fd >= 0) && (LOCAL->ld >= 0)) { fsync (LOCAL->fd); fstat (LOCAL->fd,&sbuf); /* get current write time */ tp[1] = LOCAL->filetime = sbuf.st_mtime; /* we are the last flag updater */ LOCAL->lastpid = (unsigned long) getpid (); /* update header if needed */ if (((LOCAL->ffuserflag < NUSERFLAGS) && stream->user_flags[LOCAL->ffuserflag]) || (oldpid != LOCAL->lastpid)) mbx_update_header (stream); tp[0] = time (0); /* make sure read comes after all that */ utime (stream->mailbox,tp); } if (LOCAL->ld >= 0) { /* unlock now */ unlockfd (LOCAL->ld,LOCAL->lock); LOCAL->ld = -1; } } /* MBX mail per-message modify flags * Accepts: MAIL stream * message cache element */ void mbx_flagmsg (MAILSTREAM *stream,MESSAGECACHE *elt) { if (mbx_flaglock (stream)) mbx_update_status (stream,elt->msgno,NIL); } /* MBX mail ping mailbox * Accepts: MAIL stream * Returns: T if stream still alive, NIL if not */ long mbx_ping (MAILSTREAM *stream) { unsigned long i,pos; long ret = NIL; int ld; char lock[MAILTMPLEN]; MESSAGECACHE *elt; struct stat sbuf; if (stream && LOCAL) { /* only if stream already open */ int snarf = stream->inbox && !stream->rdonly; ret = LONGT; /* assume OK */ fstat (LOCAL->fd,&sbuf); /* get current file poop */ /* allow expunge if permitted at ping */ if (mail_parameters (NIL,GET_EXPUNGEATPING,NIL)) LOCAL->expok = T; /* if external modification */ if (LOCAL->filetime && (LOCAL->filetime < sbuf.st_mtime)) LOCAL->flagcheck = T; /* upgrade to flag checking */ /* new mail or flagcheck handling needed? */ if (((sbuf.st_size - LOCAL->filesize) || LOCAL->flagcheck || !stream->nmsgs || snarf) && ((ld = lockfd (LOCAL->fd,lock,LOCK_EX)) >= 0)) { /* reparse header if not flagchecking */ if (!LOCAL->flagcheck) ret = mbx_parse (stream); /* sweep mailbox for changed message status */ else if (ret = mbx_parse (stream)) { unsigned long recent = 0; LOCAL->filetime = sbuf.st_mtime; for (i = 1; i <= stream->nmsgs; ) if (elt = mbx_elt (stream,i,LOCAL->expok)) { if (elt->recent) ++recent; ++i; } mail_recent (stream,recent); LOCAL->flagcheck = NIL; /* got all the updates */ } /* always reparse header at least */ if (ret && snarf) { /* snarf new messages if still OK */ mbx_snarf (stream); /* parse snarfed messages */ ret = mbx_parse (stream); } unlockfd (ld,lock); /* release shared parse/append permission */ } if (ret) { /* must still be alive */ if (!LOCAL->expunged) /* look for holes if none known yet */ for (i = 1, pos = HDRSIZE; !LOCAL->expunged && (i <= stream->nmsgs); i++, pos += elt->private.special.text.size + elt->rfc822_size) if ((elt = mail_elt (stream,i))->private.special.offset != pos) LOCAL->expunged = T;/* found a hole */ /* burp any holes */ if (LOCAL->expunged && !stream->rdonly) { if (mbx_rewrite (stream,&i,NIL)) fatal ("expunge on check"); if (i) { /* any space reclaimed? */ LOCAL->expunged = NIL;/* no more pending expunge */ sprintf (LOCAL->buf,"Reclaimed %lu bytes of expunged space",i); MM_LOG (LOCAL->buf,(long) NIL); } } LOCAL->expok = NIL; /* no more expok */ } } return ret; /* return result of the parse */ } /* MBX mail check mailbox (reparses status too) * Accepts: MAIL stream */ void mbx_check (MAILSTREAM *stream) { if (LOCAL) LOCAL->expok = T; /* mark that a check is desired */ if (mbx_ping (stream)) MM_LOG ("Check completed",(long) NIL); } /* MBX mail expunge mailbox * Accepts: MAIL stream * sequence to expunge if non-NIL * expunge options * Returns: T if success, NIL if failure */ long mbx_expunge (MAILSTREAM *stream,char *sequence,long options) { long ret; unsigned long nexp,reclaimed; if (ret = sequence ? ((options & EX_UID) ? mail_uid_sequence (stream,sequence) : mail_sequence (stream,sequence)) : LONGT) { if (!mbx_ping (stream)); /* do nothing if stream dead */ else if (stream->rdonly) /* won't do on readonly files! */ MM_LOG ("Expunge ignored on readonly mailbox",WARN); /* if expunged any messages */ else if (nexp = mbx_rewrite (stream,&reclaimed,sequence ? -1 : 1)) { sprintf (LOCAL->buf,"Expunged %lu messages",nexp); MM_LOG (LOCAL->buf,(long) NIL); } else if (reclaimed) { /* or if any prior expunged space reclaimed */ sprintf (LOCAL->buf,"Reclaimed %lu bytes of expunged space",reclaimed); MM_LOG (LOCAL->buf,(long) NIL); } else MM_LOG ("No messages deleted, so no update needed",(long) NIL); } return ret; } /* MBX mail snarf messages from system inbox * Accepts: MAIL stream, already locked */ void mbx_snarf (MAILSTREAM *stream) { unsigned long i = 0; unsigned long j,r,hdrlen,txtlen; struct stat sbuf; char *hdr,*txt,tmp[MAILTMPLEN]; MESSAGECACHE *elt; MAILSTREAM *sysibx = NIL; /* give up if can't get exclusive permission */ if ((time (0) >= (LOCAL->lastsnarf + (long) mail_parameters (NIL,GET_SNARFINTERVAL,NIL))) && strcmp (sysinbox (),stream->mailbox)) { MM_CRITICAL (stream); /* go critical */ /* sizes match and anything in sysinbox? */ if (!stat (sysinbox (),&sbuf) && sbuf.st_size && !fstat (LOCAL->fd,&sbuf) && (sbuf.st_size == LOCAL->filesize) && (sysibx = mail_open (sysibx,sysinbox (),OP_SILENT)) && (!sysibx->rdonly) && (r = sysibx->nmsgs)) { /* yes, go to end of file in our mailbox */ lseek (LOCAL->fd,sbuf.st_size,L_SET); /* for each message in sysibx mailbox */ while (r && (++i <= sysibx->nmsgs)) { /* snarf message from system INBOX */ hdr = cpystr (mail_fetchheader_full (sysibx,i,NIL,&hdrlen,NIL)); txt = mail_fetchtext_full (sysibx,i,&txtlen,FT_PEEK); /* if have a message */ if (j = hdrlen + txtlen) { /* build header line */ mail_date (LOCAL->buf,elt = mail_elt (sysibx,i)); sprintf (LOCAL->buf + strlen (LOCAL->buf), ",%lu;00000000%04x-00000000\015\012",j,(unsigned) ((fSEEN * elt->seen) + (fDELETED * elt->deleted) + (fFLAGGED * elt->flagged) + (fANSWERED * elt->answered) + (fDRAFT * elt->draft))); /* copy message */ if ((write (LOCAL->fd,LOCAL->buf,strlen (LOCAL->buf)) < 0) || (write (LOCAL->fd,hdr,hdrlen) < 0) || (write (LOCAL->fd,txt,txtlen) < 0)) r = 0; } fs_give ((void **) &hdr); } /* make sure all the updates take */ if (fsync (LOCAL->fd)) r = 0; if (r) { /* delete all the messages we copied */ if (r == 1) strcpy (tmp,"1"); else sprintf (tmp,"1:%lu",r); mail_setflag (sysibx,tmp,"\\Deleted"); mail_expunge (sysibx); /* now expunge all those messages */ } else { sprintf (LOCAL->buf,"Can't copy new mail: %s",strerror (errno)); MM_LOG (LOCAL->buf,WARN); ftruncate (LOCAL->fd,sbuf.st_size); } fstat (LOCAL->fd,&sbuf); /* yes, get current file size */ LOCAL->filetime = sbuf.st_mtime; } if (sysibx) mail_close (sysibx); MM_NOCRITICAL (stream); /* release critical */ LOCAL->lastsnarf = time (0);/* note time of last snarf */ } } /* MBX mail copy message(s) * Accepts: MAIL stream * sequence * destination mailbox * copy options * Returns: T if success, NIL if failed */ long mbx_copy (MAILSTREAM *stream,char *sequence,char *mailbox,long options) { struct stat sbuf; time_t tp[2]; MESSAGECACHE *elt; unsigned long i,j,k,m; long ret = LONGT; int fd,ld; char *s,*t,file[MAILTMPLEN],lock[MAILTMPLEN]; mailproxycopy_t pc = (mailproxycopy_t) mail_parameters (stream,GET_MAILPROXYCOPY,NIL); copyuid_t cu = (copyuid_t) mail_parameters (NIL,GET_COPYUID,NIL); SEARCHSET *source = cu ? mail_newsearchset () : NIL; SEARCHSET *dest = cu ? mail_newsearchset () : NIL; MAILSTREAM *dstream = NIL; if (!((options & CP_UID) ? mail_uid_sequence (stream,sequence) : mail_sequence (stream,sequence))) return NIL; /* make sure valid mailbox */ if ((fd = mbx_isvalid (&dstream,mailbox,file,&ld,lock, cu ? MBXISVALIDUID : MBXISVALIDNOUID)) < 0) switch (errno) { case ENOENT: /* no such file? */ MM_NOTIFY (stream,"[TRYCREATE] Must create mailbox before copy",NIL); return NIL; case EACCES: /* file protected */ sprintf (LOCAL->buf,"Can't access destination: %.80s",mailbox); MM_LOG (LOCAL->buf,ERROR); return NIL; case EINVAL: if (pc) return (*pc) (stream,sequence,mailbox,options); sprintf (LOCAL->buf,"Invalid MBX-format mailbox name: %.80s",mailbox); MM_LOG (LOCAL->buf,ERROR); return NIL; default: if (pc) return (*pc) (stream,sequence,mailbox,options); sprintf (LOCAL->buf,"Not a MBX-format mailbox: %.80s",mailbox); MM_LOG (LOCAL->buf,ERROR); return NIL; } MM_CRITICAL (stream); /* go critical */ fstat (fd,&sbuf); /* get current file size */ lseek (fd,sbuf.st_size,L_SET);/* move to end of file */ /* for each requested message */ for (i = 1; ret && (i <= stream->nmsgs); i++) if ((elt = mail_elt (stream,i))->sequence) { lseek (LOCAL->fd,elt->private.special.offset + elt->private.special.text.size,L_SET); mail_date(LOCAL->buf,elt);/* build target header */ /* get target keyword mask */ for (j = elt->user_flags, k = 0; j; ) if (s = stream->user_flags[find_rightmost_bit (&j)]) for (m = 0; (m < NUSERFLAGS) && (t = dstream->user_flags[m]); m++) if (!compare_cstring (s,t) && (k |= 1 << m)) break; sprintf (LOCAL->buf+strlen(LOCAL->buf),",%lu;%08lx%04x-%08lx\015\012", elt->rfc822_size,k,(unsigned) ((fSEEN * elt->seen) + (fDELETED * elt->deleted) + (fFLAGGED * elt->flagged) + (fANSWERED * elt->answered) + (fDRAFT * elt->draft)),cu ? ++dstream->uid_last : 0); /* write target header */ if (ret = (write (fd,LOCAL->buf,strlen (LOCAL->buf)) > 0)) { for (k = elt->rfc822_size; ret && (j = min (k,LOCAL->buflen)); k -= j){ read (LOCAL->fd,LOCAL->buf,j); ret = write (fd,LOCAL->buf,j) >= 0; } if (cu) { /* need to pass back new UID? */ mail_append_set (source,mail_uid (stream,i)); mail_append_set (dest,dstream->uid_last); } } } /* make sure all the updates take */ if (!(ret && (ret = !fsync (fd)))) { sprintf (LOCAL->buf,"Unable to write message: %s",strerror (errno)); MM_LOG (LOCAL->buf,ERROR); ftruncate (fd,sbuf.st_size); } if (cu && ret) { /* return sets if doing COPYUID */ (*cu) (stream,mailbox,dstream->uid_validity,source,dest); lseek (fd,15,L_SET); /* update UIDLAST */ sprintf (LOCAL->buf,"%08lx",dstream->uid_last); write (fd,LOCAL->buf,8); } else { /* flush any sets we may have built */ mail_free_searchset (&source); mail_free_searchset (&dest); } if (ret) tp[0] = time (0) - 1;/* set atime to now-1 if successful copy */ /* else preserve \Marked status */ else tp[0] = (sbuf.st_ctime > sbuf.st_atime) ? sbuf.st_atime : time(0); tp[1] = sbuf.st_mtime; /* preserve mtime */ utime (file,tp); /* set the times */ close (fd); /* close the file */ MM_NOCRITICAL (stream); /* release critical */ unlockfd (ld,lock); /* release exclusive parse/append permission */ /* delete all requested messages */ if (ret && (options & CP_MOVE) && mbx_flaglock (stream)) { for (i = 1; i <= stream->nmsgs; i++) if (mail_elt (stream,i)->sequence) { /* mark message deleted */ mbx_elt (stream,i,NIL)->deleted = T; /* recalculate status */ mbx_update_status (stream,i,NIL); } /* update flags */ mbx_flag (stream,NIL,NIL,NIL); } if (dstream != stream) mail_close (dstream); return ret; } /* MBX mail append message from stringstruct * Accepts: MAIL stream * destination mailbox * append callback * data for callback * Returns: T if append successful, else NIL */ long mbx_append (MAILSTREAM *stream,char *mailbox,append_t af,void *data) { struct stat sbuf; int fd,ld; char *flags,*date,tmp[MAILTMPLEN],file[MAILTMPLEN],lock[MAILTMPLEN]; time_t tp[2]; FILE *df; MESSAGECACHE elt; long f; unsigned long i,uf; STRING *message; long ret = NIL; MAILSTREAM *dstream = NIL; appenduid_t au = (appenduid_t) mail_parameters (NIL,GET_APPENDUID,NIL); SEARCHSET *dst = au ? mail_newsearchset () : NIL; /* make sure valid mailbox */ if ((fd = mbx_isvalid (&dstream,mailbox,file,&ld,lock, au ? MBXISVALIDUID : MBXISVALIDNOUID)) < 0) switch (errno) { case ENOENT: /* no such file? */ if (compare_cstring (mailbox,"INBOX")) { MM_NOTIFY (stream,"[TRYCREATE] Must create mailbox before append",NIL); return NIL; } /* can create INBOX here */ mbx_create (dstream = stream ? stream : user_flags (&mbxproto),"INBOX"); if ((fd = mbx_isvalid (&dstream,mailbox,file,&ld,lock, au ? MBXISVALIDUID : MBXISVALIDNOUID)) >= 0) break; case EACCES: /* file protected */ sprintf (tmp,"Can't access destination: %.80s",mailbox); MM_LOG (tmp,ERROR); return NIL; case EINVAL: sprintf (tmp,"Invalid MBX-format mailbox name: %.80s",mailbox); MM_LOG (tmp,ERROR); return NIL; default: sprintf (tmp,"Not a MBX-format mailbox: %.80s",mailbox); MM_LOG (tmp,ERROR); return NIL; } /* get first message */ if (!MM_APPEND (af) (dstream,data,&flags,&date,&message)) close (fd); else if (!(df = fdopen (fd,"r+b"))) { MM_LOG ("Unable to reopen append mailbox",ERROR); close (fd); } else { MM_CRITICAL (dstream); /* go critical */ fstat (fd,&sbuf); /* get current file size */ fseek (df,sbuf.st_size,SEEK_SET); errno = 0; for (ret = LONGT; ret && message; ) { if (!SIZE (message)) { /* guard against zero-length */ MM_LOG ("Append of zero-length message",ERROR); ret = NIL; break; } f = mail_parse_flags (dstream,flags,&uf); if (date) { /* parse date if given */ if (!mail_parse_date (&elt,date)) { sprintf (tmp,"Bad date in append: %.80s",date); MM_LOG (tmp,ERROR); ret = NIL; /* mark failure */ break; } mail_date (tmp,&elt); /* write preseved date */ } else internal_date (tmp); /* get current date in IMAP format */ /* write header */ if (fprintf (df,"%s,%lu;%08lx%04lx-%08lx\015\012",tmp,i = SIZE (message), uf,(unsigned long) f,au ? ++dstream->uid_last : 0) < 0) ret = NIL; else { /* write message */ size_t j; if (!message->cursize) SETPOS (message,GETPOS (message)); while (i && (j = fwrite (message->curpos,1,message->cursize,df))) { i -= j; SETPOS (message,GETPOS (message) + j); } /* get next message */ if (i || !MM_APPEND (af) (dstream,data,&flags,&date,&message)) ret = NIL; else if (au) mail_append_set (dst,dstream->uid_last); } } /* if error... */ if (!ret || (fflush (df) == EOF)) { /* revert file */ ftruncate (fd,sbuf.st_size); close (fd); /* make sure fclose() doesn't corrupt us */ if (errno) { sprintf (tmp,"Message append failed: %s",strerror (errno)); MM_LOG (tmp,ERROR); } ret = NIL; } if (au && ret) { /* return sets if doing APPENDUID */ (*au) (mailbox,dstream->uid_validity,dst); fseek (df,15,SEEK_SET); /* update UIDLAST */ fprintf (df,"%08lx",dstream->uid_last); } else mail_free_searchset (&dst); /* set atime to now-1 if successful copy */ if (ret) tp[0] = time (0) - 1; /* else preserve \Marked status */ else tp[0] = (sbuf.st_ctime > sbuf.st_atime) ? sbuf.st_atime : time(0); tp[1] = sbuf.st_mtime; /* preserve mtime */ utime (file,tp); /* set the times */ fclose (df); /* close the file */ MM_NOCRITICAL (dstream); /* release critical */ } unlockfd (ld,lock); /* release exclusive parse/append permission */ if (dstream != stream) mail_close (dstream); return ret; } /* Internal routines */ /* MBX mail generate file string * Accepts: temporary buffer to write into * mailbox name string * Returns: local file string or NIL if failure */ char *mbx_file (char *dst,char *name) { char *s = mailboxfile (dst,name); return (s && !*s) ? mailboxfile (dst,"~/INBOX") : s; } /* MBX mail parse mailbox * Accepts: MAIL stream * Returns: T if parse OK * NIL if failure, stream aborted */ long mbx_parse (MAILSTREAM *stream) { struct stat sbuf; MESSAGECACHE *elt = NIL; unsigned char c,*s,*t,*x; char tmp[MAILTMPLEN]; unsigned long i,j,k,m; off_t curpos = LOCAL->filesize; unsigned long nmsgs = stream->nmsgs; unsigned long recent = stream->recent; unsigned long lastuid = 0; short dirty = NIL; short added = NIL; short silent = stream->silent; short uidwarn = T; fstat (LOCAL->fd,&sbuf); /* get status */ if (sbuf.st_size < curpos) { /* sanity check */ sprintf (tmp,"Mailbox shrank from %lu to %lu!", (unsigned long) curpos,(unsigned long) sbuf.st_size); MM_LOG (tmp,ERROR); mbx_abort (stream); return NIL; } lseek (LOCAL->fd,0,L_SET); /* rewind file */ /* read internal header */ read (LOCAL->fd,LOCAL->buf,HDRSIZE); LOCAL->buf[HDRSIZE] = '\0'; /* tie off header */ c = LOCAL->buf[15]; /* save first character of last UID */ LOCAL->buf[15] = '\0'; /* parse UID validity */ stream->uid_validity = strtoul (LOCAL->buf + 7,NIL,16); LOCAL->buf[15] = c; /* restore first character of last UID */ /* parse last UID */ i = strtoul (LOCAL->buf + 15,NIL,16); stream->uid_last = stream->rdonly ? max (i,stream->uid_last) : i; /* parse user flags */ for (i = 0, s = LOCAL->buf + 25; (i < NUSERFLAGS) && (t = strchr (s,'\015')) && (t - s); i++, s = t + 2) { *t = '\0'; /* tie off flag */ if (!stream->user_flags[i] && (strlen (s) <= MAXUSERFLAG)) stream->user_flags[i] = cpystr (s); } LOCAL->ffuserflag = (int) i; /* first free user flag */ /* get current last flag updater PID */ i = (isxdigit (LOCAL->buf[HDRSIZE-10]) && isxdigit (LOCAL->buf[HDRSIZE-9]) && isxdigit (LOCAL->buf[HDRSIZE-8]) && isxdigit (LOCAL->buf[HDRSIZE-7]) && isxdigit (LOCAL->buf[HDRSIZE-6]) && isxdigit (LOCAL->buf[HDRSIZE-5]) && isxdigit (LOCAL->buf[HDRSIZE-4]) && isxdigit (LOCAL->buf[HDRSIZE-3]) && (LOCAL->buf[HDRSIZE-2] == '\015') && (LOCAL->buf[HDRSIZE-1] == '\012'))? strtoul (LOCAL->buf + HDRSIZE - 8,NIL,16) : 0; /* set flagcheck if lastpid changed */ if (LOCAL->lastpid && (LOCAL->lastpid != i)) LOCAL->flagcheck = T; LOCAL->lastpid = i; /* set as last PID */ stream->silent = T; /* don't pass up exists events yet */ while (sbuf.st_size - curpos){/* while there is stuff to parse */ /* get to that position in the file */ lseek (LOCAL->fd,curpos,L_SET); if ((i = read (LOCAL->fd,LOCAL->buf,64)) <= 0) { sprintf (tmp,"Unable to read internal header at %lu, size = %lu: %s", (unsigned long) curpos,(unsigned long) sbuf.st_size, i ? strerror (errno) : "no data read"); MM_LOG (tmp,ERROR); mbx_abort (stream); return NIL; } LOCAL->buf[i] = '\0'; /* tie off buffer just in case */ if (!((s = strchr (LOCAL->buf,'\015')) && (s[1] == '\012'))) { sprintf (tmp,"Unable to find CRLF at %lu in %lu bytes, text: %.80s", (unsigned long) curpos,i,(char *) LOCAL->buf); MM_LOG (tmp,ERROR); mbx_abort (stream); return NIL; } *s = '\0'; /* tie off header line */ i = (s + 2) - LOCAL->buf; /* note start of text offset */ if (!((s = strchr (LOCAL->buf,',')) && (t = strchr (s+1,';')))) { sprintf (tmp,"Unable to parse internal header at %lu: %.80s", (unsigned long) curpos,(char *) LOCAL->buf); MM_LOG (tmp,ERROR); mbx_abort (stream); return NIL; } if (!(isxdigit (t[1]) && isxdigit (t[2]) && isxdigit (t[3]) && isxdigit (t[4]) && isxdigit (t[5]) && isxdigit (t[6]) && isxdigit (t[7]) && isxdigit (t[8]) && isxdigit (t[9]) && isxdigit (t[10]) && isxdigit (t[11]) && isxdigit (t[12]))) { sprintf (tmp,"Unable to parse message flags at %lu: %.80s", (unsigned long) curpos,(char *) LOCAL->buf); MM_LOG (tmp,ERROR); mbx_abort (stream); return NIL; } if ((t[13] != '-') || t[22] || !(isxdigit (t[14]) && isxdigit (t[15]) && isxdigit (t[16]) && isxdigit (t[17]) && isxdigit (t[18]) && isxdigit (t[19]) && isxdigit (t[20]) && isxdigit (t[21]))) { sprintf (tmp,"Unable to parse message UID at %lu: %.80s", (unsigned long) curpos,(char *) LOCAL->buf); MM_LOG (tmp,ERROR); mbx_abort (stream); return NIL; } *s++ = '\0'; *t++ = '\0'; /* break up fields */ /* get message size */ if (!(j = strtoul (s,(char **) &x,10)) && (!(x && *x))) { sprintf (tmp,"Unable to parse message size at %lu: %.80s,%.80s;%.80s", (unsigned long) curpos,(char *) LOCAL->buf,(char *) s, (char *) t); MM_LOG (tmp,ERROR); mbx_abort (stream); return NIL; } /* make sure didn't run off end of file */ if (((off_t) (curpos + i + j)) > sbuf.st_size) { sprintf (tmp,"Last message (at %lu) runs past end of file (%lu > %lu)", (unsigned long) curpos,(unsigned long) (curpos + i + j), (unsigned long) sbuf.st_size); MM_LOG (tmp,ERROR); mbx_abort (stream); return NIL; } /* parse UID */ if ((m = strtoul (t+13,NIL,16)) && ((m <= lastuid) || (m > stream->uid_last))) { if (uidwarn) { sprintf (tmp,"Invalid UID %08lx in message %lu, rebuilding UIDs", m,nmsgs+1); MM_LOG (tmp,WARN); uidwarn = NIL; /* restart UID validity */ stream->uid_validity = time (0); } m = 0; /* lose this UID */ dirty = T; /* mark dirty, set new lastuid */ stream->uid_last = lastuid; } t[12] = '\0'; /* parse system flags */ if ((k = strtoul (t+8,NIL,16)) & fEXPUNGED) { if (m) lastuid = m; /* expunge message, update last UID seen */ else { /* no UID assigned? */ lastuid = ++stream->uid_last; dirty = T; } } else { /* not expunged, swell the cache */ added = T; /* note that a new message was added */ mail_exists (stream,++nmsgs); /* instantiate an elt for this message */ (elt = mail_elt (stream,nmsgs))->valid = T; /* parse the date */ if (!mail_parse_date (elt,LOCAL->buf)) { sprintf (tmp,"Unable to parse message date at %lu: %.80s", (unsigned long) curpos,(char *) LOCAL->buf); MM_LOG (tmp,ERROR); mbx_abort (stream); return NIL; } /* note file offset of header */ elt->private.special.offset = curpos; /* and internal header size */ elt->private.special.text.size = i; /* header size not known yet */ elt->private.msg.header.text.size = 0; elt->rfc822_size = j; /* note message size */ /* calculate system flags */ if (k & fSEEN) elt->seen = T; if (k & fDELETED) elt->deleted = T; if (k & fFLAGGED) elt->flagged = T; if (k & fANSWERED) elt->answered = T; if (k & fDRAFT) elt->draft = T; t[8] = '\0'; /* get user flags value */ elt->user_flags = strtoul (t,NIL,16); /* UID already assigned? */ if (!(elt->private.uid = m) || !(k & fOLD)) { elt->recent = T; /* no, mark as recent */ ++recent; /* count up a new recent message */ dirty = T; /* and must rewrite header */ /* assign new UID */ if (!elt->private.uid) elt->private.uid = ++stream->uid_last; mbx_update_status (stream,elt->msgno,NIL); } /* update last parsed UID */ lastuid = elt->private.uid; } curpos += i + j; /* update position */ } if (dirty && !stream->rdonly){/* update header */ mbx_update_header (stream); fsync (LOCAL->fd); /* make sure all the UID updates take */ } /* update parsed file size and time */ LOCAL->filesize = sbuf.st_size; fstat (LOCAL->fd,&sbuf); /* get status again to ensure time is right */ LOCAL->filetime = sbuf.st_mtime; if (added && !stream->rdonly){/* make sure atime updated */ time_t tp[2]; tp[0] = time (0); tp[1] = LOCAL->filetime; utime (stream->mailbox,tp); } stream->silent = silent; /* can pass up events now */ mail_exists (stream,nmsgs); /* notify upper level of new mailbox size */ mail_recent (stream,recent); /* and of change in recent messages */ return LONGT; /* return the winnage */ } /* MBX get cache element with status updating from file * Accepts: MAIL stream * message number * expunge OK flag * Returns: cache element */ MESSAGECACHE *mbx_elt (MAILSTREAM *stream,unsigned long msgno,long expok) { MESSAGECACHE *elt = mail_elt (stream,msgno); struct { /* old flags */ unsigned int seen : 1; unsigned int deleted : 1; unsigned int flagged : 1; unsigned int answered : 1; unsigned int draft : 1; unsigned long user_flags; } old; old.seen = elt->seen; old.deleted = elt->deleted; old.flagged = elt->flagged; old.answered = elt->answered; old.draft = elt->draft; old.user_flags = elt->user_flags; /* get new flags */ if (mbx_read_flags (stream,elt) && expok) { mail_expunged (stream,elt->msgno); return NIL; /* return this message was expunged */ } if ((old.seen != elt->seen) || (old.deleted != elt->deleted) || (old.flagged != elt->flagged) || (old.answered != elt->answered) || (old.draft != elt->draft) || (old.user_flags != elt->user_flags)) MM_FLAGS (stream,msgno); /* let top level know */ return elt; } /* MBX read flags from file * Accepts: MAIL stream * cache element * Returns: non-NIL if message expunged */ unsigned long mbx_read_flags (MAILSTREAM *stream,MESSAGECACHE *elt) { unsigned long i; struct stat sbuf; fstat (LOCAL->fd,&sbuf); /* get status */ /* make sure file size is good */ if (sbuf.st_size < LOCAL->filesize) { sprintf (LOCAL->buf,"Mailbox shrank from %lu to %lu in flag read!", (unsigned long) LOCAL->filesize,(unsigned long) sbuf.st_size); fatal (LOCAL->buf); } /* set the seek pointer */ lseek (LOCAL->fd,(off_t) elt->private.special.offset + elt->private.special.text.size - 24,L_SET); /* read the new flags */ if (read (LOCAL->fd,LOCAL->buf,14) < 0) { sprintf (LOCAL->buf,"Unable to read new status: %s",strerror (errno)); fatal (LOCAL->buf); } if ((LOCAL->buf[0] != ';') || (LOCAL->buf[13] != '-')) { LOCAL->buf[14] = '\0'; /* tie off buffer for error message */ sprintf (LOCAL->buf+50,"Invalid flags for message %lu (%lu %lu): %s", elt->msgno,elt->private.special.offset, elt->private.special.text.size,(char *) LOCAL->buf); fatal (LOCAL->buf+50); } LOCAL->buf[13] = '\0'; /* tie off buffer */ /* calculate system flags */ i = strtoul (LOCAL->buf+9,NIL,16); elt->seen = i & fSEEN ? T : NIL; elt->deleted = i & fDELETED ? T : NIL; elt->flagged = i & fFLAGGED ? T : NIL; elt->answered = i & fANSWERED ? T : NIL; elt->draft = i & fDRAFT ? T : NIL; LOCAL->expunged |= i & fEXPUNGED ? T : NIL; LOCAL->buf[9] = '\0'; /* tie off flags */ /* get user flags value */ elt->user_flags = strtoul (LOCAL->buf+1,NIL,16); elt->valid = T; /* have valid flags now */ return i & fEXPUNGED; } /* MBX update header * Accepts: MAIL stream */ #ifndef CYGKLUDGEOFFSET #define CYGKLUDGEOFFSET 0 #endif void mbx_update_header (MAILSTREAM *stream) { int i; char *s = LOCAL->buf; memset (s,'\0',HDRSIZE); /* initialize header */ sprintf (s,"*mbx*\015\012%08lx%08lx\015\012", stream->uid_validity,stream->uid_last); for (i = 0; (i < NUSERFLAGS) && stream->user_flags[i]; ++i) sprintf (s += strlen (s),"%s\015\012",stream->user_flags[i]); LOCAL->ffuserflag = i; /* first free user flag */ /* can we create more user flags? */ stream->kwd_create = (i < NUSERFLAGS) ? T : NIL; /* write reserved lines */ while (i++ < NUSERFLAGS) strcat (s,"\015\012"); sprintf (LOCAL->buf + HDRSIZE - 10,"%08lx\015\012",LOCAL->lastpid); while (T) { /* rewind file */ lseek (LOCAL->fd,CYGKLUDGEOFFSET,L_SET); /* write new header */ if (write (LOCAL->fd,LOCAL->buf + CYGKLUDGEOFFSET, HDRSIZE - CYGKLUDGEOFFSET) > 0) break; MM_NOTIFY (stream,strerror (errno),WARN); MM_DISKERROR (stream,errno,T); } } /* MBX update status string * Accepts: MAIL stream * message number * flags */ void mbx_update_status (MAILSTREAM *stream,unsigned long msgno,long flags) { struct stat sbuf; MESSAGECACHE *elt = mail_elt (stream,msgno); /* readonly */ if (stream->rdonly || !elt->valid) mbx_read_flags (stream,elt); else { /* readwrite */ fstat (LOCAL->fd,&sbuf); /* get status */ /* make sure file size is good */ if (sbuf.st_size < LOCAL->filesize) { sprintf (LOCAL->buf,"Mailbox shrank from %lu to %lu in flag update!", (unsigned long) LOCAL->filesize,(unsigned long) sbuf.st_size); fatal (LOCAL->buf); } /* set the seek pointer */ lseek (LOCAL->fd,(off_t) elt->private.special.offset + elt->private.special.text.size - 24,L_SET); /* read the new flags */ if (read (LOCAL->fd,LOCAL->buf,14) < 0) { sprintf (LOCAL->buf,"Unable to read old status: %s",strerror (errno)); fatal (LOCAL->buf); } if ((LOCAL->buf[0] != ';') || (LOCAL->buf[13] != '-')) { LOCAL->buf[14] = '\0'; /* tie off buffer for error message */ sprintf (LOCAL->buf+50,"Invalid flags for message %lu (%lu %lu): %s", elt->msgno,elt->private.special.offset, elt->private.special.text.size,(char *) LOCAL->buf); fatal (LOCAL->buf+50); } /* print new flag string */ sprintf (LOCAL->buf,"%08lx%04x-%08lx",elt->user_flags,(unsigned) (((elt->deleted && flags) ? fEXPUNGED : (strtoul (LOCAL->buf+9,NIL,16)) & fEXPUNGED) + (fSEEN * elt->seen) + (fDELETED * elt->deleted) + (fFLAGGED * elt->flagged) + (fANSWERED * elt->answered) + (fDRAFT * elt->draft) + fOLD),elt->private.uid); while (T) { /* get to that place in the file */ lseek (LOCAL->fd,(off_t) elt->private.special.offset + elt->private.special.text.size - 23,L_SET); /* write new flags and UID */ if (write (LOCAL->fd,LOCAL->buf,21) > 0) break; MM_NOTIFY (stream,strerror (errno),WARN); MM_DISKERROR (stream,errno,T); } } } /* MBX locate header for a message * Accepts: MAIL stream * message number * pointer to returned header size * pointer to possible returned header * Returns: position of header in file */ #define HDRBUFLEN 16384 /* good enough for most headers */ #define SLOP 4 /* CR LF CR LF */ unsigned long mbx_hdrpos (MAILSTREAM *stream,unsigned long msgno, unsigned long *size,char **hdr) { unsigned long siz,done; long i; unsigned char *s,*t,*te; MESSAGECACHE *elt = mail_elt (stream,msgno); unsigned long ret = elt->private.special.offset + elt->private.special.text.size; if (hdr) *hdr = NIL; /* assume no header returned */ /* is header size known? */ if (*size = elt->private.msg.header.text.size) return ret; /* paranoia check */ if (LOCAL->buflen < (HDRBUFLEN + SLOP)) fatal ("LOCAL->buf smaller than HDRBUFLEN"); lseek (LOCAL->fd,ret,L_SET); /* get to header position */ /* read HDRBUFLEN chunks with 4 byte slop */ for (done = siz = 0, s = LOCAL->buf; (i = min ((long) (elt->rfc822_size - done),(long) HDRBUFLEN)) && (read (LOCAL->fd,s,i) == i); done += i, siz += (t - LOCAL->buf) - SLOP, s = LOCAL->buf + SLOP) { te = (t = s + i) - 12; /* calculate end of fast scan */ /* fast scan for CR */ for (s = LOCAL->buf; s < te;) if (((*s++ == '\015') || (*s++ == '\015') || (*s++ == '\015') || (*s++ == '\015') || (*s++ == '\015') || (*s++ == '\015') || (*s++ == '\015') || (*s++ == '\015') || (*s++ == '\015') || (*s++ == '\015') || (*s++ == '\015') || (*s++ == '\015')) && (*s == '\012') && (*++s == '\015') && (*++s == '\012')) { *size = elt->private.msg.header.text.size = siz + (++s - LOCAL->buf); if (hdr) *hdr = LOCAL->buf; return ret; } for (te = t - 3; (s < te);) /* final character-at-a-time scan */ if ((*s++ == '\015') && (*s == '\012') && (*++s == '\015') && (*++s == '\012')) { *size = elt->private.msg.header.text.size = siz + (++s - LOCAL->buf); if (hdr) *hdr = LOCAL->buf; return ret; } if (i <= SLOP) break; /* end of data */ /* slide over last 4 bytes */ memmove (LOCAL->buf,t - SLOP,SLOP); hdr = NIL; /* can't return header this way */ } /* not found: header consumes entire message */ elt->private.msg.header.text.size = *size = elt->rfc822_size; if (hdr) *hdr = LOCAL->buf; /* possibly return header too */ return ret; } /* MBX mail rewrite mailbox * Accepts: MAIL stream * pointer to return reclaimed size * flags (0 = no expunge, 1 = expunge deleted, -1 = expunge sequence) * Returns: number of expunged messages */ unsigned long mbx_rewrite (MAILSTREAM *stream,unsigned long *reclaimed, long flags) { time_t tp[2]; struct stat sbuf; off_t pos,ppos; int ld; unsigned long i,j,k,m,delta; unsigned long n = *reclaimed = 0; unsigned long recent = 0; char lock[MAILTMPLEN]; MESSAGECACHE *elt; blocknotify_t bn = (blocknotify_t) mail_parameters (NIL,GET_BLOCKNOTIFY,NIL); /* The cretins who designed flock() created a window of vulnerability in * upgrading locks from shared to exclusive or downgrading from exclusive * to shared. Rather than maintain the lock at shared status at a minimum, * flock() actually *releases* the former lock. Obviously they never talked * to any database guys. Fortunately, we have the parse/append permission * lock. If we require this lock before going exclusive on the mailbox, * another process can not sneak in and steal the exclusive mailbox lock on * us, because it will block on trying to get parse/append permission first. */ /* get parse/append permission */ if ((ld = lockfd (LOCAL->fd,lock,LOCK_EX)) < 0) { MM_LOG ("Unable to lock mailbox for rewrite",ERROR); return 0; } fstat (LOCAL->fd,&sbuf); /* get current write time */ if (LOCAL->filetime && !LOCAL->flagcheck && (LOCAL->filetime < sbuf.st_mtime)) LOCAL->flagcheck = T; if (!mbx_parse (stream)) { /* make sure see any newly-arrived messages */ unlockfd (ld,lock); /* failed?? */ return 0; } if (LOCAL->flagcheck) { /* sweep flags if need flagcheck */ LOCAL->filetime = sbuf.st_mtime; for (i = 1; i <= stream->nmsgs; ++i) mbx_elt (stream,i,NIL); LOCAL->flagcheck = NIL; } /* get exclusive access */ if (!flock (LOCAL->fd,LOCK_EX|LOCK_NB)) { MM_CRITICAL (stream); /* go critical */ for (i = 1,delta = 0,pos = ppos = HDRSIZE; i <= stream->nmsgs; ) { /* note if message not at predicted location */ if (m = (elt = mbx_elt (stream,i,NIL))->private.special.offset - ppos) { ppos = elt->private.special.offset; *reclaimed += m; /* note reclaimed message space */ delta += m; /* and as expunge delta */ } /* number of bytes to smash or preserve */ ppos += (k = elt->private.special.text.size + elt->rfc822_size); /* if need to expunge this message*/ if (flags && elt->deleted && ((flags > 0) || elt->sequence)) { delta += k; /* number of bytes to delete */ mail_expunged(stream,i);/* notify upper levels */ n++; /* count up one more expunged message */ } else { /* preserved message */ i++; /* count this message */ if (elt->recent) ++recent; if (delta) { /* moved, note first byte to preserve */ j = elt->private.special.offset; do { /* read from source position */ m = min (k,LOCAL->buflen); lseek (LOCAL->fd,j,L_SET); read (LOCAL->fd,LOCAL->buf,m); pos = j - delta; /* write to destination position */ while (T) { lseek (LOCAL->fd,pos,L_SET); if (write (LOCAL->fd,LOCAL->buf,m) > 0) break; MM_NOTIFY (stream,strerror (errno),WARN); MM_DISKERROR (stream,errno,T); } pos += m; /* new position */ j += m; /* next chunk, perhaps */ } while (k -= m); /* until done */ /* note the new address of this text */ elt->private.special.offset -= delta; } /* preserved but no deleted messages yet */ else pos = elt->private.special.offset + k; } } /* deltaed file size match position? */ if (m = (LOCAL->filesize -= delta) - pos) { *reclaimed += m; /* probably an fEXPUNGED msg */ LOCAL->filesize = pos; /* set correct size */ } /* truncate file after last message */ ftruncate (LOCAL->fd,LOCAL->filesize); fsync (LOCAL->fd); /* force disk update */ MM_NOCRITICAL (stream); /* release critical */ (*bn) (BLOCK_FILELOCK,NIL); flock (LOCAL->fd,LOCK_SH); /* allow sharers again */ (*bn) (BLOCK_NONE,NIL); } else { /* can't get exclusive */ (*bn) (BLOCK_FILELOCK,NIL); flock (LOCAL->fd,LOCK_SH); /* recover previous shared mailbox lock */ (*bn) (BLOCK_NONE,NIL); /* do hide-expunge when shared */ if (flags) for (i = 1; i <= stream->nmsgs; ) { if (elt = mbx_elt (stream,i,T)) { /* make the message invisible */ if (elt->deleted && ((flags > 0) || elt->sequence)) { mbx_update_status (stream,elt->msgno,LONGT); /* notify upper levels */ mail_expunged (stream,i); n++; /* count up one more expunged message */ } else { i++; /* preserved message */ if (elt->recent) ++recent; } } else n++; /* count up one more expunged message */ } fsync (LOCAL->fd); /* force disk update */ } fstat (LOCAL->fd,&sbuf); /* get new write time */ tp[1] = LOCAL->filetime = sbuf.st_mtime; tp[0] = time (0); /* reset atime to now */ utime (stream->mailbox,tp); unlockfd (ld,lock); /* release exclusive parse/append permission */ /* notify upper level of new mailbox size */ mail_exists (stream,stream->nmsgs); mail_recent (stream,recent); return n; /* return number of expunged messages */ } /* MBX mail lock for flag updating * Accepts: stream * Returns: T if successful, NIL if failure */ long mbx_flaglock (MAILSTREAM *stream) { struct stat sbuf; unsigned long i; int ld; char lock[MAILTMPLEN]; /* no-op if readonly or already locked */ if (!stream->rdonly && LOCAL && (LOCAL->fd >= 0) && (LOCAL->ld < 0)) { /* lock now */ if ((ld = lockfd (LOCAL->fd,lock,LOCK_EX)) < 0) return NIL; if (!LOCAL->flagcheck) { /* don't do this if flagcheck already needed */ if (LOCAL->filetime) { /* know previous time? */ fstat (LOCAL->fd,&sbuf);/* get current write time */ if (LOCAL->filetime < sbuf.st_mtime) LOCAL->flagcheck = T; LOCAL->filetime = 0; /* don't do this test for any other messages */ } if (!mbx_parse (stream)) {/* parse mailbox */ unlockfd (ld,lock); /* shouldn't happen */ return NIL; } if (LOCAL->flagcheck) /* invalidate cache if flagcheck */ for (i = 1; i <= stream->nmsgs; ++i) mail_elt (stream,i)->valid = NIL; } LOCAL->ld = ld; /* copy to stream for subsequent calls */ memcpy (LOCAL->lock,lock,MAILTMPLEN); } return LONGT; } alpine-2.10+dfsg/imap/src/osdep/unix/ckp_1st.c0000600000175000017500000000276011512502123022662 0ustar paulproteuspaulproteus/* ======================================================================== * Copyright 1988-2006 University of Washington * * Licensed under the Apache License, Version 2.0 (the "License"); * you may not use this file except in compliance with the License. * You may obtain a copy of the License at * * http://www.apache.org/licenses/LICENSE-2.0 * * * ======================================================================== */ /* * Program: Dual check password part 1 * * Author: Mark Crispin * Networks and Distributed Computing * Computing & Communications * University of Washington * Administration Building, AG-44 * Seattle, WA 98195 * Internet: MRC@CAC.Washington.EDU * * Date: 1 August 1988 * Last Edited: 30 August 2006 */ struct passwd *checkpw_alt(struct passwd *pw,char *pass,int argc,char *argv[]); struct passwd *checkpw_std(struct passwd *pw,char *pass,int argc,char *argv[]); /* Check password * Accepts: login passwd struct * password string * argument count * argument vector * Returns: passwd struct if password validated, NIL otherwise */ struct passwd *checkpw (struct passwd *pw,char *pass,int argc,char *argv[]) { struct passwd *ret; /* in case first checker smashes it */ char *user = cpystr (pw->pw_name); if (!(ret = checkpw_alt (pw,pass,argc,argv))) ret = checkpw_std (getpwnam (user),pass,argc,argv); fs_give ((void **) &user); return ret; } /* Redefine alt checker's routine name */ #define checkpw checkpw_alt alpine-2.10+dfsg/imap/src/osdep/unix/unix.h0000600000175000017500000001506711512502123022312 0ustar paulproteuspaulproteus/* ======================================================================== * Copyright 1988-2006 University of Washington * * Licensed under the Apache License, Version 2.0 (the "License"); * you may not use this file except in compliance with the License. * You may obtain a copy of the License at * * http://www.apache.org/licenses/LICENSE-2.0 * * * ======================================================================== */ /* * Program: UNIX mail routines * * Author: Mark Crispin * Networks and Distributed Computing * Computing & Communications * University of Washington * Administration Building, AG-44 * Seattle, WA 98195 * Internet: MRC@CAC.Washington.EDU * * Date: 20 December 1989 * Last Edited: 30 August 2006 */ /* DEDICATION * * This file is dedicated to my dog, Unix, also known as Yun-chan and * Unix J. Terwilliker Jehosophat Aloysius Monstrosity Animal Beast. Unix * passed away at the age of 11 1/2 on September 14, 1996, 12:18 PM PDT, after * a two-month bout with cirrhosis of the liver. * * He was a dear friend, and I miss him terribly. * * Lift a leg, Yunie. Luv ya forever!!!! */ /* Validate line * Accepts: pointer to candidate string to validate as a From header * return pointer to end of date/time field * return pointer to offset from t of time (hours of ``mmm dd hh:mm'') * return pointer to offset from t of time zone (if non-zero) * Returns: t,ti,zn set if valid From string, else ti is NIL */ #define VALID(s,x,ti,zn) { \ ti = 0; \ if ((*s == 'F') && (s[1] == 'r') && (s[2] == 'o') && (s[3] == 'm') && \ (s[4] == ' ')) { \ for (x = s + 5; *x && *x != '\012'; x++); \ if (*x) { \ if (x[-1] == '\015') --x; \ if (x - s >= 41) { \ for (zn = -1; x[zn] != ' '; zn--); \ if ((x[zn-1] == 'm') && (x[zn-2] == 'o') && (x[zn-3] == 'r') && \ (x[zn-4] == 'f') && (x[zn-5] == ' ') && (x[zn-6] == 'e') && \ (x[zn-7] == 't') && (x[zn-8] == 'o') && (x[zn-9] == 'm') && \ (x[zn-10] == 'e') && (x[zn-11] == 'r') && (x[zn-12] == ' '))\ x += zn - 12; \ } \ if (x - s >= 27) { \ if (x[-5] == ' ') { \ if (x[-8] == ':') zn = 0,ti = -5; \ else if (x[-9] == ' ') ti = zn = -9; \ else if ((x[-11] == ' ') && ((x[-10]=='+') || (x[-10]=='-'))) \ ti = zn = -11; \ } \ else if (x[-4] == ' ') { \ if (x[-9] == ' ') zn = -4,ti = -9; \ } \ else if (x[-6] == ' ') { \ if ((x[-11] == ' ') && ((x[-5] == '+') || (x[-5] == '-'))) \ zn = -6,ti = -11; \ } \ if (ti && !((x[ti - 3] == ':') && \ (x[ti -= ((x[ti - 6] == ':') ? 9 : 6)] == ' ') && \ (x[ti - 3] == ' ') && (x[ti - 7] == ' ') && \ (x[ti - 11] == ' '))) ti = 0; \ } \ } \ } \ } /* You are not expected to understand this macro, but read the next page if * you are not faint of heart. * * Known formats to the VALID macro are: * From user Wed Dec 2 05:53 1992 * BSD From user Wed Dec 2 05:53:22 1992 * SysV From user Wed Dec 2 05:53 PST 1992 * rn From user Wed Dec 2 05:53:22 PST 1992 * From user Wed Dec 2 05:53 -0700 1992 * emacs From user Wed Dec 2 05:53:22 -0700 1992 * From user Wed Dec 2 05:53 1992 PST * From user Wed Dec 2 05:53:22 1992 PST * From user Wed Dec 2 05:53 1992 -0700 * Solaris From user Wed Dec 2 05:53:22 1992 -0700 * * Plus all of the above with `` remote from xxx'' after it. Thank you very * much, smail and Solaris, for making my life considerably more complicated. */ /* * What? You want to understand the VALID macro anyway? Alright, since you * insist. Actually, it isn't really all that difficult, provided that you * take it step by step. * * Line 1 Initializes the return ti value to failure (0); * Lines 2-3 Validates that the 1st-5th characters are ``From ''. * Lines 4-6 Validates that there is an end of line and points x at it. * Lines 7-14 First checks to see if the line is at least 41 characters long. * If so, it scans backwards to find the rightmost space. From * that point, it scans backwards to see if the string matches * `` remote from''. If so, it sets x to point to the space at * the start of the string. * Line 15 Makes sure that there are at least 27 characters in the line. * Lines 16-21 Checks if the date/time ends with the year (there is a space * five characters back). If there is a colon three characters * further back, there is no timezone field, so zn is set to 0 * and ti is set in front of the year. Otherwise, there must * either to be a space four characters back for a three-letter * timezone, or a space six characters back followed by a + or - * for a numeric timezone; in either case, zn and ti become the * offset of the space immediately before it. * Lines 22-24 Are the failure case for line 14. If there is a space four * characters back, it is a three-letter timezone; there must be a * space for the year nine characters back. zn is the zone * offset; ti is the offset of the space. * Lines 25-28 Are the failure case for line 20. If there is a space six * characters back, it is a numeric timezone; there must be a * space eleven characters back and a + or - five characters back. * zn is the zone offset; ti is the offset of the space. * Line 29-32 If ti is valid, make sure that the string before ti is of the * form www mmm dd hh:mm or www mmm dd hh:mm:ss, otherwise * invalidate ti. There must be a colon three characters back * and a space six or nine characters back (depending upon * whether or not the character six characters back is a colon). * There must be a space three characters further back (in front * of the day), one seven characters back (in front of the month), * and one eleven characters back (in front of the day of week). * ti is set to be the offset of the space before the time. * * Why a macro? It gets invoked a *lot* in a tight loop. On some of the * newer pipelined machines it is faster being open-coded than it would be if * subroutines are called. * * Why does it scan backwards from the end of the line, instead of doing the * much easier forward scan? There is no deterministic way to parse the * ``user'' field, because it may contain unquoted spaces! Yes, I tested it to * see if unquoted spaces were possible. They are, and I've encountered enough * evil mail to be totally unwilling to trust that ``it will never happen''. */ /* Build parameters */ #define KODRETRY 15 /* kiss-of-death retry in seconds */ #define LOCKTIMEOUT 5 /* lock timeout in minutes */ alpine-2.10+dfsg/imap/src/osdep/unix/os_osf.h0000600000175000017500000000225711512502123022614 0ustar paulproteuspaulproteus/* ======================================================================== * Copyright 1988-2006 University of Washington * * Licensed under the Apache License, Version 2.0 (the "License"); * you may not use this file except in compliance with the License. * You may obtain a copy of the License at * * http://www.apache.org/licenses/LICENSE-2.0 * * * ======================================================================== */ /* * Program: Operating-system dependent routines -- OSF/Digital UNIX/Tru64 * * Author: Mark Crispin * Networks and Distributed Computing * Computing & Communications * University of Washington * Administration Building, AG-44 * Seattle, WA 98195 * Internet: MRC@CAC.Washington.EDU * * Date: 1 August 1988 * Last Edited: 30 August 2006 */ #include #include #include #include #include #include /* for struct tm */ #include #include #include /* OSF/1 gets this wrong */ #define setpgrp setpgid #define direct dirent #include "env_unix.h" #include "fs.h" #include "ftl.h" #include "nl.h" #include "tcp.h" #include "flocksim.h" alpine-2.10+dfsg/imap/src/osdep/unix/os_nto.h0000600000175000017500000000322011512502123022614 0ustar paulproteuspaulproteus/* ======================================================================== * Copyright 1988-2006 University of Washington * * Licensed under the Apache License, Version 2.0 (the "License"); * you may not use this file except in compliance with the License. * You may obtain a copy of the License at * * http://www.apache.org/licenses/LICENSE-2.0 * * * ======================================================================== */ /* * Program: Operating-system dependent routines -- QNX Neutrino RTP version * * Author: Mark Crispin * Networks and Distributed Computing * Computing & Communications * University of Washington * Administration Building, AG-44 * Seattle, WA 98195 * Internet: MRC@CAC.Washington.EDU * * Date: 10 September 1993 * Last Edited: 30 August 2006 */ #include #include #include #include #include #include #include #include #include #include /* QNX gets these wrong */ #define setpgrp setpgid #define readdir Readdir #define FNDELAY O_NONBLOCK #define d_ino d_fileno /* Different names, equivalent things in BSD and SysV */ #ifndef L_SET #define L_SET SEEK_SET #endif #ifndef L_INCR #define L_INCR SEEK_CUR #endif #ifndef L_XTND #define L_XTND SEEK_END #endif #define utime portable_utime int portable_utime (char *file,time_t timep[2]); long gethostid (void); struct direct *Readdir (DIR *dirp); typedef int (*select_t) (struct direct *name); typedef int (*compar_t) (void *d1,void *d2); #include "env_unix.h" #include "fs.h" #include "ftl.h" #include "nl.h" #include "tcp.h" #include "flocksim.h" alpine-2.10+dfsg/imap/src/osdep/unix/os_s40.h0000600000175000017500000000167511512502123022436 0ustar paulproteuspaulproteus/* ======================================================================== * Copyright 1988-2006 University of Washington * * Licensed under the Apache License, Version 2.0 (the "License"); * you may not use this file except in compliance with the License. * You may obtain a copy of the License at * * http://www.apache.org/licenses/LICENSE-2.0 * * * ======================================================================== */ /* * Program: Operating-system dependent routines -- SUN-OS 4.0 version * * Author: Mark Crispin * Networks and Distributed Computing * Computing & Communications * University of Washington * Administration Building, AG-44 * Seattle, WA 98195 * Internet: MRC@CAC.Washington.EDU * * Date: 11 May 1989 * Last Edited: 30 August 2006 */ void *malloc (size_t byteSize); void free (void *ptr); void *realloc (void *oldptr,size_t newsize); #include "os_sun.h" /* now use regular SUN-OS file */ alpine-2.10+dfsg/imap/src/osdep/unix/os_nxt.h0000600000175000017500000000227311512502123022634 0ustar paulproteuspaulproteus/* ======================================================================== * Copyright 1988-2007 University of Washington * * Licensed under the Apache License, Version 2.0 (the "License"); * you may not use this file except in compliance with the License. * You may obtain a copy of the License at * * http://www.apache.org/licenses/LICENSE-2.0 * * * ======================================================================== */ /* * Program: Operating-system dependent routines -- NeXT version * * Author: Mark Crispin * Networks and Distributed Computing * Computing & Communications * University of Washington * Administration Building, AG-44 * Seattle, WA 98195 * Internet: MRC@CAC.Washington.EDU * * Date: 1 August 1988 * Last Edited: 30 January 2007 */ #include #include #include #include #include #include #include #include /* Use ours instead of theirs */ #define strtok STRTOK #define strtok_r STRTOK_R char *strtok (char *s,char *ct); char *strtok_r (char *s,char *ct,char **r); #include "env_unix.h" #include "fs.h" #include "ftl.h" #include "nl.h" #include "tcp.h" alpine-2.10+dfsg/imap/src/osdep/unix/tcp_unix.h0000600000175000017500000000231011512502123023143 0ustar paulproteuspaulproteus/* ======================================================================== * Copyright 1988-2006 University of Washington * * Licensed under the Apache License, Version 2.0 (the "License"); * you may not use this file except in compliance with the License. * You may obtain a copy of the License at * * http://www.apache.org/licenses/LICENSE-2.0 * * * ======================================================================== */ /* * Program: UNIX TCP/IP routines * * Author: Mark Crispin * Networks and Distributed Computing * Computing & Communications * University of Washington * Administration Building, AG-44 * Seattle, WA 98195 * Internet: MRC@CAC.Washington.EDU * * Date: 1 August 1988 * Last Edited: 30 August 2006 */ /* TCP input buffer */ #define BUFLEN 8192 /* TCP I/O stream */ #define TCPSTREAM struct tcp_stream TCPSTREAM { char *host; /* host name */ unsigned long port; /* port number */ char *localhost; /* local host name */ char *remotehost; /* remote host name */ int tcpsi; /* input socket */ int tcpso; /* output socket */ int ictr; /* input counter */ char *iptr; /* input pointer */ char ibuf[BUFLEN]; /* input buffer */ }; alpine-2.10+dfsg/imap/src/osdep/unix/os_qnx.h0000600000175000017500000000265411512502123022634 0ustar paulproteuspaulproteus/* ======================================================================== * Copyright 1988-2006 University of Washington * * Licensed under the Apache License, Version 2.0 (the "License"); * you may not use this file except in compliance with the License. * You may obtain a copy of the License at * * http://www.apache.org/licenses/LICENSE-2.0 * * * ======================================================================== */ /* * Program: Operating-system dependent routines -- QNX version * * Author: Mark Crispin * Networks and Distributed Computing * Computing & Communications * University of Washington * Administration Building, AG-44 * Seattle, WA 98195 * Internet: MRC@CAC.Washington.EDU * * Date: 10 September 1993 * Last Edited: 20 December 2006 */ #include #include #include #include #include #include #include #include #include #include #include #include /* QNX gets these wrong */ #define setpgrp setpgid #define readdir Readdir #define FNDELAY O_NONBLOCK #define d_ino d_fileno typedef int (*select_t) (struct direct *name); typedef int (*compar_t) (void *d1,void *d2); #include "env_unix.h" #include "fs.h" #include "ftl.h" #include "nl.h" #include "tcp.h" long gethostid(void); struct direct *Readdir (DIR *dirp); extern long random (void); alpine-2.10+dfsg/imap/src/osdep/unix/ckp_afs.c0000600000175000017500000000354111512502123022722 0ustar paulproteuspaulproteus/* ======================================================================== * Copyright 1988-2006 University of Washington * * Licensed under the Apache License, Version 2.0 (the "License"); * you may not use this file except in compliance with the License. * You may obtain a copy of the License at * * http://www.apache.org/licenses/LICENSE-2.0 * * * ======================================================================== */ /* * Program: AFS check password * * Author: Mark Crispin * Networks and Distributed Computing * Computing & Communications * University of Washington * Administration Building, AG-44 * Seattle, WA 98195 * Internet: MRC@CAC.Washington.EDU * * Date: 1 August 1988 * Last Edited: 30 August 2006 */ /* AFS cleanup * Accepts: data */ void checkpw_cleanup (void *data) { ktc_ForgetAllTokens (); } /* Check password * Accepts: login passwd struct * password string * argument count * argument vector * Returns: passwd struct if password validated, NIL otherwise */ #undef INIT #define min AFS_MIN #define max AFS_MAX #include #include struct passwd *checkpw (struct passwd *pw,char *pass,int argc,char *argv[]) { char *reason; /* faster validation for POP servers */ if (!strcmp ((char *) mail_parameters (NIL,GET_SERVICENAME,NIL),"pop")) { struct ktc_encryptionKey key; struct ktc_token token; /* just check the password */ ka_StringToKey (pass,NIL,&key); if (ka_GetAdminToken (pw->pw_name,"","",&key,600,&token,1)) return NIL; } /* check password and get AFS token */ else if (ka_UserAuthenticateGeneral (KA_USERAUTH_VERSION + KA_USERAUTH_DOSETPAG,pw->pw_name,NIL,NIL, pass,0,0,0,&reason)) return NIL; /* arm hook to delete credentials */ mail_parameters (NIL,SET_LOGOUTHOOK,(void *) checkpw_cleanup); return pw; } alpine-2.10+dfsg/imap/src/osdep/unix/os_ult.h0000600000175000017500000000201411512502123022620 0ustar paulproteuspaulproteus/* ======================================================================== * Copyright 1988-2006 University of Washington * * Licensed under the Apache License, Version 2.0 (the "License"); * you may not use this file except in compliance with the License. * You may obtain a copy of the License at * * http://www.apache.org/licenses/LICENSE-2.0 * * * ======================================================================== */ /* * Program: Operating-system dependent routines -- Ultrix version * * Author: Mark Crispin * Networks and Distributed Computing * Computing & Communications * University of Washington * Administration Building, AG-44 * Seattle, WA 98195 * Internet: MRC@CAC.Washington.EDU * * Date: 11 May 1989 * Last Edited: 30 August 2006 */ #include #include #include #include #include #include #include #include "env_unix.h" #include "fs.h" #include "ftl.h" #include "nl.h" #include "tcp.h" alpine-2.10+dfsg/imap/src/osdep/unix/os_art.c0000600000175000017500000000420111512502123022575 0ustar paulproteuspaulproteus/* ======================================================================== * Copyright 1988-2006 University of Washington * * Licensed under the Apache License, Version 2.0 (the "License"); * you may not use this file except in compliance with the License. * You may obtain a copy of the License at * * http://www.apache.org/licenses/LICENSE-2.0 * * * ======================================================================== */ /* * Program: Operating-system dependent routines -- AIX/RT version * * Author: Mark Crispin * Networks and Distributed Computing * Computing & Communications * University of Washington * Administration Building, AG-44 * Seattle, WA 98195 * Internet: MRC@CAC.Washington.EDU * * Date: 10 April 1992 * Last Edited: 30 August 2006 */ #include "tcp_unix.h" /* must be before osdep includes tcp.h */ #include "mail.h" #include "osdep.h" #include #include #include #include #include #include #include extern int errno; #include #include #include #define KERNEL #include #undef KERNEL #include "misc.h" #define DIR_SIZE(d) sizeof (DIR) extern int sys_nerr; extern char *sys_errlist[]; #define toint(c) ((c)-'0') #define isodigit(c) (((unsigned)(c)>=060)&((unsigned)(c)<=067)) #define NBBY 8 /* number of bits in a byte */ #define FD_SETSIZE 256 typedef long fd_mask; #define NFDBITS (sizeof(fd_mask) * NBBY) /* bits per mask */ #define howmany(x, y) (((x)+((y)-1))/(y)) typedef struct fd_set { fd_mask fds_bits[howmany(FD_SETSIZE, NFDBITS)]; } fd_set; #define FD_SET(n, p) ((p)->fds_bits[(n)/NFDBITS] |= \ (1 << ((n) % NFDBITS))) #define FD_CLR(n, p) ((p)->fds_bits[(n)/NFDBITS] &= \ ~(1 << ((n) % NFDBITS))) #define FD_ISSET(n, p) ((p)->fds_bits[(n)/NFDBITS] & \ (1 << ((n) % NFDBITS))) #define FD_ZERO(p) bzero((char *)(p), sizeof(*(p))) #include "fs_unix.c" #include "ftl_unix.c" #include "nl_unix.c" #include "env_unix.c" #include "tcp_unix.c" #include "gr_wait.c" #include "flocksim.c" #include "memmove2.c" #include "strerror.c" #include "tz_sv4.c" alpine-2.10+dfsg/imap/src/osdep/unix/os_mct.c0000600000175000017500000000244711512502123022604 0ustar paulproteuspaulproteus/* ======================================================================== * Copyright 1988-2006 University of Washington * * Licensed under the Apache License, Version 2.0 (the "License"); * you may not use this file except in compliance with the License. * You may obtain a copy of the License at * * http://www.apache.org/licenses/LICENSE-2.0 * * * ======================================================================== */ /* * Program: Operating-system dependent routines -- MachTen version * * Author: Mark Crispin * Networks and Distributed Computing * Computing & Communications * University of Washington * Administration Building, AG-44 * Seattle, WA 98195 * Internet: MRC@CAC.Washington.EDU * * Date: 1 August 1988 * Last Edited: 7 December 2006 */ #include "tcp_unix.h" /* must be before osdep includes tcp.h */ #include "mail.h" #include "osdep.h" #include #include #include #include #include #include #include #include #include extern int errno; /* just in case */ #include #include "misc.h" #include "fs_unix.c" #include "ftl_unix.c" #include "nl_unix.c" #include "env_unix.c" #include "tcp_unix.c" #include "gr_wait4.c" #include "tz_bsd.c" alpine-2.10+dfsg/imap/src/osdep/unix/os_do4.h0000600000175000017500000000235511512502123022512 0ustar paulproteuspaulproteus/* ======================================================================== * Copyright 1988-2006 University of Washington * * Licensed under the Apache License, Version 2.0 (the "License"); * you may not use this file except in compliance with the License. * You may obtain a copy of the License at * * http://www.apache.org/licenses/LICENSE-2.0 * * * ======================================================================== */ /* * Program: Operating-system dependent routines -- Apollo Domain/OS sr10.4 * * Author: Mark Crispin * Networks and Distributed Computing * Computing & Communications * University of Washington * Administration Building, AG-44 * Seattle, WA 98195 * Internet: MRC@CAC.Washington.EDU * * Date: 11 May 1989 * Last Edited: 30 August 2006 */ #include #include #include #include #include #include #include #ifndef htons #include /* needed for htons() prototypes */ #endif extern int daylight; /* local timzone uses daylight savings time */ extern long altzone; /* seconds west of UTC during daylight time */ #include "env_unix.h" #include "fs.h" #include "ftl.h" #include "nl.h" #include "tcp.h" alpine-2.10+dfsg/imap/src/osdep/unix/crx_std.c0000600000175000017500000000232611512502123022762 0ustar paulproteuspaulproteus/* ======================================================================== * Copyright 1988-2006 University of Washington * * Licensed under the Apache License, Version 2.0 (the "License"); * you may not use this file except in compliance with the License. * You may obtain a copy of the License at * * http://www.apache.org/licenses/LICENSE-2.0 * * * ======================================================================== */ /* * Program: Exclusive create of a file * * Author: Mark Crispin * Networks and Distributed Computing * Computing & Communications * University of Washington * Administration Building, AG-44 * Seattle, WA 98195 * Internet: MRC@CAC.Washington.EDU * * Date: 17 December 1999 * Last Edited: 30 August 2006 */ /* Exclusive create of a file * Accepts: file name * Return: T if success, NIL if failed, -1 if retry */ long crexcl (char *name) { int i; int mask = umask (0); long ret = LONGT; /* try to get the lock */ if ((i = open (name,O_WRONLY|O_CREAT|O_EXCL,(int) shlock_mode)) < 0) ret = (errno == EEXIST) ? -1 : NIL; else close (i); /* made the file, now close it */ umask (mask); /* restore previous mask */ return LONGT; /* success */ } alpine-2.10+dfsg/imap/src/osdep/unix/pseudo.h0000600000175000017500000000150611512502123022617 0ustar paulproteuspaulproteus/* ======================================================================== * Copyright 1988-2006 University of Washington * * Licensed under the Apache License, Version 2.0 (the "License"); * you may not use this file except in compliance with the License. * You may obtain a copy of the License at * * http://www.apache.org/licenses/LICENSE-2.0 * * * ======================================================================== */ /* * Program: Pseudo Header Strings * * Author: Mark Crispin * Networks and Distributed Computing * Computing & Communications * University of Washington * Administration Building, AG-44 * Seattle, WA 98195 * Internet: MRC@CAC.Washington.EDU * * Date: 26 September 1996 * Last Edited: 30 August 2006 */ extern char *pseudo_from,*pseudo_name,*pseudo_subject,*pseudo_msg; alpine-2.10+dfsg/imap/src/osdep/unix/ckp_std.c0000600000175000017500000000223711512502123022744 0ustar paulproteuspaulproteus/* ======================================================================== * Copyright 1988-2006 University of Washington * * Licensed under the Apache License, Version 2.0 (the "License"); * you may not use this file except in compliance with the License. * You may obtain a copy of the License at * * http://www.apache.org/licenses/LICENSE-2.0 * * * ======================================================================== */ /* * Program: Standard check password * * Author: Mark Crispin * Networks and Distributed Computing * Computing & Communications * University of Washington * Administration Building, AG-44 * Seattle, WA 98195 * Internet: MRC@CAC.Washington.EDU * * Date: 1 August 1988 * Last Edited: 30 August 2006 */ /* Check password * Accepts: login passwd struct * password string * argument count * argument vector * Returns: passwd struct if password validated, NIL otherwise */ struct passwd *checkpw (struct passwd *pw,char *pass,int argc,char *argv[]) { return (pw->pw_passwd && pw->pw_passwd[0] && pw->pw_passwd[1] && !strcmp (pw->pw_passwd,(char *) crypt (pass,pw->pw_passwd))) ? pw : NIL; } alpine-2.10+dfsg/imap/src/osdep/unix/flocksim.c0000600000175000017500000007033311512502123023126 0ustar paulproteuspaulproteus/* ======================================================================== * Copyright 1988-2007 University of Washington * * Licensed under the Apache License, Version 2.0 (the "License"); * you may not use this file except in compliance with the License. * You may obtain a copy of the License at * * http://www.apache.org/licenses/LICENSE-2.0 * * * ======================================================================== */ /* * Program: flock emulation via fcntl() locking * * Author: Mark Crispin * Networks and Distributed Computing * Computing & Communications * University of Washington * Administration Building, AG-44 * Seattle, WA 98195 * Internet: MRC@CAC.Washington.EDU * * Date: 10 April 2001 * Last Edited: 11 October 2007 */ #undef flock /* name is used as a struct for fcntl */ #ifndef NOFSTATVFS /* thank you, SUN. NOT! */ # ifndef NOFSTATVFS64 # ifndef _LARGEFILE64_SOURCE # define _LARGEFILE64_SOURCE # endif /* _LARGEFILE64_SOURCE */ # endif /* NOFSTATVFFS64 */ #include #endif /* NOFSTATVFS */ #ifndef NSIG /* don't know if this can happen */ #define NSIG 32 /* a common maximum */ #endif /* Emulator for flock() call * Accepts: file descriptor * operation bitmask * Returns: 0 if successful, -1 if failure under BSD conditions */ int flocksim (int fd,int op) { char tmp[MAILTMPLEN]; int logged = 0; struct stat sbuf; struct ustat usbuf; struct flock fl; /* lock zero bytes at byte 0 */ fl.l_whence = SEEK_SET; fl.l_start = fl.l_len = 0; fl.l_pid = getpid (); /* shouldn't be necessary */ switch (op & ~LOCK_NB) { /* translate to fcntl() operation */ case LOCK_EX: /* exclusive */ fl.l_type = F_WRLCK; break; case LOCK_SH: /* shared */ fl.l_type = F_RDLCK; break; case LOCK_UN: /* unlock */ fl.l_type = F_UNLCK; break; default: /* default */ errno = EINVAL; return -1; } /* always return success if disabled */ if (mail_parameters (NIL,GET_DISABLEFCNTLLOCK,NIL)) return 0; /* Make fcntl() locking of NFS files be a no-op the way it is with flock() * on BSD. This is because the rpc.statd/rpc.lockd daemons don't work very * well and cause cluster-wide hangs if you exercise them at all. The * result of this is that you lose the ability to detect shared mail_open() * on NFS-mounted files. If you are wise, you'll use IMAP instead of NFS * for mail files. * * Sun alleges that it doesn't matter, and that they have fixed all the * rpc.statd/rpc.lockd bugs. As of October 2006, that is still false. * * We need three tests for three major historical variants in SVR4: * 1) In NFSv2, ustat() would return -1 in f_tinode for NFS. * 2) When fstatvfs() was introduced with NFSv3, ustat() was "fixed". * 3) When 64-bit filesystems were introduced, fstatvfs() would return * EOVERFLOW; you have to use fstatvfs64() even though you don't care * about any of the affected values. * * We can't use fstatfs() because fstatfs(): * . is documented as being deprecated in SVR4. * . has inconsistent calling conventions (there are two additional int * arguments on Solaris and I don't know what they do). * . returns inconsistent statfs structs. On Solaris, the file system type * is a short called f_fstyp. On AIX, it's an int called f_type that is * documented as always being 0! * * For what it's worth, here's the scoop on fstatfs() elsewhere: * * On Linux, the file system type is a long called f_type that has a file * system type code. A different module (flocklnx.c) uses this because * some knothead "improved" flock() to return ENOLCK on NFS files instead * of being a successful no-op. This "improvement" apparently has been * reverted, but not before it got to many systems in the field. * * On BSD, it's a short called either f_otype or f_type that is documented * as always being zero. Fortunately, BSD has flock() the way it's supposed * to be, and none of this nonsense is necessary. */ if (!fstat (fd,&sbuf)) { /* no hope of working if can't fstat()! */ /* Any base type that begins with "nfs" or "afs" is considered to be a * network filesystem. */ #ifndef NOFSTATVFS struct statvfs vsbuf; #ifndef NOFSTATVFS64 struct statvfs64 vsbuf64; if (!fstatvfs64 (fd,&vsbuf64) && (vsbuf64.f_basetype[1] == 'f') && (vsbuf64.f_basetype[2] == 's') && ((vsbuf64.f_basetype[0] == 'n') || (vsbuf64.f_basetype[0] == 'a'))) return 0; #endif /* NOFSTATVFS64 */ if (!fstatvfs (fd,&vsbuf) && (vsbuf.f_basetype[1] == 'f') && (vsbuf.f_basetype[2] == 's') && ((vsbuf.f_basetype[0] == 'n') || (vsbuf.f_basetype[0] == 'a'))) return 0; #endif /* NOFSTATVFS */ if (!ustat (sbuf.st_dev,&usbuf) && !++usbuf.f_tinode) return 0; } /* do the lock */ while (fcntl (fd,(op & LOCK_NB) ? F_SETLK : F_SETLKW,&fl)) if (errno != EINTR) { /* Can't use switch here because these error codes may resolve to the * same value on some systems. */ if ((errno != EWOULDBLOCK) && (errno != EAGAIN) && (errno != EACCES)) { sprintf (tmp,"Unexpected file locking failure: %.100s", strerror (errno)); /* give the user a warning of what happened */ MM_NOTIFY (NIL,tmp,WARN); if (!logged++) syslog (LOG_ERR,"%s",tmp); if (op & LOCK_NB) return -1; sleep (5); /* slow things down for loops */ } /* return failure for non-blocking lock */ else if (op & LOCK_NB) return -1; } return 0; /* success */ } /* Master/slave procedures for safe fcntl() locking. * * The purpose of this nonsense is to work around a bad bug in fcntl() * locking. The cretins who designed it decided that a close() should * release any locks made by that process on the file opened on that * file descriptor. Never mind that the lock wasn't made on that file * descriptor, but rather on some other file descriptor. * * This bug is on every implementation of fcntl() locking that I have * tested. Fortunately, on BSD systems, OSF/1, and Linux, we can use the * flock() system call which doesn't have this bug. * * Note that OSF/1, Linux, and some BSD systems have both broken fcntl() * locking and the working flock() locking. * * The program below can be used to demonstrate this problem. Be sure to * let it run long enough for all the sleep() calls to finish. */ #if 0 #include #include #include #include #include #include main () { struct flock fl; int fd,fd2; char *file = "a.a"; if ((fd = creat (file,0666)) < 0) perror ("TEST FAILED: can't create test file"),_exit (errno); close (fd); if (fork ()) { /* parent */ if ((fd = open (file,O_RDWR,0)) < 0) abort(); /* lock applies to entire file */ fl.l_whence = fl.l_start = fl.l_len = 0; fl.l_pid = getpid (); /* shouldn't be necessary */ fl.l_type = F_RDLCK; if (fcntl (fd,F_SETLKW,&fl) == -1) abort (); sleep (5); if ((fd2 = open (file,O_RDWR,0)) < 0) abort (); sleep (1); puts ("parent test ready -- will hang here if locking works correctly"); close (fd2); wait (0); puts ("OS BUG: child terminated"); _exit (0); } else { /* child */ sleep (2); if ((fd = open (file,O_RDWR,0666)) < 0) abort (); puts ("child test ready -- child will hang if no bug"); /* lock applies to entire file */ fl.l_whence = fl.l_start = fl.l_len = 0; fl.l_pid = getpid (); /* shouldn't be necessary */ fl.l_type = F_WRLCK; if (fcntl (fd,F_SETLKW,&fl) == -1) abort (); puts ("OS BUG: child got lock"); } } #endif /* Beware of systems such as AIX which offer flock() as a compatibility * function that is just a jacket into fcntl() locking. The program below * is a variant of the program above, only using flock(). It can be used * to test to see if your system has real flock() or just a jacket into * fcntl(). * * Be sure to let it run long enough for all the sleep() calls to finish. * If the program hangs, then flock() works and you can dispense with the * use of this module (you lucky person!). */ #if 0 #include #include #include #include main () { int fd,fd2; char *file = "a.a"; if ((fd = creat (file,0666)) < 0) perror ("TEST FAILED: can't create test file"),_exit (errno); close (fd); if (fork ()) { /* parent */ if ((fd = open (file,O_RDWR,0)) < 0) abort(); if (flock (fd,LOCK_SH) == -1) abort (); sleep (5); if ((fd2 = open (file,O_RDWR,0)) < 0) abort (); sleep (1); puts ("parent test ready -- will hang here if flock() works correctly"); close (fd2); wait (0); puts ("OS BUG: child terminated"); _exit (0); } else { /* child */ sleep (2); if ((fd = open (file,O_RDWR,0666)) < 0) abort (); puts ("child test ready -- child will hang if no bug"); if (flock (fd,LOCK_EX) == -1) abort (); puts ("OS BUG: child got lock"); } } #endif /* Master/slave details * * On broken systems, we invoke an inferior fork to execute any driver * dispatches which are likely to tickle this bug; specifically, any * dispatch which may fiddle with a mailbox that is already selected. As * of this writing, these are: delete, rename, status, scan, copy, and append. * * Delete and rename are pretty marginal, yet there are certain clients * (e.g. Outlook Express) that really want to delete or rename the selected * mailbox. The same is true of status, but there are people (such as the * authors of Entourage) who don't understand why status of the selected * mailbox is bad news. * * However, in copy and append it is reasonable to do this to a selected * mailbox. Although scanning the selected mailbox isn't particularly * sensible, it's hard to avoid due to wildcards. * * It is still possible for an application to trigger the bug by doing * mail_open() on the same mailbox twice. Don't do it. * * Once the slave is invoked, the master only has to read events from the * slave's output (see below for these events) and translate these events * to the appropriate c-client callback. When end of file occurs on the pipe, * the master reads the slave's exit status and uses that as the function * return. The append master is slightly more complicated because it has to * send data back to the slave (see below). * * The slave takes callback events from the driver which otherwise would * pass to the main program. Only those events which a slave can actually * encounter are covered here; for example mm_searched() and mm_list() are * not covered since a slave never does the operations that trigger these. * Certain other events (mm_exists(), mm_expunged(), mm_flags()) are discarded * by the slave since the master will generate these events for itself. * * The other events cause the slave to write a newline-terminated string to * its output. The first character of string indicates the event: S for * mm_status(), N for mm_notify(), L for mm_log(), C for mm_critical(), X for * mm_nocritical(), D for mm_diskerror(), F for mm_fatal(), and "A" for append * argument callback. Most of these events also carry data, which carried as * text space-delimited in the string. * * Append argument callback requires the master to provide the slave with * data in the slave's input. The first thing that the master provides is * either a "+" (master has data for the slave) or a "-" (master has no data). * If the master has data, it will then send the flags, internal date, and * message text, each as . */ /* It should be alright for lockslavep to be a global, since it will always * be zero in the master (which is where threads would be). The slave won't * ever thread, since any driver which threads in its methods probably can't * use fcntl() locking so won't have DR_LOCKING in its driver flags * * lockslavep can not be a static, since it's used by the dispatch macros. */ int lockslavep = 0; /* non-zero means slave process for locking */ static int lockproxycopy = 0; /* non-zero means redo copy as proxy */ FILE *slavein = NIL; /* slave input */ FILE *slaveout = NIL; /* slave output */ /* Common master * Accepts: permitted stream * append callback (append calls only, else NIL) * data for callback (append calls only, else NIL) * Returns: (master) T if slave succeeded, NIL if slave failed * (slave) NIL always, with lockslavep non-NIL */ static long master (MAILSTREAM *stream,append_t af,void *data) { MAILSTREAM *st; MAILSTATUS status; STRING *message; FILE *pi,*po; blocknotify_t bn = (blocknotify_t) mail_parameters (NIL,GET_BLOCKNOTIFY,NIL); long ret = NIL; unsigned long i,j; int c,pid,pipei[2],pipeo[2]; char *s,*t,event[MAILTMPLEN],tmp[MAILTMPLEN]; lockproxycopy = NIL; /* not doing a lock proxycopy */ /* make pipe from slave */ if (pipe (pipei) < 0) mm_log ("Can't create input pipe",ERROR); else if (pipe (pipeo) < 0) { mm_log ("Can't create output pipe",ERROR); close (pipei[0]); close (pipei[1]); } else if ((pid = fork ()) < 0) {/* make slave */ mm_log ("Can't create execution process",ERROR); close (pipei[0]); close (pipei[1]); close (pipeo[0]); close (pipeo[1]); } else if (lockslavep = !pid) { /* are we slave or master? */ alarm (0); /* slave doesn't have alarms or signals */ for (c = 0; c < NSIG; c++) signal (c,SIG_DFL); if (!(slavein = fdopen (pipeo[0],"r")) || !(slaveout = fdopen (pipei[1],"w"))) fatal ("Can't do slave pipe buffered I/O"); close (pipei[0]); /* close parent's side of the pipes */ close (pipeo[1]); } else { /* master process */ void *blockdata = (*bn) (BLOCK_SENSITIVE,NIL); close (pipei[1]); /* close slave's side of the pipes */ close (pipeo[0]); if (!(pi = fdopen (pipei[0],"r")) || !(po = fdopen (pipeo[1],"w"))) fatal ("Can't do master pipe buffered I/O"); /* do slave events until EOF */ /* read event */ while (fgets (event,MAILTMPLEN-1,pi)) { if (!(s = strchr (event,'\n'))) { sprintf (tmp,"Execution process event string too long: %.500s",event); fatal (tmp); } *s = '\0'; /* tie off event at end of line */ switch (event[0]) { /* analyze event */ case 'A': /* append callback */ if ((*af) (NIL,data,&s,&t,&message)) { if (i = message ? SIZE (message) : 0) { if (!s) s = ""; /* default values */ if (!t) t = ""; } else s = t = ""; /* no flags or date if no message */ errno = NIL; /* reset last error */ /* build response */ if (fprintf (po,"+%lu %s%lu %s%lu ",strlen (s),s,strlen (t),t,i) < 0) fatal ("Failed to pipe append command"); /* write message text */ if (i) do if (putc (c = 0xff & SNX (message),po) == EOF) { sprintf (tmp,"Failed to pipe %lu bytes (of %lu), last=%u: %.100s", i,message->size,c,strerror (errno)); fatal (tmp); } while (--i); } else putc ('-',po); /* append error */ fflush (po); break; case '&': /* slave wants a proxycopy? */ lockproxycopy = T; break; case 'L': /* mm_log() */ i = strtoul (event+1,&s,10); if (!s || (*s++ != ' ')) { sprintf (tmp,"Invalid log event arguments: %.500s",event); fatal (tmp); } mm_log (s,i); break; case 'N': /* mm_notify() */ st = (MAILSTREAM *) strtoul (event+1,&s,16); if (s && (*s++ == ' ')) { i = strtoul (s,&s,10);/* get severity */ if (s && (*s++ == ' ')) { mm_notify ((st == stream) ? stream : NIL,s,i); break; } } sprintf (tmp,"Invalid notify event arguments: %.500s",event); fatal (tmp); case 'S': /* mm_status() */ st = (MAILSTREAM *) strtoul (event+1,&s,16); if (s && (*s++ == ' ')) { status.flags = strtoul (s,&s,10); if (s && (*s++ == ' ')) { status.messages = strtoul (s,&s,10); if (s && (*s++ == ' ')) { status.recent = strtoul (s,&s,10); if (s && (*s++ == ' ')) { status.unseen = strtoul (s,&s,10); if (s && (*s++ == ' ')) { status.uidnext = strtoul (s,&s,10); if (s && (*s++ == ' ')) { status.uidvalidity = strtoul (s,&s,10); if (s && (*s++ == ' ')) { mm_status ((st == stream) ? stream : NIL,s,&status); break; } } } } } } } sprintf (tmp,"Invalid status event arguments: %.500s",event); fatal (tmp); case 'C': /* mm_critical() */ st = (MAILSTREAM *) strtoul (event+1,&s,16); mm_critical ((st == stream) ? stream : NIL); break; case 'X': /* mm_nocritical() */ st = (MAILSTREAM *) strtoul (event+1,&s,16); mm_nocritical ((st == stream) ? stream : NIL); break; case 'D': /* mm_diskerror() */ st = (MAILSTREAM *) strtoul (event+1,&s,16); if (s && (*s++ == ' ')) { i = strtoul (s,&s,10); if (s && (*s++ == ' ')) { j = (long) strtoul (s,NIL,10); if (st == stream) /* let's hope it's on usable stream */ putc (mm_diskerror (stream,(long) i,j) ? '+' : '-',po); else if (j) { /* serious diskerror on slave-created stream */ mm_log ("Retrying disk write to avoid mailbox corruption!",WARN); sleep (5); /* give some time for it to clear up */ putc ('-',po); /* don't abort */ } else { /* recoverable on slave-created stream */ mm_log ("Error on disk write",ERROR); putc ('+',po); /* so abort it */ } fflush (po); /* force it out either way */ break; } } sprintf (tmp,"Invalid diskerror event arguments: %.500s",event); fatal (tmp); case 'F': /* mm_fatal() */ mm_fatal (event+1); break; default: /* random lossage */ sprintf (tmp,"Unknown event from execution process: %.500s",event); fatal (tmp); } } fclose (pi); fclose (po); /* done with the pipes */ /* get slave status */ grim_pid_reap_status (pid,NIL,&ret); if (ret & 0177) { /* signal or stopped */ sprintf (tmp,"Execution process terminated abnormally (%lx)",ret); mm_log (tmp,ERROR); ret = NIL; } else ret >>= 8; /* return exit code */ (*bn) (BLOCK_NONSENSITIVE,blockdata); } return ret; /* return status */ } /* Safe driver calls */ /* Safely delete mailbox * Accepts: driver to call under slave * MAIL stream * mailbox name to delete * Returns: T on success, NIL on failure */ long safe_delete (DRIVER *dtb,MAILSTREAM *stream,char *mbx) { long ret = master (stream,NIL,NIL); if (lockslavep) exit ((*dtb->mbxdel) (stream,mbx)); return ret; } /* Safely rename mailbox * Accepts: driver to call under slave * MAIL stream * old mailbox name * new mailbox name (or NIL for delete) * Returns: T on success, NIL on failure */ long safe_rename (DRIVER *dtb,MAILSTREAM *stream,char *old,char *newname) { long ret = master (stream,NIL,NIL); if (lockslavep) exit ((*dtb->mbxren) (stream,old,newname)); return ret; } /* Safely get status of mailbox * Accepts: driver to call under slave * MAIL stream * mailbox name * status flags * Returns: T on success, NIL on failure */ long safe_status (DRIVER *dtb,MAILSTREAM *stream,char *mbx,long flags) { long ret = master (stream,NIL,NIL); if (lockslavep) exit ((*dtb->status) (stream,mbx,flags)); return ret; } /* Scan file for contents * Accepts: driver to call under slave * file name * desired contents * length of contents * length of file * Returns: NIL if contents not found, T if found */ long safe_scan_contents (DRIVER *dtb,char *name,char *contents, unsigned long csiz,unsigned long fsiz) { long ret = master (NIL,NIL,NIL); if (lockslavep) exit (scan_contents (dtb,name,contents,csiz,fsiz)); return ret; } /* Safely copy message to mailbox * Accepts: driver to call under slave * MAIL stream * sequence * destination mailbox * copy options * Returns: T if success, NIL if failed */ long safe_copy (DRIVER *dtb,MAILSTREAM *stream,char *seq,char *mbx,long flags) { mailproxycopy_t pc = (mailproxycopy_t) mail_parameters (stream,GET_MAILPROXYCOPY,NIL); long ret = master (stream,NIL,NIL); if (lockslavep) { /* don't do proxycopy in slave */ if (pc) mail_parameters (stream,SET_MAILPROXYCOPY,(void *) slaveproxycopy); exit ((*dtb->copy) (stream,seq,mbx,flags)); } /* do any proxycopy in master */ if (lockproxycopy && pc) return (*pc) (stream,seq,mbx,flags); return ret; } /* Append package for slave */ typedef struct append_data { int first; /* flag indicating first message */ char *flags; /* message flags */ char *date; /* message date */ char *msg; /* message text */ STRING message; /* message stringstruct */ } APPENDDATA; /* Safely append message to mailbox * Accepts: driver to call under slave * MAIL stream * destination mailbox * append callback * data for callback * Returns: T if append successful, else NIL */ long safe_append (DRIVER *dtb,MAILSTREAM *stream,char *mbx,append_t af, void *data) { long ret = master (stream,af,data); if (lockslavep) { APPENDDATA ad; ad.first = T; /* initialize initial append package */ ad.flags = ad.date = ad.msg = NIL; exit ((*dtb->append) (stream,mbx,slave_append,&ad)); } return ret; } /* Slave callbacks */ /* Message exists (i.e. there are that many messages in the mailbox) * Accepts: MAIL stream * message number */ void slave_exists (MAILSTREAM *stream,unsigned long number) { /* this event never passed by slaves */ } /* Message expunged * Accepts: MAIL stream * message number */ void slave_expunged (MAILSTREAM *stream,unsigned long number) { /* this event never passed by slaves */ } /* Message status changed * Accepts: MAIL stream * message number */ void slave_flags (MAILSTREAM *stream,unsigned long number) { /* this event never passed by slaves */ } /* Mailbox status * Accepts: MAIL stream * mailbox name * mailbox status */ void slave_status (MAILSTREAM *stream,char *mailbox,MAILSTATUS *status) { int i,c; fprintf (slaveout,"S%lx %lu %lu %lu %lu %lu %lu ", (unsigned long) stream,status->flags,status->messages,status->recent, status->unseen,status->uidnext,status->uidvalidity,mailbox); /* yow! are we paranoid enough yet? */ for (i = 0; (i < 500) && (c = *mailbox++); ++i) switch (c) { case '\r': case '\n': /* newline in a mailbox name? */ c = ' '; default: putc (c,slaveout); } putc ('\n',slaveout); fflush (slaveout); } /* Notification event * Accepts: MAIL stream * string to log * error flag */ void slave_notify (MAILSTREAM *stream,char *string,long errflg) { int i,c; fprintf (slaveout,"N%lx %lu ",(unsigned long) stream,errflg); /* prevent more than 500 bytes */ for (i = 0; (i < 500) && (c = *string++); ++i) switch (c) { case '\r': case '\n': /* or embedded newline */ c = ' '; default: putc (c,slaveout); } putc ('\n',slaveout); fflush (slaveout); } /* Log an event for the user to see * Accepts: string to log * error flag */ void slave_log (char *string,long errflg) { int i,c; fprintf (slaveout,"L%lu ",errflg); /* prevent more than 500 bytes */ for (i = 0; (i < 500) && (c = *string++); ++i) switch (c) { case '\r': case '\n': /* or embedded newline */ c = ' '; default: putc (c,slaveout); } putc ('\n',slaveout); fflush (slaveout); } /* About to enter critical code * Accepts: stream */ void slave_critical (MAILSTREAM *stream) { fprintf (slaveout,"C%lx\n",(unsigned long) stream); fflush (slaveout); } /* About to exit critical code * Accepts: stream */ void slave_nocritical (MAILSTREAM *stream) { fprintf (slaveout,"X%lx\n",(unsigned long) stream); fflush (slaveout); } /* Disk error found * Accepts: stream * system error code * flag indicating that mailbox may be clobbered * Returns: abort flag */ long slave_diskerror (MAILSTREAM *stream,long errcode,long serious) { char tmp[MAILTMPLEN]; int c; long ret = NIL; fprintf (slaveout,"D%lx %lu %lu\n",(unsigned long) stream,errcode,serious); fflush (slaveout); switch (c = getc (slavein)) { case EOF: /* pipe broken */ slave_fatal ("Pipe broken reading diskerror response"); case '+': /* user wants to abort */ ret = LONGT; case '-': /* no abort */ break; default: sprintf (tmp,"Unknown master response for diskerror: %c",c); slave_fatal (tmp); } return ret; } /* Log a fatal error event * Accepts: string to log * Does not return */ void slave_fatal (char *string) { int i,c; syslog (LOG_ALERT,"IMAP toolkit slave process crash: %.500s",string); putc ('F',slaveout); /* prevent more than 500 bytes */ for (i = 0; (i < 500) && (c = *string++); ++i) switch (c) { case '\r': case '\n': /* newline in a mailbox name? */ c = ' '; default: putc (c,slaveout); } putc ('\n',slaveout); fflush (slaveout); abort (); /* die */ } /* Append read buffer * Accepts: number of bytes to read * error message if fails * Returns: read-in string */ static char *slave_append_read (unsigned long n,char *error) { #if 0 unsigned long i; #endif int c; char *t,tmp[MAILTMPLEN]; char *s = (char *) fs_get (n + 1); s[n] = '\0'; #if 0 /* This doesn't work on Solaris with GCC. I think that it's a C library * bug, since the problem only shows up if the application does fread() * on some other file */ for (t = s; n && ((i = fread (t,1,n,slavein)); t += i,n -= i); #else for (t = s; n && ((c = getc (slavein)) != EOF); *t++ = c,--n); #endif if (n) { sprintf(tmp,"Pipe broken reading %.100s with %lu bytes remaining",error,n); slave_fatal (tmp); } return s; } /* Append message callback * Accepts: MAIL stream * append data package * pointer to return initial flags * pointer to return message internal date * pointer to return stringstruct of message or NIL to stop * Returns: T if success (have message or stop), NIL if error */ long slave_append (MAILSTREAM *stream,void *data,char **flags,char **date, STRING **message) { char tmp[MAILTMPLEN]; unsigned long n; int c; APPENDDATA *ad = (APPENDDATA *) data; /* flush text of previous message */ if (ad->flags) fs_give ((void **) &ad->flags); if (ad->date) fs_give ((void **) &ad->date); if (ad->msg) fs_give ((void **) &ad->msg); *flags = *date = NIL; /* assume no flags or date */ fputs ("A\n",slaveout); /* tell master we're doing append callback */ fflush (slaveout); switch (c = getc (slavein)) { /* what did master say? */ case '+': /* have message, get size of flags */ for (n = 0; isdigit (c = getc (slavein)); n *= 10, n += (c - '0')); if (c != ' ') { if (c == EOF) sprintf (tmp,"Pipe broken after flag size %lu",n); sprintf (tmp,"Missing delimiter after flag size %lu: %c",n,c); slave_fatal (tmp); } if (n) *flags = ad->flags = slave_append_read (n,"flags"); /* get size of date */ for (n = 0; isdigit (c = getc (slavein)); n *= 10, n += (c - '0')); if (c != ' ') { if (c == EOF) sprintf (tmp,"Pipe broken after date size %lu",n); else sprintf (tmp,"Missing delimiter after date size %lu: %c",n,c); slave_fatal (tmp); } if (n) *date = ad->date = slave_append_read (n,"date"); /* get size of message */ for (n = 0; isdigit (c = getc (slavein)); n *= 10, n += (c - '0')); if (c != ' ') { if (c == EOF) sprintf (tmp,"Pipe broken after message size %lu",n); sprintf (tmp,"Missing delimiter after message size %lu: %c",n,c); slave_fatal (tmp); } if (n) { /* make buffer for message */ ad->msg = slave_append_read (n,"message"); /* initialize stringstruct */ INIT (&ad->message,mail_string,(void *) ad->msg,n); ad->first = NIL; /* no longer first message */ *message = &ad->message; /* return message */ } else *message = NIL; /* empty message */ return LONGT; case '-': /* error */ *message = NIL; /* set stop */ break; case EOF: /* end of file */ slave_fatal ("Pipe broken reading append response"); default: /* unknown event */ sprintf (tmp,"Unknown master response for append: %c",c); slave_fatal (tmp); } return NIL; /* return failure */ } /* Proxy copy across mailbox formats * Accepts: mail stream * sequence to copy on this stream * destination mailbox * option flags * Returns: T if success, else NIL */ long slaveproxycopy (MAILSTREAM *stream,char *sequence,char *mailbox, long options) { fputs ("&\n",slaveout); /* redo copy as append */ fflush (slaveout); return NIL; /* failure for now */ } alpine-2.10+dfsg/imap/src/osdep/unix/os_mct.h0000600000175000017500000000205711512502123022606 0ustar paulproteuspaulproteus/* ======================================================================== * Copyright 1988-2006 University of Washington * * Licensed under the Apache License, Version 2.0 (the "License"); * you may not use this file except in compliance with the License. * You may obtain a copy of the License at * * http://www.apache.org/licenses/LICENSE-2.0 * * * ======================================================================== */ /* * Program: Operating-system dependent routines -- MachTen version * * Author: Mark Crispin * Networks and Distributed Computing * Computing & Communications * University of Washington * Administration Building, AG-44 * Seattle, WA 98195 * Internet: MRC@CAC.Washington.EDU * * Date: 1 August 1988 * Last Edited: 7 December 2006 */ #include #include #include #include #include #include #include #include #define unix 1 #include "env_unix.h" #include "fs.h" #include "ftl.h" #include "nl.h" #include "tcp.h" alpine-2.10+dfsg/imap/src/osdep/unix/mix.c0000600000175000017500000027102011512502123022110 0ustar paulproteuspaulproteus/* ======================================================================== * Copyright 1988-2008 University of Washington * * Licensed under the Apache License, Version 2.0 (the "License"); * you may not use this file except in compliance with the License. * You may obtain a copy of the License at * * http://www.apache.org/licenses/LICENSE-2.0 * * * ======================================================================== */ /* * Program: MIX mail routines * * Author(s): Mark Crispin * UW Technology * University of Washington * Seattle, WA 98195 * Internet: MRC@Washington.EDU * * Date: 1 March 2006 * Last Edited: 7 May 2008 */ #include #include #include extern int errno; /* just in case */ #include "mail.h" #include "osdep.h" #include #include #include #include "misc.h" #include "dummy.h" #include "fdstring.h" /* MIX definitions */ #define MEGABYTE (1024*1024) #define MIXDATAROLL MEGABYTE /* size at which we roll to a new file */ /* MIX files */ #define MIXNAME ".mix" /* prefix for all MIX file names */ #define MIXMETA "meta" /* suffix for metadata */ #define MIXINDEX "index" /* suffix for index */ #define MIXSTATUS "status" /* suffix for status */ #define MIXSORTCACHE "sortcache"/* suffix for sortcache */ #define METAMAX (MEGABYTE-1) /* maximum metadata file size (sanity check) */ /* MIX file formats */ /* sequence format (all but msg files) */ #define SEQFMT "S%08lx\015\012" /* metadata file format */ #define MTAFMT "V%08lx\015\012L%08lx\015\012N%08lx\015\012" /* index file record format */ #define IXRFMT ":%08lx:%04d%02d%02d%02d%02d%02d%c%02d%02d:%08lx:%08lx:%08lx:%08lx:%08lx:\015\012" /* status file record format */ #define STRFMT ":%08lx:%08lx:%04x:%08lx:\015\012" /* message file header format */ #define MSRFMT "%s%08lx:%04d%02d%02d%02d%02d%02d%c%02d%02d:%08lx:\015\012" #define MSGTOK ":msg:" #define MSGTSZ (sizeof(MSGTOK)-1) /* sortcache file record format */ #define SCRFMT ":%08lx:%08lx:%08lx:%08lx:%08lx:%c%08lx:%08lx:%08lx:\015\012" /* MIX I/O stream local data */ typedef struct mix_local { unsigned long curmsg; /* current message file number */ unsigned long newmsg; /* current new message file number */ time_t lastsnarf; /* last snarf time */ int msgfd; /* file description of current msg file */ int mfd; /* file descriptor of open metadata */ unsigned long metaseq; /* metadata sequence */ char *index; /* mailbox index name */ unsigned long indexseq; /* index sequence */ char *status; /* mailbox status name */ unsigned long statusseq; /* status sequence */ char *sortcache; /* mailbox sortcache name */ unsigned long sortcacheseq; /* sortcache sequence */ unsigned char *buf; /* temporary buffer */ unsigned long buflen; /* current size of temporary buffer */ unsigned int expok : 1; /* non-zero if expunge reports OK */ unsigned int internal : 1; /* internally opened, do not validate */ } MIXLOCAL; #define MIXBURP struct mix_burp MIXBURP { unsigned long fileno; /* message file number */ char *name; /* message file name */ SEARCHSET *tail; /* tail of ranges */ SEARCHSET set; /* set of retained ranges */ MIXBURP *next; /* next file to burp */ }; /* Convenient access to local data */ #define LOCAL ((MIXLOCAL *) stream->local) /* Function prototypes */ DRIVER *mix_valid (char *name); long mix_isvalid (char *name,char *meta); void *mix_parameters (long function,void *value); long mix_dirfmttest (char *name); void mix_scan (MAILSTREAM *stream,char *ref,char *pat,char *contents); long mix_scan_contents (char *name,char *contents,unsigned long csiz, unsigned long fsiz); void mix_list (MAILSTREAM *stream,char *ref,char *pat); void mix_lsub (MAILSTREAM *stream,char *ref,char *pat); long mix_subscribe (MAILSTREAM *stream,char *mailbox); long mix_unsubscribe (MAILSTREAM *stream,char *mailbox); long mix_create (MAILSTREAM *stream,char *mailbox); long mix_delete (MAILSTREAM *stream,char *mailbox); long mix_rename (MAILSTREAM *stream,char *old,char *newname); int mix_rselect (struct direct *name); MAILSTREAM *mix_open (MAILSTREAM *stream); void mix_close (MAILSTREAM *stream,long options); void mix_abort (MAILSTREAM *stream); char *mix_header (MAILSTREAM *stream,unsigned long msgno,unsigned long *length, long flags); long mix_text (MAILSTREAM *stream,unsigned long msgno,STRING *bs,long flags); void mix_flag (MAILSTREAM *stream,char *sequence,char *flag,long flags); unsigned long *mix_sort (MAILSTREAM *stream,char *charset,SEARCHPGM *spg, SORTPGM *pgm,long flags); THREADNODE *mix_thread (MAILSTREAM *stream,char *type,char *charset, SEARCHPGM *spg,long flags); long mix_ping (MAILSTREAM *stream); void mix_check (MAILSTREAM *stream); long mix_expunge (MAILSTREAM *stream,char *sequence,long options); int mix_select (struct direct *name); int mix_msgfsort (const void *d1,const void *d2); long mix_addset (SEARCHSET **set,unsigned long start,unsigned long size); long mix_burp (MAILSTREAM *stream,MIXBURP *burp,unsigned long *reclaimed); long mix_burp_check (SEARCHSET *set,size_t size,char *file); long mix_copy (MAILSTREAM *stream,char *sequence,char *mailbox, long options); long mix_append (MAILSTREAM *stream,char *mailbox,append_t af,void *data); long mix_append_msg (MAILSTREAM *stream,FILE *f,char *flags,MESSAGECACHE *delt, STRING *msg,SEARCHSET *set,unsigned long seq); FILE *mix_parse (MAILSTREAM *stream,FILE **idxf,long iflags,long sflags); char *mix_meta_slurp (MAILSTREAM *stream,unsigned long *seq); long mix_meta_update (MAILSTREAM *stream); long mix_index_update (MAILSTREAM *stream,FILE *idxf,long flag); long mix_status_update (MAILSTREAM *stream,FILE *statf,long flag); FILE *mix_data_open (MAILSTREAM *stream,int *fd,long *size, unsigned long newsize); FILE *mix_sortcache_open (MAILSTREAM *stream); long mix_sortcache_update (MAILSTREAM *stream,FILE **sortcache); char *mix_read_record (FILE *f,char *buf,unsigned long buflen,char *type); unsigned long mix_read_sequence (FILE *f); char *mix_dir (char *dst,char *name); char *mix_file (char *dst,char *dir,char *name); char *mix_file_data (char *dst,char *dir,unsigned long data); unsigned long mix_modseq (unsigned long oldseq); /* MIX mail routines */ /* Driver dispatch used by MAIL */ DRIVER mixdriver = { "mix", /* driver name */ /* driver flags */ DR_MAIL|DR_LOCAL|DR_NOFAST|DR_CRLF|DR_LOCKING|DR_DIRFMT|DR_MODSEQ, (DRIVER *) NIL, /* next driver */ mix_valid, /* mailbox is valid for us */ mix_parameters, /* manipulate parameters */ mix_scan, /* scan mailboxes */ mix_list, /* find mailboxes */ mix_lsub, /* find subscribed mailboxes */ mix_subscribe, /* subscribe to mailbox */ mix_unsubscribe, /* unsubscribe from mailbox */ mix_create, /* create mailbox */ mix_delete, /* delete mailbox */ mix_rename, /* rename mailbox */ mail_status_default, /* status of mailbox */ mix_open, /* open mailbox */ mix_close, /* close mailbox */ NIL, /* fetch message "fast" attributes */ NIL, /* fetch message flags */ NIL, /* fetch overview */ NIL, /* fetch message envelopes */ mix_header, /* fetch message header only */ mix_text, /* fetch message body only */ NIL, /* fetch partial message test */ NIL, /* unique identifier */ NIL, /* message number */ mix_flag, /* modify flags */ NIL, /* per-message modify flags */ NIL, /* search for message based on criteria */ mix_sort, /* sort messages */ mix_thread, /* thread messages */ mix_ping, /* ping mailbox to see if still alive */ mix_check, /* check for new messages */ mix_expunge, /* expunge deleted messages */ mix_copy, /* copy messages to another mailbox */ mix_append, /* append string message to mailbox */ NIL /* garbage collect stream */ }; /* prototype stream */ MAILSTREAM mixproto = {&mixdriver}; /* MIX mail validate mailbox * Accepts: mailbox name * Returns: our driver if name is valid, NIL otherwise */ DRIVER *mix_valid (char *name) { char tmp[MAILTMPLEN]; return mix_isvalid (name,tmp) ? &mixdriver : NIL; } /* MIX mail test for valid mailbox * Accepts: mailbox name * buffer to return meta name * Returns: T if valid, NIL otherwise, metadata name written in both cases */ long mix_isvalid (char *name,char *meta) { char dir[MAILTMPLEN]; struct stat sbuf; /* validate name as directory */ if (!(errno = ((strlen (name) > NETMAXMBX) ? ENAMETOOLONG : NIL)) && *mix_dir (dir,name) && mix_file (meta,dir,MIXMETA) && !stat (dir,&sbuf) && ((sbuf.st_mode & S_IFMT) == S_IFDIR)) { /* name is directory; is it mix? */ if (!stat (meta,&sbuf) && ((sbuf.st_mode & S_IFMT) == S_IFREG)) return LONGT; else errno = NIL; /* directory but not mix */ } return NIL; } /* MIX manipulate driver parameters * Accepts: function code * function-dependent value * Returns: function-dependent return value */ void *mix_parameters (long function,void *value) { void *ret = NIL; switch ((int) function) { case GET_INBOXPATH: if (value) ret = mailboxfile ((char *) value,"~/INBOX"); break; case GET_DIRFMTTEST: ret = (void *) mix_dirfmttest; break; case GET_SCANCONTENTS: ret = (void *) mix_scan_contents; break; case SET_ONETIMEEXPUNGEATPING: if (value) ((MIXLOCAL *) ((MAILSTREAM *) value)->local)->expok = T; case GET_ONETIMEEXPUNGEATPING: if (value) ret = (void *) (((MIXLOCAL *) ((MAILSTREAM *) value)->local)->expok ? VOIDT : NIL); break; } return ret; } /* MIX test for directory format internal node * Accepts: candidate node name * Returns: T if internal name, NIL otherwise */ long mix_dirfmttest (char *name) { /* belongs to MIX if starts with .mix */ return strncmp (name,MIXNAME,sizeof (MIXNAME) - 1) ? NIL : LONGT; } /* MIX mail scan mailboxes * Accepts: mail stream * reference * pattern to search * string to scan */ void mix_scan (MAILSTREAM *stream,char *ref,char *pat,char *contents) { if (stream) dummy_scan (NIL,ref,pat,contents); } /* MIX scan mailbox for contents * Accepts: mailbox name * desired contents * contents size * file size (ignored) * Returns: NIL if contents not found, T if found */ long mix_scan_contents (char *name,char *contents,unsigned long csiz, unsigned long fsiz) { long i,nfiles; void *a; char *s; long ret = NIL; size_t namelen = strlen (name); struct stat sbuf; struct direct **names = NIL; if ((nfiles = scandir (name,&names,mix_select,mix_msgfsort)) > 0) for (i = 0; i < nfiles; ++i) { if (!ret) { sprintf (s = (char *) fs_get (namelen + strlen (names[i]->d_name) + 2), "%s/%s",name,names[i]->d_name); if (!stat (s,&sbuf) && (csiz <= sbuf.st_size)) ret = dummy_scan_contents (s,contents,csiz,sbuf.st_size); fs_give ((void **) &s); } fs_give ((void **) &names[i]); } /* free directory list */ if (a = (void *) names) fs_give ((void **) &a); return ret; } /* MIX list mailboxes * Accepts: mail stream * reference * pattern to search */ void mix_list (MAILSTREAM *stream,char *ref,char *pat) { if (stream) dummy_list (NIL,ref,pat); } /* MIX list subscribed mailboxes * Accepts: mail stream * reference * pattern to search */ void mix_lsub (MAILSTREAM *stream,char *ref,char *pat) { if (stream) dummy_lsub (NIL,ref,pat); } /* MIX mail subscribe to mailbox * Accepts: mail stream * mailbox to add to subscription list * Returns: T on success, NIL on failure */ long mix_subscribe (MAILSTREAM *stream,char *mailbox) { return sm_subscribe (mailbox); } /* MIX mail unsubscribe to mailbox * Accepts: mail stream * mailbox to delete from subscription list * Returns: T on success, NIL on failure */ long mix_unsubscribe (MAILSTREAM *stream,char *mailbox) { return sm_unsubscribe (mailbox); } /* MIX mail create mailbox * Accepts: mail stream * mailbox name to create * Returns: T on success, NIL on failure */ long mix_create (MAILSTREAM *stream,char *mailbox) { DRIVER *test; FILE *f; int c,i; char *t,tmp[MAILTMPLEN],file[MAILTMPLEN]; char *s = strrchr (mailbox,'/'); unsigned long now = time (NIL); long ret = NIL; /* always create \NoSelect if trailing / */ if (s && !s[1]) return dummy_create (stream,mailbox); /* validate name */ if (mix_dirfmttest (s ? s + 1 : mailbox)) sprintf(tmp,"Can't create mailbox %.80s: invalid MIX-format name",mailbox); /* must not already exist */ else if ((test = mail_valid (NIL,mailbox,NIL)) && strcmp (test->name,"dummy")) sprintf (tmp,"Can't create mailbox %.80s: mailbox already exists",mailbox); /* create directory and metadata */ else if (!dummy_create_path (stream, mix_file (file,mix_dir (tmp,mailbox),MIXMETA), get_dir_protection (mailbox))) sprintf (tmp,"Can't create mailbox %.80s: %.80s",mailbox,strerror (errno)); else if (!(f = fopen (file,"w"))) sprintf (tmp,"Can't re-open metadata %.80s: %.80s",mailbox, strerror (errno)); else { /* success, write initial metadata */ fprintf (f,SEQFMT,now); fprintf (f,MTAFMT,now,0,now); for (i = 0, c = 'K'; (i < NUSERFLAGS) && (t = (stream && stream->user_flags[i]) ? stream->user_flags[i] : default_user_flag (i)) && *t; ++i) { putc (c,f); /* write another keyword */ fputs (t,f); c = ' '; /* delimiter is now space */ } fclose (f); set_mbx_protections (mailbox,file); /* point to suffix */ s = file + strlen (file) - (sizeof (MIXMETA) - 1); strcpy (s,MIXINDEX); /* create index */ if (!dummy_create_path (stream,file,get_dir_protection (mailbox))) sprintf (tmp,"Can't create mix mailbox index: %.80s",strerror (errno)); else { set_mbx_protections (mailbox,file); strcpy (s,MIXSTATUS); /* create status */ if (!dummy_create_path (stream,file,get_dir_protection (mailbox))) sprintf (tmp,"Can't create mix mailbox status: %.80s", strerror (errno)); else { set_mbx_protections (mailbox,file); sprintf (s,"%08lx",now);/* message file */ if (!dummy_create_path (stream,file,get_dir_protection (mailbox))) sprintf (tmp,"Can't create mix mailbox data: %.80s", strerror (errno)); else { set_mbx_protections (mailbox,file); ret = LONGT; /* declare success at this point */ } } } } if (!ret) MM_LOG (tmp,ERROR); /* some error */ return ret; } /* MIX mail delete mailbox * mailbox name to delete * Returns: T on success, NIL on failure */ long mix_delete (MAILSTREAM *stream,char *mailbox) { DIR *dirp; struct direct *d; int fd = -1; char *s,tmp[MAILTMPLEN]; if (!mix_isvalid (mailbox,tmp)) sprintf (tmp,"Can't delete mailbox %.80s: no such mailbox",mailbox); else if (((fd = open (tmp,O_RDWR,NIL)) < 0) || flock (fd,LOCK_EX|LOCK_NB)) sprintf (tmp,"Can't lock mailbox for delete: %.80s",mailbox); /* delete metadata */ else if (unlink (tmp)) sprintf (tmp,"Can't delete mailbox %.80s index: %80s", mailbox,strerror (errno)); else { close (fd); /* close descriptor on deleted metadata */ /* get directory name */ *(s = strrchr (tmp,'/')) = '\0'; if (dirp = opendir (tmp)) { /* open directory */ *s++ = '/'; /* restore delimiter */ /* massacre messages */ while (d = readdir (dirp)) if (mix_dirfmttest (d->d_name)) { strcpy (s,d->d_name); /* make path */ unlink (tmp); /* sayonara */ } closedir (dirp); /* flush directory */ *(s = strrchr (tmp,'/')) = '\0'; if (rmdir (tmp)) { /* try to remove the directory */ sprintf (tmp,"Can't delete name %.80s: %.80s", mailbox,strerror (errno)); MM_LOG (tmp,WARN); } } return T; /* always success */ } if (fd >= 0) close (fd); /* close any descriptor on metadata */ MM_LOG (tmp,ERROR); /* something failed */ return NIL; } /* MIX mail rename mailbox * Accepts: MIX mail stream * old mailbox name * new mailbox name * Returns: T on success, NIL on failure */ long mix_rename (MAILSTREAM *stream,char *old,char *newname) { char c,*s,tmp[MAILTMPLEN],tmp1[MAILTMPLEN]; struct stat sbuf; int fd = -1; if (!mix_isvalid (old,tmp)) sprintf (tmp,"Can't rename mailbox %.80s: no such mailbox",old); else if (((fd = open (tmp,O_RDWR,NIL)) < 0) || flock (fd,LOCK_EX|LOCK_NB)) sprintf (tmp,"Can't lock mailbox for rename: %.80s",old); else if (mix_dirfmttest ((s = strrchr (newname,'/')) ? s + 1 : newname)) sprintf (tmp,"Can't rename to mailbox %.80s: invalid MIX-format name", newname); /* new mailbox name must not be valid */ else if (mix_isvalid (newname,tmp)) sprintf (tmp,"Can't rename to mailbox %.80s: destination already exists", newname); else { mix_dir (tmp,old); /* build old directory name */ mix_dir (tmp1,newname); /* and new directory name */ /* easy if not INBOX */ if (compare_cstring (old,"INBOX")) { /* found superior to destination name? */ if (s = strrchr (tmp1,'/')) { c = *++s; /* remember first character of inferior */ *s = '\0'; /* tie off to get just superior */ /* name doesn't exist, create it */ if ((stat (tmp1,&sbuf) || ((sbuf.st_mode & S_IFMT) != S_IFDIR)) && !dummy_create_path (stream,tmp1,get_dir_protection (newname))) return NIL; *s = c; /* restore full name */ } if (!rename (tmp,tmp1)) { close (fd); /* close descriptor on metadata */ return LONGT; } } /* RFC 3501 requires this */ else if (dummy_create_path (stream,strcat (tmp1,"/"), get_dir_protection (newname))) { void *a; int i,n,lasterror; char *src,*dst; struct direct **names = NIL; size_t srcl = strlen (tmp); size_t dstl = strlen (tmp1); /* rename each mix file to new directory */ for (i = lasterror = 0,n = scandir (tmp,&names,mix_rselect,alphasort); i < n; ++i) { size_t len = strlen (names[i]->d_name); sprintf (src = (char *) fs_get (srcl + len + 2),"%s/%s", tmp,names[i]->d_name); sprintf (dst = (char *) fs_get (dstl + len + 1),"%s%s", tmp1,names[i]->d_name); if (rename (src,dst)) lasterror = errno; fs_give ((void **) &src); fs_give ((void **) &dst); fs_give ((void **) &names[i]); } /* free directory list */ if (a = (void *) names) fs_give ((void **) &a); if (lasterror) errno = lasterror; else { close (fd); /* close descriptor on metadata */ return mix_create (NIL,"INBOX"); } } sprintf (tmp,"Can't rename mailbox %.80s to %.80s: %.80s", old,newname,strerror (errno)); } if (fd >= 0) close (fd); /* close any descriptor on metadata */ MM_LOG (tmp,ERROR); /* something failed */ return NIL; } /* MIX test for mix name * Accepts: candidate directory name * Returns: T if mix file name, NIL otherwise */ int mix_rselect (struct direct *name) { return mix_dirfmttest (name->d_name); } /* MIX mail open * Accepts: stream to open * Returns: stream on success, NIL on failure */ MAILSTREAM *mix_open (MAILSTREAM *stream) { short silent; /* return prototype for OP_PROTOTYPE call */ if (!stream) return user_flags (&mixproto); if (stream->local) fatal ("mix recycle stream"); stream->local = memset (fs_get (sizeof (MIXLOCAL)),0,sizeof (MIXLOCAL)); /* note if an INBOX or not */ stream->inbox = !compare_cstring (stream->mailbox,"INBOX"); /* make temporary buffer */ LOCAL->buf = (char *) fs_get (CHUNKSIZE); LOCAL->buflen = CHUNKSIZE - 1; /* set stream->mailbox to be directory name */ mix_dir (LOCAL->buf,stream->mailbox); fs_give ((void **) &stream->mailbox); stream->mailbox = cpystr (LOCAL->buf); LOCAL->msgfd = -1; /* currently no file open */ if (!(((!stream->rdonly && /* open metadata file */ ((LOCAL->mfd = open (mix_file (LOCAL->buf,stream->mailbox,MIXMETA), O_RDWR,NIL)) >= 0)) || ((stream->rdonly = T) && ((LOCAL->mfd = open (mix_file (LOCAL->buf,stream->mailbox,MIXMETA), O_RDONLY,NIL)) >= 0))) && !flock (LOCAL->mfd,LOCK_SH))) { MM_LOG ("Error opening mix metadata file",ERROR); mix_abort (stream); stream = NIL; /* open fails */ } else { /* metadata open, complete open */ LOCAL->index = cpystr (mix_file (LOCAL->buf,stream->mailbox,MIXINDEX)); LOCAL->status = cpystr (mix_file (LOCAL->buf,stream->mailbox,MIXSTATUS)); LOCAL->sortcache = cpystr (mix_file (LOCAL->buf,stream->mailbox, MIXSORTCACHE)); stream->sequence++; /* bump sequence number */ /* parse mailbox */ stream->nmsgs = stream->recent = 0; if (silent = stream->silent) LOCAL->internal = T; stream->silent = T; if (mix_ping (stream)) { /* do initial ping */ /* try burping in case we are exclusive */ if (!stream->rdonly) mix_expunge (stream,"",NIL); if (!(stream->nmsgs || stream->silent)) MM_LOG ("Mailbox is empty",(long) NIL); stream->silent = silent; /* now notify upper level */ mail_exists (stream,stream->nmsgs); stream->perm_seen = stream->perm_deleted = stream->perm_flagged = stream->perm_answered = stream->perm_draft = stream->rdonly ? NIL : T; stream->perm_user_flags = stream->rdonly ? NIL : 0xffffffff; stream->kwd_create = /* can we create new user flags? */ (stream->user_flags[NUSERFLAGS-1] || stream->rdonly) ? NIL : T; } else { /* got murdelyzed in ping */ mix_abort (stream); stream = NIL; } } return stream; /* return stream to caller */ } /* MIX mail close * Accepts: MAIL stream * close options */ void mix_close (MAILSTREAM *stream,long options) { if (LOCAL) { /* only if a file is open */ int silent = stream->silent; stream->silent = T; /* note this stream is dying */ /* burp-only or expunge */ mix_expunge (stream,(options & CL_EXPUNGE) ? NIL : "",NIL); mix_abort (stream); stream->silent = silent; /* reset silent state */ } } /* MIX mail abort stream * Accepts: MAIL stream */ void mix_abort (MAILSTREAM *stream) { if (LOCAL) { /* only if a file is open */ /* close current message file if open */ if (LOCAL->msgfd >= 0) close (LOCAL->msgfd); /* close current metadata file if open */ if (LOCAL->mfd >= 0) close (LOCAL->mfd); if (LOCAL->index) fs_give ((void **) &LOCAL->index); if (LOCAL->status) fs_give ((void **) &LOCAL->status); if (LOCAL->sortcache) fs_give ((void **) &LOCAL->sortcache); /* free local scratch buffer */ if (LOCAL->buf) fs_give ((void **) &LOCAL->buf); /* nuke the local data */ fs_give ((void **) &stream->local); stream->dtb = NIL; /* log out the DTB */ } } /* MIX mail fetch message header * Accepts: MAIL stream * message # to fetch * pointer to returned header text length * option flags * Returns: message header in RFC822 format */ char *mix_header (MAILSTREAM *stream,unsigned long msgno,unsigned long *length, long flags) { unsigned long i,j,k; int fd; char *s,tmp[MAILTMPLEN]; MESSAGECACHE *elt; if (length) *length = 0; /* default return */ if (flags & FT_UID) return "";/* UID call "impossible" */ elt = mail_elt (stream,msgno);/* get elt */ /* is message in current message file? */ if ((LOCAL->msgfd < 0) || (elt->private.spare.data != LOCAL->curmsg)) { if (LOCAL->msgfd >= 0) close (LOCAL->msgfd); if ((LOCAL->msgfd = open (mix_file_data (LOCAL->buf,stream->mailbox, elt->private.spare.data), O_RDONLY,NIL)) < 0) return ""; /* got file */ LOCAL->curmsg = elt->private.spare.data; } lseek (LOCAL->msgfd,elt->private.special.offset,L_SET); /* size of special data and header */ j = elt->private.msg.header.offset + elt->private.msg.header.text.size; if (j > LOCAL->buflen) { /* is buffer big enough? */ /* no, make one that is */ fs_give ((void **) &LOCAL->buf); LOCAL->buf = (char *) fs_get ((LOCAL->buflen = j) + 1); } /* Maybe someday validate internaldate too */ /* slurp special data + header, validate */ if ((read (LOCAL->msgfd,LOCAL->buf,j) == j) && !strncmp (LOCAL->buf,MSGTOK,MSGTSZ) && (elt->private.uid == strtoul ((char *) LOCAL->buf + MSGTSZ,&s,16)) && (*s++ == ':') && (s = strchr (s,':')) && (k = strtoul (s+1,&s,16)) && (*s++ == ':') && (s < (char *) (LOCAL->buf + elt->private.msg.header.offset))) { /* won, set offset and size of message */ i = elt->private.msg.header.offset; *length = elt->private.msg.header.text.size; if (k != elt->rfc822_size) { sprintf (tmp,"Inconsistency in mix message size, uid=%lx (%lu != %lu)", elt->private.uid,elt->rfc822_size,k); MM_LOG (tmp,WARN); } } else { /* document the problem */ LOCAL->buf[100] = '\0'; /* tie off buffer at no more than 100 octets */ /* or at newline, whichever is first */ if (s = strpbrk (LOCAL->buf,"\015\012")) *s = '\0'; sprintf (tmp,"Error reading mix message header, uid=%lx, s=%.0lx, h=%s", elt->private.uid,elt->rfc822_size,LOCAL->buf); MM_LOG (tmp,ERROR); *length = i = j = 0; /* default to empty */ } LOCAL->buf[j] = '\0'; /* tie off buffer at the end */ return (char *) LOCAL->buf + i; } /* MIX mail fetch message text (body only) * Accepts: MAIL stream * message # to fetch * pointer to returned stringstruct * option flags * Returns: T on success, NIL on failure */ long mix_text (MAILSTREAM *stream,unsigned long msgno,STRING *bs,long flags) { unsigned long i; FDDATA d; MESSAGECACHE *elt; /* UID call "impossible" */ if (flags & FT_UID) return NIL; elt = mail_elt (stream,msgno); /* is message in current message file? */ if ((LOCAL->msgfd < 0) || (elt->private.spare.data != LOCAL->curmsg)) { if (LOCAL->msgfd >= 0) close (LOCAL->msgfd); if ((LOCAL->msgfd = open (mix_file_data (LOCAL->buf,stream->mailbox, elt->private.spare.data), O_RDONLY,NIL)) < 0) return NIL; /* got file */ LOCAL->curmsg = elt->private.spare.data; } /* doing non-peek fetch? */ if (!(flags & FT_PEEK) && !elt->seen) { FILE *idxf; /* yes, process metadata/index/status */ FILE *statf = mix_parse (stream,&idxf,NIL,LONGT); elt->seen = T; /* mark as seen */ MM_FLAGS (stream,elt->msgno); /* update status file if possible */ if (statf && !stream->rdonly) { elt->private.mod = LOCAL->statusseq = mix_modseq (LOCAL->statusseq); mix_status_update (stream,statf,NIL); } if (idxf) fclose (idxf); /* release index and status file */ if (statf) fclose (statf); } d.fd = LOCAL->msgfd; /* set up file descriptor */ /* offset of message text */ d.pos = elt->private.special.offset + elt->private.msg.header.offset + elt->private.msg.header.text.size; d.chunk = LOCAL->buf; /* initial buffer chunk */ d.chunksize = CHUNKSIZE; /* chunk size */ INIT (bs,fd_string,&d,elt->rfc822_size - elt->private.msg.header.text.size); return T; } /* MIX mail modify flags * Accepts: MAIL stream * sequence * flag(s) * option flags */ void mix_flag (MAILSTREAM *stream,char *sequence,char *flag,long flags) { MESSAGECACHE *elt; unsigned long i,uf,ffkey; long f; short nf; FILE *idxf; FILE *statf = mix_parse (stream,&idxf,NIL,LONGT); unsigned long seq = mix_modseq (LOCAL->statusseq); /* find first free key */ for (ffkey = 0; (ffkey < NUSERFLAGS) && stream->user_flags[ffkey]; ++ffkey); /* parse sequence and flags */ if (((flags & ST_UID) ? mail_uid_sequence (stream,sequence) : mail_sequence (stream,sequence)) && ((f = mail_parse_flags (stream,flag,&uf)) || uf)) { /* alter flags */ for (i = 1,nf = (flags & ST_SET) ? T : NIL; i <= stream->nmsgs; i++) if ((elt = mail_elt (stream,i))->sequence) { struct { /* old flags */ unsigned int seen : 1; unsigned int deleted : 1; unsigned int flagged : 1; unsigned int answered : 1; unsigned int draft : 1; unsigned long user_flags; } old; old.seen = elt->seen; old.deleted = elt->deleted; old.flagged = elt->flagged; old.answered = elt->answered; old.draft = elt->draft; old.user_flags = elt->user_flags; if (f&fSEEN) elt->seen = nf; if (f&fDELETED) elt->deleted = nf; if (f&fFLAGGED) elt->flagged = nf; if (f&fANSWERED) elt->answered = nf; if (f&fDRAFT) elt->draft = nf; /* user flags */ if (flags & ST_SET) elt->user_flags |= uf; else elt->user_flags &= ~uf; if ((old.seen != elt->seen) || (old.deleted != elt->deleted) || (old.flagged != elt->flagged) || (old.answered != elt->answered) || (old.draft != elt->draft) || (old.user_flags != elt->user_flags)) { if (!stream->rdonly) elt->private.mod = LOCAL->statusseq = seq; MM_FLAGS (stream,elt->msgno); } } /* update status file after change */ if (statf && (seq == LOCAL->statusseq)) mix_status_update (stream,statf,NIL); /* update metadata if created a keyword */ if ((ffkey < NUSERFLAGS) && stream->user_flags[ffkey] && !mix_meta_update (stream)) MM_LOG ("Error updating mix metadata after keyword creation",ERROR); } if (statf) fclose (statf); /* release status file if still open */ if (idxf) fclose (idxf); /* release index file */ } /* MIX mail sort messages * Accepts: mail stream * character set * search program * sort program * option flags * Returns: vector of sorted message sequences or NIL if error */ unsigned long *mix_sort (MAILSTREAM *stream,char *charset,SEARCHPGM *spg, SORTPGM *pgm,long flags) { unsigned long *ret; FILE *sortcache = mix_sortcache_open (stream); ret = mail_sort_msgs (stream,charset,spg,pgm,flags); mix_sortcache_update (stream,&sortcache); return ret; } /* MIX mail thread messages * Accepts: mail stream * thread type * character set * search program * option flags * Returns: thread node tree or NIL if error */ THREADNODE *mix_thread (MAILSTREAM *stream,char *type,char *charset, SEARCHPGM *spg,long flags) { THREADNODE *ret; FILE *sortcache = mix_sortcache_open (stream); ret = mail_thread_msgs (stream,type,charset,spg,flags,mail_sort_msgs); mix_sortcache_update (stream,&sortcache); return ret; } /* MIX mail ping mailbox * Accepts: MAIL stream * Returns: T if stream alive, else NIL */ static int snarfing = 0; /* lock against recursive snarfing */ long mix_ping (MAILSTREAM *stream) { FILE *idxf,*statf; struct stat sbuf; STRING msg; MESSAGECACHE *elt; int mfd,ifd,sfd; unsigned long i,msglen; char *message,date[MAILTMPLEN],flags[MAILTMPLEN]; MAILSTREAM *sysibx = NIL; long ret = NIL; long snarfok = LONGT; /* time to snarf? */ if (stream->inbox && !stream->rdonly && !snarfing && (time (0) >= (LOCAL->lastsnarf + (time_t) mail_parameters (NIL,GET_SNARFINTERVAL,NIL)))) { appenduid_t au = (appenduid_t) mail_parameters (NIL,GET_APPENDUID,NIL); copyuid_t cu = (copyuid_t) mail_parameters (NIL,GET_COPYUID,NIL); MM_CRITICAL (stream); /* go critical */ snarfing = T; /* don't recursively snarf */ /* disable APPENDUID/COPYUID callbacks */ mail_parameters (NIL,SET_APPENDUID,NIL); mail_parameters (NIL,SET_COPYUID,NIL); /* sizes match and anything in sysinbox? */ if (!stat (sysinbox (),&sbuf) && ((sbuf.st_mode & S_IFMT) == S_IFREG) && sbuf.st_size && (sysibx = mail_open (sysibx,sysinbox (),OP_SILENT)) && !sysibx->rdonly && sysibx->nmsgs) { /* for each message in sysibx mailbox */ for (i = 1; snarfok && (i <= sysibx->nmsgs); ++i) if (!(elt = mail_elt (sysibx,i))->deleted && (message = mail_fetch_message (sysibx,i,&msglen,FT_PEEK)) && msglen) { mail_date (date,elt); /* make internal date string */ /* make flag string */ flags[0] = flags[1] = '\0'; if (elt->seen) strcat (flags," \\Seen"); if (elt->flagged) strcat (flags," \\Flagged"); if (elt->answered) strcat (flags," \\Answered"); if (elt->draft) strcat (flags," \\Draft"); flags[0] = '('; strcat (flags,")"); INIT (&msg,mail_string,message,msglen); if (snarfok = mail_append_full (stream,"INBOX",flags,date,&msg)) { char sequence[15]; sprintf (sequence,"%lu",i); mail_flag (sysibx,sequence,"\\Deleted",ST_SET); } } /* now expunge all those messages */ if (snarfok) mail_expunge (sysibx); else { sprintf (LOCAL->buf,"Can't copy new mail at message: %lu",i - 1); MM_LOG (LOCAL->buf,WARN); } } if (sysibx) mail_close (sysibx); /* reenable APPENDUID/COPYUID */ mail_parameters (NIL,SET_APPENDUID,(void *) au); mail_parameters (NIL,SET_COPYUID,(void *) cu); snarfing = NIL; /* no longer snarfing */ MM_NOCRITICAL (stream); /* release critical */ LOCAL->lastsnarf = time (0);/* note time of last snarf */ } /* expunging OK if global flag set */ if (mail_parameters (NIL,GET_EXPUNGEATPING,NIL)) LOCAL->expok = T; /* process metadata/index/status */ if (statf = mix_parse (stream,&idxf,LONGT, (LOCAL->internal ? NIL : LONGT))) { fclose (statf); /* just close the status file */ ret = LONGT; /* declare success */ } if (idxf) fclose (idxf); /* release index file */ LOCAL->expok = NIL; /* expunge no longer OK */ if (!ret) mix_abort (stream); /* murdelyze stream if ping fails */ return ret; } /* MIX mail checkpoint mailbox (burp only) * Accepts: MAIL stream */ void mix_check (MAILSTREAM *stream) { if (stream->rdonly) /* won't do on readonly files! */ MM_LOG ("Checkpoint ignored on readonly mailbox",NIL); /* do burp-only expunge action */ if (mix_expunge (stream,"",NIL)) MM_LOG ("Check completed",(long) NIL); } /* MIX mail expunge mailbox * Accepts: MAIL stream * sequence to expunge if non-NIL, empty string for burp only * expunge options * Returns: T on success, NIL if failure */ long mix_expunge (MAILSTREAM *stream,char *sequence,long options) { FILE *idxf = NIL; FILE *statf = NIL; MESSAGECACHE *elt; int ifd,sfd; long ret; unsigned long i; unsigned long nexp = 0; unsigned long reclaimed = 0; int burponly = (sequence && !*sequence); LOCAL->expok = T; /* expunge during ping is OK */ if (!(ret = burponly || !sequence || ((options & EX_UID) ? mail_uid_sequence (stream,sequence) : mail_sequence (stream,sequence))) || stream->rdonly); /* read index and open status exclusive */ else if (statf = mix_parse (stream,&idxf,LONGT, LOCAL->internal ? NIL : LONGT)) { /* expunge unless just burping */ if (!burponly) for (i = 1; i <= stream->nmsgs;) { elt = mail_elt (stream,i);/* need to expunge this message? */ if (sequence ? elt->sequence : elt->deleted) { ++nexp; /* yes, make it so */ mail_expunged (stream,i); } else ++i; /* otherwise advance to next message */ } /* burp if can get exclusive access */ if (!flock (LOCAL->mfd,LOCK_EX|LOCK_NB)) { void *a; struct direct **names = NIL; long nfiles = scandir (stream->mailbox,&names,mix_select,mix_msgfsort); if (nfiles > 0) { /* if have message files */ MIXBURP *burp,*cur; /* initialize burp list */ for (i = 0, burp = cur = NIL; i < nfiles; ++i) { MIXBURP *nxt = (MIXBURP *) memset (fs_get (sizeof (MIXBURP)),0, sizeof (MIXBURP)); /* another file found */ if (cur) cur = cur->next = nxt; else cur = burp = nxt; cur->name = names[i]->d_name; cur->fileno = strtoul (cur->name + sizeof (MIXNAME) - 1,NIL,16); cur->tail = &cur->set; fs_give ((void **) &names[i]); } /* now load ranges */ for (i = 1, cur = burp; ret && (i <= stream->nmsgs); i++) { /* is this message in current set? */ elt = mail_elt (stream,i); if (cur && (elt->private.spare.data != cur->fileno)) { /* restart if necessary */ if (elt->private.spare.data < cur->fileno) cur = burp; /* hunt for appropriate mailbox */ while (cur && (elt->private.spare.data > cur->fileno)) cur = cur->next; /* ought to have found it now... */ if (cur && (elt->private.spare.data != cur->fileno)) cur = NIL; } /* if found, add to set */ if (cur) ret = mix_addset (&cur->tail,elt->private.special.offset, elt->private.msg.header.offset + elt->rfc822_size); else { /* uh-oh */ sprintf (LOCAL->buf,"Can't locate mix message file %.08lx", elt->private.spare.data); MM_LOG (LOCAL->buf,ERROR); ret = NIL; } } if (ret) /* if no errors, burp all files */ for (cur = burp; ret && cur; cur = cur->next) { /* if non-empty, burp it */ if (cur->set.last) ret = mix_burp (stream,cur,&reclaimed); /* empty, delete it unless new msg file */ else if (mix_file_data (LOCAL->buf,stream->mailbox,cur->fileno) && ((cur->fileno == LOCAL->newmsg) ? truncate (LOCAL->buf,0) : unlink (LOCAL->buf))) { sprintf (LOCAL->buf, "Can't delete empty message file %.80s: %.80s", cur->name,strerror (errno)); MM_LOG (LOCAL->buf,WARN); } } } else MM_LOG ("No mix message files found during expunge",WARN); /* free directory list */ if (a = (void *) names) fs_give ((void **) &a); } /* either way, re-acquire shared lock */ if (flock (LOCAL->mfd,LOCK_SH|LOCK_NB)) fatal ("Unable to re-acquire metadata shared lock!"); /* Do this step even if ret is NIL (meaning some burp problem)! */ if (nexp || reclaimed) { /* rewrite index and status if changed */ LOCAL->indexseq = mix_modseq (LOCAL->indexseq); if (mix_index_update (stream,idxf,NIL)) { LOCAL->statusseq = mix_modseq (LOCAL->statusseq); /* set failure if update fails */ ret = mix_status_update (stream,statf,NIL); } } } if (statf) fclose (statf); /* close status if still open */ if (idxf) fclose (idxf); /* close index if still open */ LOCAL->expok = NIL; /* cancel expok */ if (ret) { /* only if success */ char *s = NIL; if (nexp) sprintf (s = LOCAL->buf,"Expunged %lu messages",nexp); else if (reclaimed) sprintf (s=LOCAL->buf,"Reclaimed %lu bytes of expunged space",reclaimed); else if (!burponly) s = stream->rdonly ? "Expunge ignored on readonly mailbox" : "No messages deleted, so no update needed"; if (s) MM_LOG (s,(long) NIL); } return ret; } /* MIX test for message file name * Accepts: candidate directory name * Returns: T if message file name, NIL otherwise * * ".mix" with no suffix was used by experimental versions */ int mix_select (struct direct *name) { char c,*s; /* make sure name has prefix */ if (mix_dirfmttest (name->d_name)) { for (c = *(s = name->d_name + sizeof (MIXNAME) - 1); c && isxdigit (c); c = *s++); if (!c) return T; /* all-hex or no suffix */ } return NIL; /* not suffix or non-hex */ } /* MIX msg file name comparision * Accepts: first candidate directory entry * second candidate directory entry * Returns: -1 if d1 < d2, 0 if d1 == d2, 1 d1 > d2 */ int mix_msgfsort (const void *d1,const void *d2) { char *n1 = (*(struct direct **) d1)->d_name + sizeof (MIXNAME) - 1; char *n2 = (*(struct direct **) d2)->d_name + sizeof (MIXNAME) - 1; return compare_ulong (*n1 ? strtoul (n1,NIL,16) : 0, *n2 ? strtoul (n2,NIL,16) : 0); } /* MIX add a range to a set * Accepts: pointer to set to add * start of set * size of set * Returns: T if success, set updated, NIL otherwise */ long mix_addset (SEARCHSET **set,unsigned long start,unsigned long size) { SEARCHSET *s = *set; if (start < s->last) { /* sanity check */ char tmp[MAILTMPLEN]; sprintf (tmp,"Backwards-running mix index %lu < %lu",start,s->last); MM_LOG (tmp,ERROR); return NIL; } /* range initially empty? */ if (!s->last) s->first = start; else if (start > s->last) /* no, start new range if can't append */ (*set = s = s->next = mail_newsearchset ())->first = start; s->last = start + size; /* end of current range */ return LONGT; } /* MIX burp message file * Accepts: MAIL stream * current burp block for this message * Returns: T if successful, NIL if failed */ static char *staterr = "Error in stat of mix message file %.80s: %.80s"; static char *truncerr = "Error truncating mix message file %.80s: %.80s"; long mix_burp (MAILSTREAM *stream,MIXBURP *burp,unsigned long *reclaimed) { MESSAGECACHE *elt; SEARCHSET *set; struct stat sbuf; off_t rpos,wpos; size_t size,wsize,wpending,written; int fd; FILE *f; void *s; unsigned long i; long ret = NIL; /* build file name */ mix_file_data (LOCAL->buf,stream->mailbox,burp->fileno); /* need to burp at start or multiple ranges? */ if (!burp->set.first && !burp->set.next) { /* easy case, single range at start of file */ if (stat (LOCAL->buf,&sbuf)) { sprintf (LOCAL->buf,staterr,burp->name,strerror (errno)); MM_LOG (LOCAL->buf,ERROR); } /* is this range sane? */ else if (mix_burp_check (&burp->set,sbuf.st_size,LOCAL->buf)) { /* if matches range then no burp needed! */ if (burp->set.last == sbuf.st_size) ret = LONGT; /* just need to remove cruft at end */ else if (ret = !truncate (LOCAL->buf,burp->set.last)) *reclaimed += sbuf.st_size - burp->set.last; else { sprintf (LOCAL->buf,truncerr,burp->name,strerror (errno)); MM_LOG (LOCAL->buf,ERROR); } } } /* have to do more work, get the file */ else if (((fd = open (LOCAL->buf,O_RDWR,NIL)) < 0) || !(f = fdopen (fd,"r+b"))) { sprintf (LOCAL->buf,"Error opening mix message file %.80s: %.80s", burp->name,strerror (errno)); MM_LOG (LOCAL->buf,ERROR); if (fd >= 0) close (fd); /* in case fdopen() failure */ } else if (fstat (fd,&sbuf)) { /* get file size */ sprintf (LOCAL->buf,staterr,burp->name,strerror (errno)); MM_LOG (LOCAL->buf,ERROR); fclose (f); } /* only if sane */ else if (mix_burp_check (&burp->set,sbuf.st_size,LOCAL->buf)) { /* make sure each range starts with token */ for (set = &burp->set; set; set = set->next) if (fseek (f,set->first,SEEK_SET) || (fread (LOCAL->buf,1,MSGTSZ,f) != MSGTSZ) || strncmp (LOCAL->buf,MSGTOK,MSGTSZ)) { sprintf (LOCAL->buf,"Bad message token in mix message file at %lu", set->first); MM_LOG (LOCAL->buf,ERROR); fclose (f); return NIL; /* burp fails for this file */ } /* burp out each old message */ for (set = &burp->set, wpos = 0; set; set = set->next) { /* move down this range */ for (rpos = set->first, size = set->last - set->first; size; size -= wsize) { if (rpos != wpos) { /* data to skip at start? */ /* no, slide this buffer down */ wsize = min (size,LOCAL->buflen); /* failure is not an option here */ while (fseek (f,rpos,SEEK_SET) || (fread (LOCAL->buf,1,wsize,f) != wsize)) { MM_NOTIFY (stream,strerror (errno),WARN); MM_DISKERROR (stream,errno,T); } /* nor here */ while (fseek (f,wpos,SEEK_SET)) { MM_NOTIFY (stream,strerror (errno),WARN); MM_DISKERROR (stream,errno,T); } /* and especially not here */ for (s = LOCAL->buf, wpending = wsize; wpending; wpending -= written) if (!(written = fwrite (LOCAL->buf,1,wpending,f))) { MM_NOTIFY (stream,strerror (errno),WARN); MM_DISKERROR (stream,errno,T); } } else wsize = size; /* nothing to skip, say we wrote it all */ rpos += wsize; wpos += wsize; } } while (fflush (f)) { /* failure also not an option here... */ MM_NOTIFY (stream,strerror (errno),WARN); MM_DISKERROR (stream,errno,T); } if (ftruncate (fd,wpos)) { /* flush cruft at end of file */ sprintf (LOCAL->buf,truncerr,burp->name,strerror (errno)); MM_LOG (LOCAL->buf,WARN); } else *reclaimed += rpos - wpos; ret = !fclose (f); /* close file */ /* slide down message positions in index */ for (i = 1,rpos = 0; i <= stream->nmsgs; ++i) if ((elt = mail_elt (stream,i))->private.spare.data == burp->fileno) { elt->private.special.offset = rpos; rpos += elt->private.msg.header.offset + elt->rfc822_size; } /* debugging */ if (rpos != wpos) fatal ("burp size consistency check!"); } return ret; } /* MIX burp sanity check to make sure not burping off end of file * Accepts: burp set * file size * file name * Returns: T if sane, NIL if insane */ long mix_burp_check (SEARCHSET *set,size_t size,char *file) { do if (set->last > size) { /* sanity check */ char tmp[MAILTMPLEN]; sprintf (tmp,"Unexpected short mix message file %.80s %lu < %lu", file,size,set->last); MM_LOG (tmp,ERROR); return NIL; /* don't burp this file at all */ } while (set = set->next); return LONGT; } /* MIX mail copy message(s) * Accepts: MAIL stream * sequence * destination mailbox * copy options * Returns: T if copy successful, else NIL */ long mix_copy (MAILSTREAM *stream,char *sequence,char *mailbox,long options) { FDDATA d; STRING st; char tmp[2*MAILTMPLEN]; long ret = mix_isvalid (mailbox,LOCAL->buf); mailproxycopy_t pc = (mailproxycopy_t) mail_parameters (stream,GET_MAILPROXYCOPY,NIL); MAILSTREAM *astream = NIL; FILE *idxf = NIL; FILE *msgf = NIL; FILE *statf = NIL; if (!ret) switch (errno) { /* make sure valid mailbox */ case NIL: /* no error in stat() */ if (pc) return (*pc) (stream,sequence,mailbox,options); sprintf (tmp,"Not a MIX-format mailbox: %.80s",mailbox); MM_LOG (tmp,ERROR); break; default: /* some stat() error */ MM_NOTIFY (stream,"[TRYCREATE] Must create mailbox before copy",NIL); break; } /* get sequence to copy */ else if (!(ret = ((options & CP_UID) ? mail_uid_sequence (stream,sequence) : mail_sequence (stream,sequence)))); /* acquire stream to append */ else if (ret = ((astream = mail_open (NIL,mailbox,OP_SILENT)) && !astream->rdonly && (((MIXLOCAL *) astream->local)->expok = T) && (statf = mix_parse (astream,&idxf,LONGT,NIL))) ? LONGT : NIL) { int fd; unsigned long i; MESSAGECACHE *elt; unsigned long newsize,hdrsize,size; MIXLOCAL *local = (MIXLOCAL *) astream->local; unsigned long seq = mix_modseq (local->metaseq); /* make sure new modseq fits */ if (local->indexseq > seq) seq = local->indexseq + 1; if (local->statusseq > seq) seq = local->statusseq + 1; /* calculate size of per-message header */ sprintf (local->buf,MSRFMT,MSGTOK,0,0,0,0,0,0,0,'+',0,0,0); hdrsize = strlen (local->buf); MM_CRITICAL (stream); /* go critical */ astream->silent = T; /* no events here */ /* calculate size that will be added */ for (i = 1, newsize = 0; i <= stream->nmsgs; ++i) if ((elt = mail_elt (stream,i))->sequence) newsize += hdrsize + elt->rfc822_size; /* open data file */ if (msgf = mix_data_open (astream,&fd,&size,newsize)) { char *t; unsigned long j,uid,uidv; copyuid_t cu = (copyuid_t) mail_parameters (NIL,GET_COPYUID,NIL); SEARCHSET *source = cu ? mail_newsearchset () : NIL; SEARCHSET *dest = cu ? mail_newsearchset () : NIL; for (i = 1,uid = uidv = 0; ret && (i <= stream->nmsgs); ++i) if (((elt = mail_elt (stream,i))->sequence) && elt->rfc822_size) { /* is message in current message file? */ if ((LOCAL->msgfd < 0) || (elt->private.spare.data != LOCAL->curmsg)) { if (LOCAL->msgfd >= 0) close (LOCAL->msgfd); if ((LOCAL->msgfd = open (mix_file_data (LOCAL->buf, stream->mailbox, elt->private.spare.data), O_RDONLY,NIL)) >= 0) LOCAL->curmsg = elt->private.spare.data; } if (LOCAL->msgfd < 0) ret = NIL; else { /* got file */ d.fd = LOCAL->msgfd;/* set up file descriptor */ /* start of message */ d.pos = elt->private.special.offset + elt->private.msg.header.offset; d.chunk = LOCAL->buf; d.chunksize = CHUNKSIZE; INIT (&st,fd_string,&d,elt->rfc822_size); /* init flag string */ tmp[0] = tmp[1] = '\0'; if (j = elt->user_flags) do if ((t = stream->user_flags[find_rightmost_bit (&j)]) && *t) strcat (strcat (tmp," "),t); while (j); if (elt->seen) strcat (tmp," \\Seen"); if (elt->deleted) strcat (tmp," \\Deleted"); if (elt->flagged) strcat (tmp," \\Flagged"); if (elt->answered) strcat (tmp," \\Answered"); if (elt->draft) strcat (tmp," \\Draft"); tmp[0] = '('; /* wrap list */ strcat (tmp,")"); /* if append OK, add to source set */ if ((ret = mix_append_msg (astream,msgf,tmp,elt,&st,dest, seq)) && source) mail_append_set (source,mail_uid (stream,i)); } } /* finish write if success */ if (ret && (ret = !fflush (msgf))) { fclose (msgf); /* all good, close the msg file now */ /* write new metadata, index, and status */ local->metaseq = local->indexseq = local->statusseq = seq; if (ret = (mix_meta_update (astream) && mix_index_update (astream,idxf,LONGT))) { /* success, delete if doing a move */ if (options & CP_MOVE) for (i = 1; i <= stream->nmsgs; i++) if ((elt = mail_elt (stream,i))->sequence) { elt->deleted = T; if (!stream->rdonly) elt->private.mod = LOCAL->statusseq = seq; MM_FLAGS (stream,elt->msgno); } /* done with status file now */ mix_status_update (astream,statf,LONGT); /* return sets if doing COPYUID */ if (cu) (*cu) (stream,mailbox,astream->uid_validity,source,dest); source = dest = NIL; /* don't free these sets now */ } } else { /* error */ if (errno) { /* output error message if system call error */ sprintf (tmp,"Message copy failed: %.80s",strerror (errno)); MM_LOG (tmp,ERROR); } ftruncate (fd,size); /* revert file */ close (fd); /* make sure that fclose doesn't corrupt us */ fclose (msgf); /* free the stdio resources */ } /* flush any sets remaining */ mail_free_searchset (&source); mail_free_searchset (&dest); } else { /* message file open failed */ sprintf (tmp,"Error opening copy message file: %.80s", strerror (errno)); MM_LOG (tmp,ERROR); ret = NIL; } MM_NOCRITICAL (stream); } else MM_LOG ("Can't open copy mailbox",ERROR); if (statf) fclose (statf); /* close status if still open */ if (idxf) fclose (idxf); /* close index if still open */ /* finished with append stream */ if (astream) mail_close (astream); return ret; /* return state */ } /* MIX mail append message from stringstruct * Accepts: MAIL stream * destination mailbox * append callback * data for callback * Returns: T if append successful, else NIL */ long mix_append (MAILSTREAM *stream,char *mailbox,append_t af,void *data) { STRING *message; char *flags,*date,tmp[MAILTMPLEN]; /* N.B.: can't use LOCAL->buf for tmp */ long ret = mix_isvalid (mailbox,tmp); /* default stream to prototype */ if (!stream) stream = user_flags (&mixproto); if (!ret) switch (errno) { /* if not valid mailbox */ case ENOENT: /* no such file? */ if (ret = compare_cstring (mailbox,"INBOX") ? NIL : mix_create (NIL,"INBOX")) break; MM_NOTIFY (stream,"[TRYCREATE] Must create mailbox before append",NIL); break; default: sprintf (tmp,"Not a MIX-format mailbox: %.80s",mailbox); MM_LOG (tmp,ERROR); break; } /* get first message */ if (ret && MM_APPEND (af) (stream,data,&flags,&date,&message)) { MAILSTREAM *astream; FILE *idxf = NIL; FILE *msgf = NIL; FILE *statf = NIL; if (ret = ((astream = mail_open (NIL,mailbox,OP_SILENT)) && !astream->rdonly && (((MIXLOCAL *) astream->local)->expok = T) && (statf = mix_parse (astream,&idxf,LONGT,NIL))) ? LONGT : NIL) { int fd; unsigned long size,hdrsize; MESSAGECACHE elt; MIXLOCAL *local = (MIXLOCAL *) astream->local; unsigned long seq = mix_modseq (local->metaseq); /* make sure new modseq fits */ if (local->indexseq > seq) seq = local->indexseq + 1; if (local->statusseq > seq) seq = local->statusseq + 1; /* calculate size of per-message header */ sprintf (local->buf,MSRFMT,MSGTOK,0,0,0,0,0,0,0,'+',0,0,0); hdrsize = strlen (local->buf); MM_CRITICAL (astream); /* go critical */ astream->silent = T; /* no events here */ /* open data file */ if (msgf = mix_data_open (astream,&fd,&size,hdrsize + SIZE (message))) { appenduid_t au = (appenduid_t) mail_parameters (NIL,GET_APPENDUID,NIL); SEARCHSET *dst = au ? mail_newsearchset () : NIL; while (ret && message) {/* while good to go and have messages */ errno = NIL; /* in case one of these causes failure */ /* guard against zero-length */ if (!(ret = SIZE (message))) MM_LOG ("Append of zero-length message",ERROR); else if (date && !(ret = mail_parse_date (&elt,date))) { sprintf (tmp,"Bad date in append: %.80s",date); MM_LOG (tmp,ERROR); } else { if (!date) { /* if date not specified, use now */ internal_date (tmp); mail_parse_date (&elt,tmp); } ret = mix_append_msg (astream,msgf,flags,&elt,message,dst,seq) && MM_APPEND (af) (stream,data,&flags,&date,&message); } } /* finish write if success */ if (ret && (ret = !fflush (msgf))) { fclose (msgf); /* all good, close the msg file now */ /* write new metadata, index, and status */ local->metaseq = local->indexseq = local->statusseq = seq; if ((ret = (mix_meta_update (astream) && mix_index_update (astream,idxf,LONGT) && mix_status_update (astream,statf,LONGT))) && au) { (*au) (mailbox,astream->uid_validity,dst); dst = NIL; /* don't free this set now */ } } else { /* failure */ if (errno) { /* output error message if system call error */ sprintf (tmp,"Message append failed: %.80s",strerror (errno)); MM_LOG (tmp,ERROR); } ftruncate (fd,size); /* revert all writes to file*/ close (fd); /* make sure that fclose doesn't corrupt us */ fclose (msgf); /* free the stdio resources */ } /* flush any set remaining */ mail_free_searchset (&dst); } else { /* message file open failed */ sprintf (tmp,"Error opening append message file: %.80s", strerror (errno)); MM_LOG (tmp,ERROR); ret = NIL; } MM_NOCRITICAL (astream); /* release critical */ } else MM_LOG ("Can't open append mailbox",ERROR); if (statf) fclose (statf); /* close status if still open */ if (idxf) fclose (idxf); /* close index if still open */ if (astream) mail_close (astream); } return ret; } /* MIX mail append single message * Accepts: MAIL stream * flags for new message if non-NIL * elt with source date if non-NIL * stringstruct of message text * searchset to place UID * modseq of message * Returns: T if success, NIL if failure */ long mix_append_msg (MAILSTREAM *stream,FILE *f,char *flags,MESSAGECACHE *delt, STRING *msg,SEARCHSET *set,unsigned long seq) { MESSAGECACHE *elt; int c,cs; unsigned long i,j,k,uf,hoff; long sf; stream->kwd_create = NIL; /* don't copy unknown keywords */ sf = mail_parse_flags (stream,flags,&uf); /* swell the cache */ mail_exists (stream,++stream->nmsgs); /* assign new UID from metadata */ (elt = mail_elt (stream,stream->nmsgs))->private.uid = ++stream->uid_last; elt->private.mod = seq; /* set requested modseq in status */ elt->rfc822_size = SIZE (msg);/* copy message size and date to index */ elt->year = delt->year; elt->month = delt->month; elt->day = delt->day; elt->hours = delt->hours; elt->minutes = delt->minutes; elt->seconds = delt->seconds; elt->zoccident = delt->zoccident; elt->zhours = delt->zhours; elt->zminutes = delt->zminutes; /* * Do NOT set elt->valid here! mix_status_update() uses it to determine * whether a message should be marked as old. */ if (sf&fSEEN) elt->seen = T; /* copy flags to status */ if (sf&fDELETED) elt->deleted = T; if (sf&fFLAGGED) elt->flagged = T; if (sf&fANSWERED) elt->answered = T; if (sf&fDRAFT) elt->draft = T; elt->user_flags |= uf; /* message is in new message file */ elt->private.spare.data = LOCAL->newmsg; /* offset to message internal header */ elt->private.special.offset = ftell (f); /* build header for message */ fprintf (f,MSRFMT,MSGTOK,elt->private.uid, elt->year + BASEYEAR,elt->month,elt->day, elt->hours,elt->minutes,elt->seconds, elt->zoccident ? '-' : '+',elt->zhours,elt->zminutes, elt->rfc822_size); /* offset to header from internal header */ elt->private.msg.header.offset = ftell (f) - elt->private.special.offset; for (cs = 0; SIZE (msg); ) { /* copy message */ if (elt->private.msg.header.text.size) { if (msg->cursize) /* blat entire chunk if have it */ for (j = msg->cursize; j; j -= k) if (!(k = fwrite (msg->curpos,1,j,f))) return NIL; SETPOS (msg,GETPOS (msg) + msg->cursize); } else { /* still searching for delimiter */ c = 0xff & SNX (msg); /* get source character */ if (putc (c,f) == EOF) return NIL; switch (cs) { /* decide what to do based on state */ case 0: /* previous char ordinary */ if (c == '\015') cs = 1;/* advance if CR */ break; case 1: /* previous CR, advance if LF */ cs = (c == '\012') ? 2 : 0; break; case 2: /* previous CRLF, advance if CR */ cs = (c == '\015') ? 3 : 0; break; case 3: /* previous CRLFCR, done if LF */ if (c == '\012') elt->private.msg.header.text.size = elt->rfc822_size - SIZE (msg); cs = 0; /* reset mechanism */ break; } } } /* if no delimiter, header is entire msg */ if (!elt->private.msg.header.text.size) elt->private.msg.header.text.size = elt->rfc822_size; /* add this message to set */ mail_append_set (set,elt->private.uid); return LONGT; /* success */ } /* MIX mail read metadata, index, and status * Accepts: MAIL stream * returned index file * index file flags (non-NIL if want to add/remove messages) * status file flags (non-NIL if want to update elt->valid and old) * Returns: open status file, or NIL if failure * * Note that this routine can return an open index file even if it fails! */ static char *shortmsg = "message %lu (UID=%.08lx) truncated by %lu byte(s) (%lu < %lu)"; FILE *mix_parse (MAILSTREAM *stream,FILE **idxf,long iflags,long sflags) { int fd; unsigned long i; char *s,*t; struct stat sbuf; FILE *statf = NIL; short metarepairneeded = 0; short indexrepairneeded = 0; short silent = stream->silent; *idxf = NIL; /* in case error */ /* readonly means no updates */ if (stream->rdonly) iflags = sflags = NIL; /* open index file */ if ((fd = open (LOCAL->index,iflags ? O_RDWR : O_RDONLY,NIL)) < 0) MM_LOG ("Error opening mix index file",ERROR); /* acquire exclusive access and FILE */ else if (!flock (fd,iflags ? LOCK_EX : LOCK_SH) && !(*idxf = fdopen (fd,iflags ? "r+b" : "rb"))) { MM_LOG ("Error obtaining stream on mix index file",ERROR); flock (fd,LOCK_UN); /* relinquish lock */ close (fd); } /* slurp metadata */ else if (s = mix_meta_slurp (stream,&i)) { unsigned long j = 0; /* non-zero if UIDVALIDITY/UIDLAST changed */ if (i != LOCAL->metaseq) { /* metadata changed? */ char *t,*k; LOCAL->metaseq = i; /* note new metadata sequence */ while (s && *s) { /* parse entire metadata file */ /* locate end of line */ if (s = strstr (t = s,"\015\012")) { *s = '\0'; /* tie off line */ s += 2; /* skip past CRLF */ switch (*t++) { /* parse line */ case 'V': /* UIDVALIDITY */ if (!isxdigit (*t) || !(i = strtoul (t,&t,16))) { MM_LOG ("Error in mix metadata file UIDVALIDITY record",ERROR); return NIL; /* give up */ } if (i != stream->uid_validity) j = stream->uid_validity = i; break; case 'L': /* new UIDLAST */ if (!isxdigit (*t)) { MM_LOG ("Error in mix metadata file UIDLAST record",ERROR); return NIL; /* give up */ } if ((i = strtoul (t,&t,16)) != stream->uid_last) j = stream->uid_last = i; break; case 'N': /* new message file */ if (!isxdigit (*t)) { MM_LOG ("Error in mix metadata file new msg record",ERROR); return NIL; /* give up */ } if ((i = strtoul (t,&t,16)) != stream->uid_last) LOCAL->newmsg = i; break; case 'K': /* new keyword list */ for (i = 0; t && *t && (i < NUSERFLAGS); ++i) { if (t = strchr (k = t,' ')) *t++ = '\0'; /* make sure keyword non-empty */ if (*k && (strlen (k) <= MAXUSERFLAG)) { /* in case value changes (shouldn't happen) */ if (stream->user_flags[i] && strcmp (stream->user_flags[i],k)){ char tmp[MAILTMPLEN]; sprintf (tmp,"flag rename old=%.80s new=%.80s", stream->user_flags[i],k); MM_LOG (tmp,WARN); fs_give ((void **) &stream->user_flags[i]); } if (!stream->user_flags[i]) stream->user_flags[i] = cpystr (k); } else break; /* empty keyword */ } if ((i < NUSERFLAGS) && stream->user_flags[i]) { MM_LOG ("Error in mix metadata file keyword record",ERROR); return NIL; /* give up */ } else if (i == NUSERFLAGS) stream->kwd_create = NIL; break; } } if (t && *t) { /* junk in line */ MM_LOG ("Error in mix metadata record",ERROR); return NIL; /* give up */ } } } /* get sequence */ if (!(i = mix_read_sequence (*idxf)) || (i < LOCAL->indexseq)) { MM_LOG ("Error in mix index file sequence record",ERROR); return NIL; /* give up */ } /* sequence changed from last time? */ else if (j || (i > LOCAL->indexseq)) { unsigned long uid,nmsgs,curfile,curfilesize,curpos; char *t,*msg,tmp[MAILTMPLEN]; /* start with no messages */ curfile = curfilesize = curpos = nmsgs = 0; /* update sequence iff expunging OK */ if (LOCAL->expok) LOCAL->indexseq = i; /* get first elt */ while ((s = mix_read_record (*idxf,LOCAL->buf,LOCAL->buflen,"index")) && *s) switch (*s) { case ':': /* message record */ if (!(isxdigit (*++s) && (uid = strtoul (s,&t,16)))) msg = "UID"; else if (!((*t++ == ':') && isdigit (*t) && isdigit (t[1]) && isdigit (t[2]) && isdigit (t[3]) && isdigit (t[4]) && isdigit (t[5]) && isdigit (t[6]) && isdigit (t[7]) && isdigit (t[8]) && isdigit (t[9]) && isdigit (t[10]) && isdigit (t[11]) && isdigit (t[12]) && isdigit (t[13]) && ((t[14] == '+') || (t[14] == '-')) && isdigit (t[15]) && isdigit (t[16]) && isdigit (t[17]) && isdigit (t[18]))) msg = "internaldate"; else if ((*(s = t+19) != ':') || !isxdigit (*++s)) msg = "size"; else { unsigned int y = (((*t - '0') * 1000) + ((t[1] - '0') * 100) + ((t[2] - '0') * 10) + t[3] - '0') - BASEYEAR; unsigned int m = ((t[4] - '0') * 10) + t[5] - '0'; unsigned int d = ((t[6] - '0') * 10) + t[7] - '0'; unsigned int hh = ((t[8] - '0') * 10) + t[9] - '0'; unsigned int mm = ((t[10] - '0') * 10) + t[11] - '0'; unsigned int ss = ((t[12] - '0') * 10) + t[13] - '0'; unsigned int z = (t[14] == '-') ? 1 : 0; unsigned int zh = ((t[15] - '0') * 10) + t[16] - '0'; unsigned int zm = ((t[17] - '0') * 10) + t[18] - '0'; unsigned long size = strtoul (s,&s,16); if ((*s++ == ':') && isxdigit (*s)) { unsigned long file = strtoul (s,&s,16); if ((*s++ == ':') && isxdigit (*s)) { unsigned long pos = strtoul (s,&s,16); if ((*s++ == ':') && isxdigit (*s)) { unsigned long hpos = strtoul (s,&s,16); if ((*s++ == ':') && isxdigit (*s)) { unsigned long hsiz = strtoul (s,&s,16); if (uid > stream->uid_last) { sprintf (tmp,"mix index invalid UID (%08lx < %08lx)", uid,stream->uid_last); if (stream->rdonly) { MM_LOG (tmp,ERROR); return NIL; } strcat (tmp,", repaired"); MM_LOG (tmp,WARN); stream->uid_last = uid; metarepairneeded = T; } /* ignore expansion values */ if (*s++ == ':') { MESSAGECACHE *elt; ++nmsgs; /* this is another mesage */ /* within current known range of messages? */ while (nmsgs <= stream->nmsgs) { /* yes, get corresponding elt */ elt = mail_elt (stream,nmsgs); /* existing message with matching data? */ if (uid == elt->private.uid) { /* beware of Dracula's resurrection */ if (elt->private.ghost) { sprintf (tmp,"mix index data unexpunged UID: %lx", uid); MM_LOG (tmp,ERROR); return NIL; } /* also of static data changing */ if ((size != elt->rfc822_size) || (file != elt->private.spare.data) || (pos != elt->private.special.offset) || (hpos != elt->private.msg.header.offset) || (hsiz != elt->private.msg.header.text.size) || (y != elt->year) || (m != elt->month) || (d != elt->day) || (hh != elt->hours) || (mm != elt->minutes) || (ss != elt->seconds) || (z != elt->zoccident) || (zh != elt->zhours) || (zm != elt->zminutes)) { sprintf (tmp,"mix index data mismatch: %lx",uid); MM_LOG (tmp,ERROR); return NIL; } break; } /* existing msg with lower UID is expunged */ else if (uid > elt->private.uid) { if (LOCAL->expok) mail_expunged (stream,nmsgs); else {/* message expunged, but not yet for us */ ++nmsgs; elt->private.ghost = T; } } else { /* unexpected message record */ sprintf (tmp,"mix index UID mismatch (%lx < %lx)", uid,elt->private.uid); MM_LOG (tmp,ERROR); return NIL; } } /* time to create a new message? */ if (nmsgs > stream->nmsgs) { /* defer announcing until later */ stream->silent = T; mail_exists (stream,nmsgs); stream->silent = silent; (elt = mail_elt (stream,nmsgs))->recent = T; elt->private.uid = uid; elt->rfc822_size = size; elt->private.spare.data = file; elt->private.special.offset = pos; elt->private.msg.header.offset = hpos; elt->private.msg.header.text.size = hsiz; elt->year = y; elt->month = m; elt->day = d; elt->hours = hh; elt->minutes = mm; elt->seconds = ss; elt->zoccident = z; elt->zhours = zh; elt->zminutes = zm; /* message in same file? */ if (curfile == file) { if (pos < curpos) { MESSAGECACHE *plt = mail_elt (stream,elt->msgno-1); /* uh-oh, calculate delta? */ i = curpos - pos; sprintf (tmp,shortmsg,plt->msgno,plt->private.uid, i,pos,curpos); /* possible to fix? */ if (!stream->rdonly && LOCAL->expok && (i < plt->rfc822_size)) { plt->rfc822_size -= i; if (plt->rfc822_size < plt->private.msg.header.text.size) plt->private.msg.header.text.size = plt->rfc822_size; strcat (tmp,", repaired"); indexrepairneeded = T; } MM_LOG (tmp,WARN); } } else { /* new file, restart */ if (stat (mix_file_data (LOCAL->buf,stream->mailbox, curfile = file),&sbuf)) { sprintf (tmp,"Missing mix data file: %.500s", LOCAL->buf); MM_LOG (tmp,ERROR); return NIL; } curfile = file; curfilesize = sbuf.st_size; } /* position of message in file */ curpos = pos + elt->private.msg.header.offset + elt->rfc822_size; /* short file? */ if (curfilesize < curpos) { /* uh-oh, calculate delta? */ i = curpos - curfilesize; sprintf (tmp,shortmsg,elt->msgno,elt->private.uid, i,curfilesize,curpos); /* possible to fix? */ if (!stream->rdonly && LOCAL->expok && (i < elt->rfc822_size)) { elt->rfc822_size -= i; if (elt->rfc822_size < elt->private.msg.header.text.size) elt->private.msg.header.text.size = elt->rfc822_size; strcat (tmp,", repaired"); indexrepairneeded = T; } MM_LOG (tmp,WARN); } } break; } else msg = "expansion"; } else msg = "header size"; } else msg = "header position"; } else msg = "message position"; } else msg = "file#"; } sprintf (tmp,"Error in %s in mix index file: %.500s",msg,s); MM_LOG (tmp,ERROR); return NIL; default: sprintf (tmp,"Unknown record in mix index file: %.500s",s); MM_LOG (tmp,ERROR); return NIL; } if (!s) return NIL; /* barfage from mix_read_record() */ /* expunge trailing messages not in index */ if (LOCAL->expok) while (nmsgs < stream->nmsgs) mail_expunged (stream,stream->nmsgs); } /* repair metadata and index if needed */ if ((metarepairneeded ? mix_meta_update (stream) : T) && (indexrepairneeded ? mix_index_update (stream,*idxf,NIL) : T)) { MESSAGECACHE *elt; int fd; unsigned long uid,uf,sf,mod; char *s; int updatep = NIL; /* open status file */ if ((fd = open (LOCAL->status, stream->rdonly ? O_RDONLY : O_RDWR,NIL)) < 0) MM_LOG ("Error opening mix status file",ERROR); /* acquire exclusive access and FILE */ else if (!flock (fd,stream->rdonly ? LOCK_SH : LOCK_EX) && !(statf = fdopen (fd,stream->rdonly ? "rb" : "r+b"))) { MM_LOG ("Error obtaining stream on mix status file",ERROR); flock (fd,LOCK_UN); /* relinquish lock */ close (fd); } /* get sequence */ else if (!(i = mix_read_sequence (statf)) || ((i < LOCAL->statusseq) && stream->nmsgs && (i != 1))) { sprintf (LOCAL->buf, "Error in mix status sequence record, i=%lx, seq=%lx", i,LOCAL->statusseq); MM_LOG (LOCAL->buf,ERROR); } /* sequence changed from last time? */ else if (i != LOCAL->statusseq) { /* update sequence, get first elt */ if (i > LOCAL->statusseq) LOCAL->statusseq = i; if (stream->nmsgs) { elt = mail_elt (stream,i = 1); /* read message records */ while ((t = s = mix_read_record (statf,LOCAL->buf,LOCAL->buflen, "status")) && *s && (*s++ == ':') && isxdigit (*s)) { uid = strtoul (s,&s,16); if ((*s++ == ':') && isxdigit (*s)) { uf = strtoul (s,&s,16); if ((*s++ == ':') && isxdigit (*s)) { sf = strtoul (s,&s,16); if ((*s++ == ':') && isxdigit (*s)) { mod = strtoul (s,&s,16); /* ignore expansion values */ if (*s++ == ':') { /* need to move ahead to next elt? */ while ((uid > elt->private.uid) && (i < stream->nmsgs)) elt = mail_elt (stream,++i); /* update elt if altered */ if ((uid == elt->private.uid) && (!elt->valid || (mod != elt->private.mod))) { elt->user_flags = uf; elt->private.mod = mod; elt->seen = (sf & fSEEN) ? T : NIL; elt->deleted = (sf & fDELETED) ? T : NIL; elt->flagged = (sf & fFLAGGED) ? T : NIL; elt->answered = (sf & fANSWERED) ? T : NIL; elt->draft = (sf & fDRAFT) ? T : NIL; /* announce if altered existing message */ if (elt->valid) MM_FLAGS (stream,elt->msgno); /* first time, is old message? */ else if (sf & fOLD) { /* yes, clear recent and set valid */ elt->recent = NIL; elt->valid = T; } /* recent, allowed to update its status? */ else if (sflags) { /* yes, set valid and check in status */ elt->valid = T; elt->private.mod = mix_modseq (elt->private.mod); updatep = T; } /* leave valid unset and recent if sflags not set */ } continue; /* everything looks good */ } } } } break; /* error somewhere */ } if (t && *t) { /* non-null means bogus record */ char msg[MAILTMPLEN]; sprintf (msg,"Error in mix status file message record%s: %.80s", stream->rdonly ? "" : ", fixing",t); MM_LOG (msg,WARN); /* update it if not readonly */ if (!stream->rdonly) updatep = T; } if (updatep) { /* need to update? */ LOCAL->statusseq = mix_modseq (LOCAL->statusseq); mix_status_update (stream,statf,LONGT); } } } } } if (statf) { /* still happy? */ unsigned long j; stream->silent = silent; /* now notify upper level */ mail_exists (stream,stream->nmsgs); for (i = 1, j = 0; i <= stream->nmsgs; ++i) if (mail_elt (stream,i)->recent) ++j; mail_recent (stream,j); } return statf; } /* MIX metadata file routines */ /* MIX read metadata * Accepts: MAIL stream * return pointer for modseq * Returns: pointer to metadata after modseq or NIL if failure */ char *mix_meta_slurp (MAILSTREAM *stream,unsigned long *seq) { struct stat sbuf; char *s; char *ret = NIL; if (fstat (LOCAL->mfd,&sbuf)) MM_LOG ("Error obtaining size of mix metatdata file",ERROR); if (sbuf.st_size > LOCAL->buflen) { /* should be just a few dozen bytes */ if (sbuf.st_size > METAMAX) fatal ("absurd mix metadata file size"); fs_give ((void **) &LOCAL->buf); LOCAL->buf = (char *) fs_get ((LOCAL->buflen = sbuf.st_size) + 1); } /* read current metadata file */ LOCAL->buf[sbuf.st_size] = '\0'; if (lseek (LOCAL->mfd,0,L_SET) || (read (LOCAL->mfd,s = LOCAL->buf,sbuf.st_size) != sbuf.st_size)) MM_LOG ("Error reading mix metadata file",ERROR); else if ((*s != 'S') || !isxdigit (s[1]) || ((*seq = strtoul (s+1,&s,16)) < LOCAL->metaseq) || (*s++ != '\015') || (*s++ != '\012')) MM_LOG ("Error in mix metadata file sequence record",ERROR); else ret = s; return ret; } /* MIX update metadata * Accepts: MAIL stream * Returns: T on success, NIL if error * * Index MUST be locked!! */ long mix_meta_update (MAILSTREAM *stream) { long ret; /* do nothing if stream readonly */ if (stream->rdonly) ret = LONGT; else { unsigned char c,*s,*ss,*t; unsigned long i; /* The worst-case metadata is limited to: * 4 * (1 + 8 + 2) + (NUSERFLAGS * (MAXUSERFLAG + 1)) * which comes out to 1994 octets. This is much smaller than the normal * CHUNKSIZE definition of 64K, and CHUNKSIZE is the smallest size of * LOCAL->buf. * * If more stuff gets added to the metadata, or if you change the value * of NUSERFLAGS, MAXUSERFLAG or CHUNKSIZE, be sure to recalculate the * above assertation. */ sprintf (LOCAL->buf,SEQFMT,LOCAL->metaseq = mix_modseq (LOCAL->metaseq)); sprintf (LOCAL->buf + strlen (LOCAL->buf),MTAFMT, stream->uid_validity,stream->uid_last,LOCAL->newmsg); for (i = 0, c = 'K', s = ss = LOCAL->buf + strlen (LOCAL->buf); (i < NUSERFLAGS) && (t = stream->user_flags[i]); ++i) { if (!*t) fatal ("impossible empty keyword"); *s++ = c; /* write delimiter */ while (*t) *s++ = *t++; /* write keyword */ c = ' '; /* delimiter is now space */ } if (s != ss) { /* tie off keywords line */ *s++ = '\015'; *s++ = '\012'; } /* calculate length of metadata */ if ((i = s - LOCAL->buf) > LOCAL->buflen) fatal ("impossible buffer overflow"); lseek (LOCAL->mfd,0,L_SET); /* rewind file */ /* write new metadata */ ret = (write (LOCAL->mfd,LOCAL->buf,i) == i) ? LONGT : NIL; ftruncate (LOCAL->mfd,i); /* and tie off at that point */ } return ret; } /* MIX index file routines */ /* MIX update index * Accepts: MAIL stream * open FILE * expansion check flag * Returns: T on success, NIL if error */ long mix_index_update (MAILSTREAM *stream,FILE *idxf,long flag) { unsigned long i; long ret = LONGT; if (!stream->rdonly) { /* do nothing if stream readonly */ if (flag) { /* need to do expansion check? */ char tmp[MAILTMPLEN]; size_t size; struct stat sbuf; /* calculate file size we need */ for (i = 1, size = 0; i <= stream->nmsgs; ++i) if (!mail_elt (stream,i)->private.ghost) ++size; if (size) { /* Winston Smith's first dairy entry */ sprintf (tmp,IXRFMT,0,14,4,4,13,0,0,'+',0,0,0,0,0,0,0); size *= strlen (tmp); } /* calculate file size we need */ sprintf (tmp,SEQFMT,LOCAL->indexseq); size += strlen (tmp); /* get current file size */ if (fstat (fileno (idxf),&sbuf)) { MM_LOG ("Error getting size of mix index file",ERROR); ret = NIL; } /* need to write additional space? */ else if (sbuf.st_size < size) { void *buf = fs_get (size -= sbuf.st_size); memset (buf,0,size); if (fseek (idxf,0,SEEK_END) || (fwrite (buf,1,size,idxf) != size) || fflush (idxf)) { fseek (idxf,sbuf.st_size,SEEK_SET); ftruncate (fileno (idxf),sbuf.st_size); MM_LOG ("Error extending mix index file",ERROR); ret = NIL; } fs_give ((void **) &buf); } } if (ret) { /* if still good to go */ rewind (idxf); /* let's start at the very beginning */ /* write modseq first */ fprintf (idxf,SEQFMT,LOCAL->indexseq); /* then write all messages */ for (i = 1; ret && (i <= stream->nmsgs); i++) { MESSAGECACHE *elt = mail_elt (stream,i); if (!elt->private.ghost)/* only write living messages */ fprintf (idxf,IXRFMT,elt->private.uid, elt->year + BASEYEAR,elt->month,elt->day, elt->hours,elt->minutes,elt->seconds, elt->zoccident ? '-' : '+',elt->zhours,elt->zminutes, elt->rfc822_size,elt->private.spare.data, elt->private.special.offset, elt->private.msg.header.offset, elt->private.msg.header.text.size); if (ferror (idxf)) { MM_LOG ("Error updating mix index file",ERROR); ret = NIL; } } if (fflush (idxf)) { MM_LOG ("Error flushing mix index file",ERROR); ret = NIL; } if (ret) ftruncate (fileno (idxf),ftell (idxf)); } } return ret; } /* MIX status file routines */ /* MIX update status * Accepts: MAIL stream * pointer to open FILE * expansion check flag * Returns: T on success, NIL if error */ long mix_status_update (MAILSTREAM *stream,FILE *statf,long flag) { unsigned long i; char tmp[MAILTMPLEN]; long ret = LONGT; if (!stream->rdonly) { /* do nothing if stream readonly */ if (flag) { /* need to do expansion check? */ char tmp[MAILTMPLEN]; size_t size; struct stat sbuf; /* calculate file size we need */ for (i = 1, size = 0; i <= stream->nmsgs; ++i) if (!mail_elt (stream,i)->private.ghost) ++size; if (size) { /* number of living messages */ sprintf (tmp,STRFMT,0,0,0,0); size *= strlen (tmp); } sprintf (tmp,SEQFMT,LOCAL->statusseq); size += strlen (tmp); /* get current file size */ if (fstat (fileno (statf),&sbuf)) { MM_LOG ("Error getting size of mix status file",ERROR); ret = NIL; } /* need to write additional space? */ else if (sbuf.st_size < size) { void *buf = fs_get (size -= sbuf.st_size); memset (buf,0,size); if (fseek (statf,0,SEEK_END) || (fwrite (buf,1,size,statf) != size) || fflush (statf)) { fseek (statf,sbuf.st_size,SEEK_SET); ftruncate (fileno (statf),sbuf.st_size); MM_LOG ("Error extending mix status file",ERROR); ret = NIL; } fs_give ((void **) &buf); } } if (ret) { /* if still good to go */ rewind (statf); /* let's start at the very beginning */ /* write sequence */ fprintf (statf,SEQFMT,LOCAL->statusseq); /* write message status records */ for (i = 1; ret && (i <= stream->nmsgs); ++i) { MESSAGECACHE *elt = mail_elt (stream,i); /* make sure all messages have a modseq */ if (!elt->private.mod) elt->private.mod = LOCAL->statusseq; if (!elt->private.ghost)/* only write living messages */ fprintf (statf,STRFMT,elt->private.uid,elt->user_flags, (fSEEN * elt->seen) + (fDELETED * elt->deleted) + (fFLAGGED * elt->flagged) + (fANSWERED * elt->answered) + (fDRAFT * elt->draft) + (elt->valid ? fOLD : NIL), elt->private.mod); if (ferror (statf)) { sprintf (tmp,"Error updating mix status file: %.80s", strerror (errno)); MM_LOG (tmp,ERROR); ret = NIL; } } if (ret && fflush (statf)) { MM_LOG ("Error flushing mix status file",ERROR); ret = NIL; } if (ret) ftruncate (fileno (statf),ftell (statf)); } } return ret; } /* MIX data file routines */ /* MIX open data file * Accepts: MAIL stream * pointer to returned fd if success * pointer to returned size if success * size of new data to be added * Returns: open FILE, or NIL if failure * * The curend test assumes that the last message of the mailbox is the furthest * point that the current data file extends, and thus that is all that needs to * be tested for short file prevention. */ FILE *mix_data_open (MAILSTREAM *stream,int *fd,long *size, unsigned long newsize) { FILE *msgf = NIL; struct stat sbuf; MESSAGECACHE *elt = stream->nmsgs ? mail_elt (stream,stream->nmsgs) : NIL; unsigned long curend = (elt && (elt->private.spare.data == LOCAL->newmsg)) ? elt->private.special.offset + elt->private.msg.header.offset + elt->rfc822_size : 0; /* allow create if curend 0 */ if ((*fd = open (mix_file_data (LOCAL->buf,stream->mailbox,LOCAL->newmsg), O_RDWR | (curend ? NIL : O_CREAT),NIL)) >= 0) { fstat (*fd,&sbuf); /* get current file size */ /* can we use this file? */ if ((curend <= sbuf.st_size) && (!sbuf.st_size || ((sbuf.st_size + newsize) <= MIXDATAROLL))) *size = sbuf.st_size; /* yes, return current size */ else { /* short file or becoming too long */ if (curend > sbuf.st_size) { char tmp[MAILTMPLEN]; sprintf (tmp,"short mix message file %.08lx (%ld > %ld), rolling", LOCAL->newmsg,curend,sbuf.st_size); MM_LOG (tmp,WARN); /* shouldn't happen */ } close (*fd); /* roll to a new file */ while ((*fd = open (mix_file_data (LOCAL->buf,stream->mailbox, LOCAL->newmsg = mix_modseq (LOCAL->newmsg)), O_RDWR | O_CREAT | O_EXCL,sbuf.st_mode)) < 0); *size = 0; /* brand new file */ fchmod (*fd,sbuf.st_mode);/* with same mode as previous file */ } } if (*fd >= 0) { /* have a data file? */ /* yes, get stdio and set position */ if (msgf = fdopen (*fd,"r+b")) fseek (msgf,*size,SEEK_SET); else close (*fd); /* fdopen() failed? */ } return msgf; /* return results */ } /* MIX open sortcache * Accepts: MAIL stream * Returns: open FILE, or NIL if failure or could only get readonly sortcache */ FILE *mix_sortcache_open (MAILSTREAM *stream) { int fd,refwd; unsigned long i,uid,sentdate,fromlen,tolen,cclen,subjlen,msgidlen,reflen; char *s,*t,*msg,tmp[MAILTMPLEN]; MESSAGECACHE *elt; SORTCACHE *sc; STRINGLIST *sl; struct stat sbuf; int rdonly = NIL; FILE *srtcf = NIL; mailcache_t mc = (mailcache_t) mail_parameters (NIL,GET_CACHE,NIL); fstat (LOCAL->mfd,&sbuf); if (!stream->nmsgs); /* do nothing if mailbox empty */ /* open sortcache file */ else if (((fd = open (LOCAL->sortcache,O_RDWR|O_CREAT,sbuf.st_mode)) < 0) && !(rdonly = ((fd = open (LOCAL->sortcache,O_RDONLY,NIL)) >= 0))) MM_LOG ("Error opening mix sortcache file",WARN); /* acquire lock and FILE */ else if (!flock (fd,rdonly ? LOCK_SH : LOCK_EX) && !(srtcf = fdopen (fd,rdonly ? "rb" : "r+b"))) { MM_LOG ("Error obtaining stream on mix sortcache file",WARN); flock (fd,LOCK_UN); /* relinquish lock */ close (fd); } else if (!(i = mix_read_sequence (srtcf)) || (i < LOCAL->sortcacheseq)) MM_LOG ("Error in mix sortcache file sequence record",WARN); /* sequence changed from last time? */ else if (i > LOCAL->sortcacheseq) { LOCAL->sortcacheseq = i; /* update sequence */ while ((s = t = mix_read_record (srtcf,LOCAL->buf,LOCAL->buflen, "sortcache")) && *s && (msg = "uid") && (*s++ == ':') && isxdigit (*s)) { uid = strtoul (s,&s,16); if ((*s++ == ':') && isxdigit (*s)) { sentdate = strtoul (s,&s,16); if ((*s++ == ':') && isxdigit (*s)) { fromlen = strtoul (s,&s,16); if ((*s++ == ':') && isxdigit (*s)) { tolen = strtoul (s,&s,16); if ((*s++ == ':') && isxdigit (*s)) { cclen = strtoul (s,&s,16); if ((*s++ == ':') && ((*s == 'R') || (*s == ' ')) && isxdigit (s[1])) { refwd = (*s++ == 'R') ? T : NIL; subjlen = strtoul (s,&s,16); if ((*s++ == ':') && isxdigit (*s)) { msgidlen = strtoul (s,&s,16); if ((*s++ == ':') && isxdigit (*s)) { reflen = strtoul (s,&s,16); /* ignore expansion values */ if (*s++ == ':') { if (i = mail_msgno (stream,uid)) { sc = (SORTCACHE *) (*mc) (stream,i,CH_SORTCACHE); sc->size = (elt = mail_elt (stream,i))->rfc822_size; sc->date = sentdate; sc->arrival = elt->day ? mail_longdate (elt) : 1; if (refwd) sc->refwd = T; if (fromlen) { if (sc->from) fseek (srtcf,fromlen + 2,SEEK_CUR); else if ((getc (srtcf) != 'F') || (fread (sc->from = (char *) fs_get(fromlen), 1,fromlen-1,srtcf) != (fromlen-1))|| (sc->from[fromlen-1] = '\0') || (getc (srtcf) != '\015') || (getc (srtcf) != '\012')) { msg = "from data"; break; } } if (tolen) { if (sc->to) fseek (srtcf,tolen + 2,SEEK_CUR); else if ((getc (srtcf) != 'T') || (fread (sc->to = (char *) fs_get (tolen), 1,tolen-1,srtcf) != (tolen - 1)) || (sc->to[tolen-1] = '\0') || (getc (srtcf) != '\015') || (getc (srtcf) != '\012')) { msg = "to data"; break; } } if (cclen) { if (sc->cc) fseek (srtcf,cclen + 2,SEEK_CUR); else if ((getc (srtcf) != 'C') || (fread (sc->cc = (char *) fs_get (cclen), 1,cclen-1,srtcf) != (cclen - 1)) || (sc->cc[cclen-1] = '\0') || (getc (srtcf) != '\015') || (getc (srtcf) != '\012')) { msg = "cc data"; break; } } if (subjlen) { if (sc->subject) fseek (srtcf,subjlen + 2,SEEK_CUR); else if ((getc (srtcf) != 'S') || (fread (sc->subject = (char *) fs_get (subjlen),1, subjlen-1,srtcf) != (subjlen-1))|| (sc->subject[subjlen-1] = '\0') || (getc (srtcf) != '\015') || (getc (srtcf) != '\012')) { msg = "subject data"; break; } } if (msgidlen) { if (sc->message_id) fseek (srtcf,msgidlen + 2,SEEK_CUR); else if ((getc (srtcf) != 'M') || (fread (sc->message_id = (char *) fs_get (msgidlen),1, msgidlen-1,srtcf) != (msgidlen-1))|| (sc->message_id[msgidlen-1] = '\0') || (getc (srtcf) != '\015') || (getc (srtcf) != '\012')) { msg = "message-id data"; break; } } if (reflen) { if (sc->references) fseek(srtcf,reflen + 2,SEEK_CUR); /* make sure it fits */ else { if (reflen >= LOCAL->buflen) { fs_give ((void **) &LOCAL->buf); LOCAL->buf = (char *) fs_get ((LOCAL->buflen = reflen) + 1); } if ((getc (srtcf) != 'R') || (fread (LOCAL->buf,1,reflen-1,srtcf) != (reflen - 1)) || (LOCAL->buf[reflen-1] = '\0') || (getc (srtcf) != '\015') || (getc (srtcf) != '\012')) { msg = "references data"; break; } for (s = LOCAL->buf,sl = NIL, sc->references = mail_newstringlist (); s && *s; s += i + 1) { if ((i = strtoul (s,&s,16)) && (*s++ == ':') && (s[i] == ':')) { if (sl) sl = sl->next = mail_newstringlist(); else sl = sc->references; s[i] = '\0'; sl->text.data = cpystr (s); sl->text.size = i; } else s = NIL; } if (!s || *s || (s != ((char *) LOCAL->buf + reflen - 1))) { msg = "references length consistency check"; break; } } } } /* UID not found, ignore this message */ else fseek (srtcf,((fromlen ? fromlen + 2 : 0) + (tolen ? tolen + 2 : 0) + (cclen ? cclen + 2 : 0) + (subjlen ? subjlen + 2 : 0) + (msgidlen ? msgidlen + 2 : 0) + (reflen ? reflen + 2 : 0)), SEEK_CUR); continue; } else msg = "expansion"; } else msg = "references"; } else msg = "message-id"; } else msg = "subject"; } else msg = "cc"; } else msg = "to"; } else msg = "from"; } else msg = "sentdate"; break; /* error somewhere */ } if (!t || *t) { /* error detected? */ if (t) { /* non-null means bogus record */ sprintf (tmp,"Error in %s in mix sortcache record: %.500s",msg,t); MM_LOG (tmp,WARN); } fclose (srtcf); /* either way, must punt */ srtcf = NIL; } } if (rdonly && srtcf) { /* can't update if readonly */ unlink (LOCAL->sortcache); /* try deleting it */ fclose (srtcf); /* so close it and return as if error */ srtcf = NIL; } else fchmod (fd,sbuf.st_mode); return srtcf; } /* MIX update and close sortcache * Accepts: MAIL stream * pointer to open FILE (if FILE is NIL, do nothing) * Returns: T on success, NIL on error */ long mix_sortcache_update (MAILSTREAM *stream,FILE **sortcache) { FILE *f = *sortcache; long ret = LONGT; if (f) { /* ignore if no file */ unsigned long i,j; mailcache_t mc = (mailcache_t) mail_parameters (NIL,GET_CACHE,NIL); for (i = 1; (i <= stream->nmsgs) && !((SORTCACHE *) (*mc) (stream,i,CH_SORTCACHE))->dirty; ++i); if (i <= stream->nmsgs) { /* only update if some entry is dirty */ rewind (f); /* let's start at the very beginning */ /* write sequence */ fprintf (f,SEQFMT,LOCAL->sortcacheseq = mix_modseq(LOCAL->sortcacheseq)); for (i = 1; ret && (i <= stream->nmsgs); ++i) { MESSAGECACHE *elt = mail_elt (stream,i); SORTCACHE *s = (SORTCACHE *) (*mc) (stream,i,CH_SORTCACHE); STRINGLIST *sl; s->dirty = NIL; /* no longer dirty */ if (sl = s->references) /* count length of references */ for (j = 1; sl && sl->text.data; sl = sl->next) j += 10 + sl->text.size; else j = 0; /* no references yet */ fprintf (f,SCRFMT,elt->private.uid,s->date, s->from ? strlen (s->from) + 1 : 0, s->to ? strlen (s->to) + 1 : 0,s->cc ? strlen (s->cc) + 1 : 0, s->refwd ? 'R' : ' ',s->subject ? strlen (s->subject) + 1: 0, s->message_id ? strlen (s->message_id) + 1 : 0,j); if (s->from) fprintf (f,"F%s\015\012",s->from); if (s->to) fprintf (f,"T%s\015\012",s->to); if (s->cc) fprintf (f,"C%s\015\012",s->cc); if (s->subject) fprintf (f,"S%s\015\012",s->subject); if (s->message_id) fprintf (f,"M%s\015\012",s->message_id); if (j) { /* any references to write? */ fputc ('R',f); /* yes, do so */ for (sl = s->references; sl && sl->text.data; sl = sl->next) fprintf (f,"%08lx:%s:",sl->text.size,sl->text.data); fputs ("\015\012",f); } if (ferror (f)) { MM_LOG ("Error updating mix sortcache file",WARN); ret = NIL; } } if (ret && fflush (f)) { MM_LOG ("Error flushing mix sortcache file",WARN); ret = NIL; } if (ret) ftruncate (fileno (f),ftell (f)); } if (fclose (f)) { MM_LOG ("Error closing mix sortcache file",WARN); ret = NIL; } } return ret; } /* MIX generic file routines */ /* MIX read record * Accepts: open FILE * buffer * buffer length * record type * Returns: buffer if success, else NIL (zero-length buffer means EOF) */ char *mix_read_record (FILE *f,char *buf,unsigned long buflen,char *type) { char *s,tmp[MAILTMPLEN]; /* ensure string tied off */ buf[buflen-2] = buf[buflen-1] = '\0'; while (fgets (buf,buflen-1,f)) { if (s = strchr (buf,'\012')) { if ((s != buf) && (s[-1] == '\015')) --s; *s = '\0'; /* tie off buffer */ if (s != buf) return buf; /* return if non-empty buffer */ sprintf (tmp,"Empty mix %s record",type); MM_LOG (tmp,WARN); } else if (buf[buflen-2]) { /* overlong record is bad news */ sprintf (tmp,"Oversize mix %s record: %.512s",type,buf); MM_LOG (tmp,ERROR); return NIL; } else { sprintf (tmp,"Truncated mix %s record: %.512s",type,buf); MM_LOG (tmp,WARN); return buf; /* pass to caller anyway */ } } buf[0] = '\0'; /* return empty buffer on EOF */ return buf; } /* MIX read sequence record * Accepts: open FILE * Returns: sequence value, or NIL if failure */ unsigned long mix_read_sequence (FILE *f) { unsigned long ret; char *s,tmp[MAILTMPLEN]; if (!mix_read_record (f,tmp,MAILTMPLEN-1,"sequence")) return NIL; switch (tmp[0]) { /* examine record */ case '\0': /* end of file */ ret = 1; /* start a new sequence regime */ break; case 'S': /* sequence record */ if (isxdigit (tmp[1])) { /* must be followed by hex value */ ret = strtoul (tmp+1,&s,16); if (!*s) break; /* and nothing more */ } /* drop into default case */ default: /* anything else is an error */ return NIL; /* return error */ } return ret; } /* MIX internal routines */ /* MIX mail build directory name * Accepts: destination string * source * Returns: destination or empty string if error */ char *mix_dir (char *dst,char *name) { char *s; /* empty string if mailboxfile fails */ if (!mailboxfile (dst,name)) *dst = '\0'; /* driver-selected INBOX */ else if (!*dst) mailboxfile (dst,"~/INBOX"); /* tie off unnecessary trailing / */ else if ((s = strrchr (dst,'/')) && !s[1]) *s = '\0'; return dst; } /* MIX mail build file name * Accepts: destination string * directory name * file name * Returns: destination */ char *mix_file (char *dst,char *dir,char *name) { sprintf (dst,"%.500s/%.80s%.80s",dir,MIXNAME,name); return dst; } /* MIX mail build file name from data file number * Accepts: destination string * directory name * data file number * Returns: destination */ char *mix_file_data (char *dst,char *dir,unsigned long data) { char tmp[MAILTMPLEN]; if (data) sprintf (tmp,"%08lx",data); else tmp[0] = '\0'; /* compatibility with experimental version */ return mix_file (dst,dir,tmp); } /* MIX mail get new modseq * Accepts: old modseq * Returns: new modseq value */ unsigned long mix_modseq (unsigned long oldseq) { /* normally time now */ unsigned long ret = (unsigned long) time (NIL); /* ensure that modseq doesn't go backwards */ if (ret <= oldseq) ret = oldseq + 1; return ret; } alpine-2.10+dfsg/imap/src/osdep/unix/ftl_unix.c0000600000175000017500000000175211512502123023146 0ustar paulproteuspaulproteus/* ======================================================================== * Copyright 1988-2006 University of Washington * * Licensed under the Apache License, Version 2.0 (the "License"); * you may not use this file except in compliance with the License. * You may obtain a copy of the License at * * http://www.apache.org/licenses/LICENSE-2.0 * * * ======================================================================== */ /* * Program: UNIX crash management routines * * Author: Mark Crispin * Networks and Distributed Computing * Computing & Communications * University of Washington * Administration Building, AG-44 * Seattle, WA 98195 * Internet: MRC@CAC.Washington.EDU * * Date: 1 August 1988 * Last Edited: 30 August 2006 */ /* Report a fatal error * Accepts: string to output */ void fatal (char *string) { MM_FATAL (string); /* pass up the string */ syslog (LOG_ALERT,"IMAP toolkit crash: %.100s",string); abort (); /* die horribly */ } alpine-2.10+dfsg/imap/src/osdep/unix/os_a52.h0000600000175000017500000000242011512502123022404 0ustar paulproteuspaulproteus/* ======================================================================== * Copyright 1988-2006 University of Washington * * Licensed under the Apache License, Version 2.0 (the "License"); * you may not use this file except in compliance with the License. * You may obtain a copy of the License at * * http://www.apache.org/licenses/LICENSE-2.0 * * * ======================================================================== */ /* * Program: Operating-system dependent routines -- AIX on RS6000 * * Author: Mark Crispin * Networks and Distributed Computing * Computing & Communications * University of Washington * Administration Building, AG-44 * Seattle, WA 98195 * Internet: MRC@CAC.Washington.EDU * * Date: 1 August 1988 * Last Edited: 30 August 2006 */ #include #include #include #include #include /* for struct tm */ #include #include #include #include #include #include #define setpgrp(a,b) Setpgrp(a,b) int Setpgrp (int pid,int gid); #define utime portable_utime int portable_utime (char *file,time_t timep[2]); #include "env_unix.h" #include "fs.h" #include "ftl.h" #include "nl.h" #include "tcp.h" #include "flocksim.h" alpine-2.10+dfsg/imap/src/osdep/unix/os_do4.c0000600000175000017500000000263211512502123022503 0ustar paulproteuspaulproteus/* ======================================================================== * Copyright 1988-2007 University of Washington * * Licensed under the Apache License, Version 2.0 (the "License"); * you may not use this file except in compliance with the License. * You may obtain a copy of the License at * * http://www.apache.org/licenses/LICENSE-2.0 * * * ======================================================================== */ /* * Program: Operating-system dependent routines -- Apollo Domain/OS sr10.4 * * Author: Mark Crispin * Networks and Distributed Computing * Computing & Communications * University of Washington * Administration Building, AG-44 * Seattle, WA 98195 * * Date: 11 May 1989 * Last Edited: 16 August 2007 */ #include "tcp_unix.h" /* must be before osdep includes tcp.h */ #include "mail.h" #include "osdep.h" #include #include #include #include #include #include #include #include extern int errno; /* just in case */ #include #include "misc.h" #define isodigit(c) (((unsigned)(c)>=060)&((unsigned)(c)<=067)) #define toint(c) ((c)-'0') extern int sys_nerr; extern char *sys_errlist[]; #include "fs_unix.c" #include "ftl_unix.c" #include "nl_unix.c" #include "env_unix.c" #define fork vfork #include "tcp_unix.c" #include "gr_waitp.c" #include "tz_sv4.c" alpine-2.10+dfsg/imap/src/osdep/unix/os_bsi.h0000600000175000017500000000204311512502123022573 0ustar paulproteuspaulproteus/* ======================================================================== * Copyright 1988-2006 University of Washington * * Licensed under the Apache License, Version 2.0 (the "License"); * you may not use this file except in compliance with the License. * You may obtain a copy of the License at * * http://www.apache.org/licenses/LICENSE-2.0 * * * ======================================================================== */ /* * Program: Operating-system dependent routines -- BSDI BSD/386 version * * Author: Mark Crispin * Networks and Distributed Computing * Computing & Communications * University of Washington * Administration Building, AG-44 * Seattle, WA 98195 * Internet: MRC@CAC.Washington.EDU * * Date: 5 March 1993 * Last Edited: 30 August 2006 */ #include #include #include #include #include #include #include #include #include "env_unix.h" #include "fs.h" #include "ftl.h" #include "nl.h" #include "tcp.h" alpine-2.10+dfsg/imap/src/osdep/unix/gethstid.c0000600000175000017500000000171711512502123023132 0ustar paulproteuspaulproteus/* ======================================================================== * Copyright 1988-2006 University of Washington * * Licensed under the Apache License, Version 2.0 (the "License"); * you may not use this file except in compliance with the License. * You may obtain a copy of the License at * * http://www.apache.org/licenses/LICENSE-2.0 * * * ======================================================================== */ /* * Program: Get host ID emulator * * Author: Mark Crispin * Networks and Distributed Computing * Computing & Communications * University of Washington * Administration Building, AG-44 * Seattle, WA 98195 * Internet: MRC@CAC.Washington.EDU * * Date: 3 May 1995 * Last Edited: 30 August 2006 */ /* Emulator for BSD gethostid() call * Returns: unique identifier for this machine */ long gethostid (void) { /* No gethostid() here, so just fake it and hope things turn out okay. */ return 0xdeadface; } alpine-2.10+dfsg/imap/src/osdep/unix/ckp_os4.c0000600000175000017500000000416511512502123022661 0ustar paulproteuspaulproteus/* ======================================================================== * Copyright 1988-2006 University of Washington * * Licensed under the Apache License, Version 2.0 (the "License"); * you may not use this file except in compliance with the License. * You may obtain a copy of the License at * * http://www.apache.org/licenses/LICENSE-2.0 * * * ======================================================================== */ /* * Program: OSF/1 (Digital UNIX) 4 check password * * Author: Mark Crispin * Networks and Distributed Computing * Computing & Communications * University of Washington * Administration Building, AG-44 * Seattle, WA 98195 * Internet: MRC@CAC.Washington.EDU * * Date: 1 August 1988 * Last Edited: 30 August 2006 */ /* Dummy collection routine * Accepts: how long to wait for user * how to run parameter collection * title * number of prompts * prompts * Returns: collection status * * Because Spider Boardman, who wrote SIA, says that it's needed for buggy SIA * mechanisms, that's why. */ static int checkpw_collect (int timeout,int rendition,uchar_t *title, int nprompts,prompt_t *prompts) { switch (rendition) { case SIAONELINER: case SIAINFO: case SIAWARNING: return SIACOLSUCCESS; } return SIACOLABORT; /* another else is bogus */ } /* Check password * Accepts: login passwd struct * password string * argument count * argument vector * Returns: passwd struct if password validated, NIL otherwise */ struct passwd *checkpw (struct passwd *pw,char *pass,int argc,char *argv[]) { int i; char *s; char *name = cpystr (pw->pw_name); char *host = cpystr (tcp_clienthost ()); struct passwd *ret = NIL; /* tie off address */ if (s = strchr (host,' ')) *s = '\0'; if (*host == '[') { /* convert [a.b.c.d] to a.b.c.d */ memmove (host,host+1,i = strlen (host + 2)); host[i] = '\0'; } /* validate password */ if (sia_validate_user (checkpw_collect,argc,argv,host,name,NIL,NIL,NIL,pass) == SIASUCCESS) ret = getpwnam (name); fs_give ((void **) &name); fs_give ((void **) &host); return ret; } alpine-2.10+dfsg/imap/src/osdep/unix/os_osf.c0000600000175000017500000000254411512502123022606 0ustar paulproteuspaulproteus/* ======================================================================== * Copyright 1988-2006 University of Washington * * Licensed under the Apache License, Version 2.0 (the "License"); * you may not use this file except in compliance with the License. * You may obtain a copy of the License at * * http://www.apache.org/licenses/LICENSE-2.0 * * * ======================================================================== */ /* * Program: Operating-system dependent routines -- OSF/Digital UNIX/Tru64 * * Author: Mark Crispin * Networks and Distributed Computing * Computing & Communications * University of Washington * Administration Building, AG-44 * Seattle, WA 98195 * Internet: MRC@CAC.Washington.EDU * * Date: 1 August 1988 * Last Edited: 30 August 2006 */ #include "tcp_unix.h" /* must be before osdep includes tcp.h */ #include "mail.h" #include "osdep.h" #include #include #include #include #include #include #include #include #include extern int errno; /* just in case */ #include #include "misc.h" #include #include "fs_unix.c" #include "ftl_unix.c" #include "nl_unix.c" #include "env_unix.c" #include "gr_waitp.c" #include "tcp_unix.c" #include "tz_bsd.c" #undef flock #include "flocksim.c" alpine-2.10+dfsg/imap/src/osdep/unix/os_sgi.h0000600000175000017500000000256411512502123022610 0ustar paulproteuspaulproteus/* ======================================================================== * Copyright 1988-2006 University of Washington * * Licensed under the Apache License, Version 2.0 (the "License"); * you may not use this file except in compliance with the License. * You may obtain a copy of the License at * * http://www.apache.org/licenses/LICENSE-2.0 * * * ======================================================================== */ /* * Program: Operating-system dependent routines -- SGI version * * Author: Mark Crispin * Networks and Distributed Computing * Computing & Communications * University of Washington * Administration Building, AG-44 * Seattle, WA 98195 * Internet: MRC@CAC.Washington.EDU * * Date: 1 August 1988 * Last Edited: 20 December 2006 */ #include #include #include #include #include #include /* for struct tm */ #include #include #include #include #include /* Many versions of SysV get this wrong */ #define setpgrp(a,b) Setpgrp(a,b) int Setpgrp (int pid,int gid); #define direct dirent #define fatal cclient_fatal #define utime portable_utime int portable_utime (char *file,time_t timep[2]); #include "env_unix.h" #include "fs.h" #include "ftl.h" #include "nl.h" #include "tcp.h" #include "flocksim.h" alpine-2.10+dfsg/imap/src/osdep/unix/mx.c0000600000175000017500000011607011512502123021742 0ustar paulproteuspaulproteus/* ======================================================================== * Copyright 1988-2008 University of Washington * * Licensed under the Apache License, Version 2.0 (the "License"); * you may not use this file except in compliance with the License. * You may obtain a copy of the License at * * http://www.apache.org/licenses/LICENSE-2.0 * * * ======================================================================== */ /* * Program: MX mail routines * * Author(s): Mark Crispin * Networks and Distributed Computing * Computing & Communications * University of Washington * Administration Building, AG-44 * Seattle, WA 98195 * Internet: MRC@CAC.Washington.EDU * * Date: 3 May 1996 * Last Edited: 6 January 2008 */ #include #include #include extern int errno; /* just in case */ #include "mail.h" #include "osdep.h" #include #include #include #include "misc.h" #include "dummy.h" #include "fdstring.h" /* Index file */ #define MXINDEXNAME "/.mxindex" #define MXINDEX(d,s) strcat (mx_file (d,s),MXINDEXNAME) /* MX I/O stream local data */ typedef struct mx_local { int fd; /* file descriptor of open index */ unsigned char *buf; /* temporary buffer */ unsigned long buflen; /* current size of temporary buffer */ unsigned long cachedtexts; /* total size of all cached texts */ time_t scantime; /* last time directory scanned */ } MXLOCAL; /* Convenient access to local data */ #define LOCAL ((MXLOCAL *) stream->local) /* Function prototypes */ DRIVER *mx_valid (char *name); int mx_isvalid (char *name,char *tmp); int mx_namevalid (char *name); void *mx_parameters (long function,void *value); long mx_dirfmttest (char *name); void mx_scan (MAILSTREAM *stream,char *ref,char *pat,char *contents); long mx_scan_contents (char *name,char *contents,unsigned long csiz, unsigned long fsiz); void mx_list (MAILSTREAM *stream,char *ref,char *pat); void mx_lsub (MAILSTREAM *stream,char *ref,char *pat); long mx_subscribe (MAILSTREAM *stream,char *mailbox); long mx_unsubscribe (MAILSTREAM *stream,char *mailbox); long mx_create (MAILSTREAM *stream,char *mailbox); long mx_delete (MAILSTREAM *stream,char *mailbox); long mx_rename (MAILSTREAM *stream,char *old,char *newname); int mx_rename_work (char *src,size_t srcl,char *dst,size_t dstl,char *name); MAILSTREAM *mx_open (MAILSTREAM *stream); void mx_close (MAILSTREAM *stream,long options); void mx_fast (MAILSTREAM *stream,char *sequence,long flags); char *mx_fast_work (MAILSTREAM *stream,MESSAGECACHE *elt); char *mx_header (MAILSTREAM *stream,unsigned long msgno,unsigned long *length, long flags); long mx_text (MAILSTREAM *stream,unsigned long msgno,STRING *bs,long flags); void mx_flag (MAILSTREAM *stream,char *sequence,char *flag,long flags); void mx_flagmsg (MAILSTREAM *stream,MESSAGECACHE *elt); long mx_ping (MAILSTREAM *stream); void mx_check (MAILSTREAM *stream); long mx_expunge (MAILSTREAM *stream,char *sequence,long options); long mx_copy (MAILSTREAM *stream,char *sequence,char *mailbox, long options); long mx_append (MAILSTREAM *stream,char *mailbox,append_t af,void *data); long mx_append_msg (MAILSTREAM *stream,char *flags,MESSAGECACHE *elt, STRING *st,SEARCHSET *set); int mx_select (struct direct *name); int mx_numsort (const void *d1,const void *d2); char *mx_file (char *dst,char *name); long mx_lockindex (MAILSTREAM *stream); void mx_unlockindex (MAILSTREAM *stream); void mx_setdate (char *file,MESSAGECACHE *elt); /* MX mail routines */ /* Driver dispatch used by MAIL */ DRIVER mxdriver = { "mx", /* driver name */ /* driver flags */ DR_MAIL|DR_LOCAL|DR_NOFAST|DR_CRLF|DR_LOCKING|DR_DIRFMT, (DRIVER *) NIL, /* next driver */ mx_valid, /* mailbox is valid for us */ mx_parameters, /* manipulate parameters */ mx_scan, /* scan mailboxes */ mx_list, /* find mailboxes */ mx_lsub, /* find subscribed mailboxes */ mx_subscribe, /* subscribe to mailbox */ mx_unsubscribe, /* unsubscribe from mailbox */ mx_create, /* create mailbox */ mx_delete, /* delete mailbox */ mx_rename, /* rename mailbox */ mail_status_default, /* status of mailbox */ mx_open, /* open mailbox */ mx_close, /* close mailbox */ mx_fast, /* fetch message "fast" attributes */ NIL, /* fetch message flags */ NIL, /* fetch overview */ NIL, /* fetch message envelopes */ mx_header, /* fetch message header only */ mx_text, /* fetch message body only */ NIL, /* fetch partial message test */ NIL, /* unique identifier */ NIL, /* message number */ mx_flag, /* modify flags */ mx_flagmsg, /* per-message modify flags */ NIL, /* search for message based on criteria */ NIL, /* sort messages */ NIL, /* thread messages */ mx_ping, /* ping mailbox to see if still alive */ mx_check, /* check for new messages */ mx_expunge, /* expunge deleted messages */ mx_copy, /* copy messages to another mailbox */ mx_append, /* append string message to mailbox */ NIL /* garbage collect stream */ }; /* prototype stream */ MAILSTREAM mxproto = {&mxdriver}; /* MX mail validate mailbox * Accepts: mailbox name * Returns: our driver if name is valid, NIL otherwise */ DRIVER *mx_valid (char *name) { char tmp[MAILTMPLEN]; return mx_isvalid (name,tmp) ? &mxdriver : NIL; } /* MX mail test for valid mailbox * Accepts: mailbox name * temporary buffer to use * Returns: T if valid, NIL otherwise with errno holding dir stat error */ int mx_isvalid (char *name,char *tmp) { struct stat sbuf; errno = NIL; /* zap error */ if ((strlen (name) <= NETMAXMBX) && *mx_file (tmp,name) && !stat (tmp,&sbuf) && ((sbuf.st_mode & S_IFMT) == S_IFDIR)) { /* name is directory; is it mx? */ if (!stat (MXINDEX (tmp,name),&sbuf) && ((sbuf.st_mode & S_IFMT) == S_IFREG)) return T; errno = NIL; /* directory but not mx */ } else if (!compare_cstring (name,"INBOX")) errno = NIL; return NIL; } /* MX mail test for valid mailbox * Accepts: mailbox name * Returns: T if valid, NIL otherwise */ int mx_namevalid (char *name) { char *s = (*name == '/') ? name + 1 : name; while (s && *s) { /* make sure valid name */ if (isdigit (*s)) s++; /* digit, check this node further... */ else if (*s == '/') break; /* all digit node, barf */ /* non-digit, skip to next node or return */ else if (!((s = strchr (s+1,'/')) && *++s)) return T; } return NIL; /* all numeric or empty node */ } /* MX manipulate driver parameters * Accepts: function code * function-dependent value * Returns: function-dependent return value */ void *mx_parameters (long function,void *value) { void *ret = NIL; switch ((int) function) { case GET_INBOXPATH: if (value) ret = mailboxfile ((char *) value,"~/INBOX"); break; case GET_DIRFMTTEST: ret = (void *) mx_dirfmttest; break; case GET_SCANCONTENTS: ret = (void *) mx_scan_contents; break; } return ret; } /* MX test for directory format internal node * Accepts: candidate node name * Returns: T if internal name, NIL otherwise */ long mx_dirfmttest (char *name) { int c; /* success if index name or all-numberic */ if (strcmp (name,MXINDEXNAME+1)) while (c = *name++) if (!isdigit (c)) return NIL; return LONGT; } /* MX scan mailboxes * Accepts: mail stream * reference * pattern to search * string to scan */ void mx_scan (MAILSTREAM *stream,char *ref,char *pat,char *contents) { if (stream) dummy_scan (NIL,ref,pat,contents); } /* MX scan mailbox for contents * Accepts: mailbox name * desired contents * contents size * file size (ignored) * Returns: NIL if contents not found, T if found */ long mx_scan_contents (char *name,char *contents,unsigned long csiz, unsigned long fsiz) { long i,nfiles; void *a; char *s; long ret = NIL; size_t namelen = strlen (name); struct stat sbuf; struct direct **names = NIL; if ((nfiles = scandir (name,&names,mx_select,mx_numsort)) > 0) for (i = 0; i < nfiles; ++i) { if (!ret) { sprintf (s = (char *) fs_get (namelen + strlen (names[i]->d_name) + 2), "%s/%s",name,names[i]->d_name); if (!stat (s,&sbuf) && (csiz <= sbuf.st_size)) ret = dummy_scan_contents (s,contents,csiz,sbuf.st_size); fs_give ((void **) &s); } fs_give ((void **) &names[i]); } /* free directory list */ if (a = (void *) names) fs_give ((void **) &a); return ret; } /* MX list mailboxes * Accepts: mail stream * reference * pattern to search */ void mx_list (MAILSTREAM *stream,char *ref,char *pat) { if (stream) dummy_list (NIL,ref,pat); } /* MX list subscribed mailboxes * Accepts: mail stream * reference * pattern to search */ void mx_lsub (MAILSTREAM *stream,char *ref,char *pat) { if (stream) dummy_lsub (NIL,ref,pat); } /* MX mail subscribe to mailbox * Accepts: mail stream * mailbox to add to subscription list * Returns: T on success, NIL on failure */ long mx_subscribe (MAILSTREAM *stream,char *mailbox) { return sm_subscribe (mailbox); } /* MX mail unsubscribe to mailbox * Accepts: mail stream * mailbox to delete from subscription list * Returns: T on success, NIL on failure */ long mx_unsubscribe (MAILSTREAM *stream,char *mailbox) { return sm_unsubscribe (mailbox); } /* MX mail create mailbox * Accepts: mail stream * mailbox name to create * Returns: T on success, NIL on failure */ long mx_create (MAILSTREAM *stream,char *mailbox) { DRIVER *test; int fd; char *s,tmp[MAILTMPLEN]; int mask = umask (0); long ret = NIL; if (!mx_namevalid (mailbox)) /* validate name */ sprintf (tmp,"Can't create mailbox %.80s: invalid MX-format name",mailbox); /* must not already exist */ else if ((test = mail_valid (NIL,mailbox,NIL)) && strcmp (test->name,"dummy")) sprintf (tmp,"Can't create mailbox %.80s: mailbox already exists",mailbox); /* create directory */ else if (!dummy_create_path (stream,MXINDEX (tmp,mailbox), get_dir_protection (mailbox))) sprintf (tmp,"Can't create mailbox %.80s: %s",mailbox,strerror (errno)); else { /* success */ /* set index protection */ set_mbx_protections (mailbox,tmp); /* tie off directory name */ *(s = strrchr (tmp,'/') + 1) = '\0'; /* set directory protection */ set_mbx_protections (mailbox,tmp); ret = LONGT; } umask (mask); /* restore mask */ if (!ret) MM_LOG (tmp,ERROR); /* some error */ return ret; } /* MX mail delete mailbox * mailbox name to delete * Returns: T on success, NIL on failure */ long mx_delete (MAILSTREAM *stream,char *mailbox) { DIR *dirp; struct direct *d; char *s; char tmp[MAILTMPLEN]; if (!mx_isvalid (mailbox,tmp)) sprintf (tmp,"Can't delete mailbox %.80s: no such mailbox",mailbox); /* delete index */ else if (unlink (MXINDEX (tmp,mailbox))) sprintf (tmp,"Can't delete mailbox %.80s index: %s", mailbox,strerror (errno)); else { /* get directory name */ *(s = strrchr (tmp,'/')) = '\0'; if (dirp = opendir (tmp)) { /* open directory */ *s++ = '/'; /* restore delimiter */ /* massacre messages */ while (d = readdir (dirp)) if (mx_select (d)) { strcpy (s,d->d_name); /* make path */ unlink (tmp); /* sayonara */ } closedir (dirp); /* flush directory */ *(s = strrchr (tmp,'/')) = '\0'; if (rmdir (tmp)) { /* try to remove the directory */ sprintf (tmp,"Can't delete name %.80s: %s",mailbox,strerror (errno)); MM_LOG (tmp,WARN); } } return T; /* always success */ } MM_LOG (tmp,ERROR); /* something failed */ return NIL; } /* MX mail rename mailbox * Accepts: MX mail stream * old mailbox name * new mailbox name * Returns: T on success, NIL on failure */ long mx_rename (MAILSTREAM *stream,char *old,char *newname) { char c,*s,tmp[MAILTMPLEN],tmp1[MAILTMPLEN]; struct stat sbuf; if (!mx_isvalid (old,tmp)) sprintf (tmp,"Can't rename mailbox %.80s: no such mailbox",old); else if (!mx_namevalid (newname)) sprintf (tmp,"Can't rename to mailbox %.80s: invalid MX-format name", newname); /* new mailbox name must not be valid */ else if (mx_isvalid (newname,tmp)) sprintf (tmp,"Can't rename to mailbox %.80s: destination already exists", newname); else { mx_file (tmp,old); /* build old directory name */ mx_file (tmp1,newname); /* and new directory name */ /* easy if not INBOX */ if (compare_cstring (old,"INBOX")) { /* found superior to destination name? */ if (s = strrchr (mx_file (tmp1,newname),'/')) { c = *++s; /* remember first character of inferior */ *s = '\0'; /* tie off to get just superior */ /* name doesn't exist, create it */ if ((stat (tmp1,&sbuf) || ((sbuf.st_mode & S_IFMT) != S_IFDIR)) && !dummy_create_path (stream,tmp1,get_dir_protection (newname))) return NIL; *s = c; /* restore full name */ } if (!rename (tmp,tmp1)) return LONGT; } /* RFC 3501 requires this */ else if (dummy_create_path (stream,strcat (tmp1,"/"), get_dir_protection (newname))) { void *a; int i,n,lasterror; struct direct **names = NIL; size_t srcl = strlen (tmp); size_t dstl = strlen (tmp1); /* rename each mx file to new directory */ for (i = lasterror = 0,n = scandir (tmp,&names,mx_select,mx_numsort); i < n; ++i) { if (mx_rename_work (tmp,srcl,tmp1,dstl,names[i]->d_name)) lasterror = errno; fs_give ((void **) &names[i]); } /* free directory list */ if (a = (void *) names) fs_give ((void **) &a); if (lasterror || mx_rename_work (tmp,srcl,tmp1,dstl,MXINDEXNAME+1)) errno = lasterror; else return mx_create (NIL,"INBOX"); } sprintf (tmp,"Can't rename mailbox %.80s to %.80s: %s", old,newname,strerror (errno)); } MM_LOG (tmp,ERROR); /* something failed */ return NIL; } /* MX rename worker routine * Accepts: source directory name * source directory name length * destination directory name * destination directory name length * name of node to move * Returns: zero if success, non-zero if error */ int mx_rename_work (char *src,size_t srcl,char *dst,size_t dstl,char *name) { int ret; size_t len = strlen (name); char *s = (char *) fs_get (srcl + len + 2); char *d = (char *) fs_get (dstl + len + 1); sprintf (s,"%s/%s",src,name); sprintf (d,"%s%s",dst,name); ret = rename (s,d); fs_give ((void **) &s); fs_give ((void **) &d); return ret; } /* MX mail open * Accepts: stream to open * Returns: stream on success, NIL on failure */ MAILSTREAM *mx_open (MAILSTREAM *stream) { char tmp[MAILTMPLEN]; /* return prototype for OP_PROTOTYPE call */ if (!stream) return user_flags (&mxproto); if (stream->local) fatal ("mx recycle stream"); stream->local = fs_get (sizeof (MXLOCAL)); /* note if an INBOX or not */ stream->inbox = !compare_cstring (stream->mailbox,"INBOX"); mx_file (tmp,stream->mailbox);/* get directory name */ /* canonicalize mailbox name */ fs_give ((void **) &stream->mailbox); stream->mailbox = cpystr (tmp); /* make temporary buffer */ LOCAL->buf = (char *) fs_get (CHUNKSIZE); LOCAL->buflen = CHUNKSIZE - 1; LOCAL->scantime = 0; /* not scanned yet */ LOCAL->fd = -1; /* no index yet */ LOCAL->cachedtexts = 0; /* no cached texts */ stream->sequence++; /* bump sequence number */ /* parse mailbox */ stream->nmsgs = stream->recent = 0; if (mx_ping (stream) && !(stream->nmsgs || stream->silent)) MM_LOG ("Mailbox is empty",(long) NIL); stream->perm_seen = stream->perm_deleted = stream->perm_flagged = stream->perm_answered = stream->perm_draft = stream->rdonly ? NIL : T; stream->perm_user_flags = stream->rdonly ? NIL : 0xffffffff; stream->kwd_create = (stream->user_flags[NUSERFLAGS-1] || stream->rdonly) ? NIL : T; /* can we create new user flags? */ return stream; /* return stream to caller */ } /* MX mail close * Accepts: MAIL stream * close options */ void mx_close (MAILSTREAM *stream,long options) { if (LOCAL) { /* only if a file is open */ int silent = stream->silent; stream->silent = T; /* note this stream is dying */ if (options & CL_EXPUNGE) mx_expunge (stream,NIL,NIL); /* free local scratch buffer */ if (LOCAL->buf) fs_give ((void **) &LOCAL->buf); /* nuke the local data */ fs_give ((void **) &stream->local); stream->dtb = NIL; /* log out the DTB */ stream->silent = silent; /* reset silent state */ } } /* MX mail fetch fast information * Accepts: MAIL stream * sequence * option flags */ void mx_fast (MAILSTREAM *stream,char *sequence,long flags) { unsigned long i; MESSAGECACHE *elt; if (stream && LOCAL && ((flags & FT_UID) ? mail_uid_sequence (stream,sequence) : mail_sequence (stream,sequence))) for (i = 1; i <= stream->nmsgs; i++) if ((elt = mail_elt (stream,i))->sequence) mx_fast_work (stream,elt); } /* MX mail fetch fast information * Accepts: MAIL stream * message cache element * Returns: name of message file */ char *mx_fast_work (MAILSTREAM *stream,MESSAGECACHE *elt) { struct stat sbuf; struct tm *tm; /* build message file name */ sprintf (LOCAL->buf,"%s/%lu",stream->mailbox,elt->private.uid); /* have size yet? */ if (!elt->rfc822_size && !stat (LOCAL->buf,&sbuf)) { /* make plausible IMAPish date string */ tm = gmtime (&sbuf.st_mtime); elt->day = tm->tm_mday; elt->month = tm->tm_mon + 1; elt->year = tm->tm_year + 1900 - BASEYEAR; elt->hours = tm->tm_hour; elt->minutes = tm->tm_min; elt->seconds = tm->tm_sec; elt->zhours = 0; elt->zminutes = 0; elt->zoccident = 0; elt->rfc822_size = sbuf.st_size; } return (char *) LOCAL->buf; /* return file name */ } /* MX mail fetch message header * Accepts: MAIL stream * message # to fetch * pointer to returned header text length * option flags * Returns: message header in RFC822 format */ char *mx_header (MAILSTREAM *stream,unsigned long msgno,unsigned long *length, long flags) { unsigned long i; int fd; MESSAGECACHE *elt; *length = 0; /* default to empty */ if (flags & FT_UID) return "";/* UID call "impossible" */ elt = mail_elt (stream,msgno);/* get elt */ if (!elt->private.msg.header.text.data) { /* purge cache if too big */ if (LOCAL->cachedtexts > max (stream->nmsgs * 4096,2097152)) { mail_gc (stream,GC_TEXTS);/* just can't keep that much */ LOCAL->cachedtexts = 0; } if ((fd = open (mx_fast_work (stream,elt),O_RDONLY,NIL)) < 0) return ""; /* is buffer big enough? */ if (elt->rfc822_size > LOCAL->buflen) { fs_give ((void **) &LOCAL->buf); LOCAL->buf = (char *) fs_get ((LOCAL->buflen = elt->rfc822_size) + 1); } /* slurp message */ read (fd,LOCAL->buf,elt->rfc822_size); /* tie off file */ LOCAL->buf[elt->rfc822_size] = '\0'; close (fd); /* flush message file */ /* find end of header */ if (elt->rfc822_size < 4) i = 0; else for (i = 4; (i < elt->rfc822_size) && !((LOCAL->buf[i - 4] == '\015') && (LOCAL->buf[i - 3] == '\012') && (LOCAL->buf[i - 2] == '\015') && (LOCAL->buf[i - 1] == '\012')); i++); /* copy header */ cpytxt (&elt->private.msg.header.text,LOCAL->buf,i); cpytxt (&elt->private.msg.text.text,LOCAL->buf+i,elt->rfc822_size - i); /* add to cached size */ LOCAL->cachedtexts += elt->rfc822_size; } *length = elt->private.msg.header.text.size; return (char *) elt->private.msg.header.text.data; } /* MX mail fetch message text (body only) * Accepts: MAIL stream * message # to fetch * pointer to returned stringstruct * option flags * Returns: T on success, NIL on failure */ long mx_text (MAILSTREAM *stream,unsigned long msgno,STRING *bs,long flags) { unsigned long i; MESSAGECACHE *elt; /* UID call "impossible" */ if (flags & FT_UID) return NIL; elt = mail_elt (stream,msgno); /* snarf message if don't have it yet */ if (!elt->private.msg.text.text.data) { mx_header (stream,msgno,&i,flags); if (!elt->private.msg.text.text.data) return NIL; } /* mark as seen */ if (!(flags & FT_PEEK) && mx_lockindex (stream)) { elt->seen = T; mx_unlockindex (stream); MM_FLAGS (stream,msgno); } INIT (bs,mail_string,elt->private.msg.text.text.data, elt->private.msg.text.text.size); return T; } /* MX mail modify flags * Accepts: MAIL stream * sequence * flag(s) * option flags */ void mx_flag (MAILSTREAM *stream,char *sequence,char *flag,long flags) { mx_unlockindex (stream); /* finished with index */ } /* MX per-message modify flags * Accepts: MAIL stream * message cache element */ void mx_flagmsg (MAILSTREAM *stream,MESSAGECACHE *elt) { mx_lockindex (stream); /* lock index if not already locked */ } /* MX mail ping mailbox * Accepts: MAIL stream * Returns: T if stream alive, else NIL */ long mx_ping (MAILSTREAM *stream) { MAILSTREAM *sysibx = NIL; MESSAGECACHE *elt,*selt; struct stat sbuf; char *s,tmp[MAILTMPLEN]; int fd; unsigned long i,j,r,old; long nmsgs = stream->nmsgs; long recent = stream->recent; int silent = stream->silent; if (stat (stream->mailbox,&sbuf)) return NIL; stream->silent = T; /* don't pass up exists events yet */ if (sbuf.st_ctime != LOCAL->scantime) { struct direct **names = NIL; long nfiles = scandir (stream->mailbox,&names,mx_select,mx_numsort); if (nfiles < 0) nfiles = 0; /* in case error */ old = stream->uid_last; /* note scanned now */ LOCAL->scantime = sbuf.st_ctime; /* scan directory */ for (i = 0; i < nfiles; ++i) { /* if newly seen, add to list */ if ((j = atoi (names[i]->d_name)) > old) { /* swell the cache */ mail_exists (stream,++nmsgs); stream->uid_last = (elt = mail_elt (stream,nmsgs))->private.uid = j; elt->valid = T; /* note valid flags */ if (old) { /* other than the first pass? */ elt->recent = T; /* yup, mark as recent */ recent++; /* bump recent count */ } } fs_give ((void **) &names[i]); } /* free directory */ if (s = (void *) names) fs_give ((void **) &s); } stream->nmsgs = nmsgs; /* don't upset mail_uid() */ /* if INBOX, snarf from system INBOX */ if (mx_lockindex (stream) && stream->inbox && !strcmp (sysinbox (),stream->mailbox)) { old = stream->uid_last; MM_CRITICAL (stream); /* go critical */ /* see if anything in system inbox */ if (!stat (sysinbox (),&sbuf) && sbuf.st_size && (sysibx = mail_open (sysibx,sysinbox (),OP_SILENT)) && !sysibx->rdonly && (r = sysibx->nmsgs)) { for (i = 1; i <= r; ++i) {/* for each message in sysinbox mailbox */ /* build file name we will use */ sprintf (LOCAL->buf,"%s/%lu",stream->mailbox,++old); /* snarf message from Berkeley mailbox */ selt = mail_elt (sysibx,i); if (((fd = open (LOCAL->buf,O_WRONLY|O_CREAT|O_EXCL, (long) mail_parameters (NIL,GET_MBXPROTECTION,NIL))) >= 0) && (s = mail_fetchheader_full (sysibx,i,NIL,&j,FT_PEEK)) && (write (fd,s,j) == j) && (s = mail_fetchtext_full (sysibx,i,&j,FT_PEEK)) && (write (fd,s,j) == j) && !fsync (fd) && !close (fd)) { /* swell the cache */ mail_exists (stream,++nmsgs); stream->uid_last = /* create new elt, note its file number */ (elt = mail_elt (stream,nmsgs))->private.uid = old; recent++; /* bump recent count */ /* set up initial flags and date */ elt->valid = elt->recent = T; elt->seen = selt->seen; elt->deleted = selt->deleted; elt->flagged = selt->flagged; elt->answered = selt->answered; elt->draft = selt->draft; elt->day = selt->day;elt->month = selt->month;elt->year = selt->year; elt->hours = selt->hours;elt->minutes = selt->minutes; elt->seconds = selt->seconds; elt->zhours = selt->zhours; elt->zminutes = selt->zminutes; elt->zoccident = selt->zoccident; mx_setdate (LOCAL->buf,elt); sprintf (tmp,"%lu",i);/* delete it from the sysinbox */ mail_flag (sysibx,tmp,"\\Deleted",ST_SET); } else { /* failed to snarf */ if (fd) { /* did it ever get opened? */ close (fd); /* close descriptor */ unlink (LOCAL->buf);/* flush this file */ } sprintf (tmp,"Message copy to MX mailbox failed: %.80s", s,strerror (errno)); MM_LOG (tmp,ERROR); r = 0; /* stop the snarf in its tracks */ } } /* update scan time */ if (!stat (stream->mailbox,&sbuf)) LOCAL->scantime = sbuf.st_ctime; mail_expunge (sysibx); /* now expunge all those messages */ } if (sysibx) mail_close (sysibx); MM_NOCRITICAL (stream); /* release critical */ } mx_unlockindex (stream); /* done with index */ stream->silent = silent; /* can pass up events now */ mail_exists (stream,nmsgs); /* notify upper level of mailbox size */ mail_recent (stream,recent); return T; /* return that we are alive */ } /* MX mail check mailbox * Accepts: MAIL stream */ void mx_check (MAILSTREAM *stream) { if (mx_ping (stream)) MM_LOG ("Check completed",(long) NIL); } /* MX mail expunge mailbox * Accepts: MAIL stream * sequence to expunge if non-NIL * expunge options * Returns: T, always */ long mx_expunge (MAILSTREAM *stream,char *sequence,long options) { long ret; MESSAGECACHE *elt; unsigned long i = 1; unsigned long n = 0; unsigned long recent = stream->recent; if (ret = (sequence ? ((options & EX_UID) ? mail_uid_sequence (stream,sequence) : mail_sequence (stream,sequence)) : LONGT) && mx_lockindex (stream)) { /* lock the index */ MM_CRITICAL (stream); /* go critical */ while (i <= stream->nmsgs) {/* for each message */ elt = mail_elt (stream,i);/* if deleted, need to trash it */ if (elt->deleted && (sequence ? elt->sequence : T)) { sprintf (LOCAL->buf,"%s/%lu",stream->mailbox,elt->private.uid); if (unlink (LOCAL->buf)) {/* try to delete the message */ sprintf (LOCAL->buf,"Expunge of message %lu failed, aborted: %s",i, strerror (errno)); MM_LOG (LOCAL->buf,(long) NIL); break; } /* note uncached */ LOCAL->cachedtexts -= ((elt->private.msg.header.text.data ? elt->private.msg.header.text.size : 0) + (elt->private.msg.text.text.data ? elt->private.msg.text.text.size : 0)); mail_gc_msg (&elt->private.msg,GC_ENV | GC_TEXTS); if(elt->recent)--recent;/* if recent, note one less recent message */ mail_expunged(stream,i);/* notify upper levels */ n++; /* count up one more expunged message */ } else i++; /* otherwise try next message */ } if (n) { /* output the news if any expunged */ sprintf (LOCAL->buf,"Expunged %lu messages",n); MM_LOG (LOCAL->buf,(long) NIL); } else MM_LOG ("No messages deleted, so no update needed",(long) NIL); MM_NOCRITICAL (stream); /* release critical */ mx_unlockindex (stream); /* finished with index */ /* notify upper level of new mailbox size */ mail_exists (stream,stream->nmsgs); mail_recent (stream,recent); } return ret; } /* MX mail copy message(s) * Accepts: MAIL stream * sequence * destination mailbox * copy options * Returns: T if copy successful, else NIL */ long mx_copy (MAILSTREAM *stream,char *sequence,char *mailbox,long options) { FDDATA d; STRING st; MESSAGECACHE *elt; MAILSTREAM *astream; struct stat sbuf; int fd; unsigned long i,j,uid,uidv; char *t,tmp[MAILTMPLEN]; long ret; mailproxycopy_t pc = (mailproxycopy_t) mail_parameters (stream,GET_MAILPROXYCOPY,NIL); /* make sure valid mailbox */ if (!mx_valid (mailbox)) switch (errno) { case NIL: /* no error in stat() */ if (pc) return (*pc) (stream,sequence,mailbox,options); sprintf (LOCAL->buf,"Not a MX-format mailbox: %.80s",mailbox); MM_LOG (LOCAL->buf,ERROR); return NIL; default: /* some stat() error */ MM_NOTIFY (stream,"[TRYCREATE] Must create mailbox before copy",NIL); return NIL; } /* copy the messages */ if (!(ret = ((options & CP_UID) ? mail_uid_sequence (stream,sequence) : mail_sequence (stream,sequence)))); /* acquire stream to append to */ else if (!(astream = mail_open (NIL,mailbox,OP_SILENT))) { MM_LOG ("Can't open copy mailbox",ERROR); ret = NIL; } else { MM_CRITICAL (stream); /* go critical */ if (!(ret = mx_lockindex (astream))) MM_LOG ("Message copy failed: unable to lock index",ERROR); else { copyuid_t cu = (copyuid_t) mail_parameters (NIL,GET_COPYUID,NIL); SEARCHSET *source = cu ? mail_newsearchset () : NIL; SEARCHSET *dest = cu ? mail_newsearchset () : NIL; for (i = 1,uid = uidv = 0; ret && (i <= stream->nmsgs); i++) if ((elt = mail_elt (stream,i))->sequence) { if (ret = ((fd = open (mx_fast_work (stream,elt),O_RDONLY,NIL)) >= 0)) { fstat (fd,&sbuf); /* get size of message */ d.fd = fd; /* set up file descriptor */ d.pos = 0; /* start of file */ d.chunk = LOCAL->buf; d.chunksize = CHUNKSIZE; INIT (&st,fd_string,&d,sbuf.st_size); /* init flag string */ tmp[0] = tmp[1] = '\0'; if (j = elt->user_flags) do if (t = stream->user_flags[find_rightmost_bit (&j)]) strcat (strcat (tmp," "),t); while (j); if (elt->seen) strcat (tmp," \\Seen"); if (elt->deleted) strcat (tmp," \\Deleted"); if (elt->flagged) strcat (tmp," \\Flagged"); if (elt->answered) strcat (tmp," \\Answered"); if (elt->draft) strcat (tmp," \\Draft"); tmp[0] = '('; /* open list */ strcat (tmp,")"); /* close list */ if (ret = mx_append_msg (astream,tmp,elt,&st,dest)) { /* add to source set if needed */ if (source) mail_append_set (source,mail_uid (stream,i)); /* delete if doing a move */ if (options & CP_MOVE) elt->deleted = T; } } } /* return sets if doing COPYUID */ if (cu && ret) (*cu) (stream,mailbox,astream->uid_validity,source,dest); else { /* flush any sets we may have built */ mail_free_searchset (&source); mail_free_searchset (&dest); } mx_unlockindex (astream); /* unlock index */ } MM_NOCRITICAL (stream); mail_close (astream); /* finished with append stream */ } return ret; /* return success */ } /* MX mail append message from stringstruct * Accepts: MAIL stream * destination mailbox * append callback * data for callback * Returns: T if append successful, else NIL */ long mx_append (MAILSTREAM *stream,char *mailbox,append_t af,void *data) { MESSAGECACHE elt; MAILSTREAM *astream; char *flags,*date,tmp[MAILTMPLEN]; STRING *message; long ret = LONGT; /* default stream to prototype */ if (!stream) stream = user_flags (&mxproto); /* N.B.: can't use LOCAL->buf for tmp */ /* make sure valid mailbox */ if (!mx_isvalid (mailbox,tmp)) switch (errno) { case ENOENT: /* no such file? */ if (!compare_cstring (mailbox,"INBOX")) mx_create (NIL,"INBOX"); else { MM_NOTIFY (stream,"[TRYCREATE] Must create mailbox before append",NIL); return NIL; } /* falls through */ case 0: /* merely empty file? */ break; case EINVAL: sprintf (tmp,"Invalid MX-format mailbox name: %.80s",mailbox); MM_LOG (tmp,ERROR); return NIL; default: sprintf (tmp,"Not a MX-format mailbox: %.80s",mailbox); MM_LOG (tmp,ERROR); return NIL; } /* get first message */ if (!MM_APPEND (af) (stream,data,&flags,&date,&message)) return NIL; if (!(astream = mail_open (NIL,mailbox,OP_SILENT))) { MM_LOG ("Can't open append mailbox",ERROR); return NIL; } MM_CRITICAL (astream); /* go critical */ /* lock the index */ if (!(ret = mx_lockindex (astream))) MM_LOG ("Message append failed: unable to lock index",ERROR); else { appenduid_t au = (appenduid_t) mail_parameters (NIL,GET_APPENDUID,NIL); SEARCHSET *dst = au ? mail_newsearchset () : NIL; do { /* guard against zero-length */ if (!(ret = SIZE (message))) MM_LOG ("Append of zero-length message",ERROR); else if (date && !(ret = mail_parse_date (&elt,date))) { sprintf (tmp,"Bad date in append: %.80s",date); MM_LOG (tmp,ERROR); } else ret = mx_append_msg (astream,flags,date ? &elt : NIL,message,dst)&& MM_APPEND (af) (stream,data,&flags,&date,&message); } while (ret && message); /* return sets if doing APPENDUID */ if (au && ret) (*au) (mailbox,astream->uid_validity,dst); else mail_free_searchset (&dst); mx_unlockindex (astream); /* unlock index */ } MM_NOCRITICAL (astream); /* release critical */ mail_close (astream); return ret; } /* MX mail append single message * Accepts: MAIL stream * flags for new message if non-NIL * elt with source date if non-NIL * stringstruct of message text * searchset to place UID * Returns: T if success, NIL if failure */ long mx_append_msg (MAILSTREAM *stream,char *flags,MESSAGECACHE *elt, STRING *st,SEARCHSET *set) { char tmp[MAILTMPLEN]; int fd; unsigned long uf; long f = mail_parse_flags (stream,flags,&uf); /* make message file name */ sprintf (tmp,"%s/%lu",stream->mailbox,++stream->uid_last); if ((fd = open (tmp,O_WRONLY|O_CREAT|O_EXCL, (long) mail_parameters (NIL,GET_MBXPROTECTION,NIL))) < 0) { sprintf (tmp,"Can't create append message: %s",strerror (errno)); MM_LOG (tmp,ERROR); return NIL; } while (SIZE (st)) { /* copy the file */ if (st->cursize && (write (fd,st->curpos,st->cursize) < 0)) { unlink (tmp); /* delete file */ close (fd); /* close the file */ sprintf (tmp,"Message append failed: %s",strerror (errno)); MM_LOG (tmp,ERROR); return NIL; } SETPOS (st,GETPOS (st) + st->cursize); } close (fd); /* close the file */ if (elt) mx_setdate (tmp,elt);/* set file date */ /* swell the cache */ mail_exists (stream,++stream->nmsgs); /* copy flags */ mail_append_set (set,(elt = mail_elt (stream,stream->nmsgs))->private.uid = stream->uid_last); if (f&fSEEN) elt->seen = T; if (f&fDELETED) elt->deleted = T; if (f&fFLAGGED) elt->flagged = T; if (f&fANSWERED) elt->answered = T; if (f&fDRAFT) elt->draft = T; elt->user_flags |= uf; return LONGT; } /* Internal routines */ /* MX file name selection test * Accepts: candidate directory entry * Returns: T to use file name, NIL to skip it */ int mx_select (struct direct *name) { char c; char *s = name->d_name; while (c = *s++) if (!isdigit (c)) return NIL; return T; } /* MX file name comparision * Accepts: first candidate directory entry * second candidate directory entry * Returns: negative if d1 < d2, 0 if d1 == d2, postive if d1 > d2 */ int mx_numsort (const void *d1,const void *d2) { return atoi ((*(struct direct **) d1)->d_name) - atoi ((*(struct direct **) d2)->d_name); } /* MX mail build file name * Accepts: destination string * source * Returns: destination */ char *mx_file (char *dst,char *name) { char *s; /* empty string if mailboxfile fails */ if (!mailboxfile (dst,name)) *dst = '\0'; /* driver-selected INBOX */ else if (!*dst) mailboxfile (dst,"~/INBOX"); /* tie off unnecessary trailing / */ else if ((s = strrchr (dst,'/')) && !s[1]) *s = '\0'; return dst; } /* MX read and lock index * Accepts: MAIL stream * Returns: T if success, NIL if failure */ long mx_lockindex (MAILSTREAM *stream) { unsigned long uf,sf,uid; int k = 0; unsigned long msgno = 1; struct stat sbuf; char *s,*t,*idx,tmp[2*MAILTMPLEN]; MESSAGECACHE *elt; blocknotify_t bn = (blocknotify_t) mail_parameters (NIL,GET_BLOCKNOTIFY,NIL); if ((LOCAL->fd < 0) && /* get index file, no-op if already have it */ (LOCAL->fd = open (strcat (strcpy (tmp,stream->mailbox),MXINDEXNAME), O_RDWR|O_CREAT, (long) mail_parameters (NIL,GET_MBXPROTECTION,NIL))) >= 0) { (*bn) (BLOCK_FILELOCK,NIL); flock (LOCAL->fd,LOCK_EX); /* get exclusive lock */ (*bn) (BLOCK_NONE,NIL); fstat (LOCAL->fd,&sbuf); /* get size of index */ /* slurp index */ read (LOCAL->fd,s = idx = (char *) fs_get (sbuf.st_size + 1),sbuf.st_size); idx[sbuf.st_size] = '\0'; /* tie off index */ /* parse index */ if (sbuf.st_size) while (s && *s) switch (*s) { case 'V': /* UID validity record */ stream->uid_validity = strtoul (s+1,&s,16); break; case 'L': /* UID last record */ stream->uid_last = strtoul (s+1,&s,16); break; case 'K': /* keyword */ /* find end of keyword */ if (s = strchr (t = ++s,'\n')) { *s++ = '\0'; /* tie off keyword */ /* copy keyword */ if ((k < NUSERFLAGS) && !stream->user_flags[k] && (strlen (t) <= MAXUSERFLAG)) stream->user_flags[k] = cpystr (t); k++; /* one more keyword */ } break; case 'M': /* message status record */ uid = strtoul (s+1,&s,16);/* get UID for this message */ if (*s == ';') { /* get user flags */ uf = strtoul (s+1,&s,16); if (*s == '.') { /* get system flags */ sf = strtoul (s+1,&s,16); while ((msgno <= stream->nmsgs) && (mail_uid (stream,msgno) < uid)) msgno++; /* find message number for this UID */ if ((msgno <= stream->nmsgs) && (mail_uid (stream,msgno) == uid)) { (elt = mail_elt (stream,msgno))->valid = T; elt->user_flags=uf; /* set user and system flags in elt */ if (sf & fSEEN) elt->seen = T; if (sf & fDELETED) elt->deleted = T; if (sf & fFLAGGED) elt->flagged = T; if (sf & fANSWERED) elt->answered = T; if (sf & fDRAFT) elt->draft = T; } break; } } default: /* bad news */ sprintf (tmp,"Error in index: %.80s",s); MM_LOG (tmp,ERROR); *s = NIL; /* ignore remainder of index */ } else { /* new index */ stream->uid_validity = time (0); user_flags (stream); /* init stream with default user flags */ } fs_give ((void **) &idx); /* flush index */ } return (LOCAL->fd >= 0) ? T : NIL; } /* MX write and unlock index * Accepts: MAIL stream */ #define MXIXBUFLEN 2048 void mx_unlockindex (MAILSTREAM *stream) { unsigned long i,j; off_t size = 0; char *s,tmp[MXIXBUFLEN + 64]; MESSAGECACHE *elt; if (LOCAL->fd >= 0) { lseek (LOCAL->fd,0,L_SET); /* rewind file */ /* write header */ sprintf (s = tmp,"V%08lxL%08lx",stream->uid_validity,stream->uid_last); for (i = 0; (i < NUSERFLAGS) && stream->user_flags[i]; ++i) sprintf (s += strlen (s),"K%s\n",stream->user_flags[i]); /* write messages */ for (i = 1; i <= stream->nmsgs; i++) { /* filled buffer? */ if (((s += strlen (s)) - tmp) > MXIXBUFLEN) { write (LOCAL->fd,tmp,j = s - tmp); size += j; *(s = tmp) = '\0'; /* dump out and restart buffer */ } elt = mail_elt (stream,i); sprintf(s,"M%08lx;%08lx.%04x",elt->private.uid,elt->user_flags,(unsigned) ((fSEEN * elt->seen) + (fDELETED * elt->deleted) + (fFLAGGED * elt->flagged) + (fANSWERED * elt->answered) + (fDRAFT * elt->draft))); } /* write tail end of buffer */ if ((s += strlen (s)) != tmp) { write (LOCAL->fd,tmp,j = s - tmp); size += j; } ftruncate (LOCAL->fd,size); flock (LOCAL->fd,LOCK_UN); /* unlock the index */ close (LOCAL->fd); /* finished with file */ LOCAL->fd = -1; /* no index now */ } } /* Set date for message * Accepts: file name * elt containing date */ void mx_setdate (char *file,MESSAGECACHE *elt) { time_t tp[2]; tp[0] = time (0); /* atime is now */ tp[1] = mail_longdate (elt); /* modification time */ utime (file,tp); /* set the times */ } alpine-2.10+dfsg/imap/src/osdep/unix/news.c0000600000175000017500000005343211512502123022274 0ustar paulproteuspaulproteus/* ======================================================================== * Copyright 1988-2007 University of Washington * * Licensed under the Apache License, Version 2.0 (the "License"); * you may not use this file except in compliance with the License. * You may obtain a copy of the License at * * http://www.apache.org/licenses/LICENSE-2.0 * * * ======================================================================== */ /* * Program: News routines * * Author: Mark Crispin * Networks and Distributed Computing * Computing & Communications * University of Washington * Administration Building, AG-44 * Seattle, WA 98195 * Internet: MRC@CAC.Washington.EDU * * Date: 4 September 1991 * Last Edited: 30 January 2007 */ #include #include #include extern int errno; /* just in case */ #include "mail.h" #include "osdep.h" #include #include #include "misc.h" #include "newsrc.h" #include "fdstring.h" /* news_load_message() flags */ #define NLM_HEADER 0x1 /* load message text */ #define NLM_TEXT 0x2 /* load message text */ /* NEWS I/O stream local data */ typedef struct news_local { unsigned int dirty : 1; /* disk copy of .newsrc needs updating */ char *dir; /* spool directory name */ char *name; /* local mailbox name */ unsigned char buf[CHUNKSIZE]; /* scratch buffer */ unsigned long cachedtexts; /* total size of all cached texts */ } NEWSLOCAL; /* Convenient access to local data */ #define LOCAL ((NEWSLOCAL *) stream->local) /* Function prototypes */ DRIVER *news_valid (char *name); DRIVER *news_isvalid (char *name,char *mbx); void *news_parameters (long function,void *value); void news_scan (MAILSTREAM *stream,char *ref,char *pat,char *contents); void news_list (MAILSTREAM *stream,char *ref,char *pat); void news_lsub (MAILSTREAM *stream,char *ref,char *pat); long news_canonicalize (char *ref,char *pat,char *pattern); long news_subscribe (MAILSTREAM *stream,char *mailbox); long news_unsubscribe (MAILSTREAM *stream,char *mailbox); long news_create (MAILSTREAM *stream,char *mailbox); long news_delete (MAILSTREAM *stream,char *mailbox); long news_rename (MAILSTREAM *stream,char *old,char *newname); MAILSTREAM *news_open (MAILSTREAM *stream); int news_select (struct direct *name); int news_numsort (const void *d1,const void *d2); void news_close (MAILSTREAM *stream,long options); void news_fast (MAILSTREAM *stream,char *sequence,long flags); void news_flags (MAILSTREAM *stream,char *sequence,long flags); void news_load_message (MAILSTREAM *stream,unsigned long msgno,long flags); char *news_header (MAILSTREAM *stream,unsigned long msgno, unsigned long *length,long flags); long news_text (MAILSTREAM *stream,unsigned long msgno,STRING *bs,long flags); void news_flagmsg (MAILSTREAM *stream,MESSAGECACHE *elt); long news_ping (MAILSTREAM *stream); void news_check (MAILSTREAM *stream); long news_expunge (MAILSTREAM *stream,char *sequence,long options); long news_copy (MAILSTREAM *stream,char *sequence,char *mailbox,long options); long news_append (MAILSTREAM *stream,char *mailbox,append_t af,void *data); /* News routines */ /* Driver dispatch used by MAIL */ DRIVER newsdriver = { "news", /* driver name */ /* driver flags */ DR_NEWS|DR_READONLY|DR_NOFAST|DR_NAMESPACE|DR_NONEWMAIL|DR_DIRFMT, (DRIVER *) NIL, /* next driver */ news_valid, /* mailbox is valid for us */ news_parameters, /* manipulate parameters */ news_scan, /* scan mailboxes */ news_list, /* find mailboxes */ news_lsub, /* find subscribed mailboxes */ news_subscribe, /* subscribe to mailbox */ news_unsubscribe, /* unsubscribe from mailbox */ news_create, /* create mailbox */ news_delete, /* delete mailbox */ news_rename, /* rename mailbox */ mail_status_default, /* status of mailbox */ news_open, /* open mailbox */ news_close, /* close mailbox */ news_fast, /* fetch message "fast" attributes */ news_flags, /* fetch message flags */ NIL, /* fetch overview */ NIL, /* fetch message envelopes */ news_header, /* fetch message header */ news_text, /* fetch message body */ NIL, /* fetch partial message text */ NIL, /* unique identifier */ NIL, /* message number */ NIL, /* modify flags */ news_flagmsg, /* per-message modify flags */ NIL, /* search for message based on criteria */ NIL, /* sort messages */ NIL, /* thread messages */ news_ping, /* ping mailbox to see if still alive */ news_check, /* check for new messages */ news_expunge, /* expunge deleted messages */ news_copy, /* copy messages to another mailbox */ news_append, /* append string message to mailbox */ NIL /* garbage collect stream */ }; /* prototype stream */ MAILSTREAM newsproto = {&newsdriver}; /* News validate mailbox * Accepts: mailbox name * Returns: our driver if name is valid, NIL otherwise */ DRIVER *news_valid (char *name) { int fd; char *s,*t,*u; struct stat sbuf; if ((name[0] == '#') && (name[1] == 'n') && (name[2] == 'e') && (name[3] == 'w') && (name[4] == 's') && (name[5] == '.') && !strchr (name,'/') && !stat ((char *) mail_parameters (NIL,GET_NEWSSPOOL,NIL),&sbuf) && ((fd = open ((char *) mail_parameters (NIL,GET_NEWSACTIVE,NIL),O_RDONLY, NIL)) >= 0)) { fstat (fd,&sbuf); /* get size of active file */ /* slurp in active file */ read (fd,t = s = (char *) fs_get (sbuf.st_size+1),sbuf.st_size); s[sbuf.st_size] = '\0'; /* tie off file */ close (fd); /* flush file */ while (*t && (u = strchr (t,' '))) { *u++ = '\0'; /* tie off at end of name */ if (!strcmp (name+6,t)) { fs_give ((void **) &s); /* flush data */ return &newsdriver; } t = 1 + strchr (u,'\n'); /* next line */ } fs_give ((void **) &s); /* flush data */ } return NIL; /* return status */ } /* News manipulate driver parameters * Accepts: function code * function-dependent value * Returns: function-dependent return value */ void *news_parameters (long function,void *value) { return (function == GET_NEWSRC) ? env_parameters (function,value) : NIL; } /* News scan mailboxes * Accepts: mail stream * reference * pattern to search * string to scan */ void news_scan (MAILSTREAM *stream,char *ref,char *pat,char *contents) { char tmp[MAILTMPLEN]; if (news_canonicalize (ref,pat,tmp)) mm_log ("Scan not valid for news mailboxes",ERROR); } /* News find list of newsgroups * Accepts: mail stream * reference * pattern to search */ void news_list (MAILSTREAM *stream,char *ref,char *pat) { int fd; int i; char *s,*t,*u,*r,pattern[MAILTMPLEN],name[MAILTMPLEN]; struct stat sbuf; if (!pat || !*pat) { /* empty pattern? */ if (news_canonicalize (ref,"*",pattern)) { /* tie off name at root */ if (s = strchr (pattern,'.')) *++s = '\0'; else pattern[0] = '\0'; mm_list (stream,'.',pattern,LATT_NOSELECT); } } else if (news_canonicalize (ref,pat,pattern) && !stat ((char *) mail_parameters (NIL,GET_NEWSSPOOL,NIL),&sbuf) && ((fd = open ((char *) mail_parameters (NIL,GET_NEWSACTIVE,NIL), O_RDONLY,NIL)) >= 0)) { fstat (fd,&sbuf); /* get file size and read data */ read (fd,s = (char *) fs_get (sbuf.st_size + 1),sbuf.st_size); close (fd); /* close file */ s[sbuf.st_size] = '\0'; /* tie off string */ strcpy (name,"#news."); /* write initial prefix */ i = strlen (pattern); /* length of pattern */ if (pattern[--i] != '%') i = 0; if (t = strtok_r (s,"\n",&r)) do if (u = strchr (t,' ')) { *u = '\0'; /* tie off at end of name */ strcpy (name + 6,t); /* make full form of name */ if (pmatch_full (name,pattern,'.')) mm_list (stream,'.',name,NIL); else if (i && (u = strchr (name + i,'.'))) { *u = '\0'; /* tie off at delimiter, see if matches */ if (pmatch_full (name,pattern,'.')) mm_list (stream,'.',name,LATT_NOSELECT); } } while (t = strtok_r (NIL,"\n",&r)); fs_give ((void **) &s); } } /* News find list of subscribed newsgroups * Accepts: mail stream * reference * pattern to search */ void news_lsub (MAILSTREAM *stream,char *ref,char *pat) { char pattern[MAILTMPLEN]; /* return data from newsrc */ if (news_canonicalize (ref,pat,pattern)) newsrc_lsub (stream,pattern); } /* News canonicalize newsgroup name * Accepts: reference * pattern * returned single pattern * Returns: T on success, NIL on failure */ long news_canonicalize (char *ref,char *pat,char *pattern) { unsigned long i; char *s; if (ref && *ref) { /* have a reference */ strcpy (pattern,ref); /* copy reference to pattern */ /* # overrides mailbox field in reference */ if (*pat == '#') strcpy (pattern,pat); /* pattern starts, reference ends, with . */ else if ((*pat == '.') && (pattern[strlen (pattern) - 1] == '.')) strcat (pattern,pat + 1); /* append, omitting one of the period */ else strcat (pattern,pat); /* anything else is just appended */ } else strcpy (pattern,pat); /* just have basic name */ if ((pattern[0] == '#') && (pattern[1] == 'n') && (pattern[2] == 'e') && (pattern[3] == 'w') && (pattern[4] == 's') && (pattern[5] == '.') && !strchr (pattern,'/')) { /* count wildcards */ for (i = 0, s = pattern; *s; *s++) if ((*s == '*') || (*s == '%')) ++i; /* success if not too many */ if (i <= MAXWILDCARDS) return LONGT; MM_LOG ("Excessive wildcards in LIST/LSUB",ERROR); } return NIL; } /* News subscribe to mailbox * Accepts: mail stream * mailbox to add to subscription list * Returns: T on success, NIL on failure */ long news_subscribe (MAILSTREAM *stream,char *mailbox) { return news_valid (mailbox) ? newsrc_update (stream,mailbox+6,':') : NIL; } /* NEWS unsubscribe to mailbox * Accepts: mail stream * mailbox to delete from subscription list * Returns: T on success, NIL on failure */ long news_unsubscribe (MAILSTREAM *stream,char *mailbox) { return news_valid (mailbox) ? newsrc_update (stream,mailbox+6,'!') : NIL; } /* News create mailbox * Accepts: mail stream * mailbox name to create * Returns: T on success, NIL on failure */ long news_create (MAILSTREAM *stream,char *mailbox) { return NIL; /* never valid for News */ } /* News delete mailbox * mailbox name to delete * Returns: T on success, NIL on failure */ long news_delete (MAILSTREAM *stream,char *mailbox) { return NIL; /* never valid for News */ } /* News rename mailbox * Accepts: mail stream * old mailbox name * new mailbox name * Returns: T on success, NIL on failure */ long news_rename (MAILSTREAM *stream,char *old,char *newname) { return NIL; /* never valid for News */ } /* News open * Accepts: stream to open * Returns: stream on success, NIL on failure */ MAILSTREAM *news_open (MAILSTREAM *stream) { long i,nmsgs; char *s,tmp[MAILTMPLEN]; struct direct **names = NIL; /* return prototype for OP_PROTOTYPE call */ if (!stream) return &newsproto; if (stream->local) fatal ("news recycle stream"); /* build directory name */ sprintf (s = tmp,"%s/%s",(char *) mail_parameters (NIL,GET_NEWSSPOOL,NIL), stream->mailbox + 6); while (s = strchr (s,'.')) *s = '/'; /* scan directory */ if ((nmsgs = scandir (tmp,&names,news_select,news_numsort)) >= 0) { mail_exists (stream,nmsgs); /* notify upper level that messages exist */ stream->local = fs_get (sizeof (NEWSLOCAL)); LOCAL->dirty = NIL; /* no update to .newsrc needed yet */ LOCAL->dir = cpystr (tmp); /* copy directory name for later */ LOCAL->name = cpystr (stream->mailbox + 6); for (i = 0; i < nmsgs; ++i) { stream->uid_last = mail_elt (stream,i+1)->private.uid = atoi (names[i]->d_name); fs_give ((void **) &names[i]); } s = (void *) names; /* stupid language */ fs_give ((void **) &s); /* free directory */ LOCAL->cachedtexts = 0; /* no cached texts */ stream->sequence++; /* bump sequence number */ stream->rdonly = stream->perm_deleted = T; /* UIDs are always valid */ stream->uid_validity = 0xbeefface; /* read .newsrc entries */ mail_recent (stream,newsrc_read (LOCAL->name,stream)); /* notify if empty newsgroup */ if (!(stream->nmsgs || stream->silent)) { sprintf (tmp,"Newsgroup %s is empty",LOCAL->name); mm_log (tmp,WARN); } } else mm_log ("Unable to scan newsgroup spool directory",ERROR); return LOCAL ? stream : NIL; /* if stream is alive, return to caller */ } /* News file name selection test * Accepts: candidate directory entry * Returns: T to use file name, NIL to skip it */ int news_select (struct direct *name) { char c; char *s = name->d_name; while (c = *s++) if (!isdigit (c)) return NIL; return T; } /* News file name comparision * Accepts: first candidate directory entry * second candidate directory entry * Returns: negative if d1 < d2, 0 if d1 == d2, postive if d1 > d2 */ int news_numsort (const void *d1,const void *d2) { return atoi ((*(struct direct **) d1)->d_name) - atoi ((*(struct direct **) d2)->d_name); } /* News close * Accepts: MAIL stream * option flags */ void news_close (MAILSTREAM *stream,long options) { if (LOCAL) { /* only if a file is open */ news_check (stream); /* dump final checkpoint */ if (LOCAL->dir) fs_give ((void **) &LOCAL->dir); if (LOCAL->name) fs_give ((void **) &LOCAL->name); /* nuke the local data */ fs_give ((void **) &stream->local); stream->dtb = NIL; /* log out the DTB */ } } /* News fetch fast information * Accepts: MAIL stream * sequence * option flags */ void news_fast (MAILSTREAM *stream,char *sequence,long flags) { MESSAGECACHE *elt; unsigned long i; /* set up metadata for all messages */ if (stream && LOCAL && ((flags & FT_UID) ? mail_uid_sequence (stream,sequence) : mail_sequence (stream,sequence))) for (i = 1; i <= stream->nmsgs; i++) if ((elt = mail_elt (stream,i))->sequence && !(elt->day && elt->rfc822_size)) news_load_message (stream,i,NIL); } /* News fetch flags * Accepts: MAIL stream * sequence * option flags */ void news_flags (MAILSTREAM *stream,char *sequence,long flags) { unsigned long i; if ((flags & FT_UID) ? /* validate all elts */ mail_uid_sequence (stream,sequence) : mail_sequence (stream,sequence)) for (i = 1; i <= stream->nmsgs; i++) mail_elt (stream,i)->valid = T; } /* News load message into cache * Accepts: MAIL stream * message # * option flags */ void news_load_message (MAILSTREAM *stream,unsigned long msgno,long flags) { unsigned long i,j,nlseen; int fd; unsigned char c,*t; struct stat sbuf; MESSAGECACHE *elt; FDDATA d; STRING bs; elt = mail_elt (stream,msgno);/* get elt */ /* build message file name */ sprintf (LOCAL->buf,"%s/%lu",LOCAL->dir,elt->private.uid); /* anything we need not currently cached? */ if ((!elt->day || !elt->rfc822_size || ((flags & NLM_HEADER) && !elt->private.msg.header.text.data) || ((flags & NLM_TEXT) && !elt->private.msg.text.text.data)) && ((fd = open (LOCAL->buf,O_RDONLY,NIL)) >= 0)) { fstat (fd,&sbuf); /* get file metadata */ d.fd = fd; /* set up file descriptor */ d.pos = 0; /* start of file */ d.chunk = LOCAL->buf; d.chunksize = CHUNKSIZE; INIT (&bs,fd_string,&d,sbuf.st_size); if (!elt->day) { /* set internaldate to file date */ struct tm *tm = gmtime (&sbuf.st_mtime); elt->day = tm->tm_mday; elt->month = tm->tm_mon + 1; elt->year = tm->tm_year + 1900 - BASEYEAR; elt->hours = tm->tm_hour; elt->minutes = tm->tm_min; elt->seconds = tm->tm_sec; elt->zhours = 0; elt->zminutes = 0; } if (!elt->rfc822_size) { /* know message size yet? */ for (i = 0, j = SIZE (&bs), nlseen = 0; j--; ) switch (SNX (&bs)) { case '\015': /* unlikely carriage return */ if (!j || (CHR (&bs) != '\012')) { i++; /* ugh, raw CR */ nlseen = NIL; break; } SNX (&bs); /* eat the line feed, drop in */ case '\012': /* line feed? */ i += 2; /* count a CRLF */ /* header size known yet? */ if (!elt->private.msg.header.text.size && nlseen) { /* note position in file */ elt->private.special.text.size = GETPOS (&bs); /* and CRLF-adjusted size */ elt->private.msg.header.text.size = i; } nlseen = T; /* note newline seen */ break; default: /* ordinary chararacter */ i++; nlseen = NIL; break; } SETPOS (&bs,0); /* restore old position */ elt->rfc822_size = i; /* note that we have size now */ /* header is entire message if no delimiter */ if (!elt->private.msg.header.text.size) elt->private.msg.header.text.size = elt->rfc822_size; /* text is remainder of message */ elt->private.msg.text.text.size = elt->rfc822_size - elt->private.msg.header.text.size; } /* need to load cache with message data? */ if (((flags & NLM_HEADER) && !elt->private.msg.header.text.data) || ((flags & NLM_TEXT) && !elt->private.msg.text.text.data)) { /* purge cache if too big */ if (LOCAL->cachedtexts > max (stream->nmsgs * 4096,2097152)) { /* just can't keep that much */ mail_gc (stream,GC_TEXTS); LOCAL->cachedtexts = 0; } if ((flags & NLM_HEADER) && !elt->private.msg.header.text.data) { t = elt->private.msg.header.text.data = (unsigned char *) fs_get (elt->private.msg.header.text.size + 1); LOCAL->cachedtexts += elt->private.msg.header.text.size; /* read in message header */ for (i = 0; i <= elt->private.msg.header.text.size; i++) switch (c = SNX (&bs)) { case '\015': /* unlikely carriage return */ *t++ = c; if ((CHR (&bs) == '\012')) *t++ = SNX (&bs); break; case '\012': /* line feed? */ *t++ = '\015'; default: *t++ = c; break; } *t = '\0'; /* tie off string */ } if ((flags & NLM_TEXT) && !elt->private.msg.text.text.data) { t = elt->private.msg.text.text.data = (unsigned char *) fs_get (elt->private.msg.text.text.size + 1); SETPOS (&bs,elt->private.msg.header.text.size); LOCAL->cachedtexts += elt->private.msg.text.text.size; /* read in message text */ for (i = 0; i <= elt->private.msg.text.text.size; i++) switch (c = SNX (&bs)) { case '\015': /* unlikely carriage return */ *t++ = c; if ((CHR (&bs) == '\012')) *t++ = SNX (&bs); break; case '\012': /* line feed? */ *t++ = '\015'; default: *t++ = c; break; } *t = '\0'; /* tie off string */ } } close (fd); /* flush message file */ } } /* News fetch message header * Accepts: MAIL stream * message # to fetch * pointer to returned header text length * option flags * Returns: message header in RFC822 format */ char *news_header (MAILSTREAM *stream,unsigned long msgno, unsigned long *length,long flags) { MESSAGECACHE *elt; *length = 0; /* default to empty */ if (flags & FT_UID) return "";/* UID call "impossible" */ elt = mail_elt (stream,msgno);/* get elt */ if (!elt->private.msg.header.text.data) news_load_message (stream,msgno,NLM_HEADER); *length = elt->private.msg.header.text.size; return (char *) elt->private.msg.header.text.data; } /* News fetch message text (body only) * Accepts: MAIL stream * message # to fetch * pointer to returned stringstruct * option flags * Returns: T on success, NIL on failure */ long news_text (MAILSTREAM *stream,unsigned long msgno,STRING *bs,long flags) { MESSAGECACHE *elt; /* UID call "impossible" */ if (flags & FT_UID) return NIL; elt = mail_elt (stream,msgno);/* get elt */ /* snarf message if don't have it yet */ if (!elt->private.msg.text.text.data) { news_load_message (stream,msgno,NLM_TEXT); if (!elt->private.msg.text.text.data) return NIL; } if (!(flags & FT_PEEK)) { /* mark as seen */ mail_elt (stream,msgno)->seen = T; mm_flags (stream,msgno); } INIT (bs,mail_string,elt->private.msg.text.text.data, elt->private.msg.text.text.size); return T; } /* News per-message modify flag * Accepts: MAIL stream * message cache element */ void news_flagmsg (MAILSTREAM *stream,MESSAGECACHE *elt) { if (!LOCAL->dirty) { /* only bother checking if not dirty yet */ if (elt->valid) { /* if done, see if deleted changed */ if (elt->sequence != elt->deleted) LOCAL->dirty = T; elt->sequence = T; /* leave the sequence set */ } /* note current setting of deleted flag */ else elt->sequence = elt->deleted; } } /* News ping mailbox * Accepts: MAIL stream * Returns: T if stream alive, else NIL */ long news_ping (MAILSTREAM *stream) { return T; /* always alive */ } /* News check mailbox * Accepts: MAIL stream */ void news_check (MAILSTREAM *stream) { /* never do if no updates */ if (LOCAL->dirty) newsrc_write (LOCAL->name,stream); LOCAL->dirty = NIL; } /* News expunge mailbox * Accepts: MAIL stream * sequence to expunge if non-NIL * expunge options * Returns: T if success, NIL if failure */ long news_expunge (MAILSTREAM *stream,char *sequence,long options) { if (!stream->silent) mm_log ("Expunge ignored on readonly mailbox",NIL); return LONGT; } /* News copy message(s) * Accepts: MAIL stream * sequence * destination mailbox * option flags * Returns: T if copy successful, else NIL */ long news_copy (MAILSTREAM *stream,char *sequence,char *mailbox,long options) { mailproxycopy_t pc = (mailproxycopy_t) mail_parameters (stream,GET_MAILPROXYCOPY,NIL); if (pc) return (*pc) (stream,sequence,mailbox,options); mm_log ("Copy not valid for News",ERROR); return NIL; } /* News append message from stringstruct * Accepts: MAIL stream * destination mailbox * append callback function * data for callback * Returns: T if append successful, else NIL */ long news_append (MAILSTREAM *stream,char *mailbox,append_t af,void *data) { mm_log ("Append not valid for news",ERROR); return NIL; } alpine-2.10+dfsg/imap/src/osdep/unix/os_nxt.c0000600000175000017500000000251211512502123022623 0ustar paulproteuspaulproteus/* ======================================================================== * Copyright 1988-2007 University of Washington * * Licensed under the Apache License, Version 2.0 (the "License"); * you may not use this file except in compliance with the License. * You may obtain a copy of the License at * * http://www.apache.org/licenses/LICENSE-2.0 * * * ======================================================================== */ /* * Program: Operating-system dependent routines -- NeXT version * * Author: Mark Crispin * Networks and Distributed Computing * Computing & Communications * University of Washington * Administration Building, AG-44 * Seattle, WA 98195 * Internet: MRC@CAC.Washington.EDU * * Date: 1 August 1988 * Last Edited: 16 August 2007 */ #include "tcp_unix.h" /* must be before osdep includes tcp.h */ #include "mail.h" #include "osdep.h" #include #include #include #include #include #include #include #include #include extern int errno; /* just in case */ #include #include "misc.h" #include "fs_unix.c" #include "ftl_unix.c" #include "nl_unix.c" #include "env_unix.c" #define fork vfork #include "tcp_unix.c" #include "gr_wait4.c" #include "tz_bsd.c" #include "strtok.c" alpine-2.10+dfsg/imap/src/osdep/unix/opendir.c0000600000175000017500000000370711512502123022760 0ustar paulproteuspaulproteus/* ======================================================================== * Copyright 1988-2006 University of Washington * * Licensed under the Apache License, Version 2.0 (the "License"); * you may not use this file except in compliance with the License. * You may obtain a copy of the License at * * http://www.apache.org/licenses/LICENSE-2.0 * * * ======================================================================== */ /* * Program: Read directories * * Author: Mark Crispin * Networks and Distributed Computing * Computing & Communications * University of Washington * Administration Building, AG-44 * Seattle, WA 98195 * Internet: MRC@CAC.Washington.EDU * * Date: 16 December 1993 * Last Edited: 30 August 2006 */ /* Emulator for BSD opendir() call * Accepts: directory name * Returns: directory structure pointer */ DIR *opendir (char *name) { DIR *d = NIL; struct stat sbuf; int fd = open (name,O_RDONLY,NIL); errno = ENOTDIR; /* default error is bogus directory */ if ((fd >= 0) && !(fstat (fd,&sbuf)) && ((sbuf.st_mode&S_IFMT) == S_IFDIR)) { d = (DIR *) fs_get (sizeof (DIR)); /* initialize structure */ d->dd_loc = 0; read (fd,d->dd_buf = (char *) fs_get (sbuf.st_size), d->dd_size = sbuf.st_size); } else if (d) fs_give ((void **) &d); if (fd >= 0) close (fd); return d; } /* Emulator for BSD closedir() call * Accepts: directory structure pointer */ int closedir (DIR *d) { /* free storage */ fs_give ((void **) &(d->dd_buf)); fs_give ((void **) &d); return NIL; /* return */ } /* Emulator for BSD readdir() call * Accepts: directory structure pointer */ struct direct *readdir (DIR *d) { /* loop through directory */ while (d->dd_loc < d->dd_size) { struct direct *dp = (struct direct *) (d->dd_buf + d->dd_loc); d->dd_loc += sizeof (struct direct); if (dp->d_ino) return dp; /* if have a good entry return it */ } return NIL; /* all done */ } alpine-2.10+dfsg/imap/src/osdep/unix/os_sgi.c0000600000175000017500000000260511512502123022577 0ustar paulproteuspaulproteus/* ======================================================================== * Copyright 1988-2006 University of Washington * * Licensed under the Apache License, Version 2.0 (the "License"); * you may not use this file except in compliance with the License. * You may obtain a copy of the License at * * http://www.apache.org/licenses/LICENSE-2.0 * * * ======================================================================== */ /* * Program: Operating-system dependent routines -- SGI version * * Author: Mark Crispin * Networks and Distributed Computing * Computing & Communications * University of Washington * Administration Building, AG-44 * Seattle, WA 98195 * Internet: MRC@CAC.Washington.EDU * * Date: 1 August 1988 * Last Edited: 30 August 2006 */ #include "tcp_unix.h" /* must be before osdep includes tcp.h */ #include "mail.h" #include "osdep.h" #include #include #include #include #include #include #include #include #include #include extern int errno; /* just in case */ #include #include "misc.h" #include "fs_unix.c" #include "ftl_unix.c" #include "nl_unix.c" #include "env_unix.c" #include "tcp_unix.c" #include "gr_waitp.c" #include "tz_nul.c" #include "flocksim.c" #undef setpgrp #include "setpgrp.c" #include "utime.c" alpine-2.10+dfsg/imap/src/osdep/unix/ckp_sec.c0000600000175000017500000000305211512502123022720 0ustar paulproteuspaulproteus/* ======================================================================== * Copyright 1988-2006 University of Washington * * Licensed under the Apache License, Version 2.0 (the "License"); * you may not use this file except in compliance with the License. * You may obtain a copy of the License at * * http://www.apache.org/licenses/LICENSE-2.0 * * * ======================================================================== */ /* * Program: SecureWare check password * * Author: Mark Crispin * Networks and Distributed Computing * Computing & Communications * University of Washington * Administration Building, AG-44 * Seattle, WA 98195 * Internet: MRC@CAC.Washington.EDU * * Date: 1 August 1988 * Last Edited: 30 August 2006 */ /* Check password * Accepts: login passwd struct * password string * argument count * argument vector * Returns: passwd struct if password validated, NIL otherwise */ struct passwd *checkpw (struct passwd *pw,char *pass,int argc,char *argv[]) { struct pr_passwd *pp; set_auth_parameters (argc,argv); if ((pw->pw_passwd && pw->pw_passwd[0] && pw->pw_passwd[1] && !strcmp (pw->pw_passwd,(char *) crypt (pass,pw->pw_passwd))) || ((pp = getprpwnam (pw->pw_name)) && !pp->ufld.fd_lock && pp->ufld.fd_encrypt && pp->ufld.fd_encrypt[0] && pp->ufld.fd_encrypt[1] && !strcmp (pp->ufld.fd_encrypt,bigcrypt (pass,pp->ufld.fd_encrypt)))) endprpwent (); /* don't need shadow password data any more */ else pw = NIL; /* password failed */ return pw; } alpine-2.10+dfsg/imap/src/osdep/unix/os_sun.h0000600000175000017500000000243311512502123022626 0ustar paulproteuspaulproteus/* ======================================================================== * Copyright 1988-2006 University of Washington * * Licensed under the Apache License, Version 2.0 (the "License"); * you may not use this file except in compliance with the License. * You may obtain a copy of the License at * * http://www.apache.org/licenses/LICENSE-2.0 * * * ======================================================================== */ /* * Program: Operating-system dependent routines -- SUN-OS version * * Author: Mark Crispin * Networks and Distributed Computing * Computing & Communications * University of Washington * Administration Building, AG-44 * Seattle, WA 98195 * Internet: MRC@CAC.Washington.EDU * * Date: 11 May 1989 * Last Edited: 30 August 2006 */ #include #include #include #include #include #include #include #define strstr Strstr /* override system definition */ #include "env_unix.h" #include "fs.h" #include "ftl.h" #include "nl.h" #include "tcp.h" char *Strstr (char *cs,char *ct); char *strerror (int n); unsigned long strtoul (char *s,char **endp,int base); #define memcpy memmove void *memmove (void *s,void *ct,size_t n); void *memset (void *s,int c,size_t n); alpine-2.10+dfsg/imap/src/osdep/unix/os_bsf.c0000600000175000017500000000252511512502123022570 0ustar paulproteuspaulproteus/* ======================================================================== * Copyright 1988-2007 University of Washington * * Licensed under the Apache License, Version 2.0 (the "License"); * you may not use this file except in compliance with the License. * You may obtain a copy of the License at * * http://www.apache.org/licenses/LICENSE-2.0 * * * ======================================================================== */ /* * Program: Operating-system dependent routines -- BSDI BSD/386 version * * Author: Mark Crispin * Networks and Distributed Computing * Computing & Communications * University of Washington * Administration Building, AG-44 * Seattle, WA 98195 * Internet: MRC@CAC.Washington.EDU * * Date: 1 August 1988 * Last Edited: 16 August 2007 */ #include "tcp_unix.h" /* must be before osdep includes tcp.h */ #include "mail.h" #include "osdep.h" #include #include #include #include #include #include #include #include #include extern int errno; /* just in case */ #include #include "misc.h" #include "fs_unix.c" #include "ftl_unix.c" #include "nl_unix.c" #include "env_unix.c" #include "getspnam.c" #define fork vfork #include "tcp_unix.c" #include "gr_waitp.c" #include "tz_bsd.c" alpine-2.10+dfsg/imap/src/osdep/unix/env_unix.c0000600000175000017500000017223011512502123023151 0ustar paulproteuspaulproteus/* ======================================================================== * Copyright 1988-2008 University of Washington * * Licensed under the Apache License, Version 2.0 (the "License"); * you may not use this file except in compliance with the License. * You may obtain a copy of the License at * * http://www.apache.org/licenses/LICENSE-2.0 * * * ======================================================================== */ /* * Program: UNIX environment routines * * Author: Mark Crispin * UW Technology * University of Washington * Seattle, WA 98195 * Internet: MRC@Washington.EDU * * Date: 1 August 1988 * Last Edited: 23 February 2009 */ #include #include #include /* in case stat.h is ancient */ #ifndef S_IRUSR #define S_IRUSR S_IREAD #endif #ifndef S_IWUSR #define S_IWUSR S_IWRITE #endif #ifndef S_IXUSR #define S_IXUSR S_IEXEC #endif #ifndef S_IRGRP #define S_IRGRP (S_IREAD >> 3) #endif #ifndef S_IWGRP #define S_IWGRP (S_IWRITE >> 3) #endif #ifndef S_IXGRP #define S_IXGRP (S_IEXEC >> 3) #endif #ifndef S_IROTH #define S_IROTH (S_IREAD >> 6) #endif #ifndef S_IWOTH #define S_IWOTH (S_IWRITE >> 6) #endif #ifndef S_IXOTH #define S_IXOTH (S_IEXEC >> 6) #endif /* c-client environment parameters */ static char *myUserName = NIL; /* user name */ static char *myHomeDir = NIL; /* home directory name */ static char *myServerName = NIL;/* server name */ static char *myLocalHost = NIL; /* local host name */ static char *myNewsrc = NIL; /* newsrc file name */ static char *mailsubdir = NIL; /* mailbox subdirectory name */ static char *sysInbox = NIL; /* system inbox name */ static char *newsActive = NIL; /* news active file */ static char *newsSpool = NIL; /* news spool */ static char *blackBoxDir = NIL; /* black box directory name */ /* black box default home directory */ static char *blackBoxDefaultHome = NIL; static char *sslCApath = NIL; /* non-standard CA path */ static short anonymous = NIL; /* is anonymous */ static short blackBox = NIL; /* is a black box */ static short closedBox = NIL; /* is a closed box (uses chroot() jail) */ static short restrictBox = NIL; /* is a restricted box */ static short has_no_life = NIL; /* is a cretin with no life */ /* block environment init */ static short block_env_init = NIL; static short hideDotFiles = NIL;/* hide files whose names start with . */ /* advertise filesystem root */ static short advertisetheworld = NIL; /* only advertise own mailboxes and #shared */ static short limitedadvertise = NIL; /* disable automatic shared namespaces */ static short noautomaticsharedns = NIL; static short no822tztext = NIL; /* disable RFC [2]822 timezone text */ /* client principals include service name */ static short kerb_cp_svr_name = NIL; static long locktimeout = 5; /* default lock timeout in minutes */ /* default prototypes */ static MAILSTREAM *createProto = NIL; static MAILSTREAM *appendProto = NIL; /* default user flags */ static char *userFlags[NUSERFLAGS] = {NIL}; static NAMESPACE *nslist[3]; /* namespace list */ static int logtry = 3; /* number of server login tries */ /* block notification */ static blocknotify_t mailblocknotify = mm_blocknotify; /* logout function */ static logouthook_t maillogouthook = NIL; /* logout data */ static void *maillogoutdata = NIL; /* allow user config files */ static short allowuserconfig = NIL; /* 1 = disable plaintext, 2 = if not SSL */ static long disablePlaintext = NIL; static long list_max_level = 20;/* maximum level of list recursion */ /* facility for syslog */ static int syslog_facility = LOG_MAIL; /* Path of the privileged system lock program (mlock). Normally set by * logic test. */ static char *lockpgm = LOCKPGM; /* Directory used for shared locks. MUST be the same for all users of the * system, and MUST be protected 1777. /var/tmp may be preferable on some * systems. */ static const char *tmpdir = "/tmp"; /* Do not change shlock_mode. Doing so can cause mailbox corruption and * denial of service. It also defeats the entire purpose of the shared * lock mechanism. The right way to avoid shared locks is to set up a * closed box (see the closedBox setting). */ /* shared lock mode */ static const int shlock_mode = S_IRUSR|S_IWUSR|S_IRGRP|S_IWGRP|S_IROTH|S_IWOTH; /* It is STRONGLY recommended that you do not change dotlock_mode. Doing so * can cause denial of service with old dot-lock files left lying around. * However, since dot-locks are only used with traditional UNIX and MMDF * formats which are not normally shared, it is much less harmful to tamper * with this than with shlock_mode. */ /* dot-lock mode */ static long dotlock_mode = S_IRUSR|S_IWUSR|S_IRGRP|S_IWGRP|S_IROTH|S_IWOTH; /* File/directory access and protection policies */ /* Unlike shlock_mode, the ????_protection modes are intended to be fully * customizable according to site policy. The values here are recommended * settings, based upon the documented purposes of the namespaces. */ /* user space - only owner can read/write */ static char *myMailboxDir = NIL;/* user space directory name */ /* default file protection */ static long mbx_protection = S_IRUSR|S_IWUSR; /* default directory protection */ static long dir_protection = S_IRUSR|S_IWUSR|S_IXUSR; /* user space for user "anonymous" */ /* anonymous home directory */ static char *anonymousHome = NIL; /* #ftp - everybody can read, only owner can write */ static char *ftpHome = NIL; /* ftp export home directory */ /* default ftp file protection */ static long ftp_protection = S_IRUSR|S_IWUSR|S_IRGRP|S_IROTH; static long ftp_dir_protection =/* default ftp directory protection */ S_IRUSR|S_IWUSR|S_IXUSR|S_IRGRP|S_IXGRP|S_IROTH|S_IXOTH; /* #public - everybody can read/write */ static char *publicHome = NIL; /* public home directory */ static long public_protection = /* default public file protection */ S_IRUSR|S_IWUSR|S_IRGRP|S_IWGRP|S_IROTH|S_IWOTH; /* default public directory protection */ static long public_dir_protection = S_IRUSR|S_IWUSR|S_IXUSR|S_IRGRP|S_IWGRP|S_IXGRP|S_IROTH|S_IWOTH|S_IXOTH; /* #shared/ - owner and group members can read/write */ static char *sharedHome = NIL; /* shared home directory */ /* default shared file protection */ static long shared_protection = S_IRUSR|S_IWUSR|S_IRGRP|S_IWGRP; /* default shared directory protection */ static long shared_dir_protection = S_IRUSR|S_IWUSR|S_IXUSR|S_IRGRP|S_IWGRP|S_IXGRP; /* OS bug workarounds - should be avoided at all cost */ /* Don't set fcntlhangbug unless you really have to, since it risks mailbox * corruption. The flocksim.c mechanism is designed to detect NFS access * and no-op in that cases only, so this flag should be unnecessary. */ static short fcntlhangbug = NIL;/* flock() emulator using fcntl() is a no-op */ /* Don't set netfsstatbug unless you really have to, since it dramatically * slows down traditional UNIX and MMDF mailbox performance. */ static short netfsstatbug = NIL;/* compensate for broken stat() on network * filesystems (AFS and old NFS) */ /* Note: setting disableLockWarning means that you assert that the * so-modified copy of this software will NEVER be used: * 1) in conjunction with any software which expects .lock files * 2) to access NFS-mounted files and directories * * Unless both of these conditions apply, then do not set this flag. * Instead, read the FAQ (item 7.10) and either use 1777 protection * on the mail spool, or install mlock. * * In addition, by setting this flag you also agree that you are fully * legally and morally responsible when (not if) mail files are damaged * as the result of your choice. * * The mlock tool exists for a reason. Use it. */ /* disable warning if can't make .lock file */ static short disableLockWarning = NIL; /* UNIX Namespaces */ /* personal mh namespace */ static NAMESPACE nsmhf = {"#mh/",'/',NIL,NIL}; static NAMESPACE nsmh = {"#mhinbox",NIL,NIL,&nsmhf}; /* home namespace */ static NAMESPACE nshome = {"",'/',NIL,&nsmh}; /* UNIX other user namespace */ static NAMESPACE nsunixother = {"~",'/',NIL,NIL}; /* black box other user namespace */ static NAMESPACE nsblackother = {"/",'/',NIL,NIL}; /* public (anonymous OK) namespace */ static NAMESPACE nspublic = {"#public/",'/',NIL,NIL}; /* netnews namespace */ static NAMESPACE nsnews = {"#news.",'.',NIL,&nspublic}; /* FTP export namespace */ static NAMESPACE nsftp = {"#ftp/",'/',NIL,&nsnews}; /* shared (no anonymous) namespace */ static NAMESPACE nsshared = {"#shared/",'/',NIL,&nsftp}; /* world namespace */ static NAMESPACE nsworld = {"/",'/',NIL,&nsshared}; /* only shared and public namespaces */ static NAMESPACE nslimited = {"#shared/",'/',NIL,&nspublic}; #include "write.c" /* include safe writing routines */ #include "crexcl.c" /* include exclusive create */ #include "pmatch.c" /* include wildcard pattern matcher */ /* Get all authenticators */ #include "auths.c" /* Environment manipulate parameters * Accepts: function code * function-dependent value * Returns: function-dependent return value */ void *env_parameters (long function,void *value) { void *ret = NIL; switch ((int) function) { case GET_NAMESPACE: ret = (void *) nslist; break; case SET_USERNAME: if (myUserName) fs_give ((void **) &myUserName); myUserName = cpystr ((char *) value); case GET_USERNAME: ret = (void *) myUserName; break; case SET_HOMEDIR: if (myHomeDir) fs_give ((void **) &myHomeDir); myHomeDir = cpystr ((char *) value); case GET_HOMEDIR: ret = (void *) myHomeDir; break; case SET_LOCALHOST: if (myLocalHost) fs_give ((void **) &myLocalHost); myLocalHost = cpystr ((char *) value); case GET_LOCALHOST: ret = (void *) myLocalHost; break; case SET_NEWSRC: if (myNewsrc) fs_give ((void **) &myNewsrc); myNewsrc = cpystr ((char *) value); case GET_NEWSRC: ret = (void *) myNewsrc; break; case SET_NEWSACTIVE: if (newsActive) fs_give ((void **) &newsActive); newsActive = cpystr ((char *) value); case GET_NEWSACTIVE: ret = (void *) newsActive; break; case SET_NEWSSPOOL: if (newsSpool) fs_give ((void **) &newsSpool); newsSpool = cpystr ((char *) value); case GET_NEWSSPOOL: ret = (void *) newsSpool; break; case SET_ANONYMOUSHOME: if (anonymousHome) fs_give ((void **) &anonymousHome); anonymousHome = cpystr ((char *) value); case GET_ANONYMOUSHOME: if (!anonymousHome) anonymousHome = cpystr (ANONYMOUSHOME); ret = (void *) anonymousHome; break; case SET_FTPHOME: if (ftpHome) fs_give ((void **) &ftpHome); ftpHome = cpystr ((char *) value); case GET_FTPHOME: ret = (void *) ftpHome; break; case SET_PUBLICHOME: if (publicHome) fs_give ((void **) &publicHome); publicHome = cpystr ((char *) value); case GET_PUBLICHOME: ret = (void *) publicHome; break; case SET_SHAREDHOME: if (sharedHome) fs_give ((void **) &sharedHome); sharedHome = cpystr ((char *) value); case GET_SHAREDHOME: ret = (void *) sharedHome; break; case SET_SYSINBOX: if (sysInbox) fs_give ((void **) &sysInbox); sysInbox = cpystr ((char *) value); case GET_SYSINBOX: ret = (void *) sysInbox; break; case SET_SSLCAPATH: /* this can be set null */ if (sslCApath) fs_give ((void **) &sslCApath); sslCApath = value ? cpystr ((char *) value) : value; break; case GET_SSLCAPATH: ret = (void *) sslCApath; break; case SET_LISTMAXLEVEL: list_max_level = (long) value; case GET_LISTMAXLEVEL: ret = (void *) list_max_level; break; case SET_MBXPROTECTION: mbx_protection = (long) value; case GET_MBXPROTECTION: ret = (void *) mbx_protection; break; case SET_DIRPROTECTION: dir_protection = (long) value; case GET_DIRPROTECTION: ret = (void *) dir_protection; break; case SET_LOCKPROTECTION: dotlock_mode = (long) value; case GET_LOCKPROTECTION: ret = (void *) dotlock_mode; break; case SET_FTPPROTECTION: ftp_protection = (long) value; case GET_FTPPROTECTION: ret = (void *) ftp_protection; break; case SET_PUBLICPROTECTION: public_protection = (long) value; case GET_PUBLICPROTECTION: ret = (void *) public_protection; break; case SET_SHAREDPROTECTION: shared_protection = (long) value; case GET_SHAREDPROTECTION: ret = (void *) shared_protection; break; case SET_FTPDIRPROTECTION: ftp_dir_protection = (long) value; case GET_FTPDIRPROTECTION: ret = (void *) ftp_dir_protection; break; case SET_PUBLICDIRPROTECTION: public_dir_protection = (long) value; case GET_PUBLICDIRPROTECTION: ret = (void *) public_dir_protection; break; case SET_SHAREDDIRPROTECTION: shared_dir_protection = (long) value; case GET_SHAREDDIRPROTECTION: ret = (void *) shared_dir_protection; break; case SET_LOCKTIMEOUT: locktimeout = (long) value; case GET_LOCKTIMEOUT: ret = (void *) locktimeout; break; case SET_DISABLEFCNTLLOCK: fcntlhangbug = value ? T : NIL; case GET_DISABLEFCNTLLOCK: ret = (void *) (fcntlhangbug ? VOIDT : NIL); break; case SET_LOCKEACCESERROR: disableLockWarning = value ? NIL : T; case GET_LOCKEACCESERROR: ret = (void *) (disableLockWarning ? NIL : VOIDT); break; case SET_HIDEDOTFILES: hideDotFiles = value ? T : NIL; case GET_HIDEDOTFILES: ret = (void *) (hideDotFiles ? VOIDT : NIL); break; case SET_DISABLEPLAINTEXT: disablePlaintext = (long) value; case GET_DISABLEPLAINTEXT: ret = (void *) disablePlaintext; break; case SET_CHROOTSERVER: closedBox = value ? T : NIL; case GET_CHROOTSERVER: ret = (void *) (closedBox ? VOIDT : NIL); break; case SET_ADVERTISETHEWORLD: advertisetheworld = value ? T : NIL; case GET_ADVERTISETHEWORLD: ret = (void *) (advertisetheworld ? VOIDT : NIL); break; case SET_LIMITEDADVERTISE: limitedadvertise = value ? T : NIL; case GET_LIMITEDADVERTISE: ret = (void *) (limitedadvertise ? VOIDT : NIL); break; case SET_DISABLEAUTOSHAREDNS: noautomaticsharedns = value ? T : NIL; case GET_DISABLEAUTOSHAREDNS: ret = (void *) (noautomaticsharedns ? VOIDT : NIL); break; case SET_DISABLE822TZTEXT: no822tztext = value ? T : NIL; case GET_DISABLE822TZTEXT: ret = (void *) (no822tztext ? VOIDT : NIL); break; case SET_USERHASNOLIFE: has_no_life = value ? T : NIL; case GET_USERHASNOLIFE: ret = (void *) (has_no_life ? VOIDT : NIL); break; case SET_KERBEROS_CP_SVR_NAME: kerb_cp_svr_name = value ? T : NIL; case GET_KERBEROS_CP_SVR_NAME: ret = (void *) (kerb_cp_svr_name ? VOIDT : NIL); break; case SET_NETFSSTATBUG: netfsstatbug = value ? T : NIL; case GET_NETFSSTATBUG: ret = (void *) (netfsstatbug ? VOIDT : NIL); break; case SET_BLOCKENVINIT: block_env_init = value ? T : NIL; case GET_BLOCKENVINIT: ret = (void *) (block_env_init ? VOIDT : NIL); break; case SET_BLOCKNOTIFY: mailblocknotify = (blocknotify_t) value; case GET_BLOCKNOTIFY: ret = (void *) mailblocknotify; break; case SET_LOGOUTHOOK: maillogouthook = (logouthook_t) value; case GET_LOGOUTHOOK: ret = maillogouthook; break; case SET_LOGOUTDATA: maillogoutdata = (void *) value; case GET_LOGOUTDATA: ret = maillogoutdata; } return ret; } /* Write current time * Accepts: destination string * optional format of day-of-week prefix * format of date and time * flag whether to append symbolic timezone */ static void do_date (char *date,char *prefix,char *fmt,int suffix) { time_t tn = time (0); struct tm *t = gmtime (&tn); int zone = t->tm_hour * 60 + t->tm_min; int julian = t->tm_yday; t = localtime (&tn); /* get local time now */ /* minus UTC minutes since midnight */ zone = t->tm_hour * 60 + t->tm_min - zone; /* julian can be one of: * 36x local time is December 31, UTC is January 1, offset -24 hours * 1 local time is 1 day ahead of UTC, offset +24 hours * 0 local time is same day as UTC, no offset * -1 local time is 1 day behind UTC, offset -24 hours * -36x local time is January 1, UTC is December 31, offset +24 hours */ if (julian = t->tm_yday -julian) zone += ((julian < 0) == (abs (julian) == 1)) ? -24*60 : 24*60; if (prefix) { /* want day of week? */ sprintf (date,prefix,days[t->tm_wday]); date += strlen (date); /* make next sprintf append */ } /* output the date */ sprintf (date,fmt,t->tm_mday,months[t->tm_mon],t->tm_year+1900, t->tm_hour,t->tm_min,t->tm_sec,zone/60,abs (zone) % 60); /* append timezone suffix if desired */ if (suffix) rfc822_timezone (date,(void *) t); } /* Write current time in RFC 822 format * Accepts: destination string */ void rfc822_date (char *date) { do_date (date,"%s, ","%d %s %d %02d:%02d:%02d %+03d%02d", no822tztext ? NIL : T); } /* Write current time in fixed-width RFC 822 format * Accepts: destination string */ void rfc822_fixed_date (char *date) { do_date (date,NIL,"%02d %s %4d %02d:%02d:%02d %+03d%02d",NIL); } /* Write current time in internal format * Accepts: destination string */ void internal_date (char *date) { do_date (date,NIL,"%02d-%s-%d %02d:%02d:%02d %+03d%02d",NIL); } /* Initialize server * Accepts: server name for syslog or NIL * /etc/services service name or NIL * alternate /etc/services service name or NIL * clock interrupt handler * kiss-of-death interrupt handler * hangup interrupt handler * termination interrupt handler */ void server_init (char *server,char *service,char *sslservice, void *clkint,void *kodint,void *hupint,void *trmint, void *staint) { int onceonly = server && service && sslservice; if (onceonly) { /* set server name in syslog */ int mask; openlog (myServerName = cpystr (server),LOG_PID,syslog_facility); fclose (stderr); /* possibly save a process ID */ dorc (NIL,NIL); /* do systemwide configuration */ switch (mask = umask (022)){/* check old umask */ case 0: /* definitely unreasonable */ case 022: /* don't need to change it */ break; default: /* already was a reasonable value */ umask (mask); /* so change it back */ } } arm_signal (SIGALRM,clkint); /* prepare for clock interrupt */ arm_signal (SIGUSR2,kodint); /* prepare for Kiss Of Death */ arm_signal (SIGHUP,hupint); /* prepare for hangup */ arm_signal (SIGPIPE,hupint); /* alternative hangup */ arm_signal (SIGTERM,trmint); /* prepare for termination */ /* status dump */ if (staint) arm_signal (SIGUSR1,staint); if (onceonly) { /* set up network and maybe SSL */ long port; struct servent *sv; /* Use SSL if SSL service, or if server starts with "s" and not service */ if (((port = tcp_serverport ()) >= 0)) { if ((sv = getservbyname (service,"tcp")) && (port == ntohs (sv->s_port))) syslog (LOG_DEBUG,"%s service init from %s",service,tcp_clientaddr ()); else if ((sv = getservbyname (sslservice,"tcp")) && (port == ntohs (sv->s_port))) { syslog (LOG_DEBUG,"%s SSL service init from %s",sslservice, tcp_clientaddr ()); ssl_server_init (server); } else { /* not service or SSL service port */ syslog (LOG_DEBUG,"port %ld service init from %s",port, tcp_clientaddr ()); if (*server == 's') ssl_server_init (server); } } } } /* Wait for stdin input * Accepts: timeout in seconds * Returns: T if have input on stdin, else NIL */ long server_input_wait (long seconds) { fd_set rfd,efd; struct timeval tmo; FD_ZERO (&rfd); FD_ZERO (&efd); FD_SET (0,&rfd); FD_SET (0,&efd); tmo.tv_sec = seconds; tmo.tv_usec = 0; return select (1,&rfd,0,&efd,&tmo) ? LONGT : NIL; } /* Return UNIX password entry for user name * Accepts: user name string * Returns: password entry * * Tries all-lowercase form of user name if given user name fails */ static struct passwd *pwuser (unsigned char *user) { unsigned char *s; struct passwd *pw = getpwnam (user); if (!pw) { /* failed, see if any uppercase characters */ for (s = user; *s && ((*s < 'A') || (*s > 'Z')); s++); if (*s) { /* yes, try all lowercase form */ pw = getpwnam (s = lcase (cpystr (user))); fs_give ((void **) &s); } } return pw; } /* Validate password for user name * Accepts: user name string * password string * argument count * argument vector * Returns: password entry if validated * * Tries password+1 if password fails and starts with space */ static struct passwd *valpwd (char *user,char *pwd,int argc,char *argv[]) { char *s; struct passwd *pw; struct passwd *ret = NIL; if (auth_md5.server) { /* using CRAM-MD5 authentication? */ if (s = auth_md5_pwd (user)) { if (!strcmp (s,pwd) || ((*pwd == ' ') && pwd[1] && !strcmp (s,pwd+1))) ret = pwuser (user); /* validated, get passwd entry for user */ memset (s,0,strlen (s)); /* erase sensitive information */ fs_give ((void **) &s); } } else if (pw = pwuser (user)) {/* can get user? */ s = cpystr (pw->pw_name); /* copy returned name in case we need it */ if (*pwd && !(ret = checkpw (pw,pwd,argc,argv)) && (*pwd == ' ') && pwd[1] && (ret = pwuser (s))) ret = checkpw (pw,pwd+1,argc,argv); fs_give ((void **) &s); /* don't need copy of name any more */ } return ret; } /* Server log in * Accepts: user name string * password string * authenticating user name string * argument count * argument vector * Returns: T if password validated, NIL otherwise */ long server_login (char *user,char *pwd,char *authuser,int argc,char *argv[]) { struct passwd *pw = NIL; int level = LOG_NOTICE; char *err = "failed"; /* cretins still haven't given up */ if ((strlen (user) >= NETMAXUSER) || (authuser && (strlen (authuser) >= NETMAXUSER))) { level = LOG_ALERT; /* escalate this alert */ err = "SYSTEM BREAK-IN ATTEMPT"; logtry = 0; /* render this session useless */ } else if (logtry-- <= 0) err = "excessive login failures"; else if (disablePlaintext) err = "disabled"; else if (!(authuser && *authuser)) pw = valpwd (user,pwd,argc,argv); else if (valpwd (authuser,pwd,argc,argv)) pw = pwuser (user); if (pw && pw_login (pw,authuser,pw->pw_name,NIL,argc,argv)) return T; syslog (level|LOG_AUTH,"Login %s user=%.64s auth=%.64s host=%.80s",err, user,(authuser && *authuser) ? authuser : user,tcp_clienthost ()); sleep (3); /* slow down possible cracker */ return NIL; } /* Authenticated server log in * Accepts: user name string * authenticating user name string * argument count * argument vector * Returns: T if password validated, NIL otherwise */ long authserver_login (char *user,char *authuser,int argc,char *argv[]) { return pw_login (pwuser (user),authuser,user,NIL,argc,argv); } /* Log in as anonymous daemon * Accepts: argument count * argument vector * Returns: T if successful, NIL if error */ long anonymous_login (int argc,char *argv[]) { /* log in Mr. A. N. Onymous */ return pw_login (getpwnam (ANONYMOUSUSER),NIL,NIL, (char *) mail_parameters (NIL,GET_ANONYMOUSHOME,NIL), argc,argv); } /* Finish log in and environment initialization * Accepts: passwd struct for loginpw() * optional authentication user name * user name (NIL for anonymous) * home directory (NIL to use directory from passwd struct) * argument count * argument vector * Returns: T if successful, NIL if error */ long pw_login (struct passwd *pw,char *auser,char *user,char *home,int argc, char *argv[]) { struct group *gr; char **t; long ret = NIL; if (pw && pw->pw_uid) { /* must have passwd struct for non-UID 0 */ /* make safe copies of user and home */ if (user) user = cpystr (pw->pw_name); home = cpystr (home ? home : pw->pw_dir); /* authorization ID .NE. authentication ID? */ if (user && auser && *auser && compare_cstring (auser,user)) { /* scan list of mail administrators */ if ((gr = getgrnam (ADMINGROUP)) && (t = gr->gr_mem)) while (*t && !ret) if (!compare_cstring (auser,*t++)) ret = pw_login (pw,NIL,user,home,argc,argv); syslog (LOG_NOTICE|LOG_AUTH,"%s %.80s override of user=%.80s host=%.80s", ret ? "Admin" : "Failed",auser,user,tcp_clienthost ()); } else if (closedBox) { /* paranoid site, lock out other directories */ if (chdir (home) || chroot (home)) syslog (LOG_NOTICE|LOG_AUTH, "Login %s failed: unable to set chroot=%.80s host=%.80s", pw->pw_name,home,tcp_clienthost ()); else if (loginpw (pw,argc,argv)) ret = env_init (user,NIL); else fatal ("Login failed after chroot"); } /* normal login */ else if (((pw->pw_uid == geteuid ()) || loginpw (pw,argc,argv)) && (ret = env_init (user,home))) chdir (myhomedir ()); fs_give ((void **) &home); /* clean up */ if (user) fs_give ((void **) &user); } endpwent (); /* in case shadow passwords in pw data */ return ret; /* return status */ } /* Initialize environment * Accepts: user name (NIL for anonymous) * home directory name * Returns: T, always */ long env_init (char *user,char *home) { extern MAILSTREAM CREATEPROTO; extern MAILSTREAM EMPTYPROTO; struct passwd *pw; struct stat sbuf; char tmp[MAILTMPLEN]; /* don't init if blocked */ if (block_env_init) return LONGT; if (myUserName) fatal ("env_init called twice!"); /* initially nothing in namespace list */ nslist[0] = nslist[1] = nslist[2] = NIL; /* myUserName must be set before dorc() call */ myUserName = cpystr (user ? user : ANONYMOUSUSER); /* force default prototypes to be set */ if (!createProto) createProto = &CREATEPROTO; if (!appendProto) appendProto = &EMPTYPROTO; dorc (NIL,NIL); /* do systemwide configuration */ if (!home) { /* closed box server */ /* standard user can only reference home */ if (user) nslist[0] = &nshome; else { /* anonymous user */ nslist[0] = &nsblackother; /* set root */ anonymous = T; /* flag as anonymous */ } myHomeDir = cpystr (""); /* home directory is root */ sysInbox = cpystr ("INBOX");/* make system INBOX */ } else { /* open or black box */ closedBox = NIL; /* definitely not a closed box */ if (user) { /* remember user name and home directory */ if (blackBoxDir) { /* build black box directory name */ sprintf (tmp,"%s/%s",blackBoxDir,myUserName); /* must exist */ if (!((!stat (home = tmp,&sbuf) && (sbuf.st_mode & S_IFDIR)) || (blackBoxDefaultHome && !stat (home = blackBoxDefaultHome,&sbuf) && (sbuf.st_mode & S_IFDIR)))) fatal ("no home"); sysInbox = (char *) fs_get (strlen (home) + 7); /* set system INBOX */ sprintf (sysInbox,"%s/INBOX",home); blackBox = T; /* mark that it's a black box */ /* mbox meaningless if black box */ mail_parameters (NIL,DISABLE_DRIVER,(void *) "mbox"); } nslist[0] = &nshome; /* home namespace */ /* limited advertise namespaces */ if (limitedadvertise) nslist[2] = &nslimited; else if (blackBox) { /* black box namespaces */ nslist[1] = &nsblackother; nslist[2] = &nsshared; } else { /* open box namespaces */ nslist[1] = &nsunixother; nslist[2] = advertisetheworld ? &nsworld : &nsshared; } } else { nslist[2] = &nsftp; /* anonymous user */ sprintf (tmp,"%s/INBOX", home = (char *) mail_parameters (NIL,GET_ANONYMOUSHOME,NIL)); sysInbox = cpystr (tmp); /* make system INBOX */ anonymous = T; /* flag as anonymous */ } myHomeDir = cpystr (home); /* set home directory */ } if (allowuserconfig) { /* allow user config files */ dorc (strcat (strcpy (tmp,myHomeDir),"/.mminit"),T); dorc (strcat (strcpy (tmp,myHomeDir),"/.imaprc"),NIL); } if (!closedBox && !noautomaticsharedns) { /* #ftp namespace */ if (!ftpHome && (pw = getpwnam ("ftp"))) ftpHome = cpystr (pw->pw_dir); /* #public namespace */ if (!publicHome && (pw = getpwnam ("imappublic"))) publicHome = cpystr (pw->pw_dir); /* #shared namespace */ if (!anonymous && !sharedHome && (pw = getpwnam ("imapshared"))) sharedHome = cpystr (pw->pw_dir); } if (!myLocalHost) mylocalhost (); if (!myNewsrc) myNewsrc = cpystr(strcat (strcpy (tmp,myHomeDir),"/.newsrc")); if (!newsActive) newsActive = cpystr (ACTIVEFILE); if (!newsSpool) newsSpool = cpystr (NEWSSPOOL); /* re-do open action to get flags */ (*createProto->dtb->open) (NIL); endpwent (); /* close pw database */ return T; } /* Return my user name * Accepts: pointer to optional flags * Returns: my user name */ char *myusername_full (unsigned long *flags) { struct passwd *pw; struct stat sbuf; char *s; unsigned long euid; char *ret = UNLOGGEDUSER; /* no user name yet and not root? */ if (!myUserName && (euid = geteuid ())) { /* yes, look up getlogin() user name or EUID */ if (((s = (char *) getlogin ()) && *s && (strlen (s) < NETMAXUSER) && (pw = getpwnam (s)) && (pw->pw_uid == euid)) || (pw = getpwuid (euid))) { if (block_env_init) { /* don't env_init if blocked */ if (flags) *flags = MU_LOGGEDIN; return pw->pw_name; } env_init (pw->pw_name, ((s = getenv ("HOME")) && *s && (strlen (s) < NETMAXMBX) && !stat (s,&sbuf) && ((sbuf.st_mode & S_IFMT) == S_IFDIR)) ? s : pw->pw_dir); } else fatal ("Unable to look up user name"); } if (myUserName) { /* logged in? */ if (flags) *flags = anonymous ? MU_ANONYMOUS : MU_LOGGEDIN; ret = myUserName; /* return user name */ } else if (flags) *flags = MU_NOTLOGGEDIN; return ret; } /* Return my local host name * Returns: my local host name */ char *mylocalhost () { if (!myLocalHost) { char *s,tmp[MAILTMPLEN]; char *t = "unknown"; tmp[0] = tmp[MAILTMPLEN-1] = '\0'; if (!gethostname (tmp,MAILTMPLEN-1) && tmp[0]) { /* sanity check of name */ for (s = tmp; (*s > 0x20) && (*s < 0x7f); ++s); if (!*s) t = tcp_canonical (tmp); } myLocalHost = cpystr (t); } return myLocalHost; } /* Return my home directory name * Returns: my home directory name */ char *myhomedir () { if (!myHomeDir) myusername ();/* initialize if first time */ return myHomeDir ? myHomeDir : ""; } /* Return my home mailbox name * Returns: my home directory name */ static char *mymailboxdir () { char *home = myhomedir (); /* initialize if first time */ if (!myMailboxDir && myHomeDir) { if (mailsubdir) { char tmp[MAILTMPLEN]; sprintf (tmp,"%s/%s",home,mailsubdir); myMailboxDir = cpystr (tmp);/* use pre-defined subdirectory of home */ } else myMailboxDir = cpystr (home); } return myMailboxDir ? myMailboxDir : ""; } /* Return system standard INBOX * Accepts: buffer string */ char *sysinbox () { char tmp[MAILTMPLEN]; if (!sysInbox) { /* initialize if first time */ sprintf (tmp,"%s/%s",MAILSPOOL,myusername ()); sysInbox = cpystr (tmp); /* system inbox is from mail spool */ } return sysInbox; } /* Return mailbox directory name * Accepts: destination buffer * directory prefix * name in directory * Returns: file name or NIL if error */ char *mailboxdir (char *dst,char *dir,char *name) { char tmp[MAILTMPLEN]; if (dir || name) { /* if either argument provided */ if (dir) { if (strlen (dir) > NETMAXMBX) return NIL; strcpy (tmp,dir); /* write directory prefix */ } else tmp[0] = '\0'; /* otherwise null string */ if (name) { if (strlen (name) > NETMAXMBX) return NIL; strcat (tmp,name); /* write name in directory */ } /* validate name, return its name */ if (!mailboxfile (dst,tmp)) return NIL; } /* no arguments, wants mailbox directory */ else strcpy (dst,mymailboxdir ()); return dst; /* return the name */ } /* Return mailbox file name * Accepts: destination buffer * mailbox name * Returns: file name or empty string for driver-selected INBOX or NIL if error */ char *mailboxfile (char *dst,char *name) { struct passwd *pw; char *s; if (!name || !*name || (*name == '{') || (strlen (name) > NETMAXMBX) || ((anonymous || blackBox || restrictBox || (*name == '#')) && (strstr (name,"..") || strstr (name,"//") || strstr (name,"/~")))) dst = NIL; /* invalid name */ else switch (*name) { /* determine mailbox type based upon name */ case '#': /* namespace name */ /* #ftp/ namespace */ if (((name[1] == 'f') || (name[1] == 'F')) && ((name[2] == 't') || (name[2] == 'T')) && ((name[3] == 'p') || (name[3] == 'P')) && (name[4] == '/') && ftpHome) sprintf (dst,"%s/%s",ftpHome,name+5); /* #public/ and #shared/ namespaces */ else if ((((name[1] == 'p') || (name[1] == 'P')) && ((name[2] == 'u') || (name[2] == 'U')) && ((name[3] == 'b') || (name[3] == 'B')) && ((name[4] == 'l') || (name[4] == 'L')) && ((name[5] == 'i') || (name[5] == 'I')) && ((name[6] == 'c') || (name[6] == 'C')) && (name[7] == '/') && (s = publicHome)) || (!anonymous && ((name[1] == 's') || (name[1] == 'S')) && ((name[2] == 'h') || (name[2] == 'H')) && ((name[3] == 'a') || (name[3] == 'A')) && ((name[4] == 'r') || (name[4] == 'R')) && ((name[5] == 'e') || (name[5] == 'E')) && ((name[6] == 'd') || (name[6] == 'D')) && (name[7] == '/') && (s = sharedHome))) sprintf (dst,"%s/%s",s,compare_cstring (name+8,"INBOX") ? name+8 : "INBOX"); else dst = NIL; /* unknown namespace */ break; case '/': /* root access */ if (anonymous) dst = NIL; /* anonymous forbidden to do this */ else if (blackBox) { /* other user access if blackbox */ if (restrictBox & RESTRICTOTHERUSER) dst = NIL; /* see if other user INBOX */ else if ((s = strchr (name+1,'/')) && !compare_cstring (s+1,"INBOX")) { *s = '\0'; /* temporarily tie off string */ sprintf (dst,"%s/%s/INBOX",blackBoxDir,name+1); *s = '/'; /* in case caller cares */ } else sprintf (dst,"%s/%s",blackBoxDir,name+1); } else if ((restrictBox & RESTRICTROOT) && strcmp (name,sysinbox ())) dst = NIL; /* restricted and not access to sysinbox */ else strcpy (dst,name); /* unrestricted, copy root name */ break; case '~': /* other user access */ /* bad syntax or anonymous can't win */ if (!*++name || anonymous) dst = NIL; /* ~/ equivalent to ordinary name */ else if (*name == '/') sprintf (dst,"%s/%s",mymailboxdir (),name+1); /* other user forbidden if closed/restricted */ else if (closedBox || (restrictBox & RESTRICTOTHERUSER)) dst = NIL; else if (blackBox) { /* black box form of other user */ /* see if other user INBOX */ if ((s = strchr (name,'/')) && compare_cstring (s+1,"INBOX")) { *s = '\0'; /* temporarily tie off string */ sprintf (dst,"%s/%s/INBOX",blackBoxDir,name); *s = '/'; /* in case caller cares */ } else sprintf (dst,"%s/%s",blackBoxDir,name); } else { /* clear box other user */ /* copy user name */ for (s = dst; *name && (*name != '/'); *s++ = *name++); *s++ = '\0'; /* tie off user name, look up in passwd file */ if ((pw = getpwnam (dst)) && pw->pw_dir) { if (*name) name++; /* skip past the slash */ /* canonicalize case of INBOX */ if (!compare_cstring (name,"INBOX")) name = "INBOX"; /* remove trailing / from directory */ if ((s = strrchr (pw->pw_dir,'/')) && !s[1]) *s = '\0'; /* don't allow ~root/ if restricted root */ if ((restrictBox & RESTRICTROOT) && !*pw->pw_dir) dst = NIL; /* build final name w/ subdir if needed */ else if (mailsubdir) sprintf (dst,"%s/%s/%s",pw->pw_dir,mailsubdir,name); else sprintf (dst,"%s/%s",pw->pw_dir,name); } else dst = NIL; /* no such user */ } break; case 'I': case 'i': /* possible INBOX */ if (!compare_cstring (name+1,"NBOX")) { /* if restricted, use INBOX in mailbox dir */ if (anonymous || blackBox || closedBox) sprintf (dst,"%s/INBOX",mymailboxdir ()); else *dst = '\0'; /* otherwise driver selects the name */ break; } /* drop into to ordinary name case */ default: /* ordinary name is easy */ sprintf (dst,"%s/%s",mymailboxdir (),name); break; } return dst; /* return final name */ } /* Dot-lock file locker * Accepts: file name to lock * destination buffer for lock file name * open file description on file name to lock * Returns: T if success, NIL if failure */ long dotlock_lock (char *file,DOTLOCK *base,int fd) { int i = locktimeout * 60; int j,mask,retry,pi[2],po[2]; char *s,tmp[MAILTMPLEN]; struct stat sb; /* flush absurd file name */ if (strlen (file) > 512) return NIL; /* build lock filename */ sprintf (base->lock,"%s.lock",file); /* assume no pipe */ base->pipei = base->pipeo = -1; do { /* make sure not symlink */ if (!(j = chk_notsymlink (base->lock,&sb))) return NIL; /* time out if file older than 5 minutes */ if ((j > 0) && ((time (0)) >= (sb.st_ctime + locktimeout * 60))) i = 0; /* try to create the lock */ switch (retry = crexcl (base->lock)) { case -1: /* OK to retry */ if (!(i%15)) { /* time to notify? */ sprintf (tmp,"Mailbox %.80s is locked, will override in %d seconds...", file,i); MM_LOG (tmp,WARN); } sleep (1); /* wait 1 second before next try */ break; case NIL: /* failure, can't retry */ i = 0; break; case T: /* success, make sure others can break lock */ chmod (base->lock,(int) dotlock_mode); return LONGT; } } while (i--); /* until out of retries */ if (retry < 0) { /* still returning retry after locktimeout? */ if (!(j = chk_notsymlink (base->lock,&sb))) return NIL; if ((j > 0) && ((time (0)) < (sb.st_ctime + locktimeout * 60))) { sprintf (tmp,"Mailbox vulnerable - seizing %ld second old lock", (long) (time (0) - sb.st_ctime)); MM_LOG (tmp,WARN); } mask = umask (0); /* want our lock protection */ unlink (base->lock); /* try to remove the old file */ /* seize the lock */ if ((i = open (base->lock,O_WRONLY|O_CREAT,(int) dotlock_mode)) >= 0) { close (i); /* don't need descriptor any more */ sprintf (tmp,"Mailbox %.80s lock overridden",file); MM_LOG (tmp,NIL); chmod (base->lock,(int) dotlock_mode); umask (mask); /* restore old umask */ return LONGT; } umask (mask); /* restore old umask */ } if (fd >= 0) switch (errno) { case EACCES: /* protection failure? */ MM_CRITICAL (NIL); /* go critical */ if (closedBox || !lockpgm); /* can't do on closed box or disabled */ else if ((*lockpgm && stat (lockpgm,&sb)) || (!*lockpgm && stat (lockpgm = LOCKPGM1,&sb) && stat (lockpgm = LOCKPGM2,&sb) && stat (lockpgm = LOCKPGM3,&sb))) lockpgm = NIL; /* disable if can't find lockpgm */ else if (pipe (pi) >= 0) { /* make command pipes */ long cf; char *argv[4],arg[20]; /* if input pipes usable create output pipes */ if ((pi[0] < FD_SETSIZE) && (pi[1] < FD_SETSIZE) && (pipe (po) >= 0)) { /* make sure output pipes are usable */ if ((po[0] >= FD_SETSIZE) || (po[1] >= FD_SETSIZE)); /* all is good, make inferior process */ else if (!(j = fork ())) { if (!fork ()) { /* make grandchild so it's inherited by init */ /* prepare argument vector */ sprintf (arg,"%d",fd); argv[0] = lockpgm; argv[1] = arg; argv[2] = file; argv[3] = NIL; /* set parent's I/O to my O/I */ dup2 (pi[1],1); dup2 (pi[1],2); dup2 (po[0],0); /* close all unnecessary descriptors */ for (cf = max (20,max (max (pi[0],pi[1]),max(po[0],po[1]))); cf >= 3; --cf) if (cf != fd) close (cf); /* be our own process group */ setpgrp (0,getpid ()); /* now run it */ _exit (execv (argv[0],argv)); } _exit (1); /* child is done */ } else if (j > 0) { /* parent process */ fd_set rfd; struct timeval tmo; FD_ZERO (&rfd); FD_SET (pi[0],&rfd); tmo.tv_sec = locktimeout * 60; grim_pid_reap (j,NIL);/* reap child; grandchild now owned by init */ /* read response from locking program */ if (select (pi[0]+1,&rfd,0,0,&tmo) && (read (pi[0],tmp,1) == 1) && (tmp[0] == '+')) { /* success, record pipes */ base->pipei = pi[0]; base->pipeo = po[1]; /* close child's side of the pipes */ close (pi[1]); close (po[0]); MM_NOCRITICAL (NIL);/* no longer critical */ return LONGT; } } close (po[0]); close (po[1]); } close (pi[0]); close (pi[1]); } MM_NOCRITICAL (NIL); /* no longer critical */ /* find directory/file delimiter */ if (s = strrchr (base->lock,'/')) { *s = '\0'; /* tie off at directory */ sprintf(tmp, /* generate default message */ "Mailbox vulnerable - directory %.80s must have 1777 protection", base->lock); /* definitely not 1777 if can't stat */ mask = stat (base->lock,&sb) ? 0 : (sb.st_mode & 1777); *s = '/'; /* restore lock name */ if (mask != 1777) { /* default warning if not 1777 */ if (!disableLockWarning) MM_LOG (tmp,WARN); break; } } default: sprintf (tmp,"Mailbox vulnerable - error creating %.80s: %s", base->lock,strerror (errno)); if (!disableLockWarning) MM_LOG (tmp,WARN); break; } base->lock[0] = '\0'; /* don't use lock files */ return NIL; } /* Dot-lock file unlocker * Accepts: lock file name * Returns: T if success, NIL if failure */ long dotlock_unlock (DOTLOCK *base) { long ret = LONGT; if (base && base->lock[0]) { if (base->pipei >= 0) { /* if running through a pipe unlocker */ ret = (write (base->pipeo,"+",1) == 1); /* nuke the pipes */ close (base->pipei); close (base->pipeo); } else ret = !unlink (base->lock); } return ret; } /* Lock file name * Accepts: scratch buffer * file name * type of locking operation (LOCK_SH or LOCK_EX) * pointer to return PID of locker * Returns: file descriptor of lock or negative if error */ int lockname (char *lock,char *fname,int op,long *pid) { struct stat sbuf; *pid = 0; /* no locker PID */ return stat (fname,&sbuf) ? -1 : lock_work (lock,&sbuf,op,pid); } /* Lock file descriptor * Accepts: file descriptor * lock file name buffer * type of locking operation (LOCK_SH or LOCK_EX) * Returns: file descriptor of lock or negative if error */ int lockfd (int fd,char *lock,int op) { struct stat sbuf; return fstat (fd,&sbuf) ? -1 : lock_work (lock,&sbuf,op,NIL); } /* Lock file name worker * Accepts: lock file name * pointer to stat() buffer * type of locking operation (LOCK_SH or LOCK_EX) * pointer to return PID of locker * Returns: file descriptor of lock or negative if error */ int lock_work (char *lock,void *sb,int op,long *pid) { struct stat lsb,fsb; struct stat *sbuf = (struct stat *) sb; char tmp[MAILTMPLEN]; long i; int fd; int mask = umask (0); if (pid) *pid = 0; /* initialize return PID */ /* make temporary lock file name */ sprintf (lock,"%s/.%lx.%lx",closedBox ? "" : tmpdir, (unsigned long) sbuf->st_dev,(unsigned long) sbuf->st_ino); while (T) { /* until get a good lock */ do switch ((int) chk_notsymlink (lock,&lsb)) { case 1: /* exists just once */ if (((fd = open (lock,O_RDWR,shlock_mode)) >= 0) || (errno != ENOENT) || (chk_notsymlink (lock,&lsb) >= 0)) break; case -1: /* name doesn't exist */ fd = open (lock,O_RDWR|O_CREAT|O_EXCL,shlock_mode); break; default: /* multiple hard links */ MM_LOG ("hard link to lock name",ERROR); syslog (LOG_CRIT,"SECURITY PROBLEM: hard link to lock name: %.80s",lock); case 0: /* symlink (already did syslog) */ umask (mask); /* restore old mask */ return -1; /* fail: no lock file */ } while ((fd < 0) && (errno == EEXIST)); if (fd < 0) { /* failed to get file descriptor */ syslog (LOG_INFO,"Mailbox lock file %s open failure: %s",lock, strerror (errno)); if (!closedBox) { /* more explicit snarl for bad configuration */ if (stat (tmpdir,&lsb)) syslog (LOG_CRIT,"SYSTEM ERROR: no %s: %s",tmpdir,strerror (errno)); else if ((lsb.st_mode & 01777) != 01777) { sprintf (tmp,"Can't lock for write: %.80s must have 1777 protection", tmpdir); MM_LOG (tmp,WARN); } } umask (mask); /* restore old mask */ return -1; /* fail: can't open lock file */ } /* non-blocking form */ if (op & LOCK_NB) i = flock (fd,op); else { /* blocking form */ (*mailblocknotify) (BLOCK_FILELOCK,NIL); i = flock (fd,op); (*mailblocknotify) (BLOCK_NONE,NIL); } if (i) { /* failed, get other process' PID */ if (pid && !fstat (fd,&fsb) && (i = min (fsb.st_size,MAILTMPLEN-1)) && (read (fd,tmp,i) == i) && !(tmp[i] = 0) && ((i = atol (tmp)) > 0)) *pid = i; close (fd); /* failed, give up on lock */ umask (mask); /* restore old mask */ return -1; /* fail: can't lock */ } /* make sure this lock is good for us */ if (!lstat (lock,&lsb) && ((lsb.st_mode & S_IFMT) != S_IFLNK) && !fstat (fd,&fsb) && (lsb.st_dev == fsb.st_dev) && (lsb.st_ino == fsb.st_ino) && (fsb.st_nlink == 1)) break; close (fd); /* lock not right, drop fd and try again */ } chmod (lock,shlock_mode); /* make sure mode OK (don't use fchmod()) */ umask (mask); /* restore old mask */ return fd; /* success */ } /* Check to make sure not a symlink * Accepts: file name * stat buffer * Returns: -1 if doesn't exist, NIL if symlink, else number of hard links */ long chk_notsymlink (char *name,void *sb) { struct stat *sbuf = (struct stat *) sb; /* name exists? */ if (lstat (name,sbuf)) return -1; /* forbid symbolic link */ if ((sbuf->st_mode & S_IFMT) == S_IFLNK) { MM_LOG ("symbolic link on lock name",ERROR); syslog (LOG_CRIT,"SECURITY PROBLEM: symbolic link on lock name: %.80s", name); return NIL; } return (long) sbuf->st_nlink; /* return number of hard links */ } /* Unlock file descriptor * Accepts: file descriptor * lock file name from lockfd() */ void unlockfd (int fd,char *lock) { /* delete the file if no sharers */ if (!flock (fd,LOCK_EX|LOCK_NB)) unlink (lock); flock (fd,LOCK_UN); /* unlock it */ close (fd); /* close it */ } /* Set proper file protection for mailbox * Accepts: mailbox name * actual file path name * Returns: T, always */ long set_mbx_protections (char *mailbox,char *path) { struct stat sbuf; int mode = (int) mbx_protection; if (*mailbox == '#') { /* possible namespace? */ if (((mailbox[1] == 'f') || (mailbox[1] == 'F')) && ((mailbox[2] == 't') || (mailbox[2] == 'T')) && ((mailbox[3] == 'p') || (mailbox[3] == 'P')) && (mailbox[4] == '/')) mode = (int) ftp_protection; else if (((mailbox[1] == 'p') || (mailbox[1] == 'P')) && ((mailbox[2] == 'u') || (mailbox[2] == 'U')) && ((mailbox[3] == 'b') || (mailbox[3] == 'B')) && ((mailbox[4] == 'l') || (mailbox[4] == 'L')) && ((mailbox[5] == 'i') || (mailbox[5] == 'I')) && ((mailbox[6] == 'c') || (mailbox[6] == 'C')) && (mailbox[7] == '/')) mode = (int) public_protection; else if (((mailbox[1] == 's') || (mailbox[1] == 'S')) && ((mailbox[2] == 'h') || (mailbox[2] == 'H')) && ((mailbox[3] == 'a') || (mailbox[3] == 'A')) && ((mailbox[4] == 'r') || (mailbox[4] == 'R')) && ((mailbox[5] == 'e') || (mailbox[5] == 'E')) && ((mailbox[6] == 'd') || (mailbox[6] == 'D')) && (mailbox[7] == '/')) mode = (int) shared_protection; } /* if a directory */ if (!stat (path,&sbuf) && ((sbuf.st_mode & S_IFMT) == S_IFDIR)) { /* set owner search if allow read or write */ if (mode & 0600) mode |= 0100; if (mode & 060) mode |= 010;/* set group search if allow read or write */ if (mode & 06) mode |= 01; /* set world search if allow read or write */ /* preserve directory SGID bit */ if (sbuf.st_mode & S_ISGID) mode |= S_ISGID; } chmod (path,mode); /* set the new protection, ignore failure */ return LONGT; } /* Get proper directory protection * Accepts: mailbox name * Returns: directory mode, always */ long get_dir_protection (char *mailbox) { if (*mailbox == '#') { /* possible namespace? */ if (((mailbox[1] == 'f') || (mailbox[1] == 'F')) && ((mailbox[2] == 't') || (mailbox[2] == 'T')) && ((mailbox[3] == 'p') || (mailbox[3] == 'P')) && (mailbox[4] == '/')) return ftp_dir_protection; else if (((mailbox[1] == 'p') || (mailbox[1] == 'P')) && ((mailbox[2] == 'u') || (mailbox[2] == 'U')) && ((mailbox[3] == 'b') || (mailbox[3] == 'B')) && ((mailbox[4] == 'l') || (mailbox[4] == 'L')) && ((mailbox[5] == 'i') || (mailbox[5] == 'I')) && ((mailbox[6] == 'c') || (mailbox[6] == 'C')) && (mailbox[7] == '/')) return public_dir_protection; else if (((mailbox[1] == 's') || (mailbox[1] == 'S')) && ((mailbox[2] == 'h') || (mailbox[2] == 'H')) && ((mailbox[3] == 'a') || (mailbox[3] == 'A')) && ((mailbox[4] == 'r') || (mailbox[4] == 'R')) && ((mailbox[5] == 'e') || (mailbox[5] == 'E')) && ((mailbox[6] == 'd') || (mailbox[6] == 'D')) && (mailbox[7] == '/')) return shared_dir_protection; } return dir_protection; } /* Determine default prototype stream to user * Accepts: type (NIL for create, T for append) * Returns: default prototype stream */ MAILSTREAM *default_proto (long type) { myusername (); /* make sure initialized */ /* return default driver's prototype */ return type ? appendProto : createProto; } /* Set up user flags for stream * Accepts: MAIL stream * Returns: MAIL stream with user flags set up */ MAILSTREAM *user_flags (MAILSTREAM *stream) { int i; myusername (); /* make sure initialized */ for (i = 0; i < NUSERFLAGS && userFlags[i]; ++i) if (!stream->user_flags[i]) stream->user_flags[i] = cpystr (userFlags[i]); return stream; } /* Return nth user flag * Accepts: user flag number * Returns: flag */ char *default_user_flag (unsigned long i) { myusername (); /* make sure initialized */ return userFlags[i]; } /* Process rc file * Accepts: file name * .mminit flag * Don't use this feature. */ void dorc (char *file,long flag) { int i; char *s,*t,*k,*r,tmp[MAILTMPLEN],tmpx[MAILTMPLEN]; extern MAILSTREAM CREATEPROTO; extern MAILSTREAM EMPTYPROTO; DRIVER *d; FILE *f; if ((f = fopen (file ? file : SYSCONFIG,"r")) && (s = fgets (tmp,MAILTMPLEN,f)) && (t = strchr (s,'\n'))) do { *t++ = '\0'; /* tie off line, find second space */ if ((k = strchr (s,' ')) && (k = strchr (++k,' '))) { *k++ = '\0'; /* tie off two words */ if (!compare_cstring (s,"set keywords") && !userFlags[0]) { /* yes, get first keyword */ k = strtok_r (k,", ",&r); /* copy keyword list */ for (i = 0; k && i < NUSERFLAGS; ++i) if (strlen (k) <= MAXUSERFLAG) { if (userFlags[i]) fs_give ((void **) &userFlags[i]); userFlags[i] = cpystr (k); k = strtok_r (NIL,", ",&r); } if (flag) break; /* found "set keywords" in .mminit */ } else if (!flag) { /* none of these valid in .mminit */ if (myUserName) { /* only valid if logged in */ if (!compare_cstring (s,"set new-mailbox-format") || !compare_cstring (s,"set new-folder-format")) { if (!compare_cstring (k,"same-as-inbox")) { if (d = mail_valid (NIL,"INBOX",NIL)) { if (!compare_cstring (d->name,"mbox")) d = (DRIVER *) mail_parameters (NIL,GET_DRIVER, (void *) "unix"); else if (!compare_cstring (d->name,"dummy")) d = NIL; } createProto = d ? ((*d->open) (NIL)) : &CREATEPROTO; } else if (!compare_cstring (k,"system-standard")) createProto = &CREATEPROTO; else { /* canonicalize mbox to unix */ if (!compare_cstring (k,"mbox")) k = "unix"; /* see if a driver name */ if (d = (DRIVER *) mail_parameters (NIL,GET_DRIVER,(void *) k)) createProto = (*d->open) (NIL); else { /* duh... */ sprintf (tmpx,"Unknown new mailbox format in %s: %s", file ? file : SYSCONFIG,k); MM_LOG (tmpx,WARN); } } } if (!compare_cstring (s,"set empty-mailbox-format") || !compare_cstring (s,"set empty-folder-format")) { if (!compare_cstring (k,"invalid")) appendProto = NIL; else if (!compare_cstring (k,"same-as-inbox")) appendProto = ((d = mail_valid (NIL,"INBOX",NIL)) && compare_cstring (d->name,"dummy")) ? ((*d->open) (NIL)) : &EMPTYPROTO; else if (!compare_cstring (k,"system-standard")) appendProto = &EMPTYPROTO; else { /* see if a driver name */ for (d = (DRIVER *) mail_parameters (NIL,GET_DRIVERS,NIL); d && compare_cstring (d->name,k); d = d->next); if (d) appendProto = (*d->open) (NIL); else { /* duh... */ sprintf (tmpx,"Unknown empty mailbox format in %s: %s", file ? file : SYSCONFIG,k); MM_LOG (tmpx,WARN); } } } } if (!compare_cstring (s,"set local-host")) { fs_give ((void **) &myLocalHost); myLocalHost = cpystr (k); } else if (!compare_cstring (s,"set news-active-file")) { fs_give ((void **) &newsActive); newsActive = cpystr (k); } else if (!compare_cstring (s,"set news-spool-directory")) { fs_give ((void **) &newsSpool); newsSpool = cpystr (k); } else if (!compare_cstring (s,"set mh-path")) mail_parameters (NIL,SET_MHPATH,(void *) k); else if (!compare_cstring (s,"set mh-allow-inbox")) mail_parameters (NIL,SET_MHALLOWINBOX,(void *) atol (k)); else if (!compare_cstring (s,"set news-state-file")) { fs_give ((void **) &myNewsrc); myNewsrc = cpystr (k); } else if (!compare_cstring (s,"set ftp-export-directory")) { fs_give ((void **) &ftpHome); ftpHome = cpystr (k); } else if (!compare_cstring (s,"set public-home-directory")) { fs_give ((void **) &publicHome); publicHome = cpystr (k); } else if (!compare_cstring (s,"set shared-home-directory")) { fs_give ((void **) &sharedHome); sharedHome = cpystr (k); } else if (!compare_cstring (s,"set system-inbox")) { fs_give ((void **) &sysInbox); sysInbox = cpystr (k); } else if (!compare_cstring (s,"set mail-subdirectory")) { fs_give ((void **) &mailsubdir); mailsubdir = cpystr (k); } else if (!compare_cstring (s,"set from-widget")) mail_parameters (NIL,SET_FROMWIDGET, compare_cstring (k,"header-only") ? VOIDT : NIL); else if (!compare_cstring (s,"set rsh-command")) mail_parameters (NIL,SET_RSHCOMMAND,(void *) k); else if (!compare_cstring (s,"set rsh-path")) mail_parameters (NIL,SET_RSHPATH,(void *) k); else if (!compare_cstring (s,"set ssh-command")) mail_parameters (NIL,SET_SSHCOMMAND,(void *) k); else if (!compare_cstring (s,"set ssh-path")) mail_parameters (NIL,SET_SSHPATH,(void *) k); else if (!compare_cstring (s,"set tcp-open-timeout")) mail_parameters (NIL,SET_OPENTIMEOUT,(void *) atol (k)); else if (!compare_cstring (s,"set tcp-read-timeout")) mail_parameters (NIL,SET_READTIMEOUT,(void *) atol (k)); else if (!compare_cstring (s,"set tcp-write-timeout")) mail_parameters (NIL,SET_WRITETIMEOUT,(void *) atol (k)); else if (!compare_cstring (s,"set rsh-timeout")) mail_parameters (NIL,SET_RSHTIMEOUT,(void *) atol (k)); else if (!compare_cstring (s,"set ssh-timeout")) mail_parameters (NIL,SET_SSHTIMEOUT,(void *) atol (k)); else if (!compare_cstring (s,"set maximum-login-trials")) mail_parameters (NIL,SET_MAXLOGINTRIALS,(void *) atol (k)); else if (!compare_cstring (s,"set lookahead")) mail_parameters (NIL,SET_LOOKAHEAD,(void *) atol (k)); else if (!compare_cstring (s,"set prefetch")) mail_parameters (NIL,SET_PREFETCH,(void *) atol (k)); else if (!compare_cstring (s,"set close-on-error")) mail_parameters (NIL,SET_CLOSEONERROR,(void *) atol (k)); else if (!compare_cstring (s,"set imap-port")) mail_parameters (NIL,SET_IMAPPORT,(void *) atol (k)); else if (!compare_cstring (s,"set pop3-port")) mail_parameters (NIL,SET_POP3PORT,(void *) atol (k)); else if (!compare_cstring (s,"set uid-lookahead")) mail_parameters (NIL,SET_UIDLOOKAHEAD,(void *) atol (k)); else if (!compare_cstring (s,"set try-ssl-first")) mail_parameters (NIL,SET_TRYSSLFIRST,(void *) atol (k)); else if (!compare_cstring (s,"set mailbox-protection")) mbx_protection = atol (k); else if (!compare_cstring (s,"set directory-protection")) dir_protection = atol (k); else if (!compare_cstring (s,"set lock-protection")) dotlock_mode = atol (k); else if (!compare_cstring (s,"set ftp-protection")) ftp_protection = atol (k); else if (!compare_cstring (s,"set public-protection")) public_protection = atol (k); else if (!compare_cstring (s,"set shared-protection")) shared_protection = atol (k); else if (!compare_cstring (s,"set ftp-directory-protection")) ftp_dir_protection = atol (k); else if (!compare_cstring (s,"set public-directory-protection")) public_dir_protection = atol (k); else if (!compare_cstring (s,"set shared-directory-protection")) shared_dir_protection = atol (k); else if (!compare_cstring (s,"set dot-lock-file-timeout")) locktimeout = atoi (k); else if (!compare_cstring (s,"set disable-fcntl-locking")) fcntlhangbug = atoi (k); else if (!compare_cstring (s,"set disable-lock-warning")) disableLockWarning = atoi (k); else if (!compare_cstring (s,"set disable-unix-UIDs-and-keywords")) has_no_life = atoi (k); else if (!compare_cstring (s,"set hide-dot-files")) hideDotFiles = atoi (k); else if (!compare_cstring (s,"set list-maximum-level")) list_max_level = atol (k); else if (!compare_cstring (s,"set trust-dns")) mail_parameters (NIL,SET_TRUSTDNS,(void *) atol (k)); else if (!compare_cstring (s,"set sasl-uses-ptr-name")) mail_parameters (NIL,SET_SASLUSESPTRNAME,(void *) atol (k)); else if (!compare_cstring (s,"set network-filesystem-stat-bug")) netfsstatbug = atoi (k); else if (!compare_cstring (s,"set nntp-range")) mail_parameters (NIL,SET_NNTPRANGE,(void *) atol (k)); else if (!file) { /* only allowed in system init */ if (!compare_cstring (s,"set black-box-directory") && !blackBoxDir) blackBoxDir = cpystr (k); else if (!compare_cstring(s,"set black-box-default-home-directory")&& blackBoxDir && !blackBoxDefaultHome) blackBoxDefaultHome = cpystr (k); else if (!compare_cstring (s,"set anonymous-home-directory") && !anonymousHome) anonymousHome = cpystr (k); /* It's tempting to allow setting the CA path * in a user init. However, that opens up a * vector of attack big enough to drive a * truck through... Resist the temptation. */ else if (!compare_cstring (s,"set CA-certificate-path")) sslCApath = cpystr (k); else if (!compare_cstring (s,"set disable-plaintext")) disablePlaintext = atoi (k); else if (!compare_cstring (s,"set allowed-login-attempts")) logtry = atoi (k); else if (!compare_cstring (s,"set chroot-server")) closedBox = atoi (k); else if (!compare_cstring (s,"set restrict-mailbox-access")) for (k = strtok_r (k,", ",&r); k; k = strtok_r (NIL,", ",&r)) { if (!compare_cstring (k,"root")) restrictBox |= RESTRICTROOT; else if (!compare_cstring (k,"otherusers")) restrictBox |= RESTRICTOTHERUSER; else if (!compare_cstring (k,"all")) restrictBox = -1; } else if (!compare_cstring (s,"set advertise-the-world")) advertisetheworld = atoi (k); else if (!compare_cstring (s,"set limited-advertise")) limitedadvertise = atoi (k); else if (!compare_cstring (s,"set disable-automatic-shared-namespaces")) noautomaticsharedns = atoi (k); else if (!compare_cstring (s,"set allow-user-config")) allowuserconfig = atoi (k); else if (!compare_cstring (s,"set allow-reverse-dns")) mail_parameters (NIL,SET_ALLOWREVERSEDNS,(void *) atol (k)); else if (!compare_cstring (s,"set k5-cp-uses-service-name")) kerb_cp_svr_name = atoi (k); /* must appear in file after any * "set disable-plaintext" command! */ else if (!compare_cstring (s,"set plaintext-allowed-clients")) { for (k = strtok_r (k,", ",&r); k && !tcp_isclienthost (k); k = strtok_r (NIL,", ",&r)); if (k) disablePlaintext = 0; } } } } } while ((s = fgets (tmp,MAILTMPLEN,f)) && (t = strchr (s,'\n'))); if (f) fclose (f); /* flush the file */ } /* INBOX create function for tmail/dmail use only * Accepts: mail stream * path name buffer, preloaded with driver-dependent path * Returns: T on success, NIL on failure * * This routine is evil and a truly incredible kludge. It is private for * tmail/dmail and is not supported for any other application. */ long path_create (MAILSTREAM *stream,char *path) { long ret; short rsave = restrictBox; restrictBox = NIL; /* can't restrict */ if (blackBox) { /* if black box */ /* toss out driver dependent names */ sprintf (path,"%s/INBOX",mymailboxdir ()); blackBox = NIL; /* well that's evil - evil is going on */ ret = mail_create (stream,path); blackBox = T; /* restore the box */ } /* easy thing otherwise */ else ret = mail_create (stream,path); restrictBox = rsave; /* restore restrictions */ return ret; } /* Default block notify routine * Accepts: reason for calling * data * Returns: data */ void *mm_blocknotify (int reason,void *data) { void *ret = data; switch (reason) { case BLOCK_SENSITIVE: /* entering sensitive code */ ret = (void *) (unsigned long) alarm (0); break; case BLOCK_NONSENSITIVE: /* exiting sensitive code */ if ((unsigned long) data) alarm ((unsigned long) data); break; default: /* ignore all other reasons */ break; } return ret; } alpine-2.10+dfsg/imap/src/osdep/unix/ckp_nul.c0000600000175000017500000000205111512502123022742 0ustar paulproteuspaulproteus/* ======================================================================== * Copyright 1988-2006 University of Washington * * Licensed under the Apache License, Version 2.0 (the "License"); * you may not use this file except in compliance with the License. * You may obtain a copy of the License at * * http://www.apache.org/licenses/LICENSE-2.0 * * * ======================================================================== */ /* * Program: Null check password * * Author: Mark Crispin * Networks and Distributed Computing * Computing & Communications * University of Washington * Administration Building, AG-44 * Seattle, WA 98195 * Internet: MRC@CAC.Washington.EDU * * Date: 23 July 1998 * Last Edited: 30 August 2006 */ /* Check password * Accepts: login passwd struct * password string * argument count * argument vector * Returns: passwd struct if password validated, NIL otherwise */ struct passwd *checkpw (struct passwd *pw,char *pass,int argc,char *argv[]) { return NIL; /* always fails */ } alpine-2.10+dfsg/imap/src/osdep/unix/setpgrp.c0000600000175000017500000000166211512502123023002 0ustar paulproteuspaulproteus/* ======================================================================== * Copyright 1988-2006 University of Washington * * Licensed under the Apache License, Version 2.0 (the "License"); * you may not use this file except in compliance with the License. * You may obtain a copy of the License at * * http://www.apache.org/licenses/LICENSE-2.0 * * * ======================================================================== */ /* * Program: Set process group emulator * * Author: Mark Crispin * Networks and Distributed Computing * Computing & Communications * University of Washington * Administration Building, AG-44 * Seattle, WA 98195 * Internet: MRC@CAC.Washington.EDU * * Date: 3 May 1995 * Last Edited: 30 August 2006 */ /* Emulator for BSD setpgrp() call * Accepts: process ID * group ID * Returns: 0 if successful, -1 if failure */ int Setpgrp (int pid,int gid) { return setpgrp (); } alpine-2.10+dfsg/imap/src/osdep/unix/write.c0000600000175000017500000000336711512502123022454 0ustar paulproteuspaulproteus/* ======================================================================== * Copyright 1988-2006 University of Washington * * Licensed under the Apache License, Version 2.0 (the "License"); * you may not use this file except in compliance with the License. * You may obtain a copy of the License at * * http://www.apache.org/licenses/LICENSE-2.0 * * * ======================================================================== */ /* * Program: Write data, treating partial writes as an error * * Author: Mark Crispin * Networks and Distributed Computing * Computing & Communications * University of Washington * Administration Building, AG-44 * Seattle, WA 98195 * Internet: MRC@CAC.Washington.EDU * * Date: 26 May 1995 * Last Edited: 30 August 2006 */ /* The whole purpose of this unfortunate routine is to deal with DOS and * certain cretinous versions of UNIX which decided that the "bytes actually * written" return value from write() gave them license to use that for things * that are really errors, such as disk quota exceeded, maximum file size * exceeded, disk full, etc. * * BSD won't screw us this way on the local filesystem, but who knows what * some NFS-mounted filesystem will do. */ #undef write /* Write data to file * Accepts: file descriptor * I/O vector structure * number of vectors in structure * Returns: number of bytes written if successful, -1 if failure */ long maxposint = (long)((((unsigned long) 1) << ((sizeof(int) * 8) - 1)) - 1); long safe_write (int fd,char *buf,long nbytes) { long i,j; if (nbytes > 0) for (i = nbytes; i; i -= j,buf += j) { while (((j = write (fd,buf,(int) min (maxposint,i))) < 0) && (errno == EINTR)); if (j < 0) return j; } return nbytes; } alpine-2.10+dfsg/imap/src/osdep/unix/ckp_bsi.c0000600000175000017500000000261011512502123022722 0ustar paulproteuspaulproteus/* ======================================================================== * Copyright 1988-2006 University of Washington * * Licensed under the Apache License, Version 2.0 (the "License"); * you may not use this file except in compliance with the License. * You may obtain a copy of the License at * * http://www.apache.org/licenses/LICENSE-2.0 * * * ======================================================================== */ /* * Program: BSI check password * * Author: Mark Crispin * Networks and Distributed Computing * Computing & Communications * University of Washington * Administration Building, AG-44 * Seattle, WA 98195 * Internet: MRC@CAC.Washington.EDU * * Date: 1 August 1988 * Last Edited: 30 August 2006 */ /* Check password * Accepts: login passwd struct * password string * argument count * argument vector * Returns: passwd struct if password validated, NIL otherwise */ #include struct passwd *checkpw (struct passwd *pw,char *pass,int argc,char *argv[]) { char *s,tmp[MAILTMPLEN]; login_cap_t *lc; /* make service name */ sprintf (tmp,"auth-%s",(char *) mail_parameters (NIL,GET_SERVICENAME,NIL)); /* validate password */ return ((lc = login_getclass (pw->pw_class)) && (s = login_getstyle (lc,NIL,tmp)) && (auth_response (pw->pw_name,lc->lc_class,s,"response",NIL,"",pass) > 0)) ? pw : NIL; } alpine-2.10+dfsg/imap/src/osdep/unix/flockcyg.h0000600000175000017500000000254111512502123023121 0ustar paulproteuspaulproteus/* ======================================================================== * Copyright 1988-2006 University of Washington * * Licensed under the Apache License, Version 2.0 (the "License"); * you may not use this file except in compliance with the License. * You may obtain a copy of the License at * * http://www.apache.org/licenses/LICENSE-2.0 * * * ======================================================================== */ /* * Program: flock() emulation via fcntl() locking * * Author: Mark Crispin * Networks and Distributed Computing * Computing & Communications * University of Washington * Administration Building, AG-44 * Seattle, WA 98195 * Internet: MRC@CAC.Washington.EDU * * Date: 10 April 2001 * Last Edited: 30 August 2006 */ /* Cygwin does not seem to have the design flaw in fcntl() locking that * most other systems do (see flocksim.c for details). If some cretin * decides to implement that design flaw, then Cygwin will have to use * flocksim. Also, we don't test NFS either */ #define flock flocksim /* use ours instead of theirs */ #undef LOCK_SH #define LOCK_SH 1 /* shared lock */ #undef LOCK_EX #define LOCK_EX 2 /* exclusive lock */ #undef LOCK_NB #define LOCK_NB 4 /* no blocking */ #undef LOCK_UN #define LOCK_UN 8 /* unlock */ /* Function prototypes */ int flocksim (int fd,int operation); alpine-2.10+dfsg/imap/src/osdep/unix/os_sua.c0000600000175000017500000000252211512502123022603 0ustar paulproteuspaulproteus/* ======================================================================== * Copyright 1988-2007 University of Washington * * Licensed under the Apache License, Version 2.0 (the "License"); * you may not use this file except in compliance with the License. * You may obtain a copy of the License at * * http://www.apache.org/licenses/LICENSE-2.0 * * * ======================================================================== */ /* * Program: Operating-system dependent routines -- Windows Vista SUA * * Author: Mark Crispin * Networks and Distributed Computing * Computing & Communications * University of Washington * Administration Building, AG-44 * Seattle, WA 98195 * Internet: MRC@CAC.Washington.EDU * * Date: 1 August 1993 * Last Edited: 16 August 2007 */ #include "tcp_unix.h" /* must be before osdep includes tcp.h */ #include "mail.h" #include "osdep.h" #include #include #include #include #include #include #include #include #include extern int errno; /* just in case */ #include #include "misc.h" #include "fs_unix.c" #include "ftl_unix.c" #include "nl_unix.c" #include "env_unix.c" #define fork vfork #include "tcp_unix.c" #include "gr_waitp.c" #include "tz_sv4.c" #include "gethstid.c" alpine-2.10+dfsg/imap/src/osdep/unix/os_soln.h0000600000175000017500000000367511512502123023005 0ustar paulproteuspaulproteus/* ======================================================================== * Copyright 1988-2006 University of Washington * * Licensed under the Apache License, Version 2.0 (the "License"); * you may not use this file except in compliance with the License. * You may obtain a copy of the License at * * http://www.apache.org/licenses/LICENSE-2.0 * * * ======================================================================== */ /* * Program: Operating-system dependent routines -- Solaris version * * Author: Mark Crispin * Networks and Distributed Computing * Computing & Communications * University of Washington * Administration Building, AG-44 * Seattle, WA 98195 * Internet: MRC@CAC.Washington.EDU * * Date: 1 August 1988 * Last Edited: 20 December 2006 */ #include #include #include #include #include #include #include #include #include #include #include /* Many versions of SysV get this wrong */ #define setpgrp(a,b) Setpgrp(a,b) int Setpgrp (int pid,int gid); /* Different names, equivalent things in BSD and SysV */ /* L_SET is defined for some strange reason in on SVR4. */ #ifndef L_SET #define L_SET SEEK_SET #endif #ifndef L_INCR #define L_INCR SEEK_CUR #endif #ifndef L_XTND #define L_XTND SEEK_END #endif #define direct dirent #define random lrand48 #define scandir Scandir #define alphasort Alphasort #define getpass getpassphrase #define utime portable_utime int portable_utime (char *file,time_t timep[2]); long gethostid (void); typedef int (*select_t) (struct direct *name); typedef int (*compar_t) (const void *d1,const void *d2); int scandir (char *dirname,struct direct ***namelist,select_t select, compar_t compar); int alphasort (void *d1,void *d2); #include "env_unix.h" #include "fs.h" #include "ftl.h" #include "nl.h" #include "tcp.h" #include "flocksim.h" alpine-2.10+dfsg/imap/src/osdep/unix/log_os4.c0000600000175000017500000000317411512502123022664 0ustar paulproteuspaulproteus/* ======================================================================== * Copyright 1988-2006 University of Washington * * Licensed under the Apache License, Version 2.0 (the "License"); * you may not use this file except in compliance with the License. * You may obtain a copy of the License at * * http://www.apache.org/licenses/LICENSE-2.0 * * * ======================================================================== */ /* * Program: OSF/1 (Digital UNIX) 4 login * * Author: Mark Crispin * Networks and Distributed Computing * Computing & Communications * University of Washington * Administration Building, AG-44 * Seattle, WA 98195 * Internet: MRC@CAC.Washington.EDU * * Date: 1 August 1988 * Last Edited: 30 August 2006 */ /* Log in * Accepts: login passwd struct * argument count * argument vector * Returns: T if success, NIL otherwise */ long loginpw (struct passwd *pw,int argc,char *argv[]) { int i; char *s; char *name = cpystr (pw->pw_name); char *host = cpystr (tcp_clienthost ()); uid_t uid = pw->pw_uid; long ret = NIL; /* tie off address */ if (s = strchr (host,' ')) *s = '\0'; if (*host == '[') { /* convert [a.b.c.d] to a.b.c.d */ memmove (host,host+1,i = strlen (host + 2)); host[i] = '\0'; } if (sia_become_user (checkpw_collect,argc,argv,host,name,NIL,NIL,NIL,NIL, SIA_BEU_REALLOGIN|SIA_BEU_OKROOTDIR) != SIASUCCESS) setreuid (0,0); /* make sure have root again */ /* probable success, complete login */ else ret = (!setreuid (0,0) && !setuid (uid)); fs_give ((void **) &name); fs_give ((void **) &host); return ret; } alpine-2.10+dfsg/imap/src/osdep/unix/drivers0000700000175000017500000000173511512502123022555 0ustar paulproteuspaulproteus#!/bin/sh # ======================================================================== # Copyright 1988-2006 University of Washington # # Licensed under the Apache License, Version 2.0 (the "License"); # you may not use this file except in compliance with the License. # You may obtain a copy of the License at # # http://www.apache.org/licenses/LICENSE-2.0 # # # ======================================================================== # Program: Driver Linkage Generator # # Author: Mark Crispin # Networks and Distributed Computing # Computing & Communications # University of Washington # Administration Building, AG-44 # Seattle, WA 98195 # Internet: MRC@CAC.Washington.EDU # # Date: 11 October 1989 # Last Edited: 30 August 2006 # Erase old driver linkage rm -f linkage.[ch] # Now define the new list for driver do echo "extern DRIVER "$driver"driver;" >> linkage.h echo " mail_link (&"$driver"driver); /* link in the $driver driver */" | cat >> linkage.c done alpine-2.10+dfsg/imap/src/osdep/unix/os_sos.h0000600000175000017500000000225711512502123022631 0ustar paulproteuspaulproteus/* ======================================================================== * Copyright 1988-2006 University of Washington * * Licensed under the Apache License, Version 2.0 (the "License"); * you may not use this file except in compliance with the License. * You may obtain a copy of the License at * * http://www.apache.org/licenses/LICENSE-2.0 * * * ======================================================================== */ /* * Program: Operating-system dependent routines -- OSF/Digital UNIX/Tru64 * * Author: Mark Crispin * Networks and Distributed Computing * Computing & Communications * University of Washington * Administration Building, AG-44 * Seattle, WA 98195 * Internet: MRC@CAC.Washington.EDU * * Date: 1 August 1988 * Last Edited: 30 August 2006 */ #include #include #include #include #include #include /* for struct tm */ #include #include #include /* OSF/1 gets this wrong */ #define setpgrp setpgid #define direct dirent #include "env_unix.h" #include "fs.h" #include "ftl.h" #include "nl.h" #include "tcp.h" #include "flocksim.h" alpine-2.10+dfsg/imap/src/osdep/unix/ckp_sce.c0000600000175000017500000000312511512502123022721 0ustar paulproteuspaulproteus/* ======================================================================== * Copyright 1988-2006 University of Washington * * Licensed under the Apache License, Version 2.0 (the "License"); * you may not use this file except in compliance with the License. * You may obtain a copy of the License at * * http://www.apache.org/licenses/LICENSE-2.0 * * * ======================================================================== */ /* * Program: SecureWare check password * * Author: Mark Crispin * Networks and Distributed Computing * Computing & Communications * University of Washington * Administration Building, AG-44 * Seattle, WA 98195 * Internet: MRC@CAC.Washington.EDU * * Date: 1 August 1988 * Last Edited: 30 August 2006 */ /* Check password * Accepts: login passwd struct * password string * argument count * argument vector * Returns: passwd struct if password validated, NIL otherwise */ struct passwd *checkpw (struct passwd *pw,char *pass,int argc,char *argv[]) { struct es_passwd *pp; set_auth_parameters (argc,argv); if ((pw->pw_passwd && pw->pw_passwd[0] && pw->pw_passwd[1] && !strcmp (pw->pw_passwd,(char *) crypt (pass,pw->pw_passwd))) || ((pp = getespwnam (pw->pw_name)) && !pp->ufld->fd_lock && !pp->ufld->fd_psw_chg_reqd && pp->ufld->fd_encrypt && pp->ufld->fd_encrypt[0] && pp->ufld->fd_encrypt[1] && !strcmp (pp->ufld->fd_encrypt,bigcrypt (pass,pp->ufld->fd_encrypt)))) endprpwent (); /* don't need shadow password data any more */ else pw = NIL; /* password failed */ return pw; } alpine-2.10+dfsg/imap/src/osdep/unix/os_sua.h0000600000175000017500000000224111512502123022606 0ustar paulproteuspaulproteus/* ======================================================================== * Copyright 1988-2007 University of Washington * * Licensed under the Apache License, Version 2.0 (the "License"); * you may not use this file except in compliance with the License. * You may obtain a copy of the License at * * http://www.apache.org/licenses/LICENSE-2.0 * * * ======================================================================== */ /* * Program: Operating-system dependent routines -- Windows Vista SUA * * Author: Mark Crispin * Networks and Distributed Computing * Computing & Communications * University of Washington * Administration Building, AG-44 * Seattle, WA 98195 * Internet: MRC@CAC.Washington.EDU * * Date: 10 September 1993 * Last Edited: 4 May 2007 */ #define _REENTRANT /* for strtok_r() */ #include #include #include #include #include #include /* for struct tm */ #include #include #include #define setpgrp setpgid #define direct dirent #include "env_unix.h" #include "fs.h" #include "ftl.h" #include "nl.h" #include "tcp.h" alpine-2.10+dfsg/imap/src/osdep/unix/tcp_unix.c0000600000175000017500000010122312074110156023146 0ustar paulproteuspaulproteus/* ======================================================================== * Copyright 1988-2008 University of Washington * * Licensed under the Apache License, Version 2.0 (the "License"); * you may not use this file except in compliance with the License. * You may obtain a copy of the License at * * http://www.apache.org/licenses/LICENSE-2.0 * * * ======================================================================== */ /* * Program: UNIX TCP/IP routines * * Author: Mark Crispin * Networks and Distributed Computing * Computing & Communications * University of Washington * Administration Building, AG-44 * Seattle, WA 98195 * Internet: MRC@CAC.Washington.EDU * * Date: 1 August 1988 * Last Edited: 13 January 2008 */ #include "ip_unix.c" #undef write /* don't use redefined write() */ static tcptimeout_t tmoh = NIL; /* TCP timeout handler routine */ static long ttmo_open = 0; /* TCP timeouts, in seconds */ static long ttmo_read = 0; static long ttmo_write = 0; static long rshtimeout = 15; /* rsh timeout */ static char *rshcommand = NIL; /* rsh command */ static char *rshpath = NIL; /* rsh path */ static long sshtimeout = 15; /* ssh timeout */ static char *sshcommand = NIL; /* ssh command */ static char *sshpath = NIL; /* ssh path */ static long allowreversedns = T;/* allow reverse DNS lookup */ static long tcpdebug = NIL; /* extra TCP debugging telemetry */ static char *myClientAddr = NIL;/* client IP address */ static char *myClientHost = NIL;/* client DNS name */ static long myClientPort = -1; /* client port number */ static char *myServerAddr = NIL;/* server IP address */ static char *myServerHost = NIL;/* server DNS name */ static long myServerPort = -1; /* server port number */ extern long maxposint; /* get this from write.c */ /* Local function prototypes */ int tcp_socket_open (int family,void *adr,size_t adrlen,unsigned short port, char *tmp,int *ctr,char *hst); static char *tcp_getline_work (TCPSTREAM *stream,unsigned long *size, long *contd); long tcp_abort (TCPSTREAM *stream); char *tcp_name (struct sockaddr *sadr,long flag); char *tcp_name_valid (char *s); /* TCP/IP manipulate parameters * Accepts: function code * function-dependent value * Returns: function-dependent return value */ void *tcp_parameters (long function,void *value) { void *ret = NIL; switch ((int) function) { case SET_TIMEOUT: tmoh = (tcptimeout_t) value; case GET_TIMEOUT: ret = (void *) tmoh; break; case SET_OPENTIMEOUT: ttmo_open = (long) value; case GET_OPENTIMEOUT: ret = (void *) ttmo_open; break; case SET_READTIMEOUT: ttmo_read = (long) value; case GET_READTIMEOUT: ret = (void *) ttmo_read; break; case SET_WRITETIMEOUT: ttmo_write = (long) value; case GET_WRITETIMEOUT: ret = (void *) ttmo_write; break; case SET_ALLOWREVERSEDNS: allowreversedns = (long) value; case GET_ALLOWREVERSEDNS: ret = (void *) allowreversedns; break; case SET_TCPDEBUG: tcpdebug = (long) value; case GET_TCPDEBUG: ret = (void *) tcpdebug; break; case SET_RSHTIMEOUT: rshtimeout = (long) value; case GET_RSHTIMEOUT: ret = (void *) rshtimeout; break; case SET_RSHCOMMAND: if (rshcommand) fs_give ((void **) &rshcommand); rshcommand = cpystr ((char *) value); case GET_RSHCOMMAND: ret = (void *) rshcommand; break; case SET_RSHPATH: if (rshpath) fs_give ((void **) &rshpath); rshpath = cpystr ((char *) value); case GET_RSHPATH: ret = (void *) rshpath; break; case SET_SSHTIMEOUT: sshtimeout = (long) value; case GET_SSHTIMEOUT: ret = (void *) sshtimeout; break; case SET_SSHCOMMAND: if (sshcommand) fs_give ((void **) &sshcommand); sshcommand = cpystr ((char *) value); case GET_SSHCOMMAND: ret = (void *) sshcommand; break; case SET_SSHPATH: if (sshpath) fs_give ((void **) &sshpath); sshpath = cpystr ((char *) value); case GET_SSHPATH: ret = (void *) sshpath; break; } return ret; } /* TCP/IP open * Accepts: host name * contact service name * contact port number and optional silent flag * Returns: TCP/IP stream if success else NIL */ TCPSTREAM *tcp_open (char *host,char *service,unsigned long port) { TCPSTREAM *stream = NIL; int family; int sock = -1; int ctr = 0; int silent = (port & NET_SILENT) ? T : NIL; int *ctrp = (port & NET_NOOPENTIMEOUT) ? NIL : &ctr; char *s,*hostname,tmp[MAILTMPLEN]; void *adr; size_t adrlen; struct servent *sv = NIL; blocknotify_t bn = (blocknotify_t) mail_parameters (NIL,GET_BLOCKNOTIFY,NIL); void *data,*next; port &= 0xffff; /* erase flags */ /* lookup service */ if (service && (sv = getservbyname (service,"tcp"))) port = ntohs (sv->s_port); /* The domain literal form is used (rather than simply the dotted decimal as with other Unix programs) because it has to be a valid "host name" in mailsystem terminology. */ /* look like domain literal? */ if (host[0] == '[' && host[(strlen (host))-1] == ']') { strcpy (tmp,host+1); /* yes, copy number part */ tmp[(strlen (tmp))-1] = '\0'; if (adr = ip_stringtoaddr (tmp,&adrlen,&family)) { (*bn) (BLOCK_TCPOPEN,NIL); /* get an open socket for this system */ sock = tcp_socket_open (family,adr,adrlen,port,tmp,ctrp,hostname = host); (*bn) (BLOCK_NONE,NIL); fs_give ((void **) &adr); } else sprintf (tmp,"Bad format domain-literal: %.80s",host); } else { /* lookup host name */ if (tcpdebug) { sprintf (tmp,"DNS resolution %.80s",host); mm_log (tmp,TCPDEBUG); } (*bn) (BLOCK_DNSLOOKUP,NIL);/* quell alarms */ data = (*bn) (BLOCK_SENSITIVE,NIL); if (!(s = ip_nametoaddr (host,&adrlen,&family,&hostname,&next))) sprintf (tmp,"No such host as %.80s",host); (*bn) (BLOCK_NONSENSITIVE,data); (*bn) (BLOCK_NONE,NIL); if (s) { /* DNS resolution won? */ if (tcpdebug) mm_log ("DNS resolution done",TCPDEBUG); do { (*bn) (BLOCK_TCPOPEN,NIL); if (((sock = tcp_socket_open (family,s,adrlen,port,tmp,ctrp, hostname)) < 0) && (s = ip_nametoaddr (NIL,&adrlen,&family,&hostname,&next)) && !silent) mm_log (tmp,WARN); (*bn) (BLOCK_NONE,NIL); } while ((sock < 0) && s);/* repeat until success or no more addreses */ } } if (sock >= 0) { /* won */ stream = (TCPSTREAM *) memset (fs_get (sizeof (TCPSTREAM)),0, sizeof (TCPSTREAM)); stream->port = port; /* port number */ /* init sockets */ stream->tcpsi = stream->tcpso = sock; /* stash in the snuck-in byte */ if (stream->ictr = ctr) *(stream->iptr = stream->ibuf) = tmp[0]; /* copy official host name */ stream->host = cpystr (hostname); if (tcpdebug) mm_log ("Stream open and ready for read",TCPDEBUG); } else if (!silent) mm_log (tmp,ERROR); return stream; /* return success */ } /* Open a TCP socket * Accepts: protocol family * address to connect to * address length * port * scratch buffer * pointer to "first byte read in" storage or NIL * host name for error message * Returns: socket if success, else -1 with error string in scratch buffer */ int tcp_socket_open (int family,void *adr,size_t adrlen,unsigned short port, char *tmp,int *ctr,char *hst) { int i,ti,sock,flgs; size_t len; time_t now; struct protoent *pt = getprotobyname ("tcp"); fd_set fds,efds; struct timeval tmo; struct sockaddr *sadr = ip_sockaddr (family,adr,adrlen,port,&len); blocknotify_t bn = (blocknotify_t) mail_parameters (NIL,GET_BLOCKNOTIFY,NIL); /* fetid Solaris */ void *data = (*bn) (BLOCK_SENSITIVE,NIL); sprintf (tmp,"Trying IP address [%s]",ip_sockaddrtostring (sadr)); mm_log (tmp,NIL); /* make a socket */ if ((sock = socket (sadr->sa_family,SOCK_STREAM,pt ? pt->p_proto : 0)) < 0) { sprintf (tmp,"Unable to create TCP socket: %s",strerror (errno)); (*bn) (BLOCK_NONSENSITIVE,data); } else if (sock >= FD_SETSIZE) {/* unselectable sockets are useless */ sprintf (tmp,"Unable to create selectable TCP socket (%d >= %d)", sock,FD_SETSIZE); (*bn) (BLOCK_NONSENSITIVE,data); close (sock); sock = -1; errno = EMFILE; } else { /* get current socket flags */ flgs = fcntl (sock,F_GETFL,0); /* set non-blocking if want open timeout */ if (ctr) fcntl (sock,F_SETFL,flgs | FNDELAY); /* open connection */ while ((i = connect (sock,sadr,len)) < 0 && (errno == EINTR)); (*bn) (BLOCK_NONSENSITIVE,data); if (i < 0) switch (errno) { /* failed? */ case EAGAIN: /* DG brain damage */ case EINPROGRESS: /* what we expect to happen */ case EALREADY: /* or another form of it */ case EISCONN: /* restart after interrupt? */ case EADDRINUSE: /* restart after interrupt? */ break; /* well, not really, it was interrupted */ default: sprintf (tmp,"Can't connect to %.80s,%u: %s",hst,(unsigned int) port, strerror (errno)); close (sock); /* flush socket */ sock = -1; } if ((sock >= 0) && ctr) { /* want open timeout? */ now = time (0); /* open timeout */ ti = ttmo_open ? now + ttmo_open : 0; tmo.tv_usec = 0; FD_ZERO (&fds); /* initialize selection vector */ FD_ZERO (&efds); /* handle errors too */ FD_SET (sock,&fds); /* block for error or readable */ FD_SET (sock,&efds); do { /* block under timeout */ tmo.tv_sec = ti ? ti - now : 0; i = select (sock+1,&fds,NIL,&efds,ti ? &tmo : NIL); now = time (0); /* fake timeout if interrupt & time expired */ if ((i < 0) && (errno == EINTR) && ti && (ti <= now)) i = 0; } while ((i < 0) && (errno == EINTR)); if (i > 0) { /* success, make sure really connected */ /* restore blocking status */ fcntl (sock,F_SETFL,flgs); /* This used to be a zero-byte read(), but that crashes Solaris */ /* get socket status */ while (((i = *ctr = read (sock,tmp,1)) < 0) && (errno == EINTR)); } if (i <= 0) { /* timeout or error? */ i = i ? errno : ETIMEDOUT;/* determine error code */ close (sock); /* flush socket */ sock = -1; errno = i; /* return error code */ sprintf (tmp,"Connection failed to %.80s,%lu: %s",hst, (unsigned long) port,strerror (errno)); } } } fs_give ((void **) &sadr); return sock; /* return the socket */ } /* TCP/IP authenticated open * Accepts: host name * service name * returned user name buffer * Returns: TCP/IP stream if success else NIL */ #define MAXARGV 20 TCPSTREAM *tcp_aopen (NETMBX *mb,char *service,char *usrbuf) { TCPSTREAM *stream = NIL; void *adr; char host[MAILTMPLEN],tmp[MAILTMPLEN],*path,*argv[MAXARGV+1],*r; int i,ti,pipei[2],pipeo[2]; size_t len; time_t now; struct timeval tmo; fd_set fds,efds; blocknotify_t bn = (blocknotify_t) mail_parameters (NIL,GET_BLOCKNOTIFY,NIL); #ifdef SSHPATH /* ssh path defined yet? */ if (!sshpath) sshpath = cpystr (SSHPATH); #endif #ifdef RSHPATH /* rsh path defined yet? */ if (!rshpath) rshpath = cpystr (RSHPATH); #endif if (*service == '*') { /* want ssh? */ /* return immediately if ssh disabled */ if (!(sshpath && (ti = sshtimeout))) return NIL; /* ssh command prototype defined yet? */ if (!sshcommand) sshcommand = cpystr ("%s %s -l %s exec /etc/r%sd"); } /* want rsh? */ else if (rshpath && (ti = rshtimeout)) { /* rsh command prototype defined yet? */ if (!rshcommand) rshcommand = cpystr ("%s %s -l %s exec /etc/r%sd"); } else return NIL; /* rsh disabled */ /* look like domain literal? */ if (mb->host[0] == '[' && mb->host[i = (strlen (mb->host))-1] == ']') { strcpy (host,mb->host+1); /* yes, copy without brackets */ host[i-1] = '\0'; /* validate domain literal */ if (adr = ip_stringtoaddr (host,&len,&i)) fs_give ((void **) &adr); else { sprintf (tmp,"Bad format domain-literal: %.80s",host); mm_log (tmp,ERROR); return NIL; } } else strcpy (host,tcp_canonical (mb->host)); if (*service == '*') /* build ssh command */ sprintf (tmp,sshcommand,sshpath,host, mb->user[0] ? mb->user : myusername (),service + 1); else sprintf (tmp,rshcommand,rshpath,host, mb->user[0] ? mb->user : myusername (),service); if (tcpdebug) { char msg[MAILTMPLEN]; sprintf (msg,"Trying %.100s",tmp); mm_log (msg,TCPDEBUG); } /* parse command into argv */ for (i = 1,path = argv[0] = strtok_r (tmp," ",&r); (i < MAXARGV) && (argv[i] = strtok_r (NIL," ",&r)); i++); argv[i] = NIL; /* make sure argv tied off */ /* make command pipes */ if (pipe (pipei) < 0) return NIL; if ((pipei[0] >= FD_SETSIZE) || (pipei[1] >= FD_SETSIZE) || (pipe (pipeo) < 0)) { close (pipei[0]); close (pipei[1]); return NIL; } (*bn) (BLOCK_TCPOPEN,NIL); /* quell alarm up here for NeXT */ if ((pipeo[0] >= FD_SETSIZE) || (pipeo[1] >= FD_SETSIZE) || ((i = fork ()) < 0)) { /* make inferior process */ close (pipei[0]); close (pipei[1]); close (pipeo[0]); close (pipeo[1]); (*bn) (BLOCK_NONE,NIL); return NIL; } if (!i) { /* if child */ alarm (0); /* never have alarms in children */ if (!fork ()) { /* make grandchild so it's inherited by init */ int cf; /* don't alter parent vars in case vfork() */ int maxfd = max (20,max (max(pipei[0],pipei[1]),max(pipeo[0],pipeo[1]))); dup2 (pipei[1],1); /* parent's input is my output */ dup2 (pipei[1],2); /* parent's input is my error output too */ dup2 (pipeo[0],0); /* parent's output is my input */ /* close all unnecessary descriptors */ for (cf = 3; cf <= maxfd; cf++) close (cf); setpgrp (0,getpid ()); /* be our own process group */ _exit (execv (path,argv));/* now run it */ } _exit (1); /* child is done */ } grim_pid_reap (i,NIL); /* reap child; grandchild now owned by init */ close (pipei[1]); /* close child's side of the pipes */ close (pipeo[0]); /* create TCP/IP stream */ stream = (TCPSTREAM *) memset (fs_get (sizeof (TCPSTREAM)),0, sizeof (TCPSTREAM)); /* copy remote host name from argument */ stream->remotehost = cpystr (stream->host = cpystr (host)); stream->tcpsi = pipei[0]; /* init sockets */ stream->tcpso = pipeo[1]; stream->ictr = 0; /* init input counter */ stream->port = 0xffffffff; /* no port number */ ti += now = time (0); /* open timeout */ tmo.tv_usec = 0; /* initialize usec timeout */ FD_ZERO (&fds); /* initialize selection vector */ FD_ZERO (&efds); /* handle errors too */ FD_SET (stream->tcpsi,&fds); /* set bit in selection vector */ FD_SET (stream->tcpsi,&efds); /* set bit in error selection vector */ FD_SET (stream->tcpso,&efds); /* set bit in error selection vector */ do { /* block under timeout */ tmo.tv_sec = ti - now; i = select (max (stream->tcpsi,stream->tcpso)+1,&fds,NIL,&efds,&tmo); now = time (0); /* fake timeout if interrupt & time expired */ if ((i < 0) && (errno == EINTR) && ti && (ti <= now)) i = 0; } while ((i < 0) && (errno == EINTR)); if (i <= 0) { /* timeout or error? */ sprintf (tmp,i ? "error in %s to IMAP server" : "%s to IMAP server timed out",(*service == '*') ? "ssh" : "rsh"); mm_log (tmp,WARN); tcp_close (stream); /* punt stream */ stream = NIL; } (*bn) (BLOCK_NONE,NIL); /* return user name */ strcpy (usrbuf,mb->user[0] ? mb->user : myusername ()); return stream; /* return success */ } /* TCP receive line * Accepts: TCP stream * Returns: text line string or NIL if failure */ char *tcp_getline (TCPSTREAM *stream) { unsigned long n,contd; char *ret = tcp_getline_work (stream,&n,&contd); if (ret && contd) { /* got a line needing continuation? */ STRINGLIST *stl = mail_newstringlist (); STRINGLIST *stc = stl; do { /* collect additional lines */ stc->text.data = (unsigned char *) ret; stc->text.size = n; stc = stc->next = mail_newstringlist (); ret = tcp_getline_work (stream,&n,&contd); } while (ret && contd); if (ret) { /* stash final part of line on list */ stc->text.data = (unsigned char *) ret; stc->text.size = n; /* determine how large a buffer we need */ for (n = 0, stc = stl; stc; stc = stc->next) n += stc->text.size; ret = fs_get (n + 1); /* copy parts into buffer */ for (n = 0, stc = stl; stc; n += stc->text.size, stc = stc->next) memcpy (ret + n,stc->text.data,stc->text.size); ret[n] = '\0'; } mail_free_stringlist (&stl);/* either way, done with list */ } return ret; } /* TCP receive line or partial line * Accepts: TCP stream * pointer to return size * pointer to return continuation flag * Returns: text line string, size and continuation flag, or NIL if failure */ static char *tcp_getline_work (TCPSTREAM *stream,unsigned long *size, long *contd) { unsigned long n; char *s,*ret,c,d; *contd = NIL; /* assume no continuation */ /* make sure have data */ if (!tcp_getdata (stream)) return NIL; for (s = stream->iptr, n = 0, c = '\0'; stream->ictr--; n++, c = d) { d = *stream->iptr++; /* slurp another character */ if ((c == '\015') && (d == '\012')) { ret = (char *) fs_get (n--); memcpy (ret,s,*size = n); /* copy into a free storage string */ ret[n] = '\0'; /* tie off string with null */ return ret; } } /* copy partial string from buffer */ memcpy ((ret = (char *) fs_get (n)),s,*size = n); /* get more data from the net */ if (!tcp_getdata (stream)) fs_give ((void **) &ret); /* special case of newline broken by buffer */ else if ((c == '\015') && (*stream->iptr == '\012')) { stream->iptr++; /* eat the line feed */ stream->ictr--; ret[*size = --n] = '\0'; /* tie off string with null */ } else *contd = LONGT; /* continuation needed */ return ret; } /* TCP/IP receive buffer * Accepts: TCP/IP stream * size in bytes * buffer to read into * Returns: T if success, NIL otherwise */ long tcp_getbuffer (TCPSTREAM *stream,unsigned long size,char *s) { unsigned long n; /* make sure socket still alive */ if (stream->tcpsi < 0) return NIL; /* can transfer bytes from buffer? */ if (n = min (size,stream->ictr)) { memcpy (s,stream->iptr,n); /* yes, slurp as much as we can from it */ s += n; /* update pointer */ stream->iptr +=n; size -= n; /* update # of bytes to do */ stream->ictr -=n; } if (size) { int i; fd_set fds,efds; struct timeval tmo; time_t t = time (0); blocknotify_t bn=(blocknotify_t) mail_parameters (NIL,GET_BLOCKNOTIFY,NIL); (*bn) (BLOCK_TCPREAD,NIL); while (size > 0) { /* until request satisfied */ time_t tl = time (0); time_t now = tl; time_t ti = ttmo_read ? now + ttmo_read : 0; if (tcpdebug) mm_log ("Reading TCP buffer",TCPDEBUG); tmo.tv_usec = 0; FD_ZERO (&fds); /* initialize selection vector */ FD_ZERO (&efds); /* handle errors too */ /* set bit in selection vectors */ FD_SET (stream->tcpsi,&fds); FD_SET (stream->tcpsi,&efds); errno = NIL; /* initially no error */ do { /* block under timeout */ tmo.tv_sec = ti ? ti - now : 0; i = select (stream->tcpsi+1,&fds,NIL,&efds,ti ? &tmo : NIL); now = time (0); /* fake timeout if interrupt & time expired */ if ((i < 0) && (errno == EINTR) && ti && (ti <= now)) i = 0; } while ((i < 0) && (errno == EINTR)); if (i) { /* non-timeout result from select? */ if (i > 0) /* read what we can */ while (((i = read (stream->tcpsi,s,(int) min (maxposint,size))) < 0) && (errno == EINTR)); if (i <= 0) { /* error seen? */ if (tcpdebug) { char tmp[MAILTMPLEN]; if (i) sprintf (s = tmp,"TCP buffer read I/O error %d",errno); else s = "TCP buffer read end of file"; mm_log (s,TCPDEBUG); } return tcp_abort (stream); } s += i; /* success, point at new place to write */ size -= i; /* reduce byte count */ if (tcpdebug) mm_log ("Successfully read TCP buffer",TCPDEBUG); } /* timeout, punt unless told not to */ else if (!tmoh || !(*tmoh) (now - t,now - tl, stream->host)) { if (tcpdebug) mm_log ("TCP buffer read timeout",TCPDEBUG); return tcp_abort (stream); } } (*bn) (BLOCK_NONE,NIL); } *s = '\0'; /* tie off string */ return LONGT; } /* TCP/IP receive data * Accepts: TCP/IP stream * Returns: T if success, NIL otherwise */ long tcp_getdata (TCPSTREAM *stream) { int i; fd_set fds,efds; struct timeval tmo; time_t t = time (0); blocknotify_t bn = (blocknotify_t) mail_parameters (NIL,GET_BLOCKNOTIFY,NIL); if (stream->tcpsi < 0) return NIL; (*bn) (BLOCK_TCPREAD,NIL); while (stream->ictr < 1) { /* if nothing in the buffer */ time_t tl = time (0); /* start of request */ time_t now = tl; time_t ti = ttmo_read ? now + ttmo_read : 0; if (tcpdebug) mm_log ("Reading TCP data",TCPDEBUG); tmo.tv_usec = 0; FD_ZERO (&fds); /* initialize selection vector */ FD_ZERO (&efds); /* handle errors too */ FD_SET (stream->tcpsi,&fds);/* set bit in selection vectors */ FD_SET (stream->tcpsi,&efds); errno = NIL; /* initially no error */ do { /* block under timeout */ tmo.tv_sec = ti ? ti - now : 0; i = select (stream->tcpsi+1,&fds,NIL,&efds,ti ? &tmo : NIL); now = time (0); /* fake timeout if interrupt & time expired */ if ((i < 0) && (errno == EINTR) && ti && (ti <= now)) i = 0; } while ((i < 0) && (errno == EINTR)); if (i) { /* non-timeout result from select? */ /* read what we can */ if (i > 0) while (((i = read (stream->tcpsi,stream->ibuf,BUFLEN)) < 0) && (errno == EINTR)); if (i <= 0) { /* error seen? */ if (tcpdebug) { char *s,tmp[MAILTMPLEN]; if (i) sprintf (s = tmp,"TCP data read I/O error %d",errno); else s = "TCP data read end of file"; mm_log (s,TCPDEBUG); } return tcp_abort (stream); } stream->ictr = i; /* success, set new count and pointer */ stream->iptr = stream->ibuf; if (tcpdebug) mm_log ("Successfully read TCP data",TCPDEBUG); } /* timeout, punt unless told not to */ else if (!tmoh || !(*tmoh) (now - t,now - tl, stream->host)) { if (tcpdebug) mm_log ("TCP data read timeout",TCPDEBUG); return tcp_abort (stream);/* error or timeout no-continue */ } } (*bn) (BLOCK_NONE,NIL); return T; } /* TCP/IP send string as record * Accepts: TCP/IP stream * string pointer * Returns: T if success else NIL */ long tcp_soutr (TCPSTREAM *stream,char *string) { return tcp_sout (stream,string,(unsigned long) strlen (string)); } /* TCP/IP send string * Accepts: TCP/IP stream * string pointer * byte count * Returns: T if success else NIL */ long tcp_sout (TCPSTREAM *stream,char *string,unsigned long size) { int i; fd_set fds,efds; struct timeval tmo; time_t t = time (0); blocknotify_t bn = (blocknotify_t) mail_parameters (NIL,GET_BLOCKNOTIFY,NIL); if (stream->tcpso < 0) return NIL; (*bn) (BLOCK_TCPWRITE,NIL); while (size > 0) { /* until request satisfied */ time_t tl = time (0); /* start of request */ time_t now = tl; time_t ti = ttmo_write ? now + ttmo_write : 0; if (tcpdebug) mm_log ("Writing to TCP",TCPDEBUG); tmo.tv_usec = 0; FD_ZERO (&fds); /* initialize selection vector */ FD_ZERO (&efds); /* handle errors too */ FD_SET (stream->tcpso,&fds);/* set bit in selection vector */ FD_SET(stream->tcpso,&efds);/* set bit in error selection vector */ errno = NIL; /* block and write */ do { /* block under timeout */ tmo.tv_sec = ti ? ti - now : 0; i = select (stream->tcpso+1,NIL,&fds,&efds,ti ? &tmo : NIL); now = time (0); /* fake timeout if interrupt & time expired */ if ((i < 0) && (errno == EINTR) && ti && (ti <= now)) i = 0; } while ((i < 0) && (errno == EINTR)); if (i) { /* non-timeout result from select? */ /* write what we can */ if (i > 0) while (((i = write (stream->tcpso,string,size)) < 0) && (errno == EINTR)); if (i <= 0) { /* error seen? */ if (tcpdebug) { char tmp[MAILTMPLEN]; sprintf (tmp,"TCP write I/O error %d",errno); mm_log (tmp,TCPDEBUG); } return tcp_abort (stream); } string += i; /* how much we sent */ size -= i; /* count this size */ if (tcpdebug) mm_log ("successfully wrote to TCP",TCPDEBUG); } /* timeout, punt unless told not to */ else if (!tmoh || !(*tmoh) (now - t,now - tl, stream->host)) { if (tcpdebug) mm_log ("TCP write timeout",TCPDEBUG); return tcp_abort (stream); } } (*bn) (BLOCK_NONE,NIL); return T; /* all done */ } /* TCP/IP close * Accepts: TCP/IP stream */ void tcp_close (TCPSTREAM *stream) { tcp_abort (stream); /* nuke the stream */ /* flush host names */ if (stream->host) fs_give ((void **) &stream->host); if (stream->remotehost) fs_give ((void **) &stream->remotehost); if (stream->localhost) fs_give ((void **) &stream->localhost); fs_give ((void **) &stream); /* flush the stream */ } /* TCP/IP abort stream * Accepts: TCP/IP stream * Returns: NIL always */ long tcp_abort (TCPSTREAM *stream) { blocknotify_t bn = (blocknotify_t) mail_parameters (NIL,GET_BLOCKNOTIFY,NIL); if (stream->tcpsi >= 0) { /* no-op if no socket */ (*bn) (BLOCK_TCPCLOSE,NIL); close (stream->tcpsi); /* nuke the socket */ if (stream->tcpsi != stream->tcpso) close (stream->tcpso); stream->tcpsi = stream->tcpso = -1; } (*bn) (BLOCK_NONE,NIL); return NIL; } /* TCP/IP get host name * Accepts: TCP/IP stream * Returns: host name for this stream */ char *tcp_host (TCPSTREAM *stream) { return stream->host; /* use tcp_remotehost() if want guarantees */ } /* TCP/IP get remote host name * Accepts: TCP/IP stream * Returns: host name for this stream */ char *tcp_remotehost (TCPSTREAM *stream) { if (!stream->remotehost) { size_t sadrlen; struct sockaddr *sadr = ip_newsockaddr (&sadrlen); stream->remotehost = /* get socket's peer name */ getpeername (stream->tcpsi,sadr,(void *) &sadrlen) ? cpystr (stream->host) : tcp_name (sadr,NIL); fs_give ((void **) &sadr); } return stream->remotehost; } /* TCP/IP return port for this stream * Accepts: TCP/IP stream * Returns: port number for this stream */ unsigned long tcp_port (TCPSTREAM *stream) { return stream->port; /* return port number */ } /* TCP/IP get local host name * Accepts: TCP/IP stream * Returns: local host name */ char *tcp_localhost (TCPSTREAM *stream) { if (!stream->localhost) { size_t sadrlen; struct sockaddr *sadr = ip_newsockaddr (&sadrlen); stream->localhost = /* get socket's name */ ((stream->port & 0xffff000) || getsockname (stream->tcpsi,sadr,(void *) &sadrlen)) ? cpystr (mylocalhost ()) : tcp_name (sadr,NIL); fs_give ((void **) &sadr); } return stream->localhost; /* return local host name */ } /* TCP/IP get client host address (server calls only) * Returns: client host address */ char *tcp_clientaddr () { if (!myClientAddr) { size_t sadrlen; struct sockaddr *sadr = ip_newsockaddr (&sadrlen); if (getpeername (0,sadr,(void *) &sadrlen)) myClientAddr = cpystr ("UNKNOWN"); else { /* get stdin's peer name */ myClientAddr = cpystr (ip_sockaddrtostring (sadr)); if (myClientPort < 0) myClientPort = ip_sockaddrtoport (sadr); } fs_give ((void **) &sadr); } return myClientAddr; } /* TCP/IP get client host name (server calls only) * Returns: client host name */ char *tcp_clienthost () { if (!myClientHost) { size_t sadrlen; struct sockaddr *sadr = ip_newsockaddr (&sadrlen); if (getpeername (0,sadr,(void *) &sadrlen)) { char *s,*t,*v,tmp[MAILTMPLEN]; if ((s = getenv (t = "SSH_CLIENT")) || (s = getenv (t = "KRB5REMOTEADDR")) || (s = getenv (t = "SSH2_CLIENT"))) { if (v = strchr (s,' ')) *v = '\0'; sprintf (v = tmp,"%.80s=%.80s",t,s); } else v = "UNKNOWN"; myClientHost = cpystr (v); } else { /* get stdin's peer name */ myClientHost = tcp_name (sadr,T); if (!myClientAddr) myClientAddr = cpystr (ip_sockaddrtostring (sadr)); if (myClientPort < 0) myClientPort = ip_sockaddrtoport (sadr); } fs_give ((void **) &sadr); } return myClientHost; } /* TCP/IP get client port number (server calls only) * Returns: client port number */ long tcp_clientport () { if (!myClientHost && !myClientAddr) tcp_clientaddr (); return myClientPort; } /* TCP/IP get server host address (server calls only) * Returns: server host address */ char *tcp_serveraddr () { if (!myServerAddr) { size_t sadrlen; struct sockaddr *sadr = ip_newsockaddr (&sadrlen); if (getsockname (0,sadr,(void *) &sadrlen)) myServerAddr = cpystr ("UNKNOWN"); else { /* get stdin's name */ myServerAddr = cpystr (ip_sockaddrtostring (sadr)); if (myServerPort < 0) myServerPort = ip_sockaddrtoport (sadr); } fs_give ((void **) &sadr); } return myServerAddr; } /* TCP/IP get server host name (server calls only) * Returns: server host name */ char *tcp_serverhost () { if (!myServerHost) { /* once-only */ size_t sadrlen; struct sockaddr *sadr = ip_newsockaddr (&sadrlen); /* get stdin's name */ if (getsockname (0,sadr,(void *) &sadrlen)) myServerHost = cpystr (mylocalhost ()); else { /* get stdin's name */ myServerHost = tcp_name (sadr,NIL); if (!myServerAddr) myServerAddr = cpystr (ip_sockaddrtostring (sadr)); if (myServerPort < 0) myServerPort = ip_sockaddrtoport (sadr); } fs_give ((void **) &sadr); } return myServerHost; } /* TCP/IP get server port number (server calls only) * Returns: server port number */ long tcp_serverport () { if (!myServerHost && !myServerAddr) tcp_serveraddr (); return myServerPort; } /* TCP/IP return canonical form of host name * Accepts: host name * Returns: canonical form of host name */ char *tcp_canonical (char *name) { char *ret,host[MAILTMPLEN]; blocknotify_t bn = (blocknotify_t) mail_parameters (NIL,GET_BLOCKNOTIFY,NIL); void *data; /* look like domain literal? */ if (name[0] == '[' && name[strlen (name) - 1] == ']') return name; (*bn) (BLOCK_DNSLOOKUP,NIL); /* quell alarms */ data = (*bn) (BLOCK_SENSITIVE,NIL); if (tcpdebug) { sprintf (host,"DNS canonicalization %.80s",name); mm_log (host,TCPDEBUG); } /* get canonical name */ if (!ip_nametoaddr (name,NIL,NIL,&ret,NIL)) ret = name; (*bn) (BLOCK_NONSENSITIVE,data); (*bn) (BLOCK_NONE,NIL); /* alarms OK now */ if (tcpdebug) mm_log ("DNS canonicalization done",TCPDEBUG); return ret; } /* TCP/IP return name from socket * Accepts: socket * verbose flag * Returns: cpystr name */ char *tcp_name (struct sockaddr *sadr,long flag) { char *ret,*t,adr[MAILTMPLEN],tmp[MAILTMPLEN]; sprintf (ret = adr,"[%.80s]",ip_sockaddrtostring (sadr)); if (allowreversedns) { blocknotify_t bn = (blocknotify_t)mail_parameters(NIL,GET_BLOCKNOTIFY,NIL); void *data; if (tcpdebug) { sprintf (tmp,"Reverse DNS resolution %s",adr); mm_log (tmp,TCPDEBUG); } (*bn) (BLOCK_DNSLOOKUP,NIL);/* quell alarms */ data = (*bn) (BLOCK_SENSITIVE,NIL); /* translate address to name */ if (t = tcp_name_valid (ip_sockaddrtoname (sadr))) { /* produce verbose form if needed */ if (flag) sprintf (ret = tmp,"%s %s",t,adr); else ret = t; } (*bn) (BLOCK_NONSENSITIVE,data); (*bn) (BLOCK_NONE,NIL); /* alarms OK now */ if (tcpdebug) mm_log ("Reverse DNS resolution done",TCPDEBUG); } return cpystr (ret); } /* TCP/IP validate name * Accepts: domain name * Returns: name if valid, NIL otherwise */ char *tcp_name_valid (char *s) { int c; char *ret,*tail; /* must be non-empty and not too long */ if ((ret = (s && *s) ? s : NIL) && (tail = ret + NETMAXHOST)) { /* must be alnum, dot, or hyphen */ while ((c = *s++) && (s <= tail) && (((c >= 'A') && (c <= 'Z')) || ((c >= 'a') && (c <= 'z')) || ((c >= '0') && (c <= '9')) || (c == '-') || (c == '.'))); if (c) ret = NIL; } return ret; } /* TCP/IP check if client is given host name * Accepts: candidate host name * Returns: T if match, NIL otherwise */ long tcp_isclienthost (char *host) { int family; size_t adrlen,sadrlen,len; void *adr,*next; struct sockaddr *sadr; long ret = NIL; /* make sure that myClientAddr is set */ if (tcp_clienthost () && myClientAddr) /* get sockaddr of client */ for (adr = ip_nametoaddr (host,&adrlen,&family,NIL,&next); adr && !ret; adr = ip_nametoaddr (NIL,&adrlen,&family,NIL,&next)) { /* build sockaddr of given address */ sadr = ip_sockaddr (family,adr,adrlen,1,&len); if (!strcmp (myClientAddr,ip_sockaddrtostring (sadr))) ret = LONGT; fs_give ((void **) &sadr); /* done with client sockaddr */ } return ret; } /* Following statement must be at end of this module */ #undef fork /* undo any use of vfork() */ alpine-2.10+dfsg/imap/src/osdep/unix/ip4_unix.c0000600000175000017500000001220411512502123023047 0ustar paulproteuspaulproteus/* ======================================================================== * Copyright 1988-2006 University of Washington * * Licensed under the Apache License, Version 2.0 (the "License"); * you may not use this file except in compliance with the License. * You may obtain a copy of the License at * * http://www.apache.org/licenses/LICENSE-2.0 * * * ======================================================================== */ /* * Program: UNIX IPv4 routines * * Author: Mark Crispin * Networks and Distributed Computing * Computing & Communications * University of Washington * Administration Building, AG-44 * Seattle, WA 98195 * Internet: MRC@CAC.Washington.EDU * * Date: 18 December 2003 * Last Edited: 30 August 2006 */ #define SADRLEN sizeof (struct sockaddr) #define SADR4(sadr) ((struct sockaddr_in *) sadr) #define SADR4LEN sizeof (struct sockaddr_in) #define SADR4ADR(sadr) SADR4 (sadr)->sin_addr #define ADR4LEN sizeof (struct in_addr) #define SADR4PORT(sadr) SADR4 (sadr)->sin_port /* IP abstraction layer */ char *ip_sockaddrtostring (struct sockaddr *sadr); long ip_sockaddrtoport (struct sockaddr *sadr); void *ip_stringtoaddr (char *text,size_t *len,int *family); struct sockaddr *ip_newsockaddr (size_t *len); struct sockaddr *ip_sockaddr (int family,void *adr,size_t adrlen, unsigned short port,size_t *len); char *ip_sockaddrtoname (struct sockaddr *sadr); void *ip_nametoaddr (char *name,size_t *len,int *family,char **canonical, void **next); /* Return IP address string from socket address * Accepts: socket address * Returns: IP address as name string */ char *ip_sockaddrtostring (struct sockaddr *sadr) { return (sadr->sa_family == PF_INET) ? inet_ntoa (SADR4ADR (sadr)) : "NON-IPv4"; } /* Return port from socket address * Accepts: socket address * Returns: port number or -1 if can't determine it */ long ip_sockaddrtoport (struct sockaddr *sadr) { return (sadr->sa_family == PF_INET) ? ntohs (SADR4PORT (sadr)) : -1; } /* Return IP address from string * Accepts: name string * pointer to returned length * pointer to returned address family * Returns: address if valid, length and family updated, or NIL */ void *ip_stringtoaddr (char *text,size_t *len,int *family) { unsigned long adr; struct in_addr *ret; /* get address */ if ((adr = inet_addr (text)) == -1) ret = NIL; else { /* make in_addr */ ret = (struct in_addr *) fs_get (*len = ADR4LEN); *family = AF_INET; /* IPv4 */ ret->s_addr = adr; /* set address */ } return (void *) ret; } /* Create a maximum-size socket address * Accepts: pointer to return maximum socket address length * Returns: new, empty socket address of maximum size */ struct sockaddr *ip_newsockaddr (size_t *len) { return (struct sockaddr *) memset (fs_get (SADRLEN),0,*len = SADRLEN); } /* Stuff a socket address * Accepts: address family * IPv4 address * length of address (always 4 in IPv4) * port number * pointer to return socket address length * Returns: socket address or NIL if error */ struct sockaddr *ip_sockaddr (int family,void *adr,size_t adrlen, unsigned short port,size_t *len) { struct sockaddr *sadr = ip_newsockaddr (len); switch (family) { /* build socket address based upon family */ case AF_INET: /* IPv4 */ sadr->sa_family = PF_INET; /* copy host address */ memcpy (&SADR4ADR (sadr),adr,adrlen); /* copy port number in network format */ SADR4PORT (sadr) = htons (port); *len = SADR4LEN; break; default: /* non-IP?? */ sadr->sa_family = PF_UNSPEC; break; } return sadr; } /* Return name from socket address * Accepts: socket address * Returns: canonical name for that address or NIL if none */ char *ip_sockaddrtoname (struct sockaddr *sadr) { struct hostent *he; return ((sadr->sa_family == PF_INET) && (he = gethostbyaddr ((char *) &SADR4ADR (sadr),ADR4LEN,AF_INET))) ? (char *) he->h_name : NIL; } /* Return address from name * Accepts: name or NIL to return next address * pointer to previous/returned length * pointer to previous/returned address family * pointer to previous/returned canonical name * pointer to previous/return state for next-address calls * Returns: address with length/family/canonical updated if needed, or NIL */ void *ip_nametoaddr (char *name,size_t *len,int *family,char **canonical, void **next) { char **adl,tmp[MAILTMPLEN]; struct hostent *he; if (name) { /* first lookup? */ /* yes, do case-independent lookup */ if ((strlen (name) < MAILTMPLEN) && (he = gethostbyname (lcase (strcpy (tmp,name))))) { adl = he->h_addr_list; if (len) *len = he->h_length; if (family) *family = he->h_addrtype; if (canonical) *canonical = (char *) he->h_name; if (next) *next = (void *) adl; } else { /* error */ adl = NIL; if (len) *len = 0; if (family) *family = 0; if (canonical) *canonical = NIL; if (next) *next = NIL; } } /* return next in series */ else if (next && (adl = (char **) *next)) *next = ++adl; else adl = NIL; /* failure */ return adl ? (void *) *adl : NIL; } alpine-2.10+dfsg/imap/src/osdep/unix/truncate.c0000600000175000017500000000207611512502123023143 0ustar paulproteuspaulproteus/* ======================================================================== * Copyright 1988-2006 University of Washington * * Licensed under the Apache License, Version 2.0 (the "License"); * you may not use this file except in compliance with the License. * You may obtain a copy of the License at * * http://www.apache.org/licenses/LICENSE-2.0 * * * ======================================================================== */ /* * Program: Truncate a file * * Author: Mark Crispin * Networks and Distributed Computing * Computing & Communications * University of Washington * Administration Building, AG-44 * Seattle, WA 98195 * Internet: MRC@CAC.Washington.EDU * * Date: 30 June 1994 * Last Edited: 30 August 2006 */ /* Emulator for ftruncate() call * Accepts: file descriptor * length * Returns: 0 if success, -1 if failure */ int ftruncate (int fd,off_t length) { struct flock fb; fb.l_whence = 0; fb.l_len = 0; fb.l_start = length; fb.l_type = F_WRLCK; /* write lock on file space */ return fcntl (fd,F_FREESP,&fb); } alpine-2.10+dfsg/imap/src/osdep/unix/os_bsd.h0000600000175000017500000000251711512502123022574 0ustar paulproteuspaulproteus/* ======================================================================== * Copyright 1988-2006 University of Washington * * Licensed under the Apache License, Version 2.0 (the "License"); * you may not use this file except in compliance with the License. * You may obtain a copy of the License at * * http://www.apache.org/licenses/LICENSE-2.0 * * * ======================================================================== */ /* * Program: Operating-system dependent routines -- 4.3BSD version * * Author: Mark Crispin * Networks and Distributed Computing * Computing & Communications * University of Washington * Administration Building, AG-44 * Seattle, WA 98195 * Internet: MRC@CAC.Washington.EDU * * Date: 11 May 1989 * Last Edited: 30 August 2006 */ #include #include #include #include #include #include #include /* needed for htons() prototypes */ char *getenv (char *name); char *strstr (char *cs,char *ct); char *strerror (int n); void *memmove (void *s,void *ct,size_t n); unsigned long strtoul (char *s,char **endp,int base); void *malloc (size_t byteSize); void free (void *ptr); void *realloc (void *oldptr,size_t newsize); #include "env_unix.h" #include "fs.h" #include "ftl.h" #include "nl.h" #include "tcp.h" alpine-2.10+dfsg/imap/src/osdep/unix/ckp_pmb.c0000600000175000017500000000751111512502123022730 0ustar paulproteuspaulproteus/* ======================================================================== * Copyright 1988-2006 University of Washington * * Licensed under the Apache License, Version 2.0 (the "License"); * you may not use this file except in compliance with the License. * You may obtain a copy of the License at * * http://www.apache.org/licenses/LICENSE-2.0 * * * ======================================================================== */ /* * Program: Pluggable Authentication Modules login services, buggy systems * (use this instead of ckp_pam.c on Solaris) * * Author: Mark Crispin * Networks and Distributed Computing * Computing & Communications * University of Washington * Administration Building, AG-44 * Seattle, WA 98195 * Internet: MRC@CAC.Washington.EDU * * Date: 1 August 1988 * Last Edited: 31 August 2006 */ #include static char *pam_uname; /* user name */ static char *pam_pass; /* password */ /* PAM conversation function * Accepts: number of messages * vector of messages * pointer to response return * application data * Returns: PAM_SUCCESS if OK, response vector filled in, else PAM_CONV_ERR */ static int checkpw_conv (int num_msg,const struct pam_message **msg, struct pam_response **resp,void *appdata_ptr) { int i; struct pam_response *reply = fs_get (sizeof (struct pam_response) * num_msg); for (i = 0; i < num_msg; i++) switch (msg[i]->msg_style) { case PAM_PROMPT_ECHO_ON: /* assume want user name */ reply[i].resp_retcode = PAM_SUCCESS; reply[i].resp = cpystr (pam_uname); break; case PAM_PROMPT_ECHO_OFF: /* assume want password */ reply[i].resp_retcode = PAM_SUCCESS; reply[i].resp = cpystr (pam_pass); break; case PAM_TEXT_INFO: case PAM_ERROR_MSG: reply[i].resp_retcode = PAM_SUCCESS; reply[i].resp = NULL; break; default: /* unknown message style */ fs_give ((void **) &reply); return PAM_CONV_ERR; } *resp = reply; return PAM_SUCCESS; } /* PAM cleanup * Accepts: handle */ static void checkpw_cleanup (pam_handle_t *hdl) { #if 0 /* see checkpw() for why this is #if 0 */ pam_close_session (hdl,NIL); /* close session [uw]tmp */ #endif pam_setcred (hdl,PAM_DELETE_CRED); pam_end (hdl,PAM_SUCCESS); } /* Server log in * Accepts: user name string * password string * Returns: T if password validated, NIL otherwise */ struct passwd *checkpw (struct passwd *pw,char *pass,int argc,char *argv[]) { pam_handle_t *hdl; struct pam_conv conv; char *name = cpystr (pw->pw_name); conv.conv = &checkpw_conv; pam_uname = pw->pw_name; pam_pass = pass; if (pw = ((pam_start ((char *) mail_parameters (NIL,GET_SERVICENAME,NIL), pw->pw_name,&conv,&hdl) == PAM_SUCCESS) && (pam_set_item (hdl,PAM_RHOST,tcp_clientaddr ()) == PAM_SUCCESS) && (pam_authenticate (hdl,NIL) == PAM_SUCCESS) && (pam_acct_mgmt (hdl,NIL) == PAM_SUCCESS) && (pam_setcred (hdl,PAM_ESTABLISH_CRED) == PAM_SUCCESS)) ? getpwnam (name) : NIL) { #if 0 /* * Some people have reported that this causes a SEGV in strncpy() from * pam_unix.so.1 */ /* * This pam_open_session() call is inconsistant with how we handle other * platforms, where we don't write [uw]tmp records. However, unlike our * code on other platforms, pam_acct_mgmt() will check those records for * inactivity and deny the authentication. */ pam_open_session (hdl,NIL); /* make sure account doesn't go inactive */ #endif /* arm hook to delete credentials */ mail_parameters (NIL,SET_LOGOUTHOOK,(void *) checkpw_cleanup); mail_parameters (NIL,SET_LOGOUTDATA,(void *) hdl); } else checkpw_cleanup (hdl); /* clean up */ fs_give ((void **) &name); /* reset log facility in case PAM broke it */ if (myServerName) openlog (myServerName,LOG_PID,syslog_facility); return pw; } alpine-2.10+dfsg/imap/src/osdep/unix/ckp_a41.c0000600000175000017500000000264011512502123022535 0ustar paulproteuspaulproteus/* ======================================================================== * Copyright 1988-2006 University of Washington * * Licensed under the Apache License, Version 2.0 (the "License"); * you may not use this file except in compliance with the License. * You may obtain a copy of the License at * * http://www.apache.org/licenses/LICENSE-2.0 * * * ======================================================================== */ /* * Program: AIX 4.1 check password * * Author: Mark Crispin * Networks and Distributed Computing * Computing & Communications * University of Washington * Administration Building, AG-44 * Seattle, WA 98195 * Internet: MRC@CAC.Washington.EDU * * Date: 1 August 1988 * Last Edited: 30 August 2006 */ #include /* Check password * Accepts: login passwd struct * password string * argument count * argument vector * Returns: passwd struct if password validated, NIL otherwise */ struct passwd *checkpw (struct passwd *pw,char *pass,int argc,char *argv[]) { int reenter = 0; char *msg = NIL; char *user = cpystr (pw->pw_name); /* validate password */ struct passwd *ret = (pw && !loginrestrictions (user,S_RLOGIN,NIL,&msg) && !authenticate (user,pass,&reenter,&msg)) ? getpwnam (user) : NIL; /* clean up any message returned */ if (msg) fs_give ((void **) &msg); if (user) fs_give ((void **) &user); return ret; } alpine-2.10+dfsg/imap/src/osdep/unix/os_bsi.c0000600000175000017500000000252511512502123022573 0ustar paulproteuspaulproteus/* ======================================================================== * Copyright 1988-2007 University of Washington * * Licensed under the Apache License, Version 2.0 (the "License"); * you may not use this file except in compliance with the License. * You may obtain a copy of the License at * * http://www.apache.org/licenses/LICENSE-2.0 * * * ======================================================================== */ /* * Program: Operating-system dependent routines -- BSDI BSD/386 version * * Author: Mark Crispin * Networks and Distributed Computing * Computing & Communications * University of Washington * Administration Building, AG-44 * Seattle, WA 98195 * Internet: MRC@CAC.Washington.EDU * * Date: 1 August 1988 * Last Edited: 16 August 2007 */ #include "tcp_unix.h" /* must be before osdep includes tcp.h */ #include "mail.h" #include "osdep.h" #include #include #include #include #include #include #include #include #include extern int errno; /* just in case */ #include #include "misc.h" #include "fs_unix.c" #include "ftl_unix.c" #include "nl_unix.c" #include "env_unix.c" #include "getspnam.c" #define fork vfork #include "tcp_unix.c" #include "gr_waitp.c" #include "tz_bsd.c" alpine-2.10+dfsg/imap/src/osdep/unix/os_shp.h0000600000175000017500000000256011512502123022614 0ustar paulproteuspaulproteus/* ======================================================================== * Copyright 1988-2006 University of Washington * * Licensed under the Apache License, Version 2.0 (the "License"); * you may not use this file except in compliance with the License. * You may obtain a copy of the License at * * http://www.apache.org/licenses/LICENSE-2.0 * * * ======================================================================== */ /* * Program: Operating-system dependent routines -- HP/UX version * * Author: Mark Crispin * Networks and Distributed Computing * Computing & Communications * University of Washington * Administration Building, AG-44 * Seattle, WA 98195 * Internet: MRC@CAC.Washington.EDU * * Date: 11 May 1989 * Last Edited: 20 December 2006 */ #include #include #include #include #include #include #include #include #include #include #include #define direct dirent #define random lrand48 /* Many versions of SysV get this wrong */ #define setpgrp(a,b) Setpgrp(a,b) int Setpgrp (int pid,int gid); #define utime portable_utime int portable_utime (char *file,time_t timep[2]); long gethostid (void); #include "env_unix.h" #include "fs.h" #include "ftl.h" #include "nl.h" #include "tcp.h" #include "flocksim.h" alpine-2.10+dfsg/imap/src/osdep/unix/Makefile.gss0000600000175000017500000000244311512502123023403 0ustar paulproteuspaulproteus# ======================================================================== # Copyright 1988-2007 University of Washington # # Licensed under the Apache License, Version 2.0 (the "License"); # you may not use this file except in compliance with the License. # You may obtain a copy of the License at # # http://www.apache.org/licenses/LICENSE-2.0 # # # ======================================================================== # Program: GSSAPI makefile # # Author: Mark Crispin # Networks and Distributed Computing # Computing & Communications # University of Washington # Administration Building, AG-44 # Seattle, WA 98195 # Internet: MRC@CAC.Washington.EDU # # Date: 11 May 1989 # Last Edited: 4 April 2007 # Extended flags needed for additional authenticators. You may need to modify. GSSDIR=/usr/local GSSINCLUDE=$(GSSDIR)/include GSSLIB=$(GSSDIR)/lib GSSCFLAGS= -I$(GSSINCLUDE) -DGSS_C_NT_HOSTBASED_SERVICE=gss_nt_service_name -DKRB5_DEPRECATED=1 GSSOLDLDFLAGS= -L$(GSSLIB) -lgssapi_krb5 -lkrb5 -lcrypto -lcom_err GSSNEWLDFLAGS= -L$(GSSLIB) -lgssapi_krb5 -lkrb5 -lk5crypto -lcom_err gss: # GSSAPI Kerberos V flags echo $(GSSCFLAGS) >> OSCFLAGS sh -c '(test -f $(GSSLIB)/libk5crypto.a) && echo $(GSSNEWLDFLAGS) || echo $(GSSOLDLDFLAGS)' >> LDFLAGS echo "#include \"kerb_mit.c\"" >> auths.c alpine-2.10+dfsg/imap/src/osdep/unix/os_hpp.c0000600000175000017500000000362411512502123022606 0ustar paulproteuspaulproteus/* ======================================================================== * Copyright 1988-2007 University of Washington * * Licensed under the Apache License, Version 2.0 (the "License"); * you may not use this file except in compliance with the License. * You may obtain a copy of the License at * * http://www.apache.org/licenses/LICENSE-2.0 * * * ======================================================================== */ /* * Program: Operating-system dependent routines -- HP/UX version * * Author: Mark Crispin * Networks and Distributed Computing * Computing & Communications * University of Washington * Administration Building, AG-44 * Seattle, WA 98195 * Internet: MRC@CAC.Washington.EDU * * Date: 11 May 1989 * Last Edited: 16 August 2007 */ #define isodigit(c) (((unsigned)(c)>=060)&((unsigned)(c)<=067)) #define toint(c) ((c)-'0') #include #include "tcp_unix.h" /* must be before osdep includes tcp.h */ #include "mail.h" #include "osdep.h" #include #include #include #include #include #include #include #include #include #include extern int errno; /* just in case */ extern char *sys_errlist[]; extern int sys_nerr; #include #include "misc.h" #include "fs_unix.c" #include "ftl_unix.c" #include "nl_unix.c" #include "env_unix.c" #define fork vfork #include "tcp_unix.c" #include "gr_waitp.c" #include "flocksim.c" #include "tz_sv4.c" #undef setpgrp #include "setpgrp.c" #include "utime.c" /* Emulator for BSD gethostid() call * Returns: a unique identifier for the system. * Even though HP/UX has an undocumented gethostid() system call, * it does not work (at least for non-privileged users). */ long gethostid (void) { struct utsname udata; return (uname (&udata)) ? 0xfeedface : atol (udata.__idnumber); } alpine-2.10+dfsg/imap/src/osdep/unix/ckp_svo.c0000600000175000017500000000615511512502123022764 0ustar paulproteuspaulproteus/* ======================================================================== * Copyright 1988-2006 University of Washington * * Licensed under the Apache License, Version 2.0 (the "License"); * you may not use this file except in compliance with the License. * You may obtain a copy of the License at * * http://www.apache.org/licenses/LICENSE-2.0 * * * ======================================================================== */ /* * Program: Old SVR4 check password * * Author: Mark Crispin * Networks and Distributed Computing * Computing & Communications * University of Washington * Administration Building, AG-44 * Seattle, WA 98195 * Internet: MRC@CAC.Washington.EDU * * Date: 1 August 1988 * Last Edited: 30 August 2006 */ /* Check password * Accepts: login passwd struct * password string * argument count * argument vector * Returns: passwd struct if password validated, NIL otherwise */ struct passwd *checkpw (struct passwd *pw,char *pass,int argc,char *argv[]) { char tmp[MAILTMPLEN]; struct spwd *sp = NIL; time_t left; time_t now = time (0); struct tm *t = gmtime (&now); int zone = t->tm_hour * 60 + t->tm_min; int julian = t->tm_yday; t = localtime (&now); /* get local time now */ /* minus UTC minutes since midnight */ zone = t->tm_hour * 60 + t->tm_min - zone; /* julian can be one of: * 36x local time is December 31, UTC is January 1, offset -24 hours * 1 local time is 1 day ahead of UTC, offset +24 hours * 0 local time is same day as UTC, no offset * -1 local time is 1 day behind UTC, offset -24 hours * -36x local time is January 1, UTC is December 31, offset +24 hours */ if (julian = t->tm_yday -julian) zone += ((julian < 0) == (abs (julian) == 1)) ? -24*60 : 24*60; /* days since 1/1/1970 local time */ now = ((now /60) + zone) / (60*24); /* non-shadow authentication */ if (!pw->pw_passwd || !pw->pw_passwd[0] || !pw->pw_passwd[1] || strcmp (pw->pw_passwd,(char *) crypt (pass,pw->pw_passwd))) { /* As far as I've been able to determine, here is how the expiration * fields in the shadow authentication data work: * lstchg last password change date if non-negative. If zero, the * user can not log in without changing password. * max number of days a password is valid if positive * The expiration day is the *last* day that the password is valid. */ /* shadow authentication */ if ((sp = getspnam (pw->pw_name)) && sp->sp_lstchg && ((sp->sp_lstchg < 0) || (sp->sp_max <= 0) || ((sp->sp_lstchg + sp->sp_max) >= now)) && sp->sp_pwdp && sp->sp_pwdp[0] && sp->sp_pwdp[1] && !strcmp (sp->sp_pwdp,(char *) crypt (pass,sp->sp_pwdp))) { if ((sp->sp_lstchg > 0) && (sp->sp_max > 0) && ((left = (sp->sp_lstchg + sp->sp_max) - now) <= 28)) { if (left) { sprintf (tmp,"[ALERT] Password expires in %ld day(s)",(long) left); mm_notify (NIL,tmp,NIL); } else mm_notify (NIL,"[ALERT] Password expires today!",WARN); } endspent (); /* don't need shadow password data any more */ } else pw = NIL; /* password failed */ } return pw; } alpine-2.10+dfsg/imap/src/osdep/unix/os_ptx.c0000600000175000017500000000561211512502123022631 0ustar paulproteuspaulproteus/* ======================================================================== * Copyright 1988-2007 University of Washington * * Licensed under the Apache License, Version 2.0 (the "License"); * you may not use this file except in compliance with the License. * You may obtain a copy of the License at * * http://www.apache.org/licenses/LICENSE-2.0 * * * ======================================================================== */ /* * Program: Operating-system dependent routines -- PTX version * * Author: Mark Crispin * Networks and Distributed Computing * Computing & Communications * University of Washington * Administration Building, AG-44 * Seattle, WA 98195 * Internet: MRC@CAC.Washington.EDU * * Date: 11 May 1989 * Last Edited: 16 August 2007 */ #include "tcp_unix.h" /* must be before osdep includes tcp.h */ #include "mail.h" #include "osdep.h" #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include "misc.h" extern int sys_nerr; extern char *sys_errlist[]; #define DIR_SIZE(d) d->d_reclen #define toint(c) ((c)-'0') #define isodigit(c) (((unsigned)(c)>=060)&((unsigned)(c)<=067)) #include "fs_unix.c" #include "ftl_unix.c" #include "nl_unix.c" #define env_init ENV_INIT #include "env_unix.c" #undef env_init #define getpeername Getpeername #define fork vfork #include "tcp_unix.c" #include "gr_waitp.c" #include "flocksim.c" #include "scandir.c" #include "tz_sv4.c" #include "utime.c" /* Jacket around env_init() to work around PTX inetd braindamage */ static char may_need_server_init = T; long env_init (char *user,char *home) { if (may_need_server_init) { /* maybe need to do server init cruft? */ may_need_server_init = NIL; /* not any more we don't */ if (!getuid ()) { /* if root, we're most likely a server */ t_sync (0); /* PTX inetd is stupid, stupid, stupid */ ioctl (0,I_PUSH,"tirdwr");/* it needs this cruft, else servers won't */ dup2 (0,1); /* work. How obnoxious!!! */ } } ENV_INIT (user,home); /* call the real routine */ } /* Emulator for BSD gethostid() call * Returns: unique identifier for this machine */ long gethostid (void) { struct sockaddr_in sin; int inet = t_open (TLI_TCP, O_RDWR, 0); if (inet < 0) return 0; getmyinaddr (inet,&sin,sizeof (sin)); close (inet); return sin.sin_addr.s_addr; } /* Replaced version of getpeername() that jackets into getpeerinaddr() * Accepts: file descriptor * pointer to Internet socket addr * length * Returns: zero if success, data in socket addr */ int Getpeername (int s,struct sockaddr *name,int *namelen) { return getpeerinaddr (s,(struct sockaddr_in *) name,*namelen); } alpine-2.10+dfsg/imap/src/osdep/unix/rename.c0000600000175000017500000000217211512502123022562 0ustar paulproteuspaulproteus/* ======================================================================== * Copyright 1988-2006 University of Washington * * Licensed under the Apache License, Version 2.0 (the "License"); * you may not use this file except in compliance with the License. * You may obtain a copy of the License at * * http://www.apache.org/licenses/LICENSE-2.0 * * * ======================================================================== */ /* * Program: Rename file * * Author: Mark Crispin * Networks and Distributed Computing * Computing & Communications * University of Washington * Administration Building, AG-44 * Seattle, WA 98195 * Internet: MRC@CAC.Washington.EDU * * Date: 20 May 1996 * Last Edited: 30 August 2006 */ /* Emulator for working Unix rename() call * Accepts: old file name * new file name * Returns: 0 if success, -1 if error with error in errno */ int Rename (char *oldname,char *newname) { int ret; unlink (newname); /* make sure the old name doesn't exist */ /* link to new name, unlink old name */ if (!(ret = link (oldname,newname))) unlink (oldname); return ret; } alpine-2.10+dfsg/imap/src/osdep/unix/ckp_psx.c0000600000175000017500000000715211512502123022765 0ustar paulproteuspaulproteus/* ======================================================================== * Copyright 1988-2006 University of Washington * * Licensed under the Apache License, Version 2.0 (the "License"); * you may not use this file except in compliance with the License. * You may obtain a copy of the License at * * http://www.apache.org/licenses/LICENSE-2.0 * * * ======================================================================== */ /* * Program: POSIX check password * * Author: Mark Crispin * Networks and Distributed Computing * Computing & Communications * University of Washington * Administration Building, AG-44 * Seattle, WA 98195 * Internet: MRC@CAC.Washington.EDU * * Date: 1 August 1988 * Last Edited: 30 August 2006 */ /* Check password * Accepts: login passwd struct * password string * argument count * argument vector * Returns: passwd struct if password validated, NIL otherwise */ struct passwd *checkpw (struct passwd *pw,char *pass,int argc,char *argv[]) { char tmp[MAILTMPLEN]; struct spwd *sp = NIL; time_t left; time_t now = time (0); struct tm *t = gmtime (&now); int zone = t->tm_hour * 60 + t->tm_min; int julian = t->tm_yday; t = localtime (&now); /* get local time now */ /* minus UTC minutes since midnight */ zone = t->tm_hour * 60 + t->tm_min - zone; /* julian can be one of: * 36x local time is December 31, UTC is January 1, offset -24 hours * 1 local time is 1 day ahead of UTC, offset +24 hours * 0 local time is same day as UTC, no offset * -1 local time is 1 day behind UTC, offset -24 hours * -36x local time is January 1, UTC is December 31, offset +24 hours */ if (julian = t->tm_yday -julian) zone += ((julian < 0) == (abs (julian) == 1)) ? -24*60 : 24*60; /* days since 1/1/1970 local time */ now = ((now /60) + zone) / (60*24); /* non-shadow authentication */ if (!pw->pw_passwd || !pw->pw_passwd[0] || !pw->pw_passwd[1] || strcmp (pw->pw_passwd,(char *) crypt (pass,pw->pw_passwd))) { /* As far as I've been able to determine, here is how the expiration * fields in the shadow authentication data work: * lstchg last password change date if non-negative. If zero, the * user can not log in without changing password. * max number of days a password is valid if positive * warn number of days of password expiration warning * expire date account expires if positive * inact number of days an accout can be inactive (not checked!) * The expiration day is the *last* day that the password or account * is valid. */ /* shadow authentication */ if ((sp = getspnam (pw->pw_name)) && sp->sp_lstchg && ((sp->sp_lstchg < 0) || (sp->sp_max <= 0) || ((sp->sp_lstchg + sp->sp_max) >= now)) && ((sp->sp_expire <= 0) || (sp->sp_expire >= now)) && sp->sp_pwdp && sp->sp_pwdp[0] && sp->sp_pwdp[1] && !strcmp (sp->sp_pwdp,(char *) crypt (pass,sp->sp_pwdp))) { if ((sp->sp_lstchg > 0) && (sp->sp_max > 0) && ((left = (sp->sp_lstchg + sp->sp_max) - now) <= sp->sp_warn)) { if (left) { sprintf (tmp,"[ALERT] Password expires in %ld day(s)",(long) left); mm_notify (NIL,tmp,NIL); } else mm_notify (NIL,"[ALERT] Password expires today!",WARN); } if ((sp->sp_expire > 0) && ((left = sp->sp_expire - now) < 28)) { if (left) { sprintf (tmp,"[ALERT] Account expires in %ld day(s)",(long) left); mm_notify (NIL,tmp,NIL); } else mm_notify (NIL,"[ALERT] Account expires today!",WARN); } endspent (); /* don't need shadow password data any more */ } else pw = NIL; /* password failed */ } return pw; } alpine-2.10+dfsg/imap/src/osdep/unix/mkauths0000700000175000017500000000227011512502123022546 0ustar paulproteuspaulproteus#!/bin/sh # ======================================================================== # Copyright 1988-2006 University of Washington # # Licensed under the Apache License, Version 2.0 (the "License"); # you may not use this file except in compliance with the License. # You may obtain a copy of the License at # # http://www.apache.org/licenses/LICENSE-2.0 # # # ======================================================================== # Program: Authenticator Linkage Generator # # Author: Mark Crispin # Networks and Distributed Computing # Computing & Communications # University of Washington # Administration Building, AG-44 # Seattle, WA 98195 # Internet: MRC@CAC.Washington.EDU # # Date: 5 December 1995 # Last Edited: 30 August 2006 # Erase old authenticators list rm -f auths.c touch auths.c # Now define the new list for authenticator do if [ -f Makefile."$authenticator" ]; then make -f Makefile."$authenticator" `cat SPECIALS` fi echo "extern AUTHENTICATOR auth_"$authenticator";" >> linkage.h echo " auth_link (&auth_"$authenticator"); /* link in the $authenticator authenticator */" | cat >> linkage.c echo "#include \"auth_"$authenticator".c\"" >> auths.c done alpine-2.10+dfsg/imap/src/osdep/unix/os_bsd.c0000600000175000017500000000277411512502123022574 0ustar paulproteuspaulproteus/* ======================================================================== * Copyright 1988-2007 University of Washington * * Licensed under the Apache License, Version 2.0 (the "License"); * you may not use this file except in compliance with the License. * You may obtain a copy of the License at * * http://www.apache.org/licenses/LICENSE-2.0 * * * ======================================================================== */ /* * Program: Operating-system dependent routines -- 4.3BSD version * * Author: Mark Crispin * Networks and Distributed Computing * Computing & Communications * University of Washington * Administration Building, AG-44 * Seattle, WA 98195 * * Date: 11 May 1989 * Last Edited: 16 August 2007 */ #include "tcp_unix.h" /* must be before osdep includes tcp.h */ #include "mail.h" #include "osdep.h" #include #include #include #include #include #include #include #include #include extern int errno; /* just in case */ #include #include "misc.h" #define isodigit(c) (((unsigned)(c)>=060)&((unsigned)(c)<=067)) #define toint(c) ((c)-'0') extern int sys_nerr; extern char *sys_errlist[]; #include "fs_unix.c" #include "ftl_unix.c" #include "nl_unix.c" #include "env_unix.c" #define fork vfork #include "tcp_unix.c" #include "gr_wait.c" #include "memmove.c" #include "strerror.c" #include "strstr.c" #include "strtoul.c" #include "tz_bsd.c" alpine-2.10+dfsg/imap/src/osdep/unix/env_unix.h0000600000175000017500000000556511512502123023164 0ustar paulproteuspaulproteus/* ======================================================================== * Copyright 1988-2006 University of Washington * * Licensed under the Apache License, Version 2.0 (the "License"); * you may not use this file except in compliance with the License. * You may obtain a copy of the License at * * http://www.apache.org/licenses/LICENSE-2.0 * * * ======================================================================== */ /* * Program: UNIX environment routines * * Author: Mark Crispin * Networks and Distributed Computing * Computing & Communications * University of Washington * Administration Building, AG-44 * Seattle, WA 98195 * Internet: MRC@CAC.Washington.EDU * * Date: 1 August 1988 * Last Edited: 30 August 2006 */ typedef struct dotlock_base { char lock[MAILTMPLEN]; int pipei; int pipeo; } DOTLOCK; /* Bits that can be set in restrictBox */ #define RESTRICTROOT 0x1 /* restricted box doesn't allow root */ #define RESTRICTOTHERUSER 0x2 /* restricted box doesn't allow other user */ /* Subscription definitions for UNIX */ #define SUBSCRIPTIONFILE(t) sprintf (t,"%s/.mailboxlist",myhomedir ()) #define SUBSCRIPTIONTEMP(t) sprintf (t,"%s/.mlbxlsttmp",myhomedir ()) /* dorc() options */ #define SYSCONFIG "/etc/c-client.cf" /* Special users */ #define ANONYMOUSUSER "nobody" /* anonymous user */ #define UNLOGGEDUSER "root" /* unlogged-in user */ #define ADMINGROUP "mailadm" /* mail administrator group */ /* Function prototypes */ #include "env.h" void rfc822_fixed_date (char *date); long env_init (char *user,char *home); char *myusername_full (unsigned long *flags); #define MU_LOGGEDIN 0 #define MU_NOTLOGGEDIN 1 #define MU_ANONYMOUS 2 #define myusername() \ myusername_full (NIL) char *sysinbox (); char *mailboxdir (char *dst,char *dir,char *name); long dotlock_lock (char *file,DOTLOCK *base,int fd); long dotlock_unlock (DOTLOCK *base); int lockname (char *lock,char *fname,int op,long *pid); int lockfd (int fd,char *lock,int op); int lock_work (char *lock,void *sbuf,int op,long *pid); long chk_notsymlink (char *name,void *sbuf); void unlockfd (int fd,char *lock); long set_mbx_protections (char *mailbox,char *path); long get_dir_protection (char *mailbox); MAILSTREAM *user_flags (MAILSTREAM *stream); char *default_user_flag (unsigned long i); void dorc (char *file,long flag); long path_create (MAILSTREAM *stream,char *mailbox); void grim_pid_reap_status (int pid,int killreq,void *status); #define grim_pid_reap(pid,killreq) \ grim_pid_reap_status (pid,killreq,NIL) long safe_write (int fd,char *buf,long nbytes); void *arm_signal (int sig,void *action); struct passwd *checkpw (struct passwd *pw,char *pass,int argc,char *argv[]); long loginpw (struct passwd *pw,int argc,char *argv[]); long pw_login (struct passwd *pw,char *auser,char *user,char *home,int argc, char *argv[]); void *mm_blocknotify (int reason,void *data); alpine-2.10+dfsg/imap/src/osdep/unix/os_nto.c0000600000175000017500000000354011512502123022614 0ustar paulproteuspaulproteus/* ======================================================================== * Copyright 1988-2006 University of Washington * * Licensed under the Apache License, Version 2.0 (the "License"); * you may not use this file except in compliance with the License. * You may obtain a copy of the License at * * http://www.apache.org/licenses/LICENSE-2.0 * * * ======================================================================== */ /* * Program: Operating-system dependent routines -- QNX Neutrino RTP version * * Author: Mark Crispin * Networks and Distributed Computing * Computing & Communications * University of Washington * Administration Building, AG-44 * Seattle, WA 98195 * Internet: MRC@CAC.Washington.EDU * * Date: 1 August 1993 * Last Edited: 30 August 2006 */ #include "tcp_unix.h" /* must be before osdep includes tcp.h */ #include "mail.h" #include "osdep.h" #include #include #include #include #include #include #include #include #include extern int errno; /* just in case */ #include #include #include #include "misc.h" #define DIR_SIZE(d) d->d_reclen #include "fs_unix.c" #include "ftl_unix.c" #include "nl_unix.c" #include "env_unix.c" #include "tcp_unix.c" #include "gr_wait.c" #include "tz_sv4.c" #include "gethstid.c" #include "flocksim.c" #include "utime.c" /* QNX local readdir() * Accepts: directory structure * Returns: direct struct or NIL if failed */ #undef readdir struct direct *Readdir (DIR *dirp) { static struct direct dc; struct dirent *de = readdir (dirp); if (!de) return NIL; /* end of data */ dc.d_fileno = 0; /* could get from de->stat.st_ino */ dc.d_namlen = strlen (strcpy (dc.d_name,de->d_name)); dc.d_reclen = sizeof (dc); return &dc; } alpine-2.10+dfsg/imap/src/osdep/unix/crx_nfs.c0000600000175000017500000000470711512502123022763 0ustar paulproteuspaulproteus/* ======================================================================== * Copyright 1988-2006 University of Washington * * Licensed under the Apache License, Version 2.0 (the "License"); * you may not use this file except in compliance with the License. * You may obtain a copy of the License at * * http://www.apache.org/licenses/LICENSE-2.0 * * * ======================================================================== */ /* * Program: Exclusive create of a file, NFS kludge version * * Author: Mark Crispin * Networks and Distributed Computing * Computing & Communications * University of Washington * Administration Building, AG-44 * Seattle, WA 98195 * Internet: MRC@CAC.Washington.EDU * * Date: 17 December 1999 * Last Edited: 30 August 2006 */ /* SUN-OS had an NFS, As kludgy as an albatross; * And everywhere that it was installed, It was a total loss. * -- MRC 9/25/91 */ /* Exclusive create of a file * Accepts: file name * Return: T if success, NIL if failed, -1 if retry */ long crexcl (char *name) { long ret = -1; int i; char hitch[MAILTMPLEN]; struct stat sb; int mask = umask (0); /* build hitching post file name */ sprintf (hitch,"%s.%lu.%d.",name,(unsigned long) time (0),getpid ()); i = strlen (hitch); /* append local host name */ gethostname (hitch + i,(MAILTMPLEN - i) - 1); /* try to get hitching-post file */ if ((i = open (hitch,O_WRONLY|O_CREAT|O_EXCL,(int) shlock_mode)) >= 0) { close (i); /* close the hitching-post */ /* Note: link() may return an error even if it actually succeeded. So we * always check for success via the link count, and ignore the error if * the link count is right. */ /* tie hitching-post to lock */ i = link (hitch,name) ? errno : 0; /* success if link count now 2 */ if (!stat (hitch,&sb) && (sb.st_nlink == 2)) ret = LONGT; else if (i == EPERM) { /* links not allowed? */ /* Probably a FAT filesystem on Linux. It can't be NFS, so try creating * the lock file directly. */ if ((i = open (name,O_WRONLY|O_CREAT|O_EXCL,(int) shlock_mode)) >= 0){ close (i); /* close the file */ ret = LONGT; /* success */ } /* fail unless error is EEXIST */ else if (errno != EEXIST) ret = NIL; } unlink (hitch); /* flush hitching post */ } /* fail unless error is EEXIST */ else if (errno != EEXIST) ret = NIL; umask (mask); /* restore previous mask */ return ret; } alpine-2.10+dfsg/imap/src/osdep/unix/os_sc5.h0000600000175000017500000000334111512502123022512 0ustar paulproteuspaulproteus/* ======================================================================== * Copyright 1988-2006 University of Washington * * Licensed under the Apache License, Version 2.0 (the "License"); * you may not use this file except in compliance with the License. * You may obtain a copy of the License at * * http://www.apache.org/licenses/LICENSE-2.0 * * * ======================================================================== */ /* * Program: Operating-system dependent routines -- SCO Unix version * * Author: Mark Crispin * Networks and Distributed Computing * Computing & Communications * University of Washington * Administration Building, AG-44 * Seattle, WA 98195 * Internet: MRC@CAC.Washington.EDU * * Date: 1 August 1988 * Last Edited: 20 December 2006 */ #include #include #include #include #include #include #include #include #include #include #include #include /* SCO gets this wrong */ #define setpgrp Setpgrp int Setpgrp (int pid,int gid); #define rename Rename /* Different names, equivalent things in BSD and SysV */ #define L_SET SEEK_SET #define L_INCR SEEK_CUR #define L_XTND SEEK_END #define direct dirent #define utime portable_utime int portable_utime (char *file,time_t timep[2]); long gethostid (void); typedef int (*select_t) (struct direct *name); typedef int (*compar_t) (void *d1,void *d2); int scandir (char *dirname,struct direct ***namelist,select_t select, compar_t compar); int alphasort (void *d1,void *d2); int fsync (int fd); #include "env_unix.h" #include "fs.h" #include "ftl.h" #include "nl.h" #include "tcp.h" #include "flocksim.h" alpine-2.10+dfsg/imap/src/osdep/unix/os_a41.h0000600000175000017500000000231611512502123022406 0ustar paulproteuspaulproteus/* ======================================================================== * Copyright 1988-2006 University of Washington * * Licensed under the Apache License, Version 2.0 (the "License"); * you may not use this file except in compliance with the License. * You may obtain a copy of the License at * * http://www.apache.org/licenses/LICENSE-2.0 * * * ======================================================================== */ /* * Program: Operating-system dependent routines -- AIX on RS6000 * * Author: Mark Crispin * Networks and Distributed Computing * Computing & Communications * University of Washington * Administration Building, AG-44 * Seattle, WA 98195 * Internet: MRC@CAC.Washington.EDU * * Date: 1 August 1988 * Last Edited: 30 August 2006 */ #include #include #include #include #include /* for struct tm */ #include #include #include #include #include #include #define utime portable_utime int portable_utime (char *file,time_t timep[2]); #include "env_unix.h" #include "fs.h" #include "ftl.h" #include "nl.h" #include "tcp.h" #include "flocksim.h" alpine-2.10+dfsg/imap/src/osdep/unix/os_dyn.h0000600000175000017500000000277311512502123022622 0ustar paulproteuspaulproteus/* ======================================================================== * Copyright 1988-2007 University of Washington * * Licensed under the Apache License, Version 2.0 (the "License"); * you may not use this file except in compliance with the License. * You may obtain a copy of the License at * * http://www.apache.org/licenses/LICENSE-2.0 * * * ======================================================================== */ /* * Program: Operating-system dependent routines -- Dynix version * * Author: Mark Crispin * Networks and Distributed Computing * Computing & Communications * University of Washington * Administration Building, AG-44 * Seattle, WA 98195 * Internet: MRC@CAC.Washington.EDU * * Date: 11 May 1989 * Last Edited: 30 January 2007 */ #include #include #include #include #include #include typedef unsigned long size_t; char *strtok (char *s,char *ct); char *strtok_r (char *s,char *ct,char **r); char *strstr (char *cs,char *ct); char *strpbrk (char *cs,char *ct); char *strerror (int n); void *memmove (void *s,void *ct,size_t n); void *memset (void *s,int c,size_t n); unsigned long strtoul (char *s,char **endp,int base); void *malloc (size_t byteSize); void free (void *ptr); void *realloc (void *oldptr,size_t newsize); int errno; #define memcpy memmove #define strchr index #define strrchr rindex #include "env_unix.h" #include "fs.h" #include "ftl.h" #include "nl.h" #include "tcp.h" alpine-2.10+dfsg/imap/src/osdep/unix/tz_bsd.c0000600000175000017500000000173511512502123022604 0ustar paulproteuspaulproteus/* ======================================================================== * Copyright 1988-2006 University of Washington * * Licensed under the Apache License, Version 2.0 (the "License"); * you may not use this file except in compliance with the License. * You may obtain a copy of the License at * * http://www.apache.org/licenses/LICENSE-2.0 * * * ======================================================================== */ /* * Program: BSD-style Time Zone String * * Author: Mark Crispin * Networks and Distributed Computing * Computing & Communications * University of Washington * Administration Building, AG-44 * Seattle, WA 98195 * Internet: MRC@CAC.Washington.EDU * * Date: 30 August 1994 * Last Edited: 30 August 2006 */ /* Append local timezone name * Accepts: destination string */ void rfc822_timezone (char *s,void *t) { /* append timezone from tm struct */ sprintf (s + strlen (s)," (%.50s)",((struct tm *) t)->tm_zone); } alpine-2.10+dfsg/imap/src/osdep/unix/fdstring.c0000600000175000017500000000540711512502123023137 0ustar paulproteuspaulproteus/* ======================================================================== * Copyright 1988-2007 University of Washington * * Licensed under the Apache License, Version 2.0 (the "License"); * you may not use this file except in compliance with the License. * You may obtain a copy of the License at * * http://www.apache.org/licenses/LICENSE-2.0 * * * ======================================================================== */ /* * Program: File descriptor string routines * * Author: Mark Crispin * Networks and Distributed Computing * Computing & Communications * University of Washington * Administration Building, AG-44 * Seattle, WA 98195 * Internet: MRC@CAC.Washington.EDU * * Date: 15 April 1997 * Last Edited: 4 April 2007 */ #include "mail.h" #include "osdep.h" #include "misc.h" #include "fdstring.h" /* String driver for fd stringstructs */ static void fd_string_init (STRING *s,void *data,unsigned long size); static char fd_string_next (STRING *s); static void fd_string_setpos (STRING *s,unsigned long i); STRINGDRIVER fd_string = { fd_string_init, /* initialize string structure */ fd_string_next, /* get next byte in string structure */ fd_string_setpos /* set position in string structure */ }; /* Initialize string structure for fd stringstruct * Accepts: string structure * pointer to string * size of string */ static void fd_string_init (STRING *s,void *data,unsigned long size) { FDDATA *d = (FDDATA *) data; /* note fd */ s->data = (void *) (unsigned long) d->fd; s->data1 = d->pos; /* note file offset */ s->size = size; /* note size */ s->curpos = s->chunk = d->chunk; s->chunksize = (unsigned long) d->chunksize; s->offset = 0; /* initial position */ /* and size of data */ s->cursize = min (s->chunksize,size); /* move to that position in the file */ lseek (d->fd,d->pos,L_SET); read (d->fd,s->chunk,(size_t) s->cursize); } /* Get next character from fd stringstruct * Accepts: string structure * Returns: character, string structure chunk refreshed */ static char fd_string_next (STRING *s) { char c = *s->curpos++; /* get next byte */ SETPOS (s,GETPOS (s)); /* move to next chunk */ return c; /* return the byte */ } /* Set string pointer position for fd stringstruct * Accepts: string structure * new position */ static void fd_string_setpos (STRING *s,unsigned long i) { if (i > s->size) i = s->size; /* don't permit setting beyond EOF */ s->offset = i; /* set new offset */ s->curpos = s->chunk; /* reset position */ /* set size of data */ if (s->cursize = min (s->chunksize,SIZE (s))) { /* move to that position in the file */ lseek ((long) s->data,s->data1 + s->offset,L_SET); read ((long) s->data,s->curpos,(size_t) s->cursize); } } alpine-2.10+dfsg/imap/src/osdep/unix/os_a32.c0000600000175000017500000000270211512502123022400 0ustar paulproteuspaulproteus/* ======================================================================== * Copyright 1988-2006 University of Washington * * Licensed under the Apache License, Version 2.0 (the "License"); * you may not use this file except in compliance with the License. * You may obtain a copy of the License at * * http://www.apache.org/licenses/LICENSE-2.0 * * * ======================================================================== */ /* * Program: Operating-system dependent routines -- AIX 3.2 on RS 6000 * * Author: Mark Crispin * Networks and Distributed Computing * Computing & Communications * University of Washington * Administration Building, AG-44 * Seattle, WA 98195 * Internet: MRC@CAC.Washington.EDU * * Date: 1 August 1988 * Last Edited: 30 August 2006 */ #include "tcp_unix.h" /* must be before osdep includes tcp.h */ #include "mail.h" #include "osdep.h" #include #include #include #include #include #include #include #include #include extern int errno; /* just in case */ #include #include "misc.h" #include char *crypt (char *key,char *salt); extern int sys_nerr; extern char *sys_errlist[]; #include "fs_unix.c" #include "ftl_unix.c" #include "nl_unix.c" #include "env_unix.c" #include "tcp_unix.c" #include "gr_waitp.c" #include "tz_sv4.c" #include "flocksim.c" #include "utime.c" alpine-2.10+dfsg/imap/src/osdep/unix/sig_bsd.c0000600000175000017500000000167211512502123022731 0ustar paulproteuspaulproteus/* ======================================================================== * Copyright 1988-2006 University of Washington * * Licensed under the Apache License, Version 2.0 (the "License"); * you may not use this file except in compliance with the License. * You may obtain a copy of the License at * * http://www.apache.org/licenses/LICENSE-2.0 * * * ======================================================================== */ /* * Program: BSD Signals * * Author: Mark Crispin * Networks and Distributed Computing * Computing & Communications * University of Washington * Administration Building, AG-44 * Seattle, WA 98195 * Internet: MRC@CAC.Washington.EDU * * Date: 29 April 1997 * Last Edited: 30 August 2006 */ #include /* Arm a signal * Accepts: signal number * desired action * Returns: old action */ void *arm_signal (int sig,void *action) { return (void *) signal (sig,action); } alpine-2.10+dfsg/imap/src/osdep/unix/os_ult.c0000600000175000017500000000242111512502123022615 0ustar paulproteuspaulproteus/* ======================================================================== * Copyright 1988-2007 University of Washington * * Licensed under the Apache License, Version 2.0 (the "License"); * you may not use this file except in compliance with the License. * You may obtain a copy of the License at * * http://www.apache.org/licenses/LICENSE-2.0 * * * ======================================================================== */ /* * Program: Operating-system dependent routines -- Ultrix version * * Author: Mark Crispin * Networks and Distributed Computing * Computing & Communications * University of Washington * Administration Building, AG-44 * Seattle, WA 98195 * * Date: 11 May 1989 * Last Edited: 16 August 2007 */ #include "tcp_unix.h" /* must be before osdep includes tcp.h */ #include "mail.h" #include "osdep.h" #include #include #include #include #include #include #include #include #include extern int errno; /* just in case */ #include #include "misc.h" #include "fs_unix.c" #include "ftl_unix.c" #include "nl_unix.c" #include "env_unix.c" #define fork vfork #include "tcp_unix.c" #include "gr_waitp.c" #include "tz_bsd.c" alpine-2.10+dfsg/imap/src/osdep/unix/os_lyn.h0000600000175000017500000000204211512502123022617 0ustar paulproteuspaulproteus/* ======================================================================== * Copyright 1988-2006 University of Washington * * Licensed under the Apache License, Version 2.0 (the "License"); * you may not use this file except in compliance with the License. * You may obtain a copy of the License at * * http://www.apache.org/licenses/LICENSE-2.0 * * * ======================================================================== */ /* * Program: Operating-system dependent routines -- LynxOS version * * Author: Mark Crispin * Networks and Distributed Computing * Computing & Communications * University of Washington * Administration Building, AG-44 * Seattle, WA 98195 * Internet: MRC@CAC.Washington.EDU * * Date: 5 March 1993 * Last Edited: 30 August 2006 */ #include #include #include #include #include #include #include #define gethostid clock #include "env_unix.h" #include "fs.h" #include "ftl.h" #include "nl.h" #include "tcp.h" alpine-2.10+dfsg/imap/src/osdep/unix/os_asv.h0000600000175000017500000000365011512502123022614 0ustar paulproteuspaulproteus/* ======================================================================== * Copyright 1988-2006 University of Washington * * Licensed under the Apache License, Version 2.0 (the "License"); * you may not use this file except in compliance with the License. * You may obtain a copy of the License at * * http://www.apache.org/licenses/LICENSE-2.0 * * * ======================================================================== */ /* * Program: Operating-system dependent routines -- Altos System V version * * Author: Mark Crispin * Networks and Distributed Computing * Computing & Communications * University of Washington * Administration Building, AG-44 * Seattle, WA 98195 * Internet: MRC@CAC.Washington.EDU * * Date: 10 April 1992 * Last Edited: 15 September 2006 */ #include #include #include #include #include #include #include #include #include #include /* Different names, equivalent things in BSD and SysV */ #define L_SET SEEK_SET #define L_INCR SEEK_CUR #define L_XTND SEEK_END #define direct dirent #define ftruncate chsize #define random lrand48 struct passwd *getpwent (void); struct passwd *getpwuid (int uid); struct passwd *getpwnam (char *name); char *getenv (char *name); long gethostid (void); void *memmove (void *s,void *ct,size_t n); char *strstr (char *cs,char *ct); char *strerror (int n); unsigned long strtoul (char *s,char **endp,int base); typedef int (*select_t) (struct direct *name); typedef int (*compar_t) (void *d1,void *d2); int scandir (char *dirname,struct direct ***namelist,select_t select, compar_t compar); int alphasort (void *d1,void *d2); void *malloc (size_t byteSize); void free (void *ptr); void *realloc (void *oldptr,size_t newsize); #include "env_unix.h" #include "fs.h" #include "ftl.h" #include "nl.h" #include "tcp.h" #include "flocksim.h" alpine-2.10+dfsg/imap/src/osdep/unix/os_isc.c0000600000175000017500000000323211512502123022570 0ustar paulproteuspaulproteus/* ======================================================================== * Copyright 1988-2006 University of Washington * * Licensed under the Apache License, Version 2.0 (the "License"); * you may not use this file except in compliance with the License. * You may obtain a copy of the License at * * http://www.apache.org/licenses/LICENSE-2.0 * * * ======================================================================== */ /* * Program: Operating-system dependent routines -- ISC version * * Author: Mark Crispin * Networks and Distributed Computing * Computing & Communications * University of Washington * Administration Building, AG-44 * Seattle, WA 98195 * Internet: MRC@CAC.Washington.EDU * * Date: 10 April 1992 * Last Edited: 30 August 2006 */ #include "tcp_unix.h" /* must be before osdep includes tcp.h */ #include "mail.h" #include "osdep.h" #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include "misc.h" extern int sys_nerr; extern char *sys_errlist[]; #define toint(c) ((c)-'0') #define isodigit(c) (((unsigned)(c)>=060)&((unsigned)(c)<=067)) #define DIR_SIZE(d) d->d_reclen #define pid_t short /* may not be known on all ISC systems */ #include "fs_unix.c" #include "ftl_unix.c" #include "nl_unix.c" #include "env_unix.c" #include "tcp_unix.c" #include "gr_waitp.c" #include "strerror.c" #include "flocksim.c" #include "scandir.c" #include "tz_sv4.c" #include "fsync.c" alpine-2.10+dfsg/imap/src/osdep/unix/ckp_2nd.c0000600000175000017500000000157011512502123022634 0ustar paulproteuspaulproteus/* ======================================================================== * Copyright 1988-2006 University of Washington * * Licensed under the Apache License, Version 2.0 (the "License"); * you may not use this file except in compliance with the License. * You may obtain a copy of the License at * * http://www.apache.org/licenses/LICENSE-2.0 * * * ======================================================================== */ /* * Program: Dual check password part 2 * * Author: Mark Crispin * Networks and Distributed Computing * Computing & Communications * University of Washington * Administration Building, AG-44 * Seattle, WA 98195 * Internet: MRC@CAC.Washington.EDU * * Date: 1 August 1988 * Last Edited: 30 August 2006 */ /* Undefine routine name */ #undef checkpw /* Redefine std checker's routine name */ #define checkpw checkpw_std alpine-2.10+dfsg/imap/src/osdep/unix/os_d-g.c0000600000175000017500000000251411512502123022463 0ustar paulproteuspaulproteus/* ======================================================================== * Copyright 1988-2006 University of Washington * * Licensed under the Apache License, Version 2.0 (the "License"); * you may not use this file except in compliance with the License. * You may obtain a copy of the License at * * http://www.apache.org/licenses/LICENSE-2.0 * * * ======================================================================== */ /* * Program: Operating-system dependent routines -- D-G version * * Author: Mark Crispin * Networks and Distributed Computing * Computing & Communications * University of Washington * Administration Building, AG-44 * Seattle, WA 98195 * Internet: MRC@CAC.Washington.EDU * * Date: 1 August 1988 * Last Edited: 30 August 2006 */ #include "tcp_unix.h" /* must be before osdep includes tcp.h */ #include "mail.h" #include "osdep.h" #include #include #include #include #include #include #include #include #include extern int errno; /* just in case */ #include #include "misc.h" #include "fs_unix.c" #include "ftl_unix.c" #include "nl_unix.c" #include "env_unix.c" #include "tcp_unix.c" #include "gr_waitp.c" #include "tz_sv4.c" #include "flocksim.c" #include "utime.c" alpine-2.10+dfsg/imap/src/osdep/unix/log_bsi.c0000600000175000017500000000305311512502123022730 0ustar paulproteuspaulproteus/* ======================================================================== * Copyright 1988-2006 University of Washington * * Licensed under the Apache License, Version 2.0 (the "License"); * you may not use this file except in compliance with the License. * You may obtain a copy of the License at * * http://www.apache.org/licenses/LICENSE-2.0 * * * ======================================================================== */ /* * Program: BSI login * * Author: Mark Crispin * Networks and Distributed Computing * Computing & Communications * University of Washington * Administration Building, AG-44 * Seattle, WA 98195 * Internet: MRC@CAC.Washington.EDU * * Date: 1 August 1988 * Last Edited: 30 August 2006 */ /* Log in * Accepts: login passwd struct * argument count * argument vector * Returns: T if success, NIL otherwise */ long loginpw (struct passwd *pw,int argc,char *argv[]) { long ret = NIL; uid_t euid = geteuid (); login_cap_t *lc = login_getclass (pw->pw_class); /* have class and can become user? */ if (lc && !seteuid (pw->pw_uid)) { /* ask for approval */ if (auth_approve (lc,pw->pw_name, (char *) mail_parameters (NIL,GET_SERVICENAME,NIL)) <= 0) seteuid (euid); /* not approved, restore root euid */ else { /* approved */ seteuid (euid); /* restore former root euid first */ setsid (); /* ensure we are session leader */ /* log the guy in */ ret = !setusercontext (lc,pw,pw->pw_uid,LOGIN_SETALL&~LOGIN_SETPATH); } } return ret; } alpine-2.10+dfsg/imap/src/osdep/unix/os_asv.c0000600000175000017500000000331611512502123022606 0ustar paulproteuspaulproteus/* ======================================================================== * Copyright 1988-2006 University of Washington * * Licensed under the Apache License, Version 2.0 (the "License"); * you may not use this file except in compliance with the License. * You may obtain a copy of the License at * * http://www.apache.org/licenses/LICENSE-2.0 * * * ======================================================================== */ /* * Program: Operating-system dependent routines -- Altos System V version * * Author: Mark Crispin * Networks and Distributed Computing * Computing & Communications * University of Washington * Administration Building, AG-44 * Seattle, WA 98195 * Internet: MRC@CAC.Washington.EDU * * Date: 10 April 1992 * Last Edited: 30 August 2006 */ #include "tcp_unix.h" /* must be before osdep includes tcp.h */ #include "mail.h" #include "osdep.h" #include #include #include #include #include #include #include #include #include #include #include #include #include "misc.h" extern int sys_nerr; extern char *sys_errlist[]; #define toint(c) ((c)-'0') #define isodigit(c) (((unsigned)(c)>=060)&((unsigned)(c)<=067)) #define DIR_SIZE(d) d->d_reclen #define pid_t short /* may not be known on all ASV systems */ #include "strstr.c" #include "fs_unix.c" #include "ftl_unix.c" #include "nl_unix.c" #include "env_unix.c" #include "tcp_unix.c" #include "gr_waitp.c" #include "strerror.c" #include "flocksim.c" #include "scandir.c" #include "strtoul.c" #include "tz_sv4.c" #include "gethstid.c" #include "memmove.c" #include "fsync.c" alpine-2.10+dfsg/imap/src/osdep/unix/os_art.h0000600000175000017500000000401511512502123022605 0ustar paulproteuspaulproteus/* ======================================================================== * Copyright 1988-2006 University of Washington * * Licensed under the Apache License, Version 2.0 (the "License"); * you may not use this file except in compliance with the License. * You may obtain a copy of the License at * * http://www.apache.org/licenses/LICENSE-2.0 * * * ======================================================================== */ /* * Program: Operating-system dependent routines -- AIX/RT version * * Author: Mark Crispin * Networks and Distributed Computing * Computing & Communications * University of Washington * Administration Building, AG-44 * Seattle, WA 98195 * Internet: MRC@CAC.Washington.EDU * * Date: 10 April 1992 * Last Edited: 15 September 2006 */ #include #include #include #include #define direct dirent #include #include #include #include #include /* Different names between BSD and SVR4 */ #define L_SET SEEK_SET #define L_INCR SEEK_CUR #define L_XTND SEEK_END #define random lrand48 #define SIGSTOP SIGQUIT /* For setitimer() emulation */ #define ITIMER_REAL 0 struct passwd *getpwent (void); struct passwd *getpwuid (int uid); struct passwd *getpwnam (char *name); char *getenv (char *name); long gethostid (void); void *memmove (void *s,void *ct,size_t n); char *strstr (char *cs,char *ct); char *strerror (int n); unsigned long strtoul (char *s,char **endp,int base); typedef int (*select_t) (struct direct *name); typedef int (*compar_t) (void *d1,void *d2); int scandir (char *dirname,struct direct ***namelist,select_t select, compar_t compar); int alphasort (void *d1,void *d2); void *malloc (size_t byteSize); void free (void *ptr); void *realloc (void *oldptr,size_t newsize); int openlog (ident,logopt,facility); int syslog (priority,message,parameters ...); #include "env_unix.h" #include "fs.h" #include "ftl.h" #include "nl.h" #include "tcp.h" #include "flocksim.h" alpine-2.10+dfsg/imap/src/osdep/unix/os_aos.c0000600000175000017500000000277411512502123022606 0ustar paulproteuspaulproteus/* ======================================================================== * Copyright 1988-2007 University of Washington * * Licensed under the Apache License, Version 2.0 (the "License"); * you may not use this file except in compliance with the License. * You may obtain a copy of the License at * * http://www.apache.org/licenses/LICENSE-2.0 * * * ======================================================================== */ /* * Program: Operating-system dependent routines -- 4.3BSD version * * Author: Mark Crispin * Networks and Distributed Computing * Computing & Communications * University of Washington * Administration Building, AG-44 * Seattle, WA 98195 * * Date: 11 May 1989 * Last Edited: 16 August 2007 */ #include "tcp_unix.h" /* must be before osdep includes tcp.h */ #include "mail.h" #include "osdep.h" #include #include #include #include #include #include #include #include #include extern int errno; /* just in case */ #include #include "misc.h" #define isodigit(c) (((unsigned)(c)>=060)&((unsigned)(c)<=067)) #define toint(c) ((c)-'0') extern int sys_nerr; extern char *sys_errlist[]; #include "fs_unix.c" #include "ftl_unix.c" #include "nl_unix.c" #include "env_unix.c" #define fork vfork #include "tcp_unix.c" #include "gr_wait.c" #include "memmove.c" #include "strerror.c" #include "strstr.c" #include "strtoul.c" #include "tz_bsd.c" alpine-2.10+dfsg/imap/src/osdep/unix/flocksim.h0000600000175000017500000001044411512502123023130 0ustar paulproteuspaulproteus/* ======================================================================== * Copyright 1988-2006 University of Washington * * Licensed under the Apache License, Version 2.0 (the "License"); * you may not use this file except in compliance with the License. * You may obtain a copy of the License at * * http://www.apache.org/licenses/LICENSE-2.0 * * * ======================================================================== */ /* * Program: flock() emulation via fcntl() locking * * Author: Mark Crispin * Networks and Distributed Computing * Computing & Communications * University of Washington * Administration Building, AG-44 * Seattle, WA 98195 * Internet: MRC@CAC.Washington.EDU * * Date: 10 April 2001 * Last Edited: 20 December 2006 */ #include "dummy.h" /* get scan_contents() prototype */ #define flock flocksim /* use ours instead of theirs */ #undef LOCK_SH #define LOCK_SH 1 /* shared lock */ #undef LOCK_EX #define LOCK_EX 2 /* exclusive lock */ #undef LOCK_NB #define LOCK_NB 4 /* no blocking */ #undef LOCK_UN #define LOCK_UN 8 /* unlock */ /* Safe locking definitions */ extern int lockslavep; /* non-zero means slave process */ #undef SAFE_DELETE #define SAFE_DELETE(dtb,stream,mbx) (dtb->flags & DR_LOCKING) ? \ safe_delete (dtb,stream,mbx) : (*dtb->mbxdel) (stream,mbx) #undef SAFE_RENAME #define SAFE_RENAME(dtb,stream,old,newname) (dtb->flags & DR_LOCKING) ? \ safe_rename (dtb,stream,old,newname) : (*dtb->mbxren) (stream,old,newname) #undef SAFE_STATUS #define SAFE_STATUS(dtb,stream,mbx,bits) (dtb->flags & DR_LOCKING) ? \ safe_status (dtb,stream,mbx,bits) : (*dtb->status) (stream,mbx,bits) #undef SAFE_SCAN_CONTENTS #define SAFE_SCAN_CONTENTS(dtb,name,contents,csiz,fsiz) \ (!dtb || (dtb->flags & DR_LOCKING)) ? \ safe_scan_contents (dtb,name,contents,csiz,fsiz) : \ scan_contents (dtb,name,contents,csiz,fsiz) #undef SAFE_COPY #define SAFE_COPY(dtb,stream,seq,mbx,bits) (dtb->flags & DR_LOCKING) ? \ safe_copy (dtb,stream,seq,mbx,bits) : (*dtb->copy) (stream,seq,mbx,bits) #undef SAFE_APPEND #define SAFE_APPEND(dtb,stream,mbx,af,data) (dtb->flags & DR_LOCKING) ? \ safe_append (dtb,stream,mbx,af,data) : (*dtb->append) (stream,mbx,af,data) #undef MM_EXISTS #define MM_EXISTS (lockslavep ? slave_exists : mm_exists) #undef MM_EXPUNGED #define MM_EXPUNGED (lockslavep ? slave_expunged : mm_expunged) #undef MM_FLAGS #define MM_FLAGS (lockslavep ? slave_flags : mm_flags) #undef MM_NOTIFY #define MM_NOTIFY (lockslavep ? slave_notify : mm_notify) #undef MM_STATUS #define MM_STATUS (lockslavep ? slave_status : mm_status) #undef MM_LOG #define MM_LOG (lockslavep ? slave_log : mm_log) #undef MM_CRITICAL #define MM_CRITICAL (lockslavep ? slave_critical : mm_critical) #undef MM_NOCRITICAL #define MM_NOCRITICAL (lockslavep ? slave_nocritical : mm_nocritical) #undef MM_DISKERROR #define MM_DISKERROR (lockslavep ? slave_diskerror : mm_diskerror) #undef MM_FATAL #define MM_FATAL (lockslavep ? slave_fatal : mm_fatal) #undef MM_APPEND #define MM_APPEND(af) (lockslavep ? slave_append : (*af)) /* Function prototypes */ int flocksim (int fd,int operation); long safe_delete (DRIVER *dtb,MAILSTREAM *stream,char *mbx); long safe_rename (DRIVER *dtb,MAILSTREAM *stream,char *old,char *newname); long safe_status (DRIVER *dtb,MAILSTREAM *stream,char *mbx,long flags); long safe_scan_contents (DRIVER *dtb,char *name,char *contents, unsigned long csiz,unsigned long fsiz); long safe_copy (DRIVER *dtb,MAILSTREAM *stream,char *seq,char *mbx,long flags); long safe_append (DRIVER *dtb,MAILSTREAM *stream,char *mbx,append_t af, void *data); void slave_exists (MAILSTREAM *stream,unsigned long number); void slave_expunged (MAILSTREAM *stream,unsigned long number); void slave_flags (MAILSTREAM *stream,unsigned long number); void slave_notify (MAILSTREAM *stream,char *string,long errflg); void slave_status (MAILSTREAM *stream,char *mailbox,MAILSTATUS *status); void slave_log (char *string,long errflg); void slave_critical (MAILSTREAM *stream); void slave_nocritical (MAILSTREAM *stream); long slave_diskerror (MAILSTREAM *stream,long errcode,long serious); void slave_fatal (char *string); long slave_append (MAILSTREAM *stream,void *data,char **flags,char **date, STRING **message); long slaveproxycopy (MAILSTREAM *stream,char *sequence,char *mailbox, long options); alpine-2.10+dfsg/imap/src/osdep/unix/pmatch.c0000600000175000017500000000542411512502123022572 0ustar paulproteuspaulproteus/* ======================================================================== * Copyright 1988-2006 University of Washington * * Licensed under the Apache License, Version 2.0 (the "License"); * you may not use this file except in compliance with the License. * You may obtain a copy of the License at * * http://www.apache.org/licenses/LICENSE-2.0 * * * ======================================================================== */ /* * Program: IMAP Wildcard Matching Routines (case-dependent) * * Author: Mark Crispin * Networks and Distributed Computing * Computing & Communications * University of Washington * Administration Building, AG-44 * Seattle, WA 98195 * Internet: MRC@CAC.Washington.EDU * * Date: 15 June 2000 * Last Edited: 30 August 2006 */ /* Wildcard pattern match * Accepts: base string * pattern string * delimiter character * Returns: T if pattern matches base, else NIL */ long pmatch_full (unsigned char *s,unsigned char *pat,unsigned char delim) { switch (*pat) { case '%': /* non-recursive */ /* % at end, OK if no inferiors */ if (!pat[1]) return (delim && strchr (s,delim)) ? NIL : T; /* scan remainder of string until delimiter */ do if (pmatch_full (s,pat+1,delim)) return T; while ((*s != delim) && *s++); break; case '*': /* match 0 or more characters */ if (!pat[1]) return T; /* * at end, unconditional match */ /* scan remainder of string */ do if (pmatch_full (s,pat+1,delim)) return T; while (*s++); break; case '\0': /* end of pattern */ return *s ? NIL : T; /* success if also end of base */ default: /* match this character */ return (*pat == *s) ? pmatch_full (s+1,pat+1,delim) : NIL; } return NIL; } /* Directory pattern match * Accepts: base string * pattern string * delimiter character * Returns: T if base is a matching directory of pattern, else NIL */ long dmatch (unsigned char *s,unsigned char *pat,unsigned char delim) { switch (*pat) { case '%': /* non-recursive */ if (!*s) return T; /* end of base means have a subset match */ if (!*++pat) return NIL; /* % at end, no inferiors permitted */ /* scan remainder of string until delimiter */ do if (dmatch (s,pat,delim)) return T; while ((*s != delim) && *s++); if (*s && !s[1]) return T; /* ends with delimiter, must be subset */ return dmatch (s,pat,delim);/* do new scan */ case '*': /* match 0 or more characters */ return T; /* unconditional match */ case '\0': /* end of pattern */ break; default: /* match this character */ if (*s) return (*pat == *s) ? dmatch (s+1,pat+1,delim) : NIL; /* end of base, return if at delimiter */ else if (*pat == delim) return T; break; } return NIL; } alpine-2.10+dfsg/imap/src/osdep/unix/fsync.c0000600000175000017500000000161611512502123022437 0ustar paulproteuspaulproteus/* ======================================================================== * Copyright 1988-2006 University of Washington * * Licensed under the Apache License, Version 2.0 (the "License"); * you may not use this file except in compliance with the License. * You may obtain a copy of the License at * * http://www.apache.org/licenses/LICENSE-2.0 * * * ======================================================================== */ /* * Program: File sync emulator * * Author: Mark Crispin * Networks and Distributed Computing * Computing & Communications * University of Washington * Administration Building, AG-44 * Seattle, WA 98195 * Internet: MRC@CAC.Washington.EDU * * Date: 3 May 1995 * Last Edited: 30 August 2006 */ /* Emulator for BSD fsync() call * Accepts: file name * Returns: 0 if successful, -1 if failure */ int fsync (int fd) { sync (); return 0; } alpine-2.10+dfsg/imap/src/osdep/unix/os_os4.h0000600000175000017500000000225711512502123022532 0ustar paulproteuspaulproteus/* ======================================================================== * Copyright 1988-2006 University of Washington * * Licensed under the Apache License, Version 2.0 (the "License"); * you may not use this file except in compliance with the License. * You may obtain a copy of the License at * * http://www.apache.org/licenses/LICENSE-2.0 * * * ======================================================================== */ /* * Program: Operating-system dependent routines -- OSF/Digital UNIX/Tru64 * * Author: Mark Crispin * Networks and Distributed Computing * Computing & Communications * University of Washington * Administration Building, AG-44 * Seattle, WA 98195 * Internet: MRC@CAC.Washington.EDU * * Date: 1 August 1988 * Last Edited: 30 August 2006 */ #include #include #include #include #include #include /* for struct tm */ #include #include #include /* OSF/1 gets this wrong */ #define setpgrp setpgid #define direct dirent #include "env_unix.h" #include "fs.h" #include "ftl.h" #include "nl.h" #include "tcp.h" #include "flocksim.h" alpine-2.10+dfsg/imap/src/osdep/unix/fs_unix.c0000600000175000017500000000353511512502123022772 0ustar paulproteuspaulproteus/* ======================================================================== * Copyright 1988-2006 University of Washington * * Licensed under the Apache License, Version 2.0 (the "License"); * you may not use this file except in compliance with the License. * You may obtain a copy of the License at * * http://www.apache.org/licenses/LICENSE-2.0 * * * ======================================================================== */ /* * Program: Free storage management routines * * Author: Mark Crispin * Networks and Distributed Computing * Computing & Communications * University of Washington * Administration Building, AG-44 * Seattle, WA 98195 * Internet: MRC@CAC.Washington.EDU * * Date: 1 August 1988 * Last Edited: 30 August 2006 */ /* Get a block of free storage * Accepts: size of desired block * Returns: free storage block */ void *fs_get (size_t size) { blocknotify_t bn = (blocknotify_t) mail_parameters (NIL,GET_BLOCKNOTIFY,NIL); void *data = (*bn) (BLOCK_SENSITIVE,NIL); void *block = malloc (size ? size : (size_t) 1); if (!block) fatal ("Out of memory"); (*bn) (BLOCK_NONSENSITIVE,data); return (block); } /* Resize a block of free storage * Accepts: ** pointer to current block * new size */ void fs_resize (void **block,size_t size) { blocknotify_t bn = (blocknotify_t) mail_parameters (NIL,GET_BLOCKNOTIFY,NIL); void *data = (*bn) (BLOCK_SENSITIVE,NIL); if (!(*block = realloc (*block,size ? size : (size_t) 1))) fatal ("Can't resize memory"); (*bn) (BLOCK_NONSENSITIVE,data); } /* Return a block of free storage * Accepts: ** pointer to free storage block */ void fs_give (void **block) { blocknotify_t bn = (blocknotify_t) mail_parameters (NIL,GET_BLOCKNOTIFY,NIL); void *data = (*bn) (BLOCK_SENSITIVE,NIL); free (*block); *block = NIL; (*bn) (BLOCK_NONSENSITIVE,data); } alpine-2.10+dfsg/imap/src/osdep/unix/tz_nul.c0000600000175000017500000000156711512502123022635 0ustar paulproteuspaulproteus/* ======================================================================== * Copyright 1988-2006 University of Washington * * Licensed under the Apache License, Version 2.0 (the "License"); * you may not use this file except in compliance with the License. * You may obtain a copy of the License at * * http://www.apache.org/licenses/LICENSE-2.0 * * * ======================================================================== */ /* * Program: Null Time Zone String (unknown) * * Author: Mark Crispin * Networks and Distributed Computing * Computing & Communications * University of Washington * Administration Building, AG-44 * Seattle, WA 98195 * Internet: MRC@CAC.Washington.EDU * * Date: 30 August 1994 * Last Edited: 30 August 2006 */ /* Append local timezone name * Accepts: destination string */ void rfc822_timezone (char *s,void *t) { } alpine-2.10+dfsg/imap/src/osdep/unix/ipo_unix.c0000600000175000017500000001204511512502123023145 0ustar paulproteuspaulproteus/* ======================================================================== * Copyright 1988-2006 University of Washington * * Licensed under the Apache License, Version 2.0 (the "License"); * you may not use this file except in compliance with the License. * You may obtain a copy of the License at * * http://www.apache.org/licenses/LICENSE-2.0 * * * ======================================================================== */ /* * Program: UNIX IPv4 old routines * * Author: Mark Crispin * Networks and Distributed Computing * Computing & Communications * University of Washington * Administration Building, AG-44 * Seattle, WA 98195 * Internet: MRC@CAC.Washington.EDU * * Date: 18 December 2003 * Last Edited: 30 August 2006 */ #define SADRLEN sizeof (struct sockaddr) #define SADR4(sadr) ((struct sockaddr_in *) sadr) #define SADR4LEN sizeof (struct sockaddr_in) #define SADR4ADR(sadr) SADR4 (sadr)->sin_addr #define ADR4LEN sizeof (struct in_addr) #define SADR4PORT(sadr) SADR4 (sadr)->sin_port /* IP abstraction layer */ char *ip_sockaddrtostring (struct sockaddr *sadr); long ip_sockaddrtoport (struct sockaddr *sadr); void *ip_stringtoaddr (char *text,size_t *len,int *family); struct sockaddr *ip_newsockaddr (size_t *len); struct sockaddr *ip_sockaddr (int family,void *adr,size_t adrlen, unsigned short port,size_t *len); char *ip_sockaddrtoname (struct sockaddr *sadr); void *ip_nametoaddr (char *name,size_t *len,int *family,char **canonical, void **next); /* Return IP address string from socket address * Accepts: socket address * Returns: IP address as name string */ char *ip_sockaddrtostring (struct sockaddr *sadr) { return (sadr->sa_family == PF_INET) ? inet_ntoa (SADR4ADR (sadr)) : "NON-IPv4"; } /* Return port from socket address * Accepts: socket address * Returns: port number or -1 if can't determine it */ long ip_sockaddrtoport (struct sockaddr *sadr) { return (sadr->sa_family == PF_INET) ? ntohs (SADR4PORT (sadr)) : -1; } /* Return IP address from string * Accepts: name string * pointer to returned length * pointer to returned address family * Returns: address if valid, length and family updated, or NIL */ void *ip_stringtoaddr (char *text,size_t *len,int *family) { unsigned long adr; struct in_addr *ret; /* get address */ if ((adr = inet_addr (text)) == -1) ret = NIL; else { /* make in_addr */ ret = (struct in_addr *) fs_get (*len = ADR4LEN); *family = AF_INET; /* IPv4 */ ret->s_addr = adr; /* set address */ } return (void *) ret; } /* Create a maximum-size socket address * Accepts: pointer to return maximum socket address length * Returns: new, empty socket address of maximum size */ struct sockaddr *ip_newsockaddr (size_t *len) { return (struct sockaddr *) memset (fs_get (SADRLEN),0,*len = SADRLEN); } /* Stuff a socket address * Accepts: address family * IPv4 address * length of address (always 4 in IPv4) * port number * pointer to return socket address length * Returns: socket address or NIL if error */ struct sockaddr *ip_sockaddr (int family,void *adr,size_t adrlen, unsigned short port,size_t *len) { struct sockaddr *sadr = ip_newsockaddr (len); switch (family) { /* build socket address based upon family */ case AF_INET: /* IPv4 */ sadr->sa_family = PF_INET; /* copy host address */ memcpy (&SADR4ADR (sadr),adr,adrlen); /* copy port number in network format */ SADR4PORT (sadr) = htons (port); *len = SADR4LEN; break; default: /* non-IP?? */ sadr->sa_family = PF_UNSPEC; break; } return sadr; } /* Return name from socket address * Accepts: socket address * Returns: canonical name for that address or NIL if none */ char *ip_sockaddrtoname (struct sockaddr *sadr) { struct hostent *he; return ((sadr->sa_family == PF_INET) && (he = gethostbyaddr ((char *) &SADR4ADR (sadr),ADR4LEN,AF_INET))) ? (char *) he->h_name : NIL; } /* Return address from name * Accepts: name or NIL to return next address * pointer to previous/returned length * pointer to previous/returned address family * pointer to previous/returned canonical name * pointer to previous/return state for next-address calls * Returns: address with length/family/canonical updated if needed, or NIL */ void *ip_nametoaddr (char *name,size_t *len,int *family,char **canonical, void **next) { char tmp[MAILTMPLEN]; struct hostent *he; void *ret = NIL; if (name) { /* first lookup? */ /* yes, do case-independent lookup */ if ((strlen (name) < MAILTMPLEN) && (he = gethostbyname (lcase (strcpy (tmp,name))))) { if (len) *len = he->h_length; if (family) *family = he->h_addrtype; if (canonical) *canonical = (char *) he->h_name; if (next) *next = 0; ret = he->h_addr; /* set result to this one and only block */ } else { /* error */ if (len) *len = 0; if (family) *family = 0; if (canonical) *canonical = NIL; if (next) *next = NIL; } } return ret; /* return result */ } alpine-2.10+dfsg/imap/src/osdep/unix/os_sv2.h0000600000175000017500000000564311512502123022541 0ustar paulproteuspaulproteus/* ======================================================================== * Copyright 1988-2006 University of Washington * * Licensed under the Apache License, Version 2.0 (the "License"); * you may not use this file except in compliance with the License. * You may obtain a copy of the License at * * http://www.apache.org/licenses/LICENSE-2.0 * * * ======================================================================== */ /* * Program: Operating-system dependent routines -- SVR2 version * * Author: Mark Crispin * Networks and Distributed Computing * Computing & Communications * University of Washington * Administration Building, AG-44 * Seattle, WA 98195 * Internet: MRC@CAC.Washington.EDU * * Date: 10 April 1992 * Last Edited: 20 December 2006 */ #include #include #define char void #include #undef char #include #include #include #include #include #include /* Many versions of SysV get this wrong */ #define setpgrp(a,b) Setpgrp(a,b) int Setpgrp (int pid,int gid); /* Different names between BSD and SVR4 */ #define L_SET SEEK_SET #define L_INCR SEEK_CUR #define L_XTND SEEK_END #define lstat stat #define random lrand48 #define SIGSTOP SIGQUIT #define S_IFLNK 0120000 /* syslog() emulation */ #define LOG_MAIL (2<<3) /* mail system */ #define LOG_DAEMON (3<<3) /* system daemons */ #define LOG_AUTH (4<<3) /* security/authorization messages */ #define LOG_ALERT 1 /* action must be taken immediately */ #define LOG_CONS 0x02 /* log on the console if errors in sending */ #define LOG_ODELAY 0x04 /* delay open until syslog() is called */ #define LOG_NDELAY 0x08 /* don't delay open */ #define LOG_NOWAIT 0x10 /* if forking to log on console, don't wait() */ /* For setitimer() emulation */ #define ITIMER_REAL 0 /* For opendir() emulation */ typedef struct _dirdesc { int dd_fd; long dd_loc; long dd_size; char *dd_buf; } DIR; struct passwd *getpwent (void); struct passwd *getpwuid (int uid); struct passwd *getpwnam (char *name); struct group *getgrnam (char *name); char *getenv (char *name); long gethostid (void); void *memmove (void *s,void *ct,size_t n); char *strstr (char *cs,char *ct); char *strerror (int n); unsigned long strtoul (char *s,char **endp,int base); DIR *opendir (char * name); int closedir (DIR *d); struct direct *readdir (DIR *d); typedef int (*select_t) (struct direct *name); typedef int (*compar_t) (void *d1,void *d2); int scandir (char *dirname,struct direct ***namelist,select_t select, compar_t compar); int alphasort (void *d1,void *d2); int fsync (int fd); int openlog (ident,logopt,facility); int syslog (priority,message,parameters ...); void *malloc (size_t byteSize); void free (void *ptr); void *realloc (void *oldptr,size_t newsize); #include "env_unix.h" #include "fs.h" #include "ftl.h" #include "nl.h" #include "tcp.h" #include "flocksim.h" alpine-2.10+dfsg/imap/src/osdep/unix/os_lnx.c0000600000175000017500000000252211512502123022614 0ustar paulproteuspaulproteus/* ======================================================================== * Copyright 1988-2007 University of Washington * * Licensed under the Apache License, Version 2.0 (the "License"); * you may not use this file except in compliance with the License. * You may obtain a copy of the License at * * http://www.apache.org/licenses/LICENSE-2.0 * * * ======================================================================== */ /* * Program: Operating-system dependent routines -- old Linux version * * Author: Mark Crispin * Networks and Distributed Computing * Computing & Communications * University of Washington * Administration Building, AG-44 * Seattle, WA 98195 * Internet: MRC@CAC.Washington.EDU * * Date: 1 August 1993 * Last Edited: 16 August 2007 */ #include "tcp_unix.h" /* must be before osdep includes tcp.h */ #include "mail.h" #include "osdep.h" #include #include #include #include #include #include #include #include #include extern int errno; /* just in case */ #include #include "misc.h" #include "fs_unix.c" #include "ftl_unix.c" #include "nl_unix.c" #include "env_unix.c" #define fork vfork #include "tcp_unix.c" #include "gr_waitp.c" #include "tz_sv4.c" #include "flocklnx.c" alpine-2.10+dfsg/imap/src/osdep/unix/log_sv4.c0000600000175000017500000000214711512502123022672 0ustar paulproteuspaulproteus/* ======================================================================== * Copyright 1988-2006 University of Washington * * Licensed under the Apache License, Version 2.0 (the "License"); * you may not use this file except in compliance with the License. * You may obtain a copy of the License at * * http://www.apache.org/licenses/LICENSE-2.0 * * * ======================================================================== */ /* * Program: SVR4 login * * Author: Mark Crispin * Networks and Distributed Computing * Computing & Communications * University of Washington * Administration Building, AG-44 * Seattle, WA 98195 * Internet: MRC@CAC.Washington.EDU * * Date: 1 August 1988 * Last Edited: 30 August 2006 */ /* Log in * Accepts: login passwd struct * argument count * argument vector * Returns: T if success, NIL otherwise */ long loginpw (struct passwd *pw,int argc,char *argv[]) { uid_t uid = pw->pw_uid; char *name = cpystr (pw->pw_name); long ret = !(setgid (pw->pw_gid) || initgroups (name) || setuid (uid)); fs_give ((void **) &name); return ret; } alpine-2.10+dfsg/imap/src/osdep/unix/tz_sv4.c0000600000175000017500000000202311512502123022537 0ustar paulproteuspaulproteus/* ======================================================================== * Copyright 1988-2006 University of Washington * * Licensed under the Apache License, Version 2.0 (the "License"); * you may not use this file except in compliance with the License. * You may obtain a copy of the License at * * http://www.apache.org/licenses/LICENSE-2.0 * * * ======================================================================== */ /* * Program: SVR4-style Time Zone String * * Author: Mark Crispin * Networks and Distributed Computing * Computing & Communications * University of Washington * Administration Building, AG-44 * Seattle, WA 98195 * Internet: MRC@CAC.Washington.EDU * * Date: 30 August 1994 * Last Edited: 30 August 2006 */ /* Append local timezone name * Accepts: destination string */ void rfc822_timezone (char *s,void *t) { tzset (); /* get timezone from TZ environment stuff */ sprintf (s + strlen (s)," (%.50s)", tzname[daylight ? (((struct tm *) t)->tm_isdst > 0) : 0]); } alpine-2.10+dfsg/imap/src/osdep/unix/unix.c0000600000175000017500000027174311512502123022312 0ustar paulproteuspaulproteus/* ======================================================================== * Copyright 1988-2008 University of Washington * * Licensed under the Apache License, Version 2.0 (the "License"); * you may not use this file except in compliance with the License. * You may obtain a copy of the License at * * http://www.apache.org/licenses/LICENSE-2.0 * * * ======================================================================== */ /* * Program: UNIX mail routines * * Author: Mark Crispin * UW Technology * University of Washington * Seattle, WA 98195 * Internet: MRC@Washington.EDU * * Date: 20 December 1989 * Last Edited: 27 March 2008 */ /* DEDICATION * * This file is dedicated to my dog, Unix, also known as Yun-chan and * Unix J. Terwilliker Jehosophat Aloysius Monstrosity Animal Beast. Unix * passed away at the age of 11 1/2 on September 14, 1996, 12:18 PM PDT, after * a two-month bout with cirrhosis of the liver. * * He was a dear friend, and I miss him terribly. * * Lift a leg, Yunie. Luv ya forever!!!! */ #include #include #include extern int errno; /* just in case */ #include #include "mail.h" #include "osdep.h" #include #include #include "unix.h" #include "pseudo.h" #include "fdstring.h" #include "misc.h" #include "dummy.h" /* UNIX I/O stream local data */ typedef struct unix_local { unsigned int dirty : 1; /* disk copy needs updating */ unsigned int ddirty : 1; /* double-dirty, ping becomes checkpoint */ unsigned int pseudo : 1; /* uses a pseudo message */ unsigned int appending : 1; /* don't mark new messages as old */ int fd; /* mailbox file descriptor */ int ld; /* lock file descriptor */ char *lname; /* lock file name */ off_t filesize; /* file size parsed */ time_t filetime; /* last file time */ time_t lastsnarf; /* last snarf time (for mbox driver) */ unsigned char *buf; /* temporary buffer */ unsigned long buflen; /* current size of temporary buffer */ unsigned long uid; /* current text uid */ SIZEDTEXT text; /* current text */ unsigned long textlen; /* current text length */ char *line; /* returned line */ char *linebuf; /* line readin buffer */ unsigned long linebuflen; /* current line readin buffer length */ } UNIXLOCAL; /* Convenient access to local data */ #define LOCAL ((UNIXLOCAL *) stream->local) /* UNIX protected file structure */ typedef struct unix_file { MAILSTREAM *stream; /* current stream */ off_t curpos; /* current file position */ off_t protect; /* protected position */ off_t filepos; /* current last written file position */ char *buf; /* overflow buffer */ size_t buflen; /* current overflow buffer length */ char *bufpos; /* current buffer position */ } UNIXFILE; /* Function prototypes */ DRIVER *unix_valid (char *name); long unix_isvalid_fd (int fd); void *unix_parameters (long function,void *value); void unix_scan (MAILSTREAM *stream,char *ref,char *pat,char *contents); void unix_list (MAILSTREAM *stream,char *ref,char *pat); void unix_lsub (MAILSTREAM *stream,char *ref,char *pat); long unix_create (MAILSTREAM *stream,char *mailbox); long unix_delete (MAILSTREAM *stream,char *mailbox); long unix_rename (MAILSTREAM *stream,char *old,char *newname); MAILSTREAM *unix_open (MAILSTREAM *stream); void unix_close (MAILSTREAM *stream,long options); char *unix_header (MAILSTREAM *stream,unsigned long msgno, unsigned long *length,long flags); long unix_text (MAILSTREAM *stream,unsigned long msgno,STRING *bs,long flags); char *unix_text_work (MAILSTREAM *stream,MESSAGECACHE *elt, unsigned long *length,long flags); void unix_flagmsg (MAILSTREAM *stream,MESSAGECACHE *elt); long unix_ping (MAILSTREAM *stream); void unix_check (MAILSTREAM *stream); long unix_expunge (MAILSTREAM *stream,char *sequence,long options); long unix_copy (MAILSTREAM *stream,char *sequence,char *mailbox,long options); long unix_append (MAILSTREAM *stream,char *mailbox,append_t af,void *data); int unix_collect_msg (MAILSTREAM *stream,FILE *sf,char *flags,char *date, STRING *msg); int unix_append_msgs (MAILSTREAM *stream,FILE *sf,FILE *df,SEARCHSET *set); void unix_abort (MAILSTREAM *stream); char *unix_file (char *dst,char *name); int unix_lock (char *file,int flags,int mode,DOTLOCK *lock,int op); void unix_unlock (int fd,MAILSTREAM *stream,DOTLOCK *lock); int unix_parse (MAILSTREAM *stream,DOTLOCK *lock,int op); char *unix_mbxline (MAILSTREAM *stream,STRING *bs,unsigned long *size); unsigned long unix_pseudo (MAILSTREAM *stream,char *hdr); unsigned long unix_xstatus (MAILSTREAM *stream,char *status,MESSAGECACHE *elt, unsigned long uid,long flag); long unix_rewrite (MAILSTREAM *stream,unsigned long *nexp,DOTLOCK *lock, long flags); long unix_extend (MAILSTREAM *stream,unsigned long size); void unix_write (UNIXFILE *f,char *s,unsigned long i); void unix_phys_write (UNIXFILE *f,char *buf,size_t size); /* mbox mail routines */ /* Function prototypes */ DRIVER *mbox_valid (char *name); long mbox_create (MAILSTREAM *stream,char *mailbox); long mbox_delete (MAILSTREAM *stream,char *mailbox); long mbox_rename (MAILSTREAM *stream,char *old,char *newname); long mbox_status (MAILSTREAM *stream,char *mbx,long flags); MAILSTREAM *mbox_open (MAILSTREAM *stream); long mbox_ping (MAILSTREAM *stream); void mbox_check (MAILSTREAM *stream); long mbox_expunge (MAILSTREAM *stream,char *sequence,long options); long mbox_append (MAILSTREAM *stream,char *mailbox,append_t af,void *data); /* UNIX mail routines */ /* Driver dispatch used by MAIL */ DRIVER unixdriver = { "unix", /* driver name */ /* driver flags */ DR_LOCAL|DR_MAIL|DR_LOCKING|DR_NONEWMAILRONLY|DR_XPOINT, (DRIVER *) NIL, /* next driver */ unix_valid, /* mailbox is valid for us */ unix_parameters, /* manipulate parameters */ unix_scan, /* scan mailboxes */ unix_list, /* list mailboxes */ unix_lsub, /* list subscribed mailboxes */ NIL, /* subscribe to mailbox */ NIL, /* unsubscribe from mailbox */ unix_create, /* create mailbox */ unix_delete, /* delete mailbox */ unix_rename, /* rename mailbox */ mail_status_default, /* status of mailbox */ unix_open, /* open mailbox */ unix_close, /* close mailbox */ NIL, /* fetch message "fast" attributes */ NIL, /* fetch message flags */ NIL, /* fetch overview */ NIL, /* fetch message envelopes */ unix_header, /* fetch message header */ unix_text, /* fetch message text */ NIL, /* fetch partial message text */ NIL, /* unique identifier */ NIL, /* message number */ NIL, /* modify flags */ unix_flagmsg, /* per-message modify flags */ NIL, /* search for message based on criteria */ NIL, /* sort messages */ NIL, /* thread messages */ unix_ping, /* ping mailbox to see if still alive */ unix_check, /* check for new messages */ unix_expunge, /* expunge deleted messages */ unix_copy, /* copy messages to another mailbox */ unix_append, /* append string message to mailbox */ NIL /* garbage collect stream */ }; /* prototype stream */ MAILSTREAM unixproto = {&unixdriver}; /* driver parameters */ static long unix_fromwidget = T; /* UNIX mail validate mailbox * Accepts: mailbox name * Returns: our driver if name is valid, NIL otherwise */ DRIVER *unix_valid (char *name) { int fd; DRIVER *ret = NIL; char *t,file[MAILTMPLEN]; struct stat sbuf; time_t tp[2]; errno = EINVAL; /* assume invalid argument */ /* must be non-empty file */ if ((t = dummy_file (file,name)) && !stat (t,&sbuf)) { if (!sbuf.st_size)errno = 0;/* empty file */ else if ((fd = open (file,O_RDONLY,NIL)) >= 0) { /* OK if mailbox format good */ if (unix_isvalid_fd (fd)) ret = &unixdriver; else errno = -1; /* invalid format */ close (fd); /* close the file */ /* \Marked status? */ if ((sbuf.st_ctime > sbuf.st_atime) || (sbuf.st_mtime > sbuf.st_atime)) { tp[0] = sbuf.st_atime; /* yes, preserve atime and mtime */ tp[1] = sbuf.st_mtime; utime (file,tp); /* set the times */ } } } return ret; /* return what we should */ } /* UNIX mail test for valid mailbox * Accepts: file descriptor * scratch buffer * Returns: T if valid, NIL otherwise */ long unix_isvalid_fd (int fd) { int zn; int ret = NIL; char tmp[MAILTMPLEN],*s,*t,c = '\n'; memset (tmp,'\0',MAILTMPLEN); if (read (fd,tmp,MAILTMPLEN-1) >= 0) { for (s = tmp; (*s == '\r') || (*s == '\n') || (*s == ' ') || (*s == '\t');) c = *s++; if (c == '\n') VALID (s,t,ret,zn); } return ret; /* return what we should */ } /* UNIX manipulate driver parameters * Accepts: function code * function-dependent value * Returns: function-dependent return value */ void *unix_parameters (long function,void *value) { void *ret = NIL; switch ((int) function) { case GET_INBOXPATH: if (value) ret = dummy_file ((char *) value,"INBOX"); break; case SET_FROMWIDGET: unix_fromwidget = (long) value; case GET_FROMWIDGET: ret = (void *) unix_fromwidget; break; } return ret; } /* UNIX mail scan mailboxes * Accepts: mail stream * reference * pattern to search * string to scan */ void unix_scan (MAILSTREAM *stream,char *ref,char *pat,char *contents) { if (stream) dummy_scan (NIL,ref,pat,contents); } /* UNIX mail list mailboxes * Accepts: mail stream * reference * pattern to search */ void unix_list (MAILSTREAM *stream,char *ref,char *pat) { if (stream) dummy_list (NIL,ref,pat); } /* UNIX mail list subscribed mailboxes * Accepts: mail stream * reference * pattern to search */ void unix_lsub (MAILSTREAM *stream,char *ref,char *pat) { if (stream) dummy_lsub (NIL,ref,pat); } /* UNIX mail create mailbox * Accepts: MAIL stream * mailbox name to create * Returns: T on success, NIL on failure */ long unix_create (MAILSTREAM *stream,char *mailbox) { char *s,mbx[MAILTMPLEN],tmp[MAILTMPLEN]; long ret = NIL; int i,fd; time_t ti = time (0); if (!(s = dummy_file (mbx,mailbox))) { sprintf (tmp,"Can't create %.80s: invalid name",mailbox); MM_LOG (tmp,ERROR); } /* create underlying file */ else if (dummy_create_path (stream,s,get_dir_protection (mailbox))) { /* done if dir-only or whiner */ if (((s = strrchr (s,'/')) && !s[1]) || mail_parameters (NIL,GET_USERHASNOLIFE,NIL)) ret = T; else if ((fd = open (mbx,O_WRONLY, (long) mail_parameters (NIL,GET_MBXPROTECTION,NIL))) < 0) { sprintf (tmp,"Can't reopen mailbox node %.80s: %s",mbx,strerror (errno)); MM_LOG (tmp,ERROR); unlink (mbx); /* delete the file */ } else { /* initialize header */ memset (tmp,'\0',MAILTMPLEN); sprintf (tmp,"From %s %sDate: ",pseudo_from,ctime (&ti)); rfc822_fixed_date (s = tmp + strlen (tmp)); /* write the pseudo-header */ sprintf (s += strlen (s), "\nFrom: %s <%s@%s>\nSubject: %s\nX-IMAP: %010lu 0000000000", pseudo_name,pseudo_from,mylocalhost (),pseudo_subject, (unsigned long) ti); for (i = 0; i < NUSERFLAGS; ++i) if (default_user_flag (i)) sprintf (s += strlen (s)," %s",default_user_flag (i)); sprintf (s += strlen (s),"\nStatus: RO\n\n%s\n\n",pseudo_msg); if (write (fd,tmp,strlen (tmp)) > 0) ret = T; else { sprintf (tmp,"Can't initialize mailbox node %.80s: %s",mbx, strerror (errno)); MM_LOG (tmp,ERROR); unlink (mbx); /* delete the file */ } close (fd); /* close file */ } } /* set proper protections */ return ret ? set_mbx_protections (mailbox,mbx) : NIL; } /* UNIX mail delete mailbox * Accepts: MAIL stream * mailbox name to delete * Returns: T on success, NIL on failure */ long unix_delete (MAILSTREAM *stream,char *mailbox) { return unix_rename (stream,mailbox,NIL); } /* UNIX mail rename mailbox * Accepts: MAIL stream * old mailbox name * new mailbox name (or NIL for delete) * Returns: T on success, NIL on failure */ long unix_rename (MAILSTREAM *stream,char *old,char *newname) { long ret = NIL; char c,*s = NIL; char tmp[MAILTMPLEN],file[MAILTMPLEN],lock[MAILTMPLEN]; DOTLOCK lockx; int fd,ld; long i; struct stat sbuf; MM_CRITICAL (stream); /* get the c-client lock */ if (!dummy_file (file,old) || (newname && (!((s = mailboxfile (tmp,newname)) && *s) || ((s = strrchr (tmp,'/')) && !s[1])))) sprintf (tmp,newname ? "Can't rename mailbox %.80s to %.80s: invalid name" : "Can't delete mailbox %.80s: invalid name", old,newname); /* lock out other c-clients */ else if ((ld = lockname (lock,file,LOCK_EX|LOCK_NB,&i)) < 0) sprintf (tmp,"Mailbox %.80s is in use by another process",old); else { if ((fd = unix_lock (file,O_RDWR, (long) mail_parameters (NIL,GET_MBXPROTECTION,NIL), &lockx,LOCK_EX)) < 0) sprintf (tmp,"Can't lock mailbox %.80s: %s",old,strerror (errno)); else { if (newname) { /* want rename? */ /* found superior to destination name? */ if (s = strrchr (s,'/')) { c = *++s; /* remember first character of inferior */ *s = '\0'; /* tie off to get just superior */ /* name doesn't exist, create it */ if ((stat (tmp,&sbuf) || ((sbuf.st_mode & S_IFMT) != S_IFDIR)) && !dummy_create_path (stream,tmp,get_dir_protection (newname))) { unix_unlock (fd,NIL,&lockx); unix_unlock (ld,NIL,NIL); unlink (lock); MM_NOCRITICAL (stream); return ret; /* return success or failure */ } *s = c; /* restore full name */ } if (rename (file,tmp)) sprintf (tmp,"Can't rename mailbox %.80s to %.80s: %s",old,newname, strerror (errno)); else ret = T; /* set success */ } else if (unlink (file)) sprintf (tmp,"Can't delete mailbox %.80s: %s",old,strerror (errno)); else ret = T; /* set success */ unix_unlock (fd,NIL,&lockx); } unix_unlock (ld,NIL,NIL); /* flush the lock */ unlink (lock); } MM_NOCRITICAL (stream); /* no longer critical */ if (!ret) MM_LOG (tmp,ERROR); /* log error */ return ret; /* return success or failure */ } /* UNIX mail open * Accepts: Stream to open * Returns: Stream on success, NIL on failure */ MAILSTREAM *unix_open (MAILSTREAM *stream) { long i; int fd; char tmp[MAILTMPLEN]; DOTLOCK lock; long retry; /* return prototype for OP_PROTOTYPE call */ if (!stream) return user_flags (&unixproto); retry = stream->silent ? 1 : KODRETRY; if (stream->local) fatal ("unix recycle stream"); stream->local = memset (fs_get (sizeof (UNIXLOCAL)),0,sizeof (UNIXLOCAL)); /* note if an INBOX or not */ stream->inbox = !compare_cstring (stream->mailbox,"INBOX"); /* canonicalize the stream mailbox name */ if (!dummy_file (tmp,stream->mailbox)) { sprintf (tmp,"Can't open - invalid name: %.80s",stream->mailbox); MM_LOG (tmp,ERROR); return NIL; } /* flush old name */ fs_give ((void **) &stream->mailbox); /* save canonical name */ stream->mailbox = cpystr (tmp); LOCAL->fd = LOCAL->ld = -1; /* no file or state locking yet */ LOCAL->buf = (char *) fs_get (CHUNKSIZE); LOCAL->buflen = CHUNKSIZE - 1; LOCAL->text.data = (unsigned char *) fs_get (CHUNKSIZE); LOCAL->text.size = CHUNKSIZE - 1; LOCAL->linebuf = (char *) fs_get (CHUNKSIZE); LOCAL->linebuflen = CHUNKSIZE - 1; stream->sequence++; /* bump sequence number */ /* make lock for read/write access */ if (!stream->rdonly) while (retry) { /* try to lock file */ if ((fd = lockname (tmp,stream->mailbox,LOCK_EX|LOCK_NB,&i)) < 0) { /* suppressing kiss-of-death? */ if (stream->nokod) retry = 0; /* no, first time through? */ else if (retry-- == KODRETRY) { /* learned other guy's PID and can signal? */ if (i && !kill ((int) i,SIGUSR2)) { sprintf (tmp,"Trying to get mailbox lock from process %ld",i); MM_LOG (tmp,WARN); } else retry = 0; /* give up */ } if (!stream->silent) { /* nothing if silent stream */ if (retry) sleep (1); /* wait a second before trying again */ else MM_LOG ("Mailbox is open by another process, access is readonly", WARN); } } else { /* got the lock, nobody else can alter state */ LOCAL->ld = fd; /* note lock's fd and name */ LOCAL->lname = cpystr (tmp); /* make sure mode OK (don't use fchmod()) */ chmod (LOCAL->lname,(long) mail_parameters (NIL,GET_LOCKPROTECTION,NIL)); if (stream->silent) i = 0;/* silent streams won't accept KOD */ else { /* note our PID in the lock */ sprintf (tmp,"%d",getpid ()); write (fd,tmp,(i = strlen (tmp))+1); } ftruncate (fd,i); /* make sure tied off */ fsync (fd); /* make sure it's available */ retry = 0; /* no more need to try */ } } /* parse mailbox */ stream->nmsgs = stream->recent = 0; /* will we be able to get write access? */ if ((LOCAL->ld >= 0) && access (stream->mailbox,W_OK) && (errno == EACCES)) { MM_LOG ("Can't get write access to mailbox, access is readonly",WARN); flock (LOCAL->ld,LOCK_UN); /* release the lock */ close (LOCAL->ld); /* close the lock file */ LOCAL->ld = -1; /* no more lock fd */ unlink (LOCAL->lname); /* delete it */ } /* reset UID validity */ stream->uid_validity = stream->uid_last = 0; if (stream->silent && !stream->rdonly && (LOCAL->ld < 0)) unix_abort (stream); /* abort if can't get RW silent stream */ /* parse mailbox */ else if (unix_parse (stream,&lock,LOCK_SH)) { unix_unlock (LOCAL->fd,stream,&lock); mail_unlock (stream); MM_NOCRITICAL (stream); /* done with critical */ } if (!LOCAL) return NIL; /* failure if stream died */ /* make sure upper level knows readonly */ stream->rdonly = (LOCAL->ld < 0); /* notify about empty mailbox */ if (!(stream->nmsgs || stream->silent)) MM_LOG ("Mailbox is empty",NIL); if (!stream->rdonly) { /* flags stick if readwrite */ stream->perm_seen = stream->perm_deleted = stream->perm_flagged = stream->perm_answered = stream->perm_draft = T; if (!stream->uid_nosticky) {/* users with lives get permanent keywords */ stream->perm_user_flags = 0xffffffff; /* and maybe can create them too! */ stream->kwd_create = stream->user_flags[NUSERFLAGS-1] ? NIL : T; } } return stream; /* return stream alive to caller */ } /* UNIX mail close * Accepts: MAIL stream * close options */ void unix_close (MAILSTREAM *stream,long options) { int silent = stream->silent; stream->silent = T; /* go silent */ /* expunge if requested */ if (options & CL_EXPUNGE) unix_expunge (stream,NIL,NIL); /* else dump final checkpoint */ else if (LOCAL->dirty) unix_check (stream); stream->silent = silent; /* restore old silence state */ unix_abort (stream); /* now punt the file and local data */ } /* UNIX mail fetch message header * Accepts: MAIL stream * message # to fetch * pointer to returned header text length * option flags * Returns: message header in RFC822 format */ /* lines to filter from header */ static STRINGLIST *unix_hlines = NIL; char *unix_header (MAILSTREAM *stream,unsigned long msgno, unsigned long *length,long flags) { MESSAGECACHE *elt; unsigned char *s,*t,*tl; *length = 0; /* default to empty */ if (flags & FT_UID) return "";/* UID call "impossible" */ elt = mail_elt (stream,msgno);/* get cache */ if (!unix_hlines) { /* once only code */ STRINGLIST *lines = unix_hlines = mail_newstringlist (); lines->text.size = strlen ((char *) (lines->text.data = (unsigned char *) "Status")); lines = lines->next = mail_newstringlist (); lines->text.size = strlen ((char *) (lines->text.data = (unsigned char *) "X-Status")); lines = lines->next = mail_newstringlist (); lines->text.size = strlen ((char *) (lines->text.data = (unsigned char *) "X-Keywords")); lines = lines->next = mail_newstringlist (); lines->text.size = strlen ((char *) (lines->text.data = (unsigned char *) "X-UID")); lines = lines->next = mail_newstringlist (); lines->text.size = strlen ((char *) (lines->text.data = (unsigned char *) "X-IMAP")); lines = lines->next = mail_newstringlist (); lines->text.size = strlen ((char *) (lines->text.data = (unsigned char *) "X-IMAPbase")); } /* go to header position */ lseek (LOCAL->fd,elt->private.special.offset + elt->private.msg.header.offset,L_SET); if (flags & FT_INTERNAL) { /* initial data OK? */ if (elt->private.msg.header.text.size > LOCAL->buflen) { fs_give ((void **) &LOCAL->buf); LOCAL->buf = (char *) fs_get ((LOCAL->buflen = elt->private.msg.header.text.size) + 1); } /* read message */ read (LOCAL->fd,LOCAL->buf,elt->private.msg.header.text.size); /* got text, tie off string */ LOCAL->buf[*length = elt->private.msg.header.text.size] = '\0'; /* squeeze out CRs (in case from PC) */ for (s = t = LOCAL->buf,tl = LOCAL->buf + *length; t < tl; t++) if (*t != '\r') *s++ = *t; *s = '\0'; *length = s - LOCAL->buf; /* adjust length */ } else { /* need to make a CRLF version */ read (LOCAL->fd,s = (char *) fs_get (elt->private.msg.header.text.size+1), elt->private.msg.header.text.size); /* tie off string, and convert to CRLF */ s[elt->private.msg.header.text.size] = '\0'; *length = strcrlfcpy (&LOCAL->buf,&LOCAL->buflen,s, elt->private.msg.header.text.size); fs_give ((void **) &s); /* free readin buffer */ /* squeeze out spurious CRs */ for (s = t = LOCAL->buf,tl = LOCAL->buf + *length; t < tl; t++) if ((*t != '\r') || (t[1] == '\n')) *s++ = *t; *s = '\0'; *length = s - LOCAL->buf; /* adjust length */ } *length = mail_filter (LOCAL->buf,*length,unix_hlines,FT_NOT); return (char *) LOCAL->buf; /* return processed copy */ } /* UNIX mail fetch message text * Accepts: MAIL stream * message # to fetch * pointer to returned stringstruct * option flags * Returns: T on success, NIL if failure */ long unix_text (MAILSTREAM *stream,unsigned long msgno,STRING *bs,long flags) { char *s; unsigned long i; MESSAGECACHE *elt; /* UID call "impossible" */ if (flags & FT_UID) return NIL; elt = mail_elt (stream,msgno);/* get cache element */ /* if message not seen */ if (!(flags & FT_PEEK) && !elt->seen) { /* mark message seen and dirty */ elt->seen = elt->private.dirty = LOCAL->dirty = T; MM_FLAGS (stream,msgno); } s = unix_text_work (stream,elt,&i,flags); INIT (bs,mail_string,s,i); /* set up stringstruct */ return T; /* success */ } /* UNIX mail fetch message text worker routine * Accepts: MAIL stream * message cache element * pointer to returned header text length * option flags */ char *unix_text_work (MAILSTREAM *stream,MESSAGECACHE *elt, unsigned long *length,long flags) { FDDATA d; STRING bs; unsigned char c,*s,*t,*tl,tmp[CHUNKSIZE]; /* go to text position */ lseek (LOCAL->fd,elt->private.special.offset + elt->private.msg.text.offset,L_SET); if (flags & FT_INTERNAL) { /* initial data OK? */ if (elt->private.msg.text.text.size > LOCAL->buflen) { fs_give ((void **) &LOCAL->buf); LOCAL->buf = (char *) fs_get ((LOCAL->buflen = elt->private.msg.text.text.size) + 1); } /* read message */ read (LOCAL->fd,LOCAL->buf,elt->private.msg.text.text.size); /* got text, tie off string */ LOCAL->buf[*length = elt->private.msg.text.text.size] = '\0'; /* squeeze out CRs (in case from PC) */ for (s = t = LOCAL->buf,tl = LOCAL->buf + *length; t < tl; t++) if (*t != '\r') *s++ = *t; *s = '\0'; *length = s - LOCAL->buf; /* adjust length */ return (char *) LOCAL->buf; } /* have it cached already? */ if (elt->private.uid != LOCAL->uid) { /* not cached, cache it now */ LOCAL->uid = elt->private.uid; /* is buffer big enough? */ if (elt->rfc822_size > LOCAL->text.size) { /* excessively conservative, but the right thing is too hard to do */ fs_give ((void **) &LOCAL->text.data); LOCAL->text.data = (unsigned char *) fs_get ((LOCAL->text.size = elt->rfc822_size) + 1); } d.fd = LOCAL->fd; /* yes, set up file descriptor */ d.pos = elt->private.special.offset + elt->private.msg.text.offset; d.chunk = tmp; /* initial buffer chunk */ d.chunksize = CHUNKSIZE; /* file chunk size */ INIT (&bs,fd_string,&d,elt->private.msg.text.text.size); for (s = (char *) LOCAL->text.data; SIZE (&bs);) switch (c = SNX (&bs)) { case '\r': /* carriage return seen */ break; case '\n': *s++ = '\r'; /* insert a CR */ default: *s++ = c; /* copy characters */ } *s = '\0'; /* tie off buffer */ /* calculate length of cached data */ LOCAL->textlen = s - LOCAL->text.data; } *length = LOCAL->textlen; /* return from cache */ return (char *) LOCAL->text.data; } /* UNIX per-message modify flag * Accepts: MAIL stream * message cache element */ void unix_flagmsg (MAILSTREAM *stream,MESSAGECACHE *elt) { /* only after finishing */ if (elt->valid) elt->private.dirty = LOCAL->dirty = T; } /* UNIX mail ping mailbox * Accepts: MAIL stream * Returns: T if stream alive, else NIL */ long unix_ping (MAILSTREAM *stream) { DOTLOCK lock; struct stat sbuf; long reparse; /* big no-op if not readwrite */ if (LOCAL && (LOCAL->ld >= 0) && !stream->lock) { if (stream->rdonly) { /* does he want to give up readwrite? */ /* checkpoint if we changed something */ if (LOCAL->dirty) unix_check (stream); flock (LOCAL->ld,LOCK_UN);/* release readwrite lock */ close (LOCAL->ld); /* close the readwrite lock file */ LOCAL->ld = -1; /* no more readwrite lock fd */ unlink (LOCAL->lname); /* delete the readwrite lock file */ } else { /* see if need to reparse */ if (!(reparse = (long) mail_parameters (NIL,GET_NETFSSTATBUG,NIL))) { /* get current mailbox size */ if (LOCAL->fd >= 0) fstat (LOCAL->fd,&sbuf); else if (stat (stream->mailbox,&sbuf)) { sprintf (LOCAL->buf,"Mailbox stat failed, aborted: %s", strerror (errno)); MM_LOG (LOCAL->buf,ERROR); unix_abort (stream); return NIL; } reparse = (sbuf.st_size != LOCAL->filesize); } /* parse if mailbox changed */ if ((LOCAL->ddirty || reparse) && unix_parse (stream,&lock,LOCK_EX)) { /* force checkpoint if double-dirty */ if (LOCAL->ddirty) unix_rewrite (stream,NIL,&lock,NIL); /* unlock mailbox */ else unix_unlock (LOCAL->fd,stream,&lock); mail_unlock (stream); /* and stream */ MM_NOCRITICAL (stream); /* done with critical */ } } } return LOCAL ? LONGT : NIL; /* return if still alive */ } /* UNIX mail check mailbox * Accepts: MAIL stream */ void unix_check (MAILSTREAM *stream) { DOTLOCK lock; /* parse and lock mailbox */ if (LOCAL && (LOCAL->ld >= 0) && !stream->lock && unix_parse (stream,&lock,LOCK_EX)) { /* any unsaved changes? */ if (LOCAL->dirty && unix_rewrite (stream,NIL,&lock,NIL)) { if (!stream->silent) MM_LOG ("Checkpoint completed",NIL); } /* no checkpoint needed, just unlock */ else unix_unlock (LOCAL->fd,stream,&lock); mail_unlock (stream); /* unlock the stream */ MM_NOCRITICAL (stream); /* done with critical */ } } /* UNIX mail expunge mailbox * Accepts: MAIL stream * sequence to expunge if non-NIL * expunge options * Returns: T, always */ long unix_expunge (MAILSTREAM *stream,char *sequence,long options) { long ret; unsigned long i; DOTLOCK lock; char *msg = NIL; /* parse and lock mailbox */ if (ret = (sequence ? ((options & EX_UID) ? mail_uid_sequence (stream,sequence) : mail_sequence (stream,sequence)) : LONGT) && LOCAL && (LOCAL->ld >= 0) && !stream->lock && unix_parse (stream,&lock,LOCK_EX)) { /* check expunged messages if not dirty */ for (i = 1; !LOCAL->dirty && (i <= stream->nmsgs); i++) { MESSAGECACHE *elt = mail_elt (stream,i); if (mail_elt (stream,i)->deleted) LOCAL->dirty = T; } if (!LOCAL->dirty) { /* not dirty and no expunged messages */ unix_unlock (LOCAL->fd,stream,&lock); msg = "No messages deleted, so no update needed"; } else if (unix_rewrite (stream,&i,&lock,sequence ? LONGT : NIL)) { if (i) sprintf (msg = LOCAL->buf,"Expunged %lu messages",i); else msg = "Mailbox checkpointed, but no messages expunged"; } /* rewrite failed */ else unix_unlock (LOCAL->fd,stream,&lock); mail_unlock (stream); /* unlock the stream */ MM_NOCRITICAL (stream); /* done with critical */ if (msg && !stream->silent) MM_LOG (msg,NIL); } else if (!stream->silent) MM_LOG("Expunge ignored on readonly mailbox",WARN); return ret; } /* UNIX mail copy message(s) * Accepts: MAIL stream * sequence * destination mailbox * copy options * Returns: T if copy successful, else NIL */ long unix_copy (MAILSTREAM *stream,char *sequence,char *mailbox,long options) { struct stat sbuf; int fd; char *s,file[MAILTMPLEN]; DOTLOCK lock; time_t tp[2]; unsigned long i,j; MESSAGECACHE *elt; long ret = T; mailproxycopy_t pc = (mailproxycopy_t) mail_parameters (stream,GET_MAILPROXYCOPY,NIL); copyuid_t cu = (copyuid_t) (mail_parameters (NIL,GET_USERHASNOLIFE,NIL) ? NIL : mail_parameters (NIL,GET_COPYUID,NIL)); SEARCHSET *source = cu ? mail_newsearchset () : NIL; SEARCHSET *dest = cu ? mail_newsearchset () : NIL; MAILSTREAM *tstream = NIL; DRIVER *d; for (d = (DRIVER *) mail_parameters (NIL,GET_DRIVERS,NIL); (d && strcmp (d->name,"mbox") && !(d->flags & DR_DISABLE)); d = d->next); /* see if mbox driver active */ if (!((options & CP_UID) ? mail_uid_sequence (stream,sequence) : mail_sequence (stream,sequence))) return NIL; /* make sure destination is valid */ if (!((d && mbox_valid (mailbox) && (mailbox = "mbox")) || unix_valid (mailbox) || !errno)) switch (errno) { case ENOENT: /* no such file? */ if (compare_cstring (mailbox,"INBOX")) { MM_NOTIFY (stream,"[TRYCREATE] Must create mailbox before copy",NIL); return NIL; } if (pc) return (*pc) (stream,sequence,mailbox,options); unix_create (NIL,"INBOX");/* create empty INBOX */ case EACCES: /* file protected */ sprintf (LOCAL->buf,"Can't access destination: %.80s",mailbox); MM_LOG (LOCAL->buf,ERROR); return NIL; case EINVAL: if (pc) return (*pc) (stream,sequence,mailbox,options); sprintf (LOCAL->buf,"Invalid UNIX-format mailbox name: %.80s",mailbox); MM_LOG (LOCAL->buf,ERROR); return NIL; default: if (pc) return (*pc) (stream,sequence,mailbox,options); sprintf (LOCAL->buf,"Not a UNIX-format mailbox: %.80s",mailbox); MM_LOG (LOCAL->buf,ERROR); return NIL; } /* try to open rewrite for UIDPLUS */ if ((tstream = mail_open_work (&unixdriver,NIL,mailbox, OP_SILENT|OP_NOKOD)) && tstream->rdonly) tstream = mail_close (tstream); if (cu && !tstream) { /* wanted a COPYUID? */ sprintf (LOCAL->buf,"Unable to write-open mailbox for COPYUID: %.80s", mailbox); MM_LOG (LOCAL->buf,WARN); cu = NIL; /* don't try to do COPYUID */ } LOCAL->buf[0] = '\0'; MM_CRITICAL (stream); /* go critical */ if ((fd = unix_lock (dummy_file (file,mailbox),O_WRONLY|O_APPEND, (long) mail_parameters (NIL,GET_MBXPROTECTION,NIL), &lock,LOCK_EX)) < 0) { MM_NOCRITICAL (stream); /* done with critical */ sprintf (LOCAL->buf,"Can't open destination mailbox: %s",strerror (errno)); MM_LOG (LOCAL->buf,ERROR);/* log the error */ return NIL; /* failed */ } fstat (fd,&sbuf); /* get current file size */ /* write all requested messages to mailbox */ for (i = 1; ret && (i <= stream->nmsgs); i++) if ((elt = mail_elt (stream,i))->sequence) { lseek (LOCAL->fd,elt->private.special.offset,L_SET); read (LOCAL->fd,LOCAL->buf,elt->private.special.text.size); if (write (fd,LOCAL->buf,elt->private.special.text.size) < 0) ret = NIL; else { /* internal header succeeded */ s = unix_header (stream,i,&j,FT_INTERNAL); /* header size, sans trailing newline */ if (j && (s[j - 2] == '\n')) j--; if (write (fd,s,j) < 0) ret = NIL; else { /* message header succeeded */ j = tstream ? /* write UIDPLUS data if have readwrite */ unix_xstatus (stream,LOCAL->buf,elt,++(tstream->uid_last),LONGT) : unix_xstatus (stream,LOCAL->buf,elt,NIL,NIL); if (write (fd,LOCAL->buf,j) < 0) ret = NIL; else { /* message status succeeded */ s = unix_text_work (stream,elt,&j,FT_INTERNAL); if ((write (fd,s,j) < 0) || (write (fd,"\n",1) < 0)) ret = NIL; else if (cu) { /* need to pass back new UID? */ mail_append_set (source,mail_uid (stream,i)); mail_append_set (dest,tstream->uid_last); } } } } } if (!ret || fsync (fd)) { /* force out the update */ sprintf (LOCAL->buf,"Message copy failed: %s",strerror (errno)); ftruncate (fd,sbuf.st_size); ret = NIL; } /* force UIDVALIDITY assignment now */ if (tstream && !tstream->uid_validity) tstream->uid_validity = time (0); /* return sets if doing COPYUID */ if (cu && ret) (*cu) (stream,mailbox,tstream->uid_validity,source,dest); else { /* flush any sets we may have built */ mail_free_searchset (&source); mail_free_searchset (&dest); } tp[1] = time (0); /* set mtime to now */ if (ret) tp[0] = tp[1] - 1; /* set atime to now-1 if successful copy */ else tp[0] = /* else preserve \Marked status */ ((sbuf.st_ctime > sbuf.st_atime) || (sbuf.st_mtime > sbuf.st_atime)) ? sbuf.st_atime : tp[1]; utime (file,tp); /* set the times */ unix_unlock (fd,NIL,&lock); /* unlock and close mailbox */ if (tstream) { /* update last UID if we can */ UNIXLOCAL *local = (UNIXLOCAL *) tstream->local; local->dirty = T; /* do a rewrite */ local->appending = T; /* but not at the cost of marking as old */ tstream = mail_close (tstream); } /* log the error */ if (!ret) MM_LOG (LOCAL->buf,ERROR); /* delete if requested message */ else if (options & CP_MOVE) for (i = 1; i <= stream->nmsgs; i++) if ((elt = mail_elt (stream,i))->sequence) elt->deleted = elt->private.dirty = LOCAL->dirty = T; MM_NOCRITICAL (stream); /* release critical */ return ret; } /* UNIX mail append message from stringstruct * Accepts: MAIL stream * destination mailbox * append callback * data for callback * Returns: T if append successful, else NIL */ #define BUFLEN 8*MAILTMPLEN long unix_append (MAILSTREAM *stream,char *mailbox,append_t af,void *data) { struct stat sbuf; int fd; unsigned long i; char *flags,*date,buf[BUFLEN],tmp[MAILTMPLEN],file[MAILTMPLEN]; time_t tp[2]; FILE *sf,*df; MESSAGECACHE elt; DOTLOCK lock; STRING *message; unsigned long uidlocation = 0; appenduid_t au = (appenduid_t) (mail_parameters (NIL,GET_USERHASNOLIFE,NIL) ? NIL : mail_parameters (NIL,GET_APPENDUID,NIL)); SEARCHSET *dst = au ? mail_newsearchset () : NIL; long ret = LONGT; MAILSTREAM *tstream = NIL; if (!stream) { /* stream specified? */ stream = &unixproto; /* no, default stream to prototype */ for (i = 0; i < NUSERFLAGS && stream->user_flags[i]; ++i) fs_give ((void **) &stream->user_flags[i]); } if (!unix_valid (mailbox)) switch (errno) { case ENOENT: /* no such file? */ if (compare_cstring (mailbox,"INBOX")) { MM_NOTIFY (stream,"[TRYCREATE] Must create mailbox before append",NIL); return NIL; } unix_create (NIL,"INBOX"); /* create empty INBOX */ case 0: /* merely empty file? */ tstream = stream; break; case EACCES: /* file protected */ sprintf (tmp,"Can't access destination: %.80s",mailbox); MM_LOG (tmp,ERROR); return NIL; case EINVAL: sprintf (tmp,"Invalid UNIX-format mailbox name: %.80s",mailbox); MM_LOG (tmp,ERROR); return NIL; default: sprintf (tmp,"Not a UNIX-format mailbox: %.80s",mailbox); MM_LOG (tmp,ERROR); return NIL; } /* get sniffing stream for keywords */ else if (!(tstream = mail_open (NIL,mailbox, OP_READONLY|OP_SILENT|OP_NOKOD|OP_SNIFF))) { sprintf (tmp,"Unable to examine mailbox for APPEND: %.80s",mailbox); MM_LOG (tmp,ERROR); return NIL; } /* get first message */ if (!MM_APPEND (af) (tstream,data,&flags,&date,&message)) return NIL; if (!(sf = tmpfile ())) { /* must have scratch file */ sprintf (tmp,".%lx.%lx",(unsigned long) time (0),(unsigned long)getpid ()); if (!stat (tmp,&sbuf) || !(sf = fopen (tmp,"wb+"))) { sprintf (tmp,"Unable to create scratch file: %.80s",strerror (errno)); MM_LOG (tmp,ERROR); return NIL; } unlink (tmp); } do { /* parse date */ if (!date) rfc822_date (date = tmp); if (!mail_parse_date (&elt,date)) { sprintf (tmp,"Bad date in append: %.80s",date); MM_LOG (tmp,ERROR); } else { /* user wants to suppress time zones? */ if (mail_parameters (NIL,GET_NOTIMEZONES,NIL)) { time_t when = mail_longdate (&elt); date = ctime (&when); /* use traditional date */ } /* use POSIX-style date */ else date = mail_cdate (tmp,&elt); if (!SIZE (message)) MM_LOG ("Append of zero-length message",ERROR); else if (!unix_collect_msg (tstream,sf,flags,date,message)) { sprintf (tmp,"Error writing scratch file: %.80s",strerror (errno)); MM_LOG (tmp,ERROR); } /* get next message */ else if (MM_APPEND (af) (tstream,data,&flags,&date,&message)) continue; } fclose (sf); /* punt scratch file */ return NIL; /* give up */ } while (message); /* until no more messages */ if (fflush (sf)) { sprintf (tmp,"Error finishing scratch file: %.80s",strerror (errno)); MM_LOG (tmp,ERROR); fclose (sf); /* punt scratch file */ return NIL; /* give up */ } i = ftell (sf); /* size of scratch file */ /* close sniffing stream */ if (tstream != stream) tstream = mail_close (tstream); MM_CRITICAL (stream); /* go critical */ /* try to open readwrite for UIDPLUS */ if ((tstream = mail_open_work (&unixdriver,NIL,mailbox, OP_SILENT|OP_NOKOD)) && tstream->rdonly) tstream = mail_close (tstream); if (au && !tstream) { /* wanted an APPENDUID? */ sprintf (tmp,"Unable to re-open mailbox for APPENDUID: %.80s",mailbox); MM_LOG (tmp,WARN); au = NIL; } if (((fd = unix_lock (dummy_file (file,mailbox),O_WRONLY|O_APPEND, (long) mail_parameters (NIL,GET_MBXPROTECTION,NIL), &lock,LOCK_EX)) < 0) || !(df = fdopen (fd,"ab"))) { MM_NOCRITICAL (stream); /* done with critical */ sprintf (tmp,"Can't open append mailbox: %s",strerror (errno)); MM_LOG (tmp,ERROR); return NIL; } fstat (fd,&sbuf); /* get current file size */ rewind (sf); tp[1] = time (0); /* set mtime to now */ /* write all messages */ if (!unix_append_msgs (tstream,sf,df,au ? dst : NIL) || (fflush (df) == EOF) || fsync (fd)) { sprintf (buf,"Message append failed: %s",strerror (errno)); MM_LOG (buf,ERROR); ftruncate (fd,sbuf.st_size); tp[0] = /* preserve \Marked status */ ((sbuf.st_ctime > sbuf.st_atime) || (sbuf.st_mtime > sbuf.st_atime)) ? sbuf.st_atime : tp[1]; ret = NIL; /* return error */ } else tp[0] = tp[1] - 1; /* set atime to now-1 if successful copy */ utime (file,tp); /* set the times */ fclose (sf); /* done with scratch file */ /* force UIDVALIDITY assignment now */ if (tstream && !tstream->uid_validity) tstream->uid_validity = time (0); /* return sets if doing APPENDUID */ if (au && ret) (*au) (mailbox,tstream->uid_validity,dst); else mail_free_searchset (&dst); unix_unlock (fd,NIL,&lock); /* unlock and close mailbox */ fclose (df); /* note that unix_unlock() released the fd */ if (tstream) { /* update last UID if we can */ UNIXLOCAL *local = (UNIXLOCAL *) tstream->local; local->dirty = T; /* do a rewrite */ local->appending = T; /* but not at the cost of marking as old */ tstream = mail_close (tstream); } MM_NOCRITICAL (stream); /* release critical */ return ret; } /* Collect and write single message to append scratch file * Accepts: MAIL stream * scratch file * flags * date * message stringstruct * Returns: NIL if write error, else T */ int unix_collect_msg (MAILSTREAM *stream,FILE *sf,char *flags,char *date, STRING *msg) { unsigned char *s,*t; unsigned long uf; long f = mail_parse_flags (stream,flags,&uf); /* write metadata, note date ends with NL */ if (fprintf (sf,"%ld %lu %s",f,SIZE (msg) + 1,date) < 0) return NIL; while (uf) /* write user flags */ if ((s = stream->user_flags[find_rightmost_bit (&uf)]) && (fprintf (sf," %s",s) < 0)) return NIL; if (putc ('\n',sf) == EOF) return NIL; while (SIZE (msg)) { /* copy text to scratch file */ for (s = (unsigned char *) msg->curpos, t = s + msg->cursize; s < t; ++s) if (!*s) *s = 0x80; /* disallow NUL */ /* write buffered text */ if (fwrite (msg->curpos,1,msg->cursize,sf) == msg->cursize) SETPOS (msg,GETPOS (msg) + msg->cursize); else return NIL; /* failed */ } /* write trailing newline and return */ return (putc ('\n',sf) == EOF) ? NIL : T; } /* Append messages from scratch file to mailbox * Accepts: MAIL stream * source file * destination file * uidset to update if non-NIL * Returns: T if success, NIL if failure */ int unix_append_msgs (MAILSTREAM *stream,FILE *sf,FILE *df,SEARCHSET *set) { int ti,zn,c; long f; unsigned long i,j; char *x,tmp[MAILTMPLEN]; int hdrp = T; /* get message metadata line */ while (fgets (tmp,MAILTMPLEN,sf)) { if (!(isdigit (tmp[0]) && strchr (tmp,'\n'))) return NIL; f = strtol (tmp,&x,10); /* get flags */ if (!((*x++ == ' ') && isdigit (*x))) return NIL; i = strtoul (x,&x,10); /* get message size */ if ((*x++ != ' ') || /* build initial header */ (fprintf (df,"From %s@%s %sStatus: ",myusername(),mylocalhost(),x)<0)|| (f&fSEEN && (putc ('R',df) == EOF)) || (fputs ("\nX-Status: ",df) == EOF) || (f&fDELETED && (putc ('D',df) == EOF)) || (f&fFLAGGED && (putc ('F',df) == EOF)) || (f&fANSWERED && (putc ('A',df) == EOF)) || (f&fDRAFT && (putc ('T',df) == EOF)) || (fputs ("\nX-Keywords:",df) == EOF)) return NIL; /* copy keywords */ while ((c = getc (sf)) != '\n') switch (c) { case EOF: return NIL; default: if (putc (c,df) == EOF) return NIL; } if ((putc ('\n',df) == EOF) || (set && (fprintf (df,"X-UID: %lu\n",++(stream->uid_last)) < 0))) return NIL; for (c = '\n'; i && fgets (tmp,MAILTMPLEN,sf); c = tmp[j-1]) { /* get read line length */ if (i < (j = strlen (tmp))) fatal ("unix_append_msgs overrun"); i -= j; /* number of bytes left */ /* squish out CRs (note also copies NUL) */ for (x = tmp; x = strchr (x,'\r'); --j) memmove (x,x+1,j-(x-tmp)); if (!j) continue; /* do nothing if line emptied */ /* start of line? */ if ((c == '\n')) switch (tmp[0]) { case 'F': /* possible "From " (case counts here) */ if ((j > 4) && (tmp[0] == 'F') && (tmp[1] == 'r') && (tmp[2] == 'o') && (tmp[3] == 'm') && (tmp[4] == ' ')) { if (!unix_fromwidget) { VALID (tmp,x,ti,zn);/* conditional, only write widget if */ if (!ti) break; /* it looks like a valid header */ } /* write the widget */ if (putc ('>',df) == EOF) return NIL; } break; case 'S': case 's': /* possible "Status:" */ if (hdrp && (j > 6) && ((tmp[1] == 't') || (tmp[1] == 'T')) && ((tmp[2] == 'a') || (tmp[2] == 'A')) && ((tmp[3] == 't') || (tmp[3] == 'T')) && ((tmp[4] == 'u') || (tmp[4] == 'U')) && ((tmp[5] == 's') || (tmp[5] == 'S')) && (tmp[6] == ':') && (fputs ("X-Original-",df) == EOF)) return NIL; break; case 'X': case 'x': /* possible X-??? header */ if (hdrp && (tmp[1] == '-') && /* possible X-UID: */ (((j > 5) && ((tmp[2] == 'U') || (tmp[2] == 'u')) && ((tmp[3] == 'I') || (tmp[3] == 'i')) && ((tmp[4] == 'D') || (tmp[4] == 'd')) && (tmp[5] == ':')) || /* possible X-IMAP: */ ((j > 6) && ((tmp[2] == 'I') || (tmp[2] == 'i')) && ((tmp[3] == 'M') || (tmp[3] == 'm')) && ((tmp[4] == 'A') || (tmp[4] == 'a')) && ((tmp[5] == 'P') || (tmp[5] == 'p')) && ((tmp[6] == ':') || /* or X-IMAPbase: */ ((j > 10) && ((tmp[6] == 'b') || (tmp[6] == 'B')) && ((tmp[7] == 'a') || (tmp[7] == 'A')) && ((tmp[8] == 's') || (tmp[8] == 'S')) && ((tmp[9] == 'e') || (tmp[9] == 'E')) && (tmp[10] == ':')))) || /* possible X-Status: */ ((j > 8) && ((tmp[2] == 'S') || (tmp[2] == 's')) && ((tmp[3] == 't') || (tmp[3] == 'T')) && ((tmp[4] == 'a') || (tmp[4] == 'A')) && ((tmp[5] == 't') || (tmp[5] == 'T')) && ((tmp[6] == 'u') || (tmp[6] == 'U')) && ((tmp[7] == 's') || (tmp[7] == 'S')) && (tmp[8] == ':')) || /* possible X-Keywords: */ ((j > 10) && ((tmp[2] == 'K') || (tmp[2] == 'k')) && ((tmp[3] == 'e') || (tmp[3] == 'E')) && ((tmp[4] == 'y') || (tmp[4] == 'Y')) && ((tmp[5] == 'w') || (tmp[5] == 'W')) && ((tmp[6] == 'o') || (tmp[6] == 'O')) && ((tmp[7] == 'r') || (tmp[7] == 'R')) && ((tmp[8] == 'd') || (tmp[8] == 'D')) && ((tmp[9] == 's') || (tmp[9] == 'S')) && (tmp[10] == ':'))) && (fputs ("X-Original-",df) == EOF)) return NIL; case '\n': /* blank line */ hdrp = NIL; break; default: /* nothing to do */ break; } /* just write the line */ if (fwrite (tmp,1,j,df) != j) return NIL; } if (i) return NIL; /* didn't read entire message */ /* update set */ if (stream) mail_append_set (set,stream->uid_last); } return T; } /* Internal routines */ /* UNIX mail abort stream * Accepts: MAIL stream */ void unix_abort (MAILSTREAM *stream) { if (LOCAL) { /* only if a file is open */ if (LOCAL->fd >= 0) close (LOCAL->fd); if (LOCAL->ld >= 0) { /* have a mailbox lock? */ flock (LOCAL->ld,LOCK_UN);/* yes, release the lock */ close (LOCAL->ld); /* close the lock file */ unlink (LOCAL->lname); /* and delete it */ } if (LOCAL->lname) fs_give ((void **) &LOCAL->lname); /* free local text buffers */ if (LOCAL->buf) fs_give ((void **) &LOCAL->buf); if (LOCAL->text.data) fs_give ((void **) &LOCAL->text.data); if (LOCAL->linebuf) fs_give ((void **) &LOCAL->linebuf); if (LOCAL->line) fs_give ((void **) &LOCAL->line); /* nuke the local data */ fs_give ((void **) &stream->local); stream->dtb = NIL; /* log out the DTB */ } } /* UNIX open and lock mailbox * Accepts: file name to open/lock * file open mode * destination buffer for lock file name * type of locking operation (LOCK_SH or LOCK_EX) */ int unix_lock (char *file,int flags,int mode,DOTLOCK *lock,int op) { int fd; blocknotify_t bn = (blocknotify_t) mail_parameters (NIL,GET_BLOCKNOTIFY,NIL); (*bn) (BLOCK_FILELOCK,NIL); /* try locking the easy way */ if (dotlock_lock (file,lock,-1)) { /* got dotlock file, easy open */ if ((fd = open (file,flags,mode)) >= 0) flock (fd,op); else dotlock_unlock (lock); /* open failed, free the dotlock */ } /* no dot lock file, open file now */ else if ((fd = open (file,flags,mode)) >= 0) { /* try paranoid way to make a dot lock file */ if (dotlock_lock (file,lock,fd)) { close (fd); /* get fresh fd in case of timing race */ if ((fd = open (file,flags,mode)) >= 0) flock (fd,op); /* open failed, free the dotlock */ else dotlock_unlock (lock); } else flock (fd,op); /* paranoid way failed, just flock() it */ } (*bn) (BLOCK_NONE,NIL); return fd; } /* UNIX unlock and close mailbox * Accepts: file descriptor * (optional) mailbox stream to check atime/mtime * (optional) lock file name */ void unix_unlock (int fd,MAILSTREAM *stream,DOTLOCK *lock) { if (stream) { /* need to muck with times? */ struct stat sbuf; time_t tp[2]; time_t now = time (0); fstat (fd,&sbuf); /* get file times */ if (LOCAL->ld >= 0) { /* yes, readwrite session? */ tp[0] = now; /* set atime to now */ /* set mtime to (now - 1) if necessary */ tp[1] = (now > sbuf.st_mtime) ? sbuf.st_mtime : now - 1; } else if (stream->recent) { /* readonly with recent messages */ if ((sbuf.st_atime >= sbuf.st_mtime) || (sbuf.st_atime >= sbuf.st_ctime)) /* keep past mtime, whack back atime */ tp[0] = (tp[1] = (sbuf.st_mtime < now) ? sbuf.st_mtime : now) - 1; else now = 0; /* no time change needed */ } /* readonly with no recent messages */ else if ((sbuf.st_atime < sbuf.st_mtime) || (sbuf.st_atime < sbuf.st_ctime)) { tp[0] = now; /* set atime to now */ /* set mtime to (now - 1) if necessary */ tp[1] = (now > sbuf.st_mtime) ? sbuf.st_mtime : now - 1; } else now = 0; /* no time change needed */ /* set the times, note change */ if (now && !utime (stream->mailbox,tp)) LOCAL->filetime = tp[1]; } flock (fd,LOCK_UN); /* release flock'ers */ if (!stream) close (fd); /* close the file if no stream */ dotlock_unlock (lock); /* flush the lock file if any */ } /* UNIX mail parse and lock mailbox * Accepts: MAIL stream * space to write lock file name * type of locking operation * Returns: T if parse OK, critical & mailbox is locked shared; NIL if failure */ int unix_parse (MAILSTREAM *stream,DOTLOCK *lock,int op) { int zn; unsigned long i,j,k,m; unsigned char c,*s,*t,*u,tmp[MAILTMPLEN],date[30]; int ti = 0,retain = T; unsigned long nmsgs = stream->nmsgs; unsigned long prevuid = nmsgs ? mail_elt (stream,nmsgs)->private.uid : 0; unsigned long recent = stream->recent; unsigned long oldnmsgs = stream->nmsgs; short silent = stream->silent; short pseudoseen = NIL; struct stat sbuf; STRING bs; FDDATA d; MESSAGECACHE *elt; mail_lock (stream); /* guard against recursion or pingers */ /* toss out previous descriptor */ if (LOCAL->fd >= 0) close (LOCAL->fd); MM_CRITICAL (stream); /* open and lock mailbox (shared OK) */ if ((LOCAL->fd = unix_lock (stream->mailbox,(LOCAL->ld >= 0) ? O_RDWR : O_RDONLY, (long)mail_parameters(NIL,GET_MBXPROTECTION,NIL), lock,op)) < 0) { sprintf (tmp,"Mailbox open failed, aborted: %s",strerror (errno)); MM_LOG (tmp,ERROR); unix_abort (stream); mail_unlock (stream); MM_NOCRITICAL (stream); /* done with critical */ return NIL; } fstat (LOCAL->fd,&sbuf); /* get status */ /* validate change in size */ if (sbuf.st_size < LOCAL->filesize) { sprintf (tmp,"Mailbox shrank from %lu to %lu bytes, aborted", (unsigned long) LOCAL->filesize,(unsigned long) sbuf.st_size); MM_LOG (tmp,ERROR); /* this is pretty bad */ unix_unlock (LOCAL->fd,stream,lock); unix_abort (stream); mail_unlock (stream); MM_NOCRITICAL (stream); /* done with critical */ return NIL; } /* new data? */ else if (i = sbuf.st_size - LOCAL->filesize) { d.fd = LOCAL->fd; /* yes, set up file descriptor */ d.pos = LOCAL->filesize; /* get to that position in the file */ d.chunk = LOCAL->buf; /* initial buffer chunk */ d.chunksize = CHUNKSIZE; /* file chunk size */ INIT (&bs,fd_string,&d,i); /* initialize stringstruct */ /* skip leading whitespace for broken MTAs */ while (((c = CHR (&bs)) == '\n') || (c == '\r') || (c == ' ') || (c == '\t')) SNX (&bs); if (SIZE (&bs)) { /* read new data */ /* remember internal header position */ j = LOCAL->filesize + GETPOS (&bs); s = unix_mbxline (stream,&bs,&i); t = NIL,zn = 0; if (i) VALID (s,t,ti,zn); /* see if valid From line */ if (!ti) { /* someone pulled the rug from under us */ sprintf (tmp,"Unexpected changes to mailbox (try restarting): %.20s", (char *) s); MM_LOG (tmp,ERROR); unix_unlock (LOCAL->fd,stream,lock); unix_abort (stream); mail_unlock (stream); /* done with critical */ MM_NOCRITICAL (stream); return NIL; } stream->silent = T; /* quell main program new message events */ do { /* found a message */ /* instantiate first new message */ mail_exists (stream,++nmsgs); (elt = mail_elt (stream,nmsgs))->valid = T; recent++; /* assume recent by default */ elt->recent = T; /* note position/size of internal header */ elt->private.special.offset = j; elt->private.msg.header.offset = elt->private.special.text.size = i; /* generate plausible IMAPish date string */ date[2] = date[6] = date[20] = '-'; date[11] = ' '; date[14] = date[17] = ':'; /* dd */ date[0] = t[ti - 2]; date[1] = t[ti - 1]; /* mmm */ date[3] = t[ti - 6]; date[4] = t[ti - 5]; date[5] = t[ti - 4]; /* hh */ date[12] = t[ti + 1]; date[13] = t[ti + 2]; /* mm */ date[15] = t[ti + 4]; date[16] = t[ti + 5]; if (t[ti += 6] == ':') {/* ss */ date[18] = t[++ti]; date[19] = t[++ti]; ti++; /* move to space */ } else date[18] = date[19] = '0'; /* yy -- advance over timezone if necessary */ if (zn == ti) ti += (((t[zn+1] == '+') || (t[zn+1] == '-')) ? 6 : 4); date[7] = t[ti + 1]; date[8] = t[ti + 2]; date[9] = t[ti + 3]; date[10] = t[ti + 4]; /* zzz */ t = zn ? (t + zn + 1) : (unsigned char *) "LCL"; date[21] = *t++; date[22] = *t++; date[23] = *t++; if ((date[21] != '+') && (date[21] != '-')) date[24] = '\0'; else { /* numeric time zone */ date[24] = *t++; date[25] = *t++; date[26] = '\0'; date[20] = ' '; } /* set internal date */ if (!mail_parse_date (elt,date)) { sprintf (tmp,"Unable to parse internal date: %s",(char *) date); MM_LOG (tmp,WARN); } do { /* look for message body */ s = t = unix_mbxline (stream,&bs,&i); if (i) switch (*s) { /* check header lines */ case 'X': /* possible X-???: line */ if (s[1] == '-') { /* must be immediately followed by hyphen */ /* X-Status: becomes Status: in S case */ if (s[2] == 'S' && s[3] == 't' && s[4] == 'a' && s[5] == 't' && s[6] == 'u' && s[7] == 's' && s[8] == ':') s += 2; /* possible X-Keywords */ else if (s[2] == 'K' && s[3] == 'e' && s[4] == 'y' && s[5] == 'w' && s[6] == 'o' && s[7] == 'r' && s[8] == 'd' && s[9] == 's' && s[10] == ':') { SIZEDTEXT uf; retain = NIL; /* don't retain continuation */ s += 11; /* flush leading whitespace */ while (*s && (*s != '\n') && ((*s != '\r') || (s[1] != '\n'))){ while (*s == ' ') s++; /* find end of keyword */ if (!(u = strpbrk (s," \n\r"))) u = s + strlen (s); /* got a keyword? */ if ((k = (u - s)) && (k <= MAXUSERFLAG)) { uf.data = (unsigned char *) s; uf.size = k; for (j = 0; (j < NUSERFLAGS) && stream->user_flags[j]; ++j) if (!compare_csizedtext (stream->user_flags[j],&uf)) { elt->user_flags |= ((long) 1) << j; break; } } s = u; /* advance to next keyword */ } break; } /* possible X-IMAP */ else if ((s[2] == 'I') && (s[3] == 'M') && (s[4] == 'A') && (s[5] == 'P') && ((m = (s[6] == ':')) || ((s[6] == 'b') && (s[7] == 'a') && (s[8] == 's') && (s[9] == 'e') && (s[10] == ':')))) { retain = NIL; /* don't retain continuation */ if ((nmsgs == 1) && !stream->uid_validity) { /* advance to data */ s += m ? 7 : 11; /* flush whitespace */ while (*s == ' ') s++; j = 0; /* slurp UID validity */ /* found a digit? */ while (isdigit (*s)) { j *= 10; /* yes, add it in */ j += *s++ - '0'; } /* flush whitespace */ while (*s == ' ') s++; /* must have valid UID validity and UID last */ if (j && isdigit (*s)) { /* pseudo-header seen if X-IMAP */ if (m) pseudoseen = LOCAL->pseudo = T; /* save UID validity */ stream->uid_validity = j; j = 0; /* slurp UID last */ while (isdigit (*s)) { j *= 10; /* yes, add it in */ j += *s++ - '0'; } /* save UID last */ stream->uid_last = j; /* process keywords */ for (j = 0; (*s != '\n') && ((*s != '\r')||(s[1] != '\n')); s = u,j++) { /* flush leading whitespace */ while (*s == ' ') s++; u = strpbrk (s," \n\r"); /* got a keyword? */ if ((j < NUSERFLAGS) && (k = (u - s)) && (k <= MAXUSERFLAG)) { if (stream->user_flags[j]) fs_give ((void **) &stream->user_flags[j]); stream->user_flags[j] = (char *) fs_get (k + 1); strncpy (stream->user_flags[j],s,k); stream->user_flags[j][k] = '\0'; } } } } break; } /* possible X-UID */ else if (s[2] == 'U' && s[3] == 'I' && s[4] == 'D' && s[5] == ':') { retain = NIL; /* don't retain continuation */ /* only believe if have a UID validity */ if (stream->uid_validity && ((nmsgs > 1) || !pseudoseen)) { s += 6; /* advance to UID value */ /* flush whitespace */ while (*s == ' ') s++; j = 0; /* found a digit? */ while (isdigit (*s)) { j *= 10; /* yes, add it in */ j += *s++ - '0'; } /* flush remainder of line */ while (*s != '\n') s++; /* make sure not duplicated */ if (elt->private.uid) sprintf (tmp,"Message %lu UID %lu already has UID %lu", pseudoseen ? elt->msgno - 1 : elt->msgno, j,elt->private.uid); /* make sure UID doesn't go backwards */ else if (j <= prevuid) sprintf (tmp,"Message %lu UID %lu less than %lu", pseudoseen ? elt->msgno - 1 : elt->msgno, j,prevuid + 1); #if 0 /* this is currently broken by UIDPLUS */ /* or skip by mailbox's recorded last */ else if (j > stream->uid_last) sprintf (tmp,"Message %lu UID %lu greater than last %lu", pseudoseen ? elt->msgno - 1 : elt->msgno, j,stream->uid_last); #endif else { /* normal UID case */ prevuid = elt->private.uid = j; #if 1 /* temporary kludge for UIDPLUS */ if (prevuid > stream->uid_last) { stream->uid_last = prevuid; LOCAL->ddirty = LOCAL->dirty = T; } #endif break; /* exit this cruft */ } MM_LOG (tmp,WARN); /* invalidate UID validity */ stream->uid_validity = 0; elt->private.uid = 0; } break; } } /* otherwise fall into S case */ case 'S': /* possible Status: line */ if (s[0] == 'S' && s[1] == 't' && s[2] == 'a' && s[3] == 't' && s[4] == 'u' && s[5] == 's' && s[6] == ':') { retain = NIL; /* don't retain continuation */ s += 6; /* advance to status flags */ do switch (*s++) {/* parse flags */ case 'R': /* message read */ elt->seen = T; break; case 'O': /* message old */ if (elt->recent) { elt->recent = NIL; recent--; /* it really wasn't recent */ } break; case 'D': /* message deleted */ elt->deleted = T; break; case 'F': /* message flagged */ elt->flagged = T; break; case 'A': /* message answered */ elt->answered = T; break; case 'T': /* message is a draft */ elt->draft = T; break; default: /* some other crap */ break; } while (*s && (*s != '\n') && ((*s != '\r') || (s[1] != '\n'))); break; /* all done */ } /* otherwise fall into default case */ default: /* ordinary header line */ if ((*s == 'S') || (*s == 's') || (((*s == 'X') || (*s == 'x')) && (s[1] == '-'))) { unsigned char *e,*v; /* must match what mail_filter() does */ for (u = s,v = tmp,e = u + min (i,MAILTMPLEN - 1); (u < e) && ((c = (*u ? *u : (*u = ' '))) != ':') && ((c > ' ') || ((c != ' ') && (c != '\t') && (c != '\r') && (c != '\n'))); *v++ = *u++); *v = '\0'; /* tie off */ /* matches internal header? */ if (!compare_cstring (tmp,"STATUS") || !compare_cstring (tmp,"X-STATUS") || !compare_cstring (tmp,"X-KEYWORDS") || !compare_cstring (tmp,"X-UID") || !compare_cstring (tmp,"X-IMAP") || !compare_cstring (tmp,"X-IMAPBASE")) { char err[MAILTMPLEN]; sprintf (err,"Discarding bogus %s header in message %lu", (char *) tmp,elt->msgno); MM_LOG (err,WARN); retain = NIL; /* don't retain continuation */ break; /* different case or something */ } } /* retain or non-continuation? */ if (retain || ((*s != ' ') && (*s != '\t'))) { retain = T; /* retaining continuation now */ /* line length in LF format newline */ for (j = k = 0; j < i; ++j) if (s[j] != '\r') ++k; /* "internal" header size */ elt->private.spare.data += k; /* message size */ elt->rfc822_size += k + 1; } else { char err[MAILTMPLEN]; sprintf (err,"Discarding bogus continuation in msg %lu: %.80s", elt->msgno,(char *) s); if (u = strpbrk (err,"\r\n")) *u = '\0'; MM_LOG (err,WARN); break; /* different case or something */ } break; } } while (i && (*t != '\n') && ((*t != '\r') || (t[1] != '\n'))); /* "internal" header sans trailing newline */ if (i) elt->private.spare.data--; /* assign a UID if none found */ if (((nmsgs > 1) || !pseudoseen) && !elt->private.uid) { prevuid = elt->private.uid = ++stream->uid_last; elt->private.dirty = T; LOCAL->ddirty = T; /* force update */ } else elt->private.dirty = elt->recent; /* note size of header, location of text */ elt->private.msg.header.text.size = (elt->private.msg.text.offset = (LOCAL->filesize + GETPOS (&bs)) - elt->private.special.offset) - elt->private.special.text.size; k = m = 0; /* no previous line size yet */ /* note current position */ j = LOCAL->filesize + GETPOS (&bs); if (i) do { /* look for next message */ s = unix_mbxline (stream,&bs,&i); if (i) { /* got new data? */ VALID (s,t,ti,zn); /* yes, parse line */ if (!ti) { /* not a header line, add it to message */ elt->rfc822_size += i; for (j = 0; j < i; ++j) switch (s[j]) { case '\r': /* squeeze out CRs */ elt->rfc822_size -= 1; break; case '\n': /* LF becomes CRLF */ elt->rfc822_size += 1; break; default: break; } if ((i == 1) && (*s == '\n')) { k = 2; m = 1; } else if ((i == 2) && (*s == '\r') && (s[1] == '\n')) k = m = 2; else k = m = 0; /* file does not end with newline! */ /* update current position */ j = LOCAL->filesize + GETPOS (&bs); } } } while (i && !ti); /* until found a header */ elt->private.msg.text.text.size = j - (elt->private.special.offset + elt->private.msg.text.offset); /* flush ending blank line */ elt->private.msg.text.text.size -= m; elt->rfc822_size -= k; /* until end of buffer */ } while (!stream->sniff && i); if (pseudoseen) { /* flush pseudo-message if present */ /* decrement recent count */ if (mail_elt (stream,1)->recent) recent--; /* and the exists count */ mail_exists (stream,nmsgs--); mail_expunged(stream,1);/* fake an expunge of that message */ } /* need to start a new UID validity? */ if (!stream->uid_validity) { stream->uid_validity = time (0); /* in case a whiner with no life */ if (mail_parameters (NIL,GET_USERHASNOLIFE,NIL)) stream->uid_nosticky = T; else if (nmsgs) { /* don't bother if empty file */ /* make dirty to restart UID epoch */ LOCAL->ddirty = LOCAL->dirty = T; /* need to rewrite msg 1 if not pseudo */ if (!LOCAL->pseudo) mail_elt (stream,1)->private.dirty = T; MM_LOG ("Assigning new unique identifiers to all messages",NIL); } } stream->nmsgs = oldnmsgs; /* whack it back down */ stream->silent = silent; /* restore old silent setting */ /* notify upper level of new mailbox sizes */ mail_exists (stream,nmsgs); mail_recent (stream,recent); /* mark dirty so O flags are set */ if (recent) LOCAL->dirty = T; } } /* no change, don't babble if never got time */ else if (LOCAL->filetime && LOCAL->filetime != sbuf.st_mtime) MM_LOG ("New mailbox modification time but apparently no changes",WARN); /* update parsed file size and time */ LOCAL->filesize = sbuf.st_size; LOCAL->filetime = sbuf.st_mtime; return T; /* return the winnage */ } /* UNIX read line from mailbox * Accepts: mail stream * stringstruct * pointer to line size * Returns: pointer to input line */ char *unix_mbxline (MAILSTREAM *stream,STRING *bs,unsigned long *size) { unsigned long i,j,k,m; char *s,*t,*te; char *ret = ""; /* flush old buffer */ if (LOCAL->line) fs_give ((void **) &LOCAL->line); /* if buffer needs refreshing */ if (!bs->cursize) SETPOS (bs,GETPOS (bs)); if (SIZE (bs)) { /* find newline */ /* end of fast scan */ te = (t = (s = bs->curpos) + bs->cursize) - 12; while (s < te) if ((*s++ == '\n') || (*s++ == '\n') || (*s++ == '\n') || (*s++ == '\n') || (*s++ == '\n') || (*s++ == '\n') || (*s++ == '\n') || (*s++ == '\n') || (*s++ == '\n') || (*s++ == '\n') || (*s++ == '\n') || (*s++ == '\n')) { --s; /* back up */ break; /* exit loop */ } /* final character-at-a-time scan */ while ((s < t) && (*s != '\n')) ++s; /* difficult case if line spans buffer */ if ((i = s - bs->curpos) == bs->cursize) { /* have space in line buffer? */ if (i > LOCAL->linebuflen) { fs_give ((void **) &LOCAL->linebuf); LOCAL->linebuf = (char *) fs_get (LOCAL->linebuflen = i); } /* remember what we have so far */ memcpy (LOCAL->linebuf,bs->curpos,i); /* load next buffer */ SETPOS (bs,k = GETPOS (bs) + i); /* end of fast scan */ te = (t = (s = bs->curpos) + bs->cursize) - 12; /* fast scan in overlap buffer */ while (s < te) if ((*s++ == '\n') || (*s++ == '\n') || (*s++ == '\n') || (*s++ == '\n') || (*s++ == '\n') || (*s++ == '\n') || (*s++ == '\n') || (*s++ == '\n') || (*s++ == '\n') || (*s++ == '\n') || (*s++ == '\n') || (*s++ == '\n')) { --s; /* back up */ break; /* exit loop */ } /* final character-at-a-time scan */ while ((s < t) && (*s != '\n')) ++s; /* huge line? */ if ((j = s - bs->curpos) == bs->cursize) { SETPOS (bs,GETPOS (bs) + j); /* look for end of line (s-l-o-w!!) */ for (m = SIZE (bs); m && (SNX (bs) != '\n'); --m,++j); SETPOS (bs,k); /* go back to where it started */ } /* got size of data, make buffer for return */ ret = LOCAL->line = (char *) fs_get (i + j + 2); /* copy first chunk */ memcpy (ret,LOCAL->linebuf,i); while (j) { /* copy remainder */ if (!bs->cursize) SETPOS (bs,GETPOS (bs)); memcpy (ret + i,bs->curpos,k = min (j,bs->cursize)); i += k; /* account for this much read in */ j -= k; bs->curpos += k; /* increment new position */ bs->cursize -= k; /* eat that many bytes */ } if (!bs->cursize) SETPOS (bs,GETPOS (bs)); /* read newline at end */ if (SIZE (bs)) ret[i++] = SNX (bs); ret[i] = '\0'; /* makes debugging easier */ } else { /* this is easy */ ret = bs->curpos; /* string it at this position */ bs->curpos += ++i; /* increment new position */ bs->cursize -= i; /* eat that many bytes */ } *size = i; /* return that to user */ } else *size = 0; /* end of data, return empty */ return ret; } /* UNIX make pseudo-header * Accepts: MAIL stream * buffer to write pseudo-header * Returns: length of pseudo-header */ unsigned long unix_pseudo (MAILSTREAM *stream,char *hdr) { int i; char *s,tmp[MAILTMPLEN]; time_t now = time (0); rfc822_fixed_date (tmp); sprintf (hdr,"From %s %.24s\nDate: %s\nFrom: %s <%s@%.80s>\nSubject: %s\nMessage-ID: <%lu@%.80s>\nX-IMAP: %010lu %010lu", pseudo_from,ctime (&now), tmp,pseudo_name,pseudo_from,mylocalhost (),pseudo_subject, (unsigned long) now,mylocalhost (),stream->uid_validity, stream->uid_last); for (s = hdr + strlen (hdr),i = 0; i < NUSERFLAGS; ++i) if (stream->user_flags[i]) sprintf (s += strlen (s)," %s",stream->user_flags[i]); sprintf (s += strlen (s),"\nStatus: RO\n\n%s\n\n",pseudo_msg); return strlen (hdr); /* return header length */ } /* UNIX make status string * Accepts: MAIL stream * destination string to write * message cache entry * UID to write if non-zero (else use elt->private.uid) * non-zero flag to write UID (.LT. 0 to write UID base info too) * Returns: length of string */ unsigned long unix_xstatus (MAILSTREAM *stream,char *status,MESSAGECACHE *elt, unsigned long uid,long flag) { char *t,stack[64]; char *s = status; unsigned long n; int pad = 50; int sticky = uid ? T : !stream->uid_nosticky; /* This used to use sprintf(), but thanks to certain cretinous C libraries with horribly slow implementations of sprintf() I had to change it to this mess. At least it should be fast. */ if ((flag < 0) && sticky) { /* need to write X-IMAPbase: header? */ *s++ = 'X'; *s++ = '-'; *s++ = 'I'; *s++ = 'M'; *s++ = 'A'; *s++ = 'P'; *s++ = 'b'; *s++ = 'a'; *s++ = 's'; *s++ = 'e'; *s++ = ':'; *s++ = ' '; t = stack; n = stream->uid_validity; /* push UID validity digits on the stack */ do *t++ = (char) (n % 10) + '0'; while (n /= 10); /* pop UID validity digits from stack */ while (t > stack) *s++ = *--t; *s++ = ' '; n = stream->uid_last; /* push UID last digits on the stack */ do *t++ = (char) (n % 10) + '0'; while (n /= 10); /* pop UID last digits from stack */ while (t > stack) *s++ = *--t; for (n = 0; n < NUSERFLAGS; ++n) if (t = stream->user_flags[n]) for (*s++ = ' '; *t; *s++ = *t++); *s++ = '\n'; pad += 30; /* increased padding if have IMAPbase */ } *s++ = 'S'; *s++ = 't'; *s++ = 'a'; *s++ = 't'; *s++ = 'u'; *s++ = 's'; *s++ = ':'; *s++ = ' '; if (elt->seen) *s++ = 'R'; /* only write O if have a UID */ if (flag && (!elt->recent || !LOCAL->appending)) *s++ = 'O'; *s++ = '\n'; *s++ = 'X'; *s++ = '-'; *s++ = 'S'; *s++ = 't'; *s++ = 'a'; *s++ = 't'; *s++ = 'u'; *s++ = 's'; *s++ = ':'; *s++ = ' '; if (elt->deleted) *s++ = 'D'; if (elt->flagged) *s++ = 'F'; if (elt->answered) *s++ = 'A'; if (elt->draft) *s++ = 'T'; *s++ = '\n'; if (sticky) { /* only do this if UIDs sticky */ *s++ = 'X'; *s++ = '-'; *s++ = 'K'; *s++ = 'e'; *s++ = 'y'; *s++ = 'w'; *s++ = 'o'; *s++ = 'r'; *s++ = 'd'; *s++ = 's'; *s++ = ':'; if (n = elt->user_flags) do { *s++ = ' '; for (t = stream->user_flags[find_rightmost_bit (&n)]; *t; *s++ = *t++); } while (n); n = s - status; /* get size of stuff so far */ /* pad X-Keywords to make size constant */ if (n < pad) for (n = pad - n; n > 0; --n) *s++ = ' '; *s++ = '\n'; if (flag) { /* want to include UID? */ t = stack; /* push UID digits on the stack */ n = uid ? uid : elt->private.uid; do *t++ = (char) (n % 10) + '0'; while (n /= 10); *s++ = 'X'; *s++ = '-'; *s++ = 'U'; *s++ = 'I'; *s++ = 'D'; *s++ = ':'; *s++ = ' '; /* pop UID from stack */ while (t > stack) *s++ = *--t; *s++ = '\n'; } } *s++ = '\n'; *s = '\0'; /* end of extended message status */ return s - status; /* return size of resulting string */ } /* Rewrite mailbox file * Accepts: MAIL stream, must be critical and locked * return pointer to number of expunged messages if want expunge * lock file name * expunge sequence, not deleted flag * Returns: T if success and mailbox unlocked, NIL if failure */ #define OVERFLOWBUFLEN 8192 /* initial overflow buffer length */ long unix_rewrite (MAILSTREAM *stream,unsigned long *nexp,DOTLOCK *lock, long flags) { MESSAGECACHE *elt; UNIXFILE f; char *s; time_t tp[2]; long ret,flag; unsigned long i,j; unsigned long recent = stream->recent; unsigned long size = LOCAL->pseudo ? unix_pseudo (stream,LOCAL->buf) : 0; if (nexp) *nexp = 0; /* initially nothing expunged */ /* calculate size of mailbox after rewrite */ for (i = 1,flag = LOCAL->pseudo ? 1 : -1; i <= stream->nmsgs; i++) { elt = mail_elt (stream,i); /* get cache */ if (!(nexp && elt->deleted && (flags ? elt->sequence : T))) { /* add RFC822 size of this message */ size += elt->private.special.text.size + elt->private.spare.data + unix_xstatus (stream,LOCAL->buf,elt,NIL,flag) + elt->private.msg.text.text.size + 1; flag = 1; /* only count X-IMAPbase once */ } } /* no messages, has a life, and no pseudo */ if (!size && !mail_parameters (NIL,GET_USERHASNOLIFE,NIL)) { LOCAL->pseudo = T; /* so make a pseudo-message now */ size = unix_pseudo (stream,LOCAL->buf); } /* extend the file as necessary */ if (ret = unix_extend (stream,size)) { /* Set up buffered I/O file structure * curpos current position being written through buffering * filepos current position being written physically to the disk * bufpos current position being written in the buffer * protect current maximum position that can be written to the disk * before buffering is forced * The code tries to buffer so that that disk is written in multiples of * OVERBLOWBUFLEN bytes. */ f.stream = stream; /* note mail stream */ f.curpos = f.filepos = 0; /* start of file */ f.protect = stream->nmsgs ? /* initial protection pointer */ mail_elt (stream,1)->private.special.offset : 8192; f.bufpos = f.buf = (char *) fs_get (f.buflen = OVERFLOWBUFLEN); if (LOCAL->pseudo) /* update pseudo-header */ unix_write (&f,LOCAL->buf,unix_pseudo (stream,LOCAL->buf)); /* loop through all messages */ for (i = 1,flag = LOCAL->pseudo ? 1 : -1; i <= stream->nmsgs;) { elt = mail_elt (stream,i);/* get cache */ /* expunge this message? */ if (nexp && elt->deleted && (flags ? elt->sequence : T)) { /* one less recent message */ if (elt->recent) --recent; mail_expunged(stream,i);/* notify upper levels */ ++*nexp; /* count up one more expunged message */ } else { /* preserve this message */ i++; /* advance to next message */ if ((flag < 0) || /* need to rewrite message? */ elt->private.dirty || (f.curpos != elt->private.special.offset) || (elt->private.msg.header.text.size != (elt->private.spare.data + unix_xstatus (stream,LOCAL->buf,elt,NIL,flag)))) { unsigned long newoffset = f.curpos; /* yes, seek to internal header */ lseek (LOCAL->fd,elt->private.special.offset,L_SET); read (LOCAL->fd,LOCAL->buf,elt->private.special.text.size); /* see if need to squeeze out a CR */ if (LOCAL->buf[elt->private.special.text.size - 2] == '\r') { LOCAL->buf[--elt->private.special.text.size - 1] = '\n'; --size; /* squeezed out a CR from PC */ } /* protection pointer moves to RFC822 header */ f.protect = elt->private.special.offset + elt->private.msg.header.offset; /* write internal header */ unix_write (&f,LOCAL->buf,elt->private.special.text.size); /* get RFC822 header */ s = unix_header (stream,elt->msgno,&j,FT_INTERNAL); /* in case this got decremented */ elt->private.msg.header.offset = elt->private.special.text.size; /* header size, sans trailing newline */ if ((j < 2) || (s[j - 2] == '\n')) j--; /* this can happen if CRs were squeezed */ if (j < elt->private.spare.data) { /* so fix up counts */ size -= elt->private.spare.data - j; elt->private.spare.data = j; } else if (j != elt->private.spare.data) fatal ("header size inconsistent"); /* protection pointer moves to RFC822 text */ f.protect = elt->private.special.offset + elt->private.msg.text.offset; unix_write (&f,s,j); /* write RFC822 header */ /* write status and UID */ unix_write (&f,LOCAL->buf, j = unix_xstatus (stream,LOCAL->buf,elt,NIL,flag)); flag = 1; /* only write X-IMAPbase once */ /* new file header size */ elt->private.msg.header.text.size = elt->private.spare.data + j; /* did text move? */ if (f.curpos != f.protect) { /* get message text */ s = unix_text_work (stream,elt,&j,FT_INTERNAL); /* this can happen if CRs were squeezed */ if (j < elt->private.msg.text.text.size) { /* so fix up counts */ size -= elt->private.msg.text.text.size - j; elt->private.msg.text.text.size = j; } /* can't happen it says here */ else if (j > elt->private.msg.text.text.size) fatal ("text size inconsistent"); /* new text offset, status/UID may change it */ elt->private.msg.text.offset = f.curpos - newoffset; /* protection pointer moves to next message */ f.protect = (i <= stream->nmsgs) ? mail_elt (stream,i)->private.special.offset : (f.curpos + j + 1); unix_write (&f,s,j);/* write text */ /* write trailing newline */ unix_write (&f,"\n",1); } else { /* tie off header and status */ unix_write (&f,NIL,NIL); /* protection pointer moves to next message */ f.protect = (i <= stream->nmsgs) ? mail_elt (stream,i)->private.special.offset : size; /* locate end of message text */ j = f.filepos + elt->private.msg.text.text.size; /* trailing newline already there? */ if (f.protect == (j + 1)) f.curpos = f.filepos = f.protect; else { /* trailing newline missing, write it */ f.curpos = f.filepos = j; unix_write (&f,"\n",1); } } /* new internal header offset */ elt->private.special.offset = newoffset; elt->private.dirty =NIL;/* message is now clean */ } else { /* no need to rewrite this message */ /* tie off previous message if needed */ unix_write (&f,NIL,NIL); /* protection pointer moves to next message */ f.protect = (i <= stream->nmsgs) ? mail_elt (stream,i)->private.special.offset : size; /* locate end of message text */ j = f.filepos + elt->private.special.text.size + elt->private.msg.header.text.size + elt->private.msg.text.text.size; /* trailing newline already there? */ if (f.protect == (j + 1)) f.curpos = f.filepos = f.protect; else { /* trailing newline missing, write it */ f.curpos = f.filepos = j; unix_write (&f,"\n",1); } } } } unix_write (&f,NIL,NIL); /* tie off final message */ if (size != f.filepos) fatal ("file size inconsistent"); fs_give ((void **) &f.buf); /* free buffer */ /* make sure tied off */ ftruncate (LOCAL->fd,LOCAL->filesize = size); fsync (LOCAL->fd); /* make sure the updates take */ if (size && (flag < 0)) fatal ("lost UID base information"); /* no longer dirty */ LOCAL->ddirty = LOCAL->dirty = NIL; /* notify upper level of new mailbox sizes */ mail_exists (stream,stream->nmsgs); mail_recent (stream,recent); /* set atime to now, mtime a second earlier */ tp[1] = (tp[0] = time (0)) - 1; /* set the times, note change */ if (!utime (stream->mailbox,tp)) LOCAL->filetime = tp[1]; close (LOCAL->fd); /* close and reopen file */ if ((LOCAL->fd = open (stream->mailbox,O_RDWR, (long) mail_parameters (NIL,GET_MBXPROTECTION,NIL))) < 0) { sprintf (LOCAL->buf,"Mailbox open failed, aborted: %s",strerror (errno)); MM_LOG (LOCAL->buf,ERROR); unix_abort (stream); } dotlock_unlock (lock); /* flush the lock file */ } return ret; /* return state from algorithm */ } /* Extend UNIX mailbox file * Accepts: MAIL stream * new desired size * Return: T if success, else NIL */ long unix_extend (MAILSTREAM *stream,unsigned long size) { unsigned long i = (size > LOCAL->filesize) ? size - LOCAL->filesize : 0; if (i) { /* does the mailbox need to grow? */ if (i > LOCAL->buflen) { /* make sure have enough space */ /* this user won the lottery all right */ fs_give ((void **) &LOCAL->buf); LOCAL->buf = (char *) fs_get ((LOCAL->buflen = i) + 1); } memset (LOCAL->buf,'\0',i); /* get a block of nulls */ while (T) { /* until write successful or punt */ lseek (LOCAL->fd,LOCAL->filesize,L_SET); if ((write (LOCAL->fd,LOCAL->buf,i) >= 0) && !fsync (LOCAL->fd)) break; else { long e = errno; /* note error before doing ftruncate */ ftruncate (LOCAL->fd,LOCAL->filesize); if (MM_DISKERROR (stream,e,NIL)) { fsync (LOCAL->fd); /* user chose to punt */ sprintf (LOCAL->buf,"Unable to extend mailbox: %s",strerror (e)); if (!stream->silent) MM_LOG (LOCAL->buf,ERROR); return NIL; } } } } return LONGT; } /* Write data to buffered file * Accepts: buffered file pointer * file data or NIL to indicate "flush buffer" * date size (ignored for "flush buffer") * Does not return until success */ void unix_write (UNIXFILE *f,char *buf,unsigned long size) { unsigned long i,j,k; if (buf) { /* doing buffered write? */ i = f->bufpos - f->buf; /* yes, get size of current buffer data */ /* yes, have space in current buffer chunk? */ if (j = i ? ((f->buflen - i) % OVERFLOWBUFLEN) : f->buflen) { /* yes, fill up buffer as much as we can */ memcpy (f->bufpos,buf,k = min (j,size)); f->bufpos += k; /* new buffer position */ f->curpos += k; /* new current position */ if (j -= k) return; /* all done if still have buffer free space */ buf += k; /* full, get new unwritten data pointer */ size -= k; /* new data size */ i += k; /* new buffer data size */ } /* This chunk of the buffer is full. See if can make some space by * writing to the disk, if there's enough unprotected space to do so. * Try to fill out any unaligned chunk, along with any subsequent full * chunks that will fit in unprotected space. */ /* any unprotected space we can write to? */ if (j = min (i,f->protect - f->filepos)) { /* yes, filepos not at chunk boundary? */ if ((k = f->filepos % OVERFLOWBUFLEN) && ((k = OVERFLOWBUFLEN - k) < j)) j -= k; /* yes, and can write out partial chunk */ else k = 0; /* no partial chunk to write */ /* if at least a chunk free, write that too */ if (j > OVERFLOWBUFLEN) k += j - (j % OVERFLOWBUFLEN); if (k) { /* write data if there is anything we can */ unix_phys_write (f,f->buf,k); /* slide buffer */ if (i -= k) memmove (f->buf,f->buf + k,i); f->bufpos = f->buf + i; /* new end of buffer */ } } /* Have flushed the buffer as best as possible. All done if no more * data to write. Otherwise, if the buffer is empty AND if the unwritten * data is larger than a chunk AND the unprotected space is also larger * than a chunk, then write as many chunks as we can directly from the * data. Buffer the rest, expanding the buffer as needed. */ if (size) { /* have more data that we need to buffer? */ /* can write any of it to disk instead? */ if ((f->bufpos == f->buf) && ((j = min (f->protect - f->filepos,size)) > OVERFLOWBUFLEN)) { /* write as much as we can right now */ unix_phys_write (f,buf,j -= (j % OVERFLOWBUFLEN)); buf += j; /* new data pointer */ size -= j; /* new data size */ f->curpos += j; /* advance current pointer */ } if (size) { /* still have data that we need to buffer? */ /* yes, need to expand the buffer? */ if ((i = ((f->bufpos + size) - f->buf)) > f->buflen) { /* note current position in buffer */ j = f->bufpos - f->buf; i += OVERFLOWBUFLEN; /* yes, grow another chunk */ fs_resize ((void **) &f->buf,f->buflen = i - (i % OVERFLOWBUFLEN)); /* in case buffer relocated */ f->bufpos = f->buf + j; } /* buffer remaining data */ memcpy (f->bufpos,buf,size); f->bufpos += size; /* new end of buffer */ f->curpos += size; /* advance current pointer */ } } } else { /* flush buffer to disk */ unix_phys_write (f,f->buf,i = f->bufpos - f->buf); f->bufpos = f->buf; /* reset buffer */ /* update positions */ f->curpos = f->protect = f->filepos; } } /* Physical disk write * Accepts: buffered file pointer * buffer address * buffer size * Does not return until success */ void unix_phys_write (UNIXFILE *f,char *buf,size_t size) { MAILSTREAM *stream = f->stream; /* write data at desired position */ while (size && ((lseek (LOCAL->fd,f->filepos,L_SET) < 0) || (write (LOCAL->fd,buf,size) < 0))) { int e; char tmp[MAILTMPLEN]; sprintf (tmp,"Unable to write to mailbox: %s",strerror (e = errno)); MM_LOG (tmp,ERROR); MM_DISKERROR (NIL,e,T); /* serious problem, must retry */ } f->filepos += size; /* update file position */ } /* MBOX mail routines */ /* Driver dispatch used by MAIL */ DRIVER mboxdriver = { "mbox", /* driver name */ /* driver flags */ DR_LOCAL|DR_MAIL|DR_LOCKING|DR_NONEWMAILRONLY, (DRIVER *) NIL, /* next driver */ mbox_valid, /* mailbox is valid for us */ unix_parameters, /* manipulate parameters */ unix_scan, /* scan mailboxes */ unix_list, /* find mailboxes */ unix_lsub, /* find subscribed mailboxes */ NIL, /* subscribe to mailbox */ NIL, /* unsubscribe from mailbox */ mbox_create, /* create mailbox */ mbox_delete, /* delete mailbox */ mbox_rename, /* rename mailbox */ mbox_status, /* status of mailbox */ mbox_open, /* open mailbox */ unix_close, /* close mailbox */ NIL, /* fetch message "fast" attributes */ NIL, /* fetch message flags */ NIL, /* fetch overview */ NIL, /* fetch message structure */ unix_header, /* fetch message header */ unix_text, /* fetch message body */ NIL, /* fetch partial message text */ NIL, /* unique identifier */ NIL, /* message number */ NIL, /* modify flags */ unix_flagmsg, /* per-message modify flags */ NIL, /* search for message based on criteria */ NIL, /* sort messages */ NIL, /* thread messages */ mbox_ping, /* ping mailbox to see if still alive */ mbox_check, /* check for new messages */ mbox_expunge, /* expunge deleted messages */ unix_copy, /* copy messages to another mailbox */ mbox_append, /* append string message to mailbox */ NIL /* garbage collect stream */ }; /* prototype stream */ MAILSTREAM mboxproto = {&mboxdriver}; /* MBOX mail validate mailbox * Accepts: mailbox name * Returns: our driver if name is valid, NIL otherwise */ DRIVER *mbox_valid (char *name) { /* only INBOX, mbox must exist */ if (!compare_cstring (name,"INBOX") && (unix_valid ("mbox") || !errno) && (unix_valid (sysinbox()) || !errno || (errno == ENOENT))) return &mboxdriver; return NIL; /* can't win (yet, anyway) */ } /* MBOX mail create mailbox * Accepts: MAIL stream * mailbox name to create * Returns: T on success, NIL on failure */ long mbox_create (MAILSTREAM *stream,char *mailbox) { char tmp[MAILTMPLEN]; if (!compare_cstring (mailbox,"INBOX")) return unix_create (NIL,"mbox"); sprintf (tmp,"Can't create non-INBOX name as mbox: %.80s",mailbox); MM_LOG (tmp,ERROR); return NIL; } /* MBOX mail delete mailbox * Accepts: MAIL stream * mailbox name to delete * Returns: T on success, NIL on failure */ long mbox_delete (MAILSTREAM *stream,char *mailbox) { return mbox_rename (stream,mailbox,NIL); } /* MBOX mail rename mailbox * Accepts: MAIL stream * old mailbox name * new mailbox name (or NIL for delete) * Returns: T on success, NIL on failure */ long mbox_rename (MAILSTREAM *stream,char *old,char *newname) { char tmp[MAILTMPLEN]; long ret = unix_rename (stream,"~/mbox",newname); /* recreate file if renamed INBOX */ if (ret) unix_create (NIL,"mbox"); else MM_LOG (tmp,ERROR); /* log error */ return ret; /* return success */ } /* MBOX Mail status * Accepts: mail stream * mailbox name * status flags * Returns: T on success, NIL on failure */ long mbox_status (MAILSTREAM *stream,char *mbx,long flags) { MAILSTATUS status; unsigned long i; MAILSTREAM *tstream = NIL; MAILSTREAM *systream = NIL; /* make temporary stream (unless this mbx) */ if (!stream && !(stream = tstream = mail_open (NIL,mbx,OP_READONLY|OP_SILENT))) return NIL; status.flags = flags; /* return status values */ status.messages = stream->nmsgs; status.recent = stream->recent; if (flags & SA_UNSEEN) /* must search to get unseen messages */ for (i = 1,status.unseen = 0; i <= stream->nmsgs; i++) if (!mail_elt (stream,i)->seen) status.unseen++; status.uidnext = stream->uid_last + 1; status.uidvalidity = stream->uid_validity; if (!status.recent && /* calculate post-snarf results */ (systream = mail_open (NIL,sysinbox (),OP_READONLY|OP_SILENT))) { status.messages += systream->nmsgs; status.recent += systream->recent; if (flags & SA_UNSEEN) /* must search to get unseen messages */ for (i = 1; i <= systream->nmsgs; i++) if (!mail_elt (systream,i)->seen) status.unseen++; /* kludge but probably good enough */ status.uidnext += systream->nmsgs; } MM_STATUS(stream,mbx,&status);/* pass status to main program */ if (tstream) mail_close (tstream); if (systream) mail_close (systream); return T; /* success */ } /* MBOX mail open * Accepts: stream to open * Returns: stream on success, NIL on failure */ MAILSTREAM *mbox_open (MAILSTREAM *stream) { unsigned long i = 1; unsigned long recent = 0; /* return prototype for OP_PROTOTYPE call */ if (!stream) return &mboxproto; /* change mailbox file name */ fs_give ((void **) &stream->mailbox); stream->mailbox = cpystr ("mbox"); /* open mailbox, snarf new mail */ if (!(unix_open (stream) && mbox_ping (stream))) return NIL; stream->inbox = T; /* mark that this is an INBOX */ /* notify upper level of mailbox sizes */ mail_exists (stream,stream->nmsgs); while (i <= stream->nmsgs) if (mail_elt (stream,i++)->recent) ++recent; mail_recent (stream,recent); /* including recent messages */ return stream; } /* MBOX mail ping mailbox * Accepts: MAIL stream * Returns: T if stream alive, else NIL * No-op for readonly files, since read/writer can expunge it from under us! */ static int snarfed = 0; /* number of snarfs */ long mbox_ping (MAILSTREAM *stream) { int sfd; unsigned long size; struct stat sbuf; char *s; DOTLOCK lock,lockx; /* time to try snarf and sysinbox non-empty? */ if (LOCAL && !stream->rdonly && !stream->lock && (time (0) >= (LOCAL->lastsnarf + (long) mail_parameters (NIL,GET_SNARFINTERVAL,NIL))) && !stat (sysinbox (),&sbuf) && sbuf.st_size) { MM_CRITICAL (stream); /* yes, go critical */ /* open and lock sysinbox */ if ((sfd = unix_lock (sysinbox (),O_RDWR, (long) mail_parameters (NIL,GET_MBXPROTECTION,NIL), &lockx,LOCK_EX)) >= 0) { /* locked sysinbox in good format? */ if (fstat (sfd,&sbuf) || !(size = sbuf.st_size) || !unix_isvalid_fd (sfd)) { sprintf (LOCAL->buf,"Mail drop %s is not in standard Unix format", sysinbox ()); MM_LOG (LOCAL->buf,ERROR); } /* sysinbox good, parse and excl-lock mbox */ else if (unix_parse (stream,&lock,LOCK_EX)) { lseek (sfd,0,L_SET); /* read entire sysinbox into memory */ read (sfd,s = (char *) fs_get (size + 1),size); s[size] = '\0'; /* tie it off */ /* append to end of mbox */ lseek (LOCAL->fd,LOCAL->filesize,L_SET); /* copy to mbox */ if ((write (LOCAL->fd,s,size) < 0) || fsync (LOCAL->fd)) { sprintf (LOCAL->buf,"New mail move failed: %s",strerror (errno)); MM_LOG (LOCAL->buf,WARN); /* revert mbox to previous size */ ftruncate (LOCAL->fd,LOCAL->filesize); } /* sysinbox better not have changed */ else if (fstat (sfd,&sbuf) || (size != sbuf.st_size)) { sprintf (LOCAL->buf,"Mail drop %s lock failure, old=%lu now=%lu", sysinbox (),size,(unsigned long) sbuf.st_size); MM_LOG (LOCAL->buf,ERROR); /* revert mbox to previous size */ ftruncate (LOCAL->fd,LOCAL->filesize); /* Believe it or not, a Singaporean government system actually had * symlinks from /var/mail/user to ~user/mbox. To compound this * error, they used an SVR4 system; BSD and OSF locks would have * prevented it but not SVR4 locks. */ if (!fstat (sfd,&sbuf) && (size == sbuf.st_size)) syslog (LOG_ALERT,"File %s and %s are the same file!", sysinbox (),stream->mailbox); } else { /* data copied OK */ ftruncate (sfd,0); /* truncate sysinbox to zero bytes */ if (!snarfed++) { /* have we snarfed before? */ /* syslog if server, else user log */ sprintf (LOCAL->buf,"Moved %lu bytes of new mail to %s from %s", size,stream->mailbox,sysinbox ()); if (strcmp ((char *) mail_parameters (NIL,GET_SERVICENAME,NIL), "unknown")) syslog (LOG_INFO,"%s host= %s",LOCAL->buf,tcp_clienthost ()); else MM_LOG (LOCAL->buf,WARN); } } /* done with sysinbox text */ fs_give ((void **) &s); /* all done with mbox */ unix_unlock (LOCAL->fd,stream,&lock); mail_unlock (stream); /* unlock the stream */ MM_NOCRITICAL (stream); /* done with critical */ } /* all done with sysinbox */ unix_unlock (sfd,NIL,&lockx); } MM_NOCRITICAL (stream); /* done with critical */ LOCAL->lastsnarf = time (0);/* note time of last snarf */ } return unix_ping (stream); /* do the unix routine now */ } /* MBOX mail check mailbox * Accepts: MAIL stream */ void mbox_check (MAILSTREAM *stream) { /* do local ping, then do unix routine */ if (mbox_ping (stream)) unix_check (stream); } /* MBOX mail expunge mailbox * Accepts: MAIL stream * sequence to expunge if non-NIL * expunge options * Returns: T, always */ long mbox_expunge (MAILSTREAM *stream,char *sequence,long options) { long ret = unix_expunge (stream,sequence,options); mbox_ping (stream); /* do local ping */ return ret; } /* MBOX mail append message from stringstruct * Accepts: MAIL stream * destination mailbox * append callback * data for callback * Returns: T if append successful, else NIL */ long mbox_append (MAILSTREAM *stream,char *mailbox,append_t af,void *data) { char tmp[MAILTMPLEN]; if (mbox_valid (mailbox)) return unix_append (stream,"mbox",af,data); sprintf (tmp,"Can't append to that name: %.80s",mailbox); MM_LOG (tmp,ERROR); return NIL; } alpine-2.10+dfsg/imap/src/osdep/unix/sig_psx.c0000600000175000017500000000246111512502123022770 0ustar paulproteuspaulproteus/* ======================================================================== * Copyright 1988-2006 University of Washington * * Licensed under the Apache License, Version 2.0 (the "License"); * you may not use this file except in compliance with the License. * You may obtain a copy of the License at * * http://www.apache.org/licenses/LICENSE-2.0 * * * ======================================================================== */ /* * Program: POSIX Signals * * Author: Mark Crispin * Networks and Distributed Computing * Computing & Communications * University of Washington * Administration Building, AG-44 * Seattle, WA 98195 * Internet: MRC@CAC.Washington.EDU * * Date: 29 April 1997 * Last Edited: 30 August 2006 */ #include #include #ifndef SA_RESTART #define SA_RESTART 0 #endif /* Arm a signal * Accepts: signal number * desired action * Returns: old action */ void *arm_signal (int sig,void *action) { struct sigaction nact,oact; memset (&nact,0,sizeof (struct sigaction)); sigemptyset (&nact.sa_mask); /* no signals blocked */ nact.sa_handler = action; /* set signal handler */ nact.sa_flags = SA_RESTART; /* needed on Linux, nice on SVR4 */ sigaction (sig,&nact,&oact); /* do the signal action */ return (void *) oact.sa_handler; } alpine-2.10+dfsg/imap/src/osdep/unix/utime.c0000600000175000017500000000234011512502123022433 0ustar paulproteuspaulproteus/* ======================================================================== * Copyright 1988-2006 University of Washington * * Licensed under the Apache License, Version 2.0 (the "License"); * you may not use this file except in compliance with the License. * You may obtain a copy of the License at * * http://www.apache.org/licenses/LICENSE-2.0 * * * ======================================================================== */ /* * Program: BSD utime() emulator * * Author: Mark Crispin * Networks and Distributed Computing * Computing & Communications * University of Washington * Administration Building, AG-44 * Seattle, WA 98195 * Internet: MRC@CAC.Washington.EDU * * Date: 10 October 1996 * Last Edited: 30 August 2006 */ #undef utime /* Portable utime() that takes it args like real Unix systems * Accepts: file path * traditional utime() argument * Returns: utime() results */ int portable_utime (char *file,time_t timep[2]) { struct utimbuf times; /* in case there's other cruft there */ memset (×,0,sizeof (struct utimbuf)); times.actime = timep[0]; /* copy the portable values */ times.modtime = timep[1]; return utime (file,×); /* now call the SVR4 routine */ } alpine-2.10+dfsg/imap/src/osdep/unix/os_qnx.c0000600000175000017500000000357211512502123022627 0ustar paulproteuspaulproteus/* ======================================================================== * Copyright 1988-2006 University of Washington * * Licensed under the Apache License, Version 2.0 (the "License"); * you may not use this file except in compliance with the License. * You may obtain a copy of the License at * * http://www.apache.org/licenses/LICENSE-2.0 * * * ======================================================================== */ /* * Program: Operating-system dependent routines -- QNX version * * Author: Mark Crispin * Networks and Distributed Computing * Computing & Communications * University of Washington * Administration Building, AG-44 * Seattle, WA 98195 * Internet: MRC@CAC.Washington.EDU * * Date: 1 August 1993 * Last Edited: 20 December 2006 */ #include "tcp_unix.h" /* must be before osdep includes tcp.h */ #include "mail.h" #include "osdep.h" #include #include #include #include #include #include #include #include #include extern int errno; /* just in case */ #include #include #include #include "misc.h" #define DIR_SIZE(d) d->d_reclen extern char *crypt (const char *pw, const char *salt); #include "fs_unix.c" #include "ftl_unix.c" #include "nl_unix.c" #include "env_unix.c" #include "tcp_unix.c" #include "gr_waitp.c" #include "tz_sv4.c" #include "gethstid.c" #include "scandir.c" /* QNX local readdir() * Accepts: directory structure * Returns: direct struct or NIL if failed */ #undef readdir struct direct *Readdir (DIR *dirp) { static struct direct dc; struct dirent *de = readdir (dirp); if (!de) return NIL; /* end of data */ dc.d_fileno = 0; /* could get from de->stat.st_ino */ dc.d_namlen = strlen (strcpy (dc.d_name,de->d_name)); dc.d_reclen = sizeof (dc); return &dc; } alpine-2.10+dfsg/imap/src/osdep/unix/os_pyr.h0000600000175000017500000000266111512502123022636 0ustar paulproteuspaulproteus/* ======================================================================== * Copyright 1988-2007 University of Washington * * Licensed under the Apache License, Version 2.0 (the "License"); * you may not use this file except in compliance with the License. * You may obtain a copy of the License at * * http://www.apache.org/licenses/LICENSE-2.0 * * * ======================================================================== */ /* * Program: Operating-system dependent routines -- Pyramid OSx 4.4c version * * Author: Mark Crispin * Networks and Distributed Computing * Computing & Communications * University of Washington * Administration Building, AG-44 * Seattle, WA 98195 * Internet: MRC@CAC.Washington.EDU * * Date: 11 May 1989 * Last Edited: 30 January 2007 */ #include #include #include #include #include #include char *strtok (char *s,char *ct); char *strtok_r (char *s,char *ct,char **r); char *strstr (char *cs,char *ct); char *strpbrk (char *cs,char *ct); char *strerror (int n); void *memmove (void *s,void *ct,size_t n); void *memset (void *s,int c,size_t n); void *malloc (size_t byteSize); void free (void *ptr); void *realloc (void *oldptr,size_t newsize); int errno; #define memcpy memmove #define strchr index #define strrchr rindex #include "env_unix.h" #include "fs.h" #include "ftl.h" #include "nl.h" #include "tcp.h" alpine-2.10+dfsg/imap/src/osdep/unix/os_osx.c0000600000175000017500000000252011512502123022622 0ustar paulproteuspaulproteus/* ======================================================================== * Copyright 1988-2007 University of Washington * * Licensed under the Apache License, Version 2.0 (the "License"); * you may not use this file except in compliance with the License. * You may obtain a copy of the License at * * http://www.apache.org/licenses/LICENSE-2.0 * * * ======================================================================== */ /* * Program: Operating-system dependent routines -- Mac OS X version * * Author: Mark Crispin * Networks and Distributed Computing * Computing & Communications * University of Washington * Administration Building, AG-44 * Seattle, WA 98195 * Internet: MRC@CAC.Washington.EDU * * Date: 1 August 1988 * Last Edited: 16 August 2007 */ #include "tcp_unix.h" /* must be before osdep includes tcp.h */ #include "mail.h" #include "osdep.h" #include #include #include #include #include #include #include #include #include extern int errno; /* just in case */ #include #include "misc.h" #include "fs_unix.c" #include "ftl_unix.c" #include "nl_unix.c" #include "env_unix.c" #define fork vfork #include "getspnam.c" #include "tcp_unix.c" #include "gr_wait4.c" #include "tz_bsd.c" alpine-2.10+dfsg/imap/src/osdep/unix/scandir.c0000600000175000017500000000515711512502123022744 0ustar paulproteuspaulproteus/* ======================================================================== * Copyright 1988-2006 University of Washington * * Licensed under the Apache License, Version 2.0 (the "License"); * you may not use this file except in compliance with the License. * You may obtain a copy of the License at * * http://www.apache.org/licenses/LICENSE-2.0 * * * ======================================================================== */ /* * Program: Scan directories * * Author: Mark Crispin * Networks and Distributed Computing * Computing & Communications * University of Washington * Administration Building, AG-44 * Seattle, WA 98195 * Internet: MRC@CAC.Washington.EDU * * Date: 1 August 1988 * Last Edited: 15 September 2006 */ /* Emulator for BSD scandir() call * Accepts: directory name * destination pointer of names array * selection function * comparison function * Returns: number of elements in the array or -1 if error */ int scandir (char *dirname,struct direct ***namelist,select_t select, compar_t compar) { struct direct *p,*d,**names; int nitems; struct stat stb; long nlmax; DIR *dirp = opendir (dirname);/* open directory and get status poop */ if ((!dirp) || (fstat (dirp->dd_fd,&stb) < 0)) return -1; nlmax = stb.st_size / 24; /* guesstimate at number of files */ names = (struct direct **) fs_get (nlmax * sizeof (struct direct *)); nitems = 0; /* initially none found */ while (d = readdir (dirp)) { /* read directory item */ /* matches select criterion? */ if (select && !(*select) (d)) continue; /* get size of direct record for this file */ p = (struct direct *) fs_get (DIR_SIZE (d)); p->d_ino = d->d_ino; /* copy the poop */ strcpy (p->d_name,d->d_name); if (++nitems >= nlmax) { /* if out of space, try bigger guesstimate */ void *s = (void *) names; /* stupid language */ nlmax *= 2; /* double it */ fs_resize ((void **) &s,nlmax * sizeof (struct direct *)); names = (struct direct **) s; } names[nitems - 1] = p; /* store this file there */ } closedir (dirp); /* done with directory */ /* sort if necessary */ if (nitems && compar) qsort (names,nitems,sizeof (struct direct *),compar); *namelist = names; /* return directory */ return nitems; /* and size */ } /* Alphabetic file name comparision * Accepts: first candidate directory entry * second candidate directory entry * Returns: negative if d1 < d2, 0 if d1 == d2, postive if d1 > d2 */ int alphasort (void *d1,void *d2) { return strcmp ((*(struct direct **) d1)->d_name, (*(struct direct **) d2)->d_name); } alpine-2.10+dfsg/imap/src/osdep/unix/os_solo.h0000600000175000017500000000363511512502123023002 0ustar paulproteuspaulproteus/* ======================================================================== * Copyright 1988-2006 University of Washington * * Licensed under the Apache License, Version 2.0 (the "License"); * you may not use this file except in compliance with the License. * You may obtain a copy of the License at * * http://www.apache.org/licenses/LICENSE-2.0 * * * ======================================================================== */ /* * Program: Operating-system dependent routines -- Solaris version * * Author: Mark Crispin * Networks and Distributed Computing * Computing & Communications * University of Washington * Administration Building, AG-44 * Seattle, WA 98195 * Internet: MRC@CAC.Washington.EDU * * Date: 1 August 1988 * Last Edited: 20 December 2006 */ #include #include #include #include #include #include #include #include #include #include #include /* Many versions of SysV get this wrong */ #define setpgrp(a,b) Setpgrp(a,b) int Setpgrp (int pid,int gid); /* Different names, equivalent things in BSD and SysV */ /* L_SET is defined for some strange reason in on SVR4. */ #ifndef L_SET #define L_SET SEEK_SET #endif #ifndef L_INCR #define L_INCR SEEK_CUR #endif #ifndef L_XTND #define L_XTND SEEK_END #endif #define direct dirent #define random lrand48 #define scandir Scandir #define alphasort Alphasort #define utime portable_utime int portable_utime (char *file,time_t timep[2]); long gethostid (void); typedef int (*select_t) (struct direct *name); typedef int (*compar_t) (const void *d1,const void *d2); int scandir (char *dirname,struct direct ***namelist,select_t select, compar_t compar); int alphasort (void *d1,void *d2); #include "env_unix.h" #include "fs.h" #include "ftl.h" #include "nl.h" #include "tcp.h" #include "flocksim.h" alpine-2.10+dfsg/imap/src/osdep/unix/os_mnt.h0000600000175000017500000000226511512502123022622 0ustar paulproteuspaulproteus/* ======================================================================== * Copyright 1988-2006 University of Washington * * Licensed under the Apache License, Version 2.0 (the "License"); * you may not use this file except in compliance with the License. * You may obtain a copy of the License at * * http://www.apache.org/licenses/LICENSE-2.0 * * * ======================================================================== */ /* * Program: Operating-system dependent routines -- Mint version * * Author: Mark Crispin * Networks and Distributed Computing * Computing & Communications * University of Washington * Administration Building, AG-44 * Seattle, WA 98195 * Internet: MRC@CAC.Washington.EDU * * Date: 10 September 1993 * Last Edited: 30 August 2006 */ #include #include #include #include #include #include #include #include #include #include #define EAGAIN EWOULDBLOCK #define FNDELAY O_NDELAY /* MiNT gets this wrong */ #define setpgrp setpgid #include "env_unix.h" #include "fs.h" #include "ftl.h" #include "nl.h" #include "tcp.h" alpine-2.10+dfsg/imap/src/osdep/unix/ssl_none.c0000600000175000017500000000511011512502123023126 0ustar paulproteuspaulproteus/* ======================================================================== * Copyright 1988-2006 University of Washington * * Licensed under the Apache License, Version 2.0 (the "License"); * you may not use this file except in compliance with the License. * You may obtain a copy of the License at * * http://www.apache.org/licenses/LICENSE-2.0 * * * ======================================================================== */ /* * Program: Dummy (no SSL) authentication/encryption module * * Author: Mark Crispin * Networks and Distributed Computing * Computing & Communications * University of Washington * Administration Building, AG-44 * Seattle, WA 98195 * Internet: MRC@CAC.Washington.EDU * * Date: 7 February 2001 * Last Edited: 30 August 2006 */ /* Init server for SSL * Accepts: server name */ void ssl_server_init (char *server) { syslog (LOG_ERR,"This server does not support SSL"); exit (1); /* punt this program too */ } /* Start TLS * Accepts: /etc/services service name * Returns: cpystr'd error string if TLS failed, else NIL for success */ char *ssl_start_tls (char *server) { return cpystr ("This server does not support TLS"); } /* Get character * Returns: character or EOF */ int PBIN (void) { return getchar (); } /* Get string * Accepts: destination string pointer * number of bytes available * Returns: destination string pointer or NIL if EOF */ char *PSIN (char *s,int n) { return fgets (s,n,stdin); } /* Get record * Accepts: destination string pointer * number of bytes to read * Returns: T if success, NIL otherwise */ long PSINR (char *s,unsigned long n) { unsigned long i; while (n && ((i = fread (s,1,n,stdin)) || (errno == EINTR))) s += i,n -= i; return n ? NIL : LONGT; } /* Wait for input * Accepts: timeout in seconds * Returns: T if have input on stdin, else NIL */ long INWAIT (long seconds) { return server_input_wait (seconds); } /* Put character * Accepts: character * Returns: character written or EOF */ int PBOUT (int c) { return putchar (c); } /* Put string * Accepts: source string pointer * Returns: 0 or EOF if error */ int PSOUT (char *s) { return fputs (s,stdout); } /* Put record * Accepts: source sized text * Returns: 0 or EOF if error */ int PSOUTR (SIZEDTEXT *s) { unsigned char *t; unsigned long i,j; for (t = s->data,i = s->size; (i && ((j = fwrite (t,1,i,stdout)) || (errno == EINTR))); t += j,i -= j); return i ? EOF : NIL; } /* Flush output * Returns: 0 or EOF if error */ int PFLUSH (void) { return fflush (stdout); } alpine-2.10+dfsg/imap/src/osdep/unix/os_bsf.h0000600000175000017500000000206511512502123022574 0ustar paulproteuspaulproteus/* ======================================================================== * Copyright 1988-2006 University of Washington * * Licensed under the Apache License, Version 2.0 (the "License"); * you may not use this file except in compliance with the License. * You may obtain a copy of the License at * * http://www.apache.org/licenses/LICENSE-2.0 * * * ======================================================================== */ /* * Program: Operating-system dependent routines -- FreeBSD version * * Author: Mark Crispin * Networks and Distributed Computing * Computing & Communications * University of Washington * Administration Building, AG-44 * Seattle, WA 98195 * Internet: MRC@CAC.Washington.EDU * * Date: 5 March 1993 * Last Edited: 30 August 2006 */ #include #include #include #include #include #include #include #include #define direct dirent #include "env_unix.h" #include "fs.h" #include "ftl.h" #include "nl.h" #include "tcp.h" alpine-2.10+dfsg/imap/src/osdep/unix/sslstdio.c0000600000175000017500000001023011512502123023151 0ustar paulproteuspaulproteus/* ======================================================================== * Copyright 1988-2006 University of Washington * * Licensed under the Apache License, Version 2.0 (the "License"); * you may not use this file except in compliance with the License. * You may obtain a copy of the License at * * http://www.apache.org/licenses/LICENSE-2.0 * * * ======================================================================== */ /* * Program: SSL standard I/O routines for server use * * Author: Mark Crispin * Networks and Distributed Computing * Computing & Communications * University of Washington * Administration Building, AG-44 * Seattle, WA 98195 * Internet: MRC@CAC.Washington.EDU * * Date: 22 September 1998 * Last Edited: 30 August 2006 */ /* Get character * Returns: character or EOF */ int PBIN (void) { if (!sslstdio) return getchar (); if (!ssl_getdata (sslstdio->sslstream)) return EOF; /* one last byte available */ sslstdio->sslstream->ictr--; return (int) *(sslstdio->sslstream->iptr)++; } /* Get string * Accepts: destination string pointer * number of bytes available * Returns: destination string pointer or NIL if EOF */ char *PSIN (char *s,int n) { int i,c; if (start_tls) { /* doing a start TLS? */ ssl_server_init (start_tls);/* enter the mode */ start_tls = NIL; /* don't do this again */ } if (!sslstdio) return fgets (s,n,stdin); for (i = c = 0, n-- ; (c != '\n') && (i < n); sslstdio->sslstream->ictr--) { if ((sslstdio->sslstream->ictr <= 0) && !ssl_getdata (sslstdio->sslstream)) return NIL; /* read error */ c = s[i++] = *(sslstdio->sslstream->iptr)++; } s[i] = '\0'; /* tie off string */ return s; } /* Get record * Accepts: destination string pointer * number of bytes to read * Returns: T if success, NIL otherwise */ long PSINR (char *s,unsigned long n) { unsigned long i; if (start_tls) { /* doing a start TLS? */ ssl_server_init (start_tls);/* enter the mode */ start_tls = NIL; /* don't do this again */ } if (sslstdio) return ssl_getbuffer (sslstdio->sslstream,n,s); /* non-SSL case */ while (n && ((i = fread (s,1,n,stdin)) || (errno == EINTR))) s += i,n -= i; return n ? NIL : LONGT; } /* Wait for stdin input * Accepts: timeout in seconds * Returns: T if have input on stdin, else NIL */ long INWAIT (long seconds) { return (sslstdio ? ssl_server_input_wait : server_input_wait) (seconds); } /* Put character * Accepts: character * Returns: character written or EOF */ int PBOUT (int c) { if (!sslstdio) return putchar (c); /* flush buffer if full */ if (!sslstdio->octr && PFLUSH ()) return EOF; sslstdio->octr--; /* count down one character */ *sslstdio->optr++ = c; /* write character */ return c; /* return that character */ } /* Put string * Accepts: destination string pointer * Returns: 0 or EOF if error */ int PSOUT (char *s) { if (!sslstdio) return fputs (s,stdout); while (*s) { /* flush buffer if full */ if (!sslstdio->octr && PFLUSH ()) return EOF; *sslstdio->optr++ = *s++; /* write one more character */ sslstdio->octr--; /* count down one character */ } return 0; /* success */ } /* Put record * Accepts: source sized text * Returns: 0 or EOF if error */ int PSOUTR (SIZEDTEXT *s) { unsigned char *t = s->data; unsigned long i = s->size; unsigned long j; if (sslstdio) while (i) { /* until request satisfied */ /* flush buffer if full */ if (!sslstdio->octr && PFLUSH ()) break; /* blat as big a chucnk as we can */ memcpy (sslstdio->optr,t,j = min (i,sslstdio->octr)); sslstdio->optr += j; /* account for chunk */ sslstdio->octr -= j; t += j; i -= j; } else while (i && ((j = fwrite (t,1,i,stdout)) || (errno == EINTR))) t += j,i -= j; return i ? EOF : NIL; } /* Flush output * Returns: 0 or EOF if error */ int PFLUSH (void) { if (!sslstdio) return fflush (stdout); /* force out buffer */ if (!ssl_sout (sslstdio->sslstream,sslstdio->obuf, SSLBUFLEN - sslstdio->octr)) return EOF; /* renew output buffer */ sslstdio->optr = sslstdio->obuf; sslstdio->octr = SSLBUFLEN; return 0; /* success */ } alpine-2.10+dfsg/imap/src/osdep/unix/dummy.c0000600000175000017500000006124411512502123022453 0ustar paulproteuspaulproteus/* ======================================================================== * Copyright 1988-2007 University of Washington * * Licensed under the Apache License, Version 2.0 (the "License"); * you may not use this file except in compliance with the License. * You may obtain a copy of the License at * * http://www.apache.org/licenses/LICENSE-2.0 * * * ======================================================================== */ /* * Program: Dummy routines * * Author: Mark Crispin * Networks and Distributed Computing * Computing & Communications * University of Washington * Administration Building, AG-44 * Seattle, WA 98195 * Internet: MRC@CAC.Washington.EDU * * Date: 9 May 1991 * Last Edited: 1 June 2007 */ #include #include #include extern int errno; /* just in case */ #include "mail.h" #include "osdep.h" #include #include #include "dummy.h" #include "misc.h" /* Function prototypes */ DRIVER *dummy_valid (char *name); void *dummy_parameters (long function,void *value); void dummy_list_work (MAILSTREAM *stream,char *dir,char *pat,char *contents, long level); long dummy_listed (MAILSTREAM *stream,char delimiter,char *name, long attributes,char *contents); long dummy_subscribe (MAILSTREAM *stream,char *mailbox); MAILSTREAM *dummy_open (MAILSTREAM *stream); void dummy_close (MAILSTREAM *stream,long options); long dummy_ping (MAILSTREAM *stream); void dummy_check (MAILSTREAM *stream); long dummy_expunge (MAILSTREAM *stream,char *sequence,long options); long dummy_copy (MAILSTREAM *stream,char *sequence,char *mailbox,long options); long dummy_append (MAILSTREAM *stream,char *mailbox,append_t af,void *data); /* Dummy routines */ /* Driver dispatch used by MAIL */ DRIVER dummydriver = { "dummy", /* driver name */ DR_LOCAL|DR_MAIL, /* driver flags */ (DRIVER *) NIL, /* next driver */ dummy_valid, /* mailbox is valid for us */ dummy_parameters, /* manipulate parameters */ dummy_scan, /* scan mailboxes */ dummy_list, /* list mailboxes */ dummy_lsub, /* list subscribed mailboxes */ dummy_subscribe, /* subscribe to mailbox */ NIL, /* unsubscribe from mailbox */ dummy_create, /* create mailbox */ dummy_delete, /* delete mailbox */ dummy_rename, /* rename mailbox */ mail_status_default, /* status of mailbox */ dummy_open, /* open mailbox */ dummy_close, /* close mailbox */ NIL, /* fetch message "fast" attributes */ NIL, /* fetch message flags */ NIL, /* fetch overview */ NIL, /* fetch message structure */ NIL, /* fetch header */ NIL, /* fetch text */ NIL, /* fetch message data */ NIL, /* unique identifier */ NIL, /* message number from UID */ NIL, /* modify flags */ NIL, /* per-message modify flags */ NIL, /* search for message based on criteria */ NIL, /* sort messages */ NIL, /* thread messages */ dummy_ping, /* ping mailbox to see if still alive */ dummy_check, /* check for new messages */ dummy_expunge, /* expunge deleted messages */ dummy_copy, /* copy messages to another mailbox */ dummy_append, /* append string message to mailbox */ NIL /* garbage collect stream */ }; /* prototype stream */ MAILSTREAM dummyproto = {&dummydriver}; /* Dummy validate mailbox * Accepts: mailbox name * Returns: our driver if name is valid, NIL otherwise */ DRIVER *dummy_valid (char *name) { char *s,tmp[MAILTMPLEN]; struct stat sbuf; /* must be valid local mailbox */ if (name && *name && (*name != '{') && (s = mailboxfile (tmp,name))) { /* indeterminate clearbox INBOX */ if (!*s) return &dummydriver; else if (!stat (s,&sbuf)) switch (sbuf.st_mode & S_IFMT) { case S_IFREG: case S_IFDIR: return &dummydriver; } /* blackbox INBOX does not exist yet */ else if (!compare_cstring (name,"INBOX")) return &dummydriver; } return NIL; } /* Dummy manipulate driver parameters * Accepts: function code * function-dependent value * Returns: function-dependent return value */ void *dummy_parameters (long function,void *value) { void *ret = NIL; switch ((int) function) { case GET_INBOXPATH: if (value) ret = dummy_file ((char *) value,"INBOX"); break; } return ret; } /* Dummy scan mailboxes * Accepts: mail stream * reference * pattern to search * string to scan */ void dummy_scan (MAILSTREAM *stream,char *ref,char *pat,char *contents) { DRIVER *drivers; char *s,test[MAILTMPLEN],file[MAILTMPLEN]; long i; if (!pat || !*pat) { /* empty pattern? */ if (dummy_canonicalize (test,ref,"*")) { /* tie off name at root */ if (s = strchr (test,'/')) *++s = '\0'; else test[0] = '\0'; dummy_listed (stream,'/',test,LATT_NOSELECT,NIL); } } /* get canonical form of name */ else if (dummy_canonicalize (test,ref,pat)) { /* found any wildcards? */ if (s = strpbrk (test,"%*")) { /* yes, copy name up to that point */ strncpy (file,test,i = s - test); file[i] = '\0'; /* tie off */ } else strcpy (file,test); /* use just that name then */ if (s = strrchr (file,'/')){/* find directory name */ *++s = '\0'; /* found, tie off at that point */ s = file; } /* silly case */ else if ((file[0] == '~') || (file[0] == '#')) s = file; /* do the work */ dummy_list_work (stream,s,test,contents,0); /* always an INBOX */ if (pmatch ("INBOX",ucase (test))) { /* done if have a dirfmt INBOX */ for (drivers = (DRIVER *) mail_parameters (NIL,GET_DRIVERS,NIL); drivers && !(!(drivers->flags & DR_DISABLE) && (drivers->flags & DR_DIRFMT) && (*drivers->valid) ("INBOX")); drivers = drivers->next); /* list INBOX appropriately */ dummy_listed (stream,drivers ? '/' : NIL,"INBOX", drivers ? NIL : LATT_NOINFERIORS,contents); } } } /* Dummy list mailboxes * Accepts: mail stream * reference * pattern to search */ void dummy_list (MAILSTREAM *stream,char *ref,char *pat) { dummy_scan (stream,ref,pat,NIL); } /* Dummy list subscribed mailboxes * Accepts: mail stream * reference * pattern to search */ void dummy_lsub (MAILSTREAM *stream,char *ref,char *pat) { void *sdb = NIL; char *s,*t,test[MAILTMPLEN],tmp[MAILTMPLEN]; int showuppers = pat[strlen (pat) - 1] == '%'; /* get canonical form of name */ if (dummy_canonicalize (test,ref,pat) && (s = sm_read (&sdb))) do if (*s != '{') { if (!compare_cstring (s,"INBOX") && pmatch ("INBOX",ucase (strcpy (tmp,test)))) mm_lsub (stream,NIL,s,LATT_NOINFERIORS); else if (pmatch_full (s,test,'/')) mm_lsub (stream,'/',s,NIL); else while (showuppers && (t = strrchr (s,'/'))) { *t = '\0'; /* tie off the name */ if (pmatch_full (s,test,'/')) mm_lsub (stream,'/',s,LATT_NOSELECT); } } while (s = sm_read (&sdb)); /* until no more subscriptions */ } /* Dummy subscribe to mailbox * Accepts: mail stream * mailbox to add to subscription list * Returns: T on success, NIL on failure */ long dummy_subscribe (MAILSTREAM *stream,char *mailbox) { char *s,tmp[MAILTMPLEN]; struct stat sbuf; /* must be valid local mailbox */ if ((s = mailboxfile (tmp,mailbox)) && *s && !stat (s,&sbuf)) switch (sbuf.st_mode & S_IFMT) { case S_IFDIR: /* allow but snarl */ sprintf (tmp,"CLIENT BUG DETECTED: subscribe of non-mailbox directory %.80s", mailbox); MM_NOTIFY (stream,tmp,WARN); case S_IFREG: return sm_subscribe (mailbox); } sprintf (tmp,"Can't subscribe %.80s: not a mailbox",mailbox); MM_LOG (tmp,ERROR); return NIL; } /* Dummy list mailboxes worker routine * Accepts: mail stream * directory name to search * search pattern * string to scan * search level */ void dummy_list_work (MAILSTREAM *stream,char *dir,char *pat,char *contents, long level) { DRIVER *drivers; dirfmttest_t dt; DIR *dp; struct direct *d; struct stat sbuf; char tmp[MAILTMPLEN],path[MAILTMPLEN]; size_t len = 0; /* punt if bogus name */ if (!mailboxdir (tmp,dir,NIL)) return; if (dp = opendir (tmp)) { /* do nothing if can't open directory */ /* see if a non-namespace directory format */ for (drivers = (DRIVER *) mail_parameters (NIL,GET_DRIVERS,NIL), dt = NIL; dir && !dt && drivers; drivers = drivers->next) if (!(drivers->flags & DR_DISABLE) && (drivers->flags & DR_DIRFMT) && (*drivers->valid) (dir)) dt = mail_parameters ((*drivers->open) (NIL),GET_DIRFMTTEST,NIL); /* list it if at top-level */ if (!level && dir && pmatch_full (dir,pat,'/') && !pmatch (dir,"INBOX")) dummy_listed (stream,'/',dir,dt ? NIL : LATT_NOSELECT,contents); /* scan directory, ignore . and .. */ if (!dir || dir[(len = strlen (dir)) - 1] == '/') while (d = readdir (dp)) if ((!(dt && (*dt) (d->d_name))) && ((d->d_name[0] != '.') || (((long) mail_parameters (NIL,GET_HIDEDOTFILES,NIL)) ? NIL : (d->d_name[1] && (((d->d_name[1] != '.') || d->d_name[2]))))) && ((len + strlen (d->d_name)) <= NETMAXMBX)) { /* see if name is useful */ if (dir) sprintf (tmp,"%s%s",dir,d->d_name); else strcpy (tmp,d->d_name); /* make sure useful and can get info */ if ((pmatch_full (strcpy (path,tmp),pat,'/') || pmatch_full (strcat (path,"/"),pat,'/') || dmatch (path,pat,'/')) && mailboxdir (path,dir,"x") && (len = strlen (path)) && strcpy (path+len-1,d->d_name) && !stat (path,&sbuf)) { /* only interested in file type */ switch (sbuf.st_mode & S_IFMT) { case S_IFDIR: /* directory? */ /* form with trailing / */ sprintf (path,"%s/",tmp); /* skip listing if INBOX */ if (!pmatch (tmp,"INBOX")) { if (pmatch_full (tmp,pat,'/')) { if (!dummy_listed (stream,'/',tmp,LATT_NOSELECT,contents)) break; } /* try again with trailing / */ else if (pmatch_full (path,pat,'/') && !dummy_listed (stream,'/',path,LATT_NOSELECT,contents)) break; } if (dmatch (path,pat,'/') && (level < (long) mail_parameters (NIL,GET_LISTMAXLEVEL,NIL))) dummy_list_work (stream,path,pat,contents,level+1); break; case S_IFREG: /* ordinary name */ /* Must use ctime for systems that don't update mtime properly */ if (pmatch_full (tmp,pat,'/') && compare_cstring (tmp,"INBOX")) dummy_listed (stream,'/',tmp,LATT_NOINFERIORS + ((sbuf.st_size && (sbuf.st_atime < sbuf.st_ctime))? LATT_MARKED : LATT_UNMARKED),contents); break; } } } closedir (dp); /* all done, flush directory */ } } /* Scan file for contents * Accepts: driver to use * file name * desired contents * length of contents * size of file * Returns: NIL if contents not found, T if found */ long scan_contents (DRIVER *dtb,char *name,char *contents, unsigned long csiz,unsigned long fsiz) { scancontents_t sc = dtb ? (scancontents_t) (*dtb->parameters) (GET_SCANCONTENTS,NIL) : NIL; return (*(sc ? sc : dummy_scan_contents)) (name,contents,csiz,fsiz); } /* Scan file for contents * Accepts: file name * desired contents * length of contents * size of file * Returns: NIL if contents not found, T if found */ #define BUFSIZE 4*MAILTMPLEN long dummy_scan_contents (char *name,char *contents,unsigned long csiz, unsigned long fsiz) { int fd; unsigned long ssiz,bsiz; char *buf; /* forget it if can't select or open */ if ((fd = open (name,O_RDONLY,NIL)) >= 0) { /* get buffer including slop */ buf = (char *) fs_get (BUFSIZE + (ssiz = 4 * ((csiz / 4) + 1)) + 1); memset (buf,'\0',ssiz); /* no slop area the first time */ while (fsiz) { /* until end of file */ read (fd,buf+ssiz,bsiz = min (fsiz,BUFSIZE)); if (search ((unsigned char *) buf,bsiz+ssiz, (unsigned char *) contents,csiz)) break; memcpy (buf,buf+BUFSIZE,ssiz); fsiz -= bsiz; /* note that we read that much */ } fs_give ((void **) &buf); /* flush buffer */ close (fd); /* finished with file */ if (fsiz) return T; /* found */ } return NIL; /* not found */ } /* Mailbox found * Accepts: MAIL stream * hierarchy delimiter * mailbox name * attributes * contents to search before calling mm_list() * Returns: NIL if should abort hierarchy search, else T (currently always) */ long dummy_listed (MAILSTREAM *stream,char delimiter,char *name, long attributes,char *contents) { DRIVER *d; DIR *dp; struct direct *dr; dirfmttest_t dt; unsigned long csiz; struct stat sbuf; int nochild; char *s,tmp[MAILTMPLEN]; if (!(attributes & LATT_NOINFERIORS) && mailboxdir (tmp,name,NIL) && (dp = opendir (tmp))) { /* if not \NoInferiors */ /* locate dirfmttest if any */ for (d = (DRIVER *) mail_parameters (NIL,GET_DRIVERS,NIL), dt = NIL; !dt && d; d = d->next) if (!(d->flags & DR_DISABLE) && (d->flags & DR_DIRFMT) && (*d->valid) (name)) dt = mail_parameters ((*d->open) (NIL),GET_DIRFMTTEST,NIL); /* scan directory for children */ for (nochild = T; nochild && (dr = readdir (dp)); ) if ((!(dt && (*dt) (dr->d_name))) && ((dr->d_name[0] != '.') || (((long) mail_parameters (NIL,GET_HIDEDOTFILES,NIL)) ? NIL : (dr->d_name[1] && ((dr->d_name[1] != '.') || dr->d_name[2]))))) nochild = NIL; attributes |= nochild ? LATT_HASNOCHILDREN : LATT_HASCHILDREN; closedir (dp); /* all done, flush directory */ } d = NIL; /* don't \NoSelect dir if it has a driver */ if ((attributes & LATT_NOSELECT) && (d = mail_valid (NIL,name,NIL)) && (d != &dummydriver)) attributes &= ~LATT_NOSELECT; if (!contents || /* notify main program */ (!(attributes & LATT_NOSELECT) && (csiz = strlen (contents)) && (s = mailboxfile (tmp,name)) && (*s || (s = mail_parameters (NIL,GET_INBOXPATH,tmp))) && !stat (s,&sbuf) && (d || (csiz <= sbuf.st_size)) && SAFE_SCAN_CONTENTS (d,tmp,contents,csiz,sbuf.st_size))) mm_list (stream,delimiter,name,attributes); return T; } /* Dummy create mailbox * Accepts: mail stream * mailbox name to create * Returns: T on success, NIL on failure */ long dummy_create (MAILSTREAM *stream,char *mailbox) { char *s,tmp[MAILTMPLEN]; long ret = NIL; /* validate name */ if (!(compare_cstring (mailbox,"INBOX") && (s = dummy_file (tmp,mailbox)))) { sprintf (tmp,"Can't create %.80s: invalid name",mailbox); MM_LOG (tmp,ERROR); } /* create the name, done if made directory */ else if ((ret = dummy_create_path (stream,tmp,get_dir_protection(mailbox)))&& (s = strrchr (s,'/')) && !s[1]) return T; return ret ? set_mbx_protections (mailbox,tmp) : NIL; } /* Dummy create path * Accepts: mail stream * path name to create * directory mode * Returns: T on success, NIL on failure */ long dummy_create_path (MAILSTREAM *stream,char *path,long dirmode) { struct stat sbuf; char c,*s,tmp[MAILTMPLEN]; int fd; long ret = NIL; char *t = strrchr (path,'/'); int wantdir = t && !t[1]; int mask = umask (0); if (wantdir) *t = '\0'; /* flush trailing delimiter for directory */ if (s = strrchr (path,'/')) { /* found superior to this name? */ c = *++s; /* remember first character of inferior */ *s = '\0'; /* tie off to get just superior */ /* name doesn't exist, create it */ if ((stat (path,&sbuf) || ((sbuf.st_mode & S_IFMT) != S_IFDIR)) && !dummy_create_path (stream,path,dirmode)) { umask (mask); /* restore mask */ return NIL; } *s = c; /* restore full name */ } if (wantdir) { /* want to create directory? */ ret = !mkdir (path,(int) dirmode); *t = '/'; /* restore directory delimiter */ } /* create file */ else if ((fd = open (path,O_WRONLY|O_CREAT|O_EXCL, (long) mail_parameters(NIL,GET_MBXPROTECTION,NIL))) >=0) ret = !close (fd); if (!ret) { /* error? */ sprintf (tmp,"Can't create mailbox node %.80s: %.80s",path,strerror (errno)); MM_LOG (tmp,ERROR); } umask (mask); /* restore mask */ return ret; /* return status */ } /* Dummy delete mailbox * Accepts: mail stream * mailbox name to delete * Returns: T on success, NIL on failure */ long dummy_delete (MAILSTREAM *stream,char *mailbox) { struct stat sbuf; char *s,tmp[MAILTMPLEN]; if (!(s = dummy_file (tmp,mailbox))) { sprintf (tmp,"Can't delete - invalid name: %.80s",s); MM_LOG (tmp,ERROR); } /* no trailing / (workaround BSD kernel bug) */ if ((s = strrchr (tmp,'/')) && !s[1]) *s = '\0'; if (stat (tmp,&sbuf) || ((sbuf.st_mode & S_IFMT) == S_IFDIR) ? rmdir (tmp) : unlink (tmp)) { sprintf (tmp,"Can't delete mailbox %.80s: %.80s",mailbox,strerror (errno)); MM_LOG (tmp,ERROR); return NIL; } return T; /* return success */ } /* Mail rename mailbox * Accepts: mail stream * old mailbox name * new mailbox name * Returns: T on success, NIL on failure */ long dummy_rename (MAILSTREAM *stream,char *old,char *newname) { struct stat sbuf; char c,*s,tmp[MAILTMPLEN],mbx[MAILTMPLEN],oldname[MAILTMPLEN]; /* no trailing / allowed */ if (!dummy_file (oldname,old) || !(s = dummy_file (mbx,newname)) || stat (oldname,&sbuf) || ((s = strrchr (s,'/')) && !s[1] && ((sbuf.st_mode & S_IFMT) != S_IFDIR))) { sprintf (mbx,"Can't rename %.80s to %.80s: invalid name",old,newname); MM_LOG (mbx,ERROR); return NIL; } if (s) { /* found a directory delimiter? */ if (!s[1]) *s = '\0'; /* ignore trailing delimiter */ else { /* found superior to destination name? */ c = *++s; /* remember first character of inferior */ *s = '\0'; /* tie off to get just superior */ /* name doesn't exist, create it */ if ((stat (mbx,&sbuf) || ((sbuf.st_mode & S_IFMT) != S_IFDIR)) && !dummy_create (stream,mbx)) return NIL; *s = c; /* restore full name */ } } /* rename of non-ex INBOX creates dest */ if (!compare_cstring (old,"INBOX") && stat (oldname,&sbuf)) return dummy_create (NIL,mbx); if (rename (oldname,mbx)) { sprintf (tmp,"Can't rename mailbox %.80s to %.80s: %.80s",old,newname, strerror (errno)); MM_LOG (tmp,ERROR); return NIL; } return T; /* return success */ } /* Dummy open * Accepts: stream to open * Returns: stream on success, NIL on failure */ MAILSTREAM *dummy_open (MAILSTREAM *stream) { int fd; char err[MAILTMPLEN],tmp[MAILTMPLEN]; struct stat sbuf; /* OP_PROTOTYPE call */ if (!stream) return &dummyproto; err[0] = '\0'; /* no error message yet */ /* can we open the file? */ if (!dummy_file (tmp,stream->mailbox)) sprintf (err,"Can't open this name: %.80s",stream->mailbox); else if ((fd = open (tmp,O_RDONLY,NIL)) < 0) { /* no, error unless INBOX */ if (compare_cstring (stream->mailbox,"INBOX")) sprintf (err,"%.80s: %.80s",strerror (errno),stream->mailbox); } else { /* file had better be empty then */ fstat (fd,&sbuf); /* sniff at its size */ close (fd); if ((sbuf.st_mode & S_IFMT) != S_IFREG) sprintf (err,"Can't open %.80s: not a selectable mailbox", stream->mailbox); else if (sbuf.st_size) /* bogus format if non-empty */ sprintf (err,"Can't open %.80s (file %.80s): not in valid mailbox format", stream->mailbox,tmp); } if (err[0]) { /* if an error happened */ MM_LOG (err,stream->silent ? WARN : ERROR); return NIL; } else if (!stream->silent) { /* only if silence not requested */ mail_exists (stream,0); /* say there are 0 messages */ mail_recent (stream,0); /* and certainly no recent ones! */ stream->uid_validity = time (0); } stream->inbox = T; /* note that it's an INBOX */ return stream; /* return success */ } /* Dummy close * Accepts: MAIL stream * options */ void dummy_close (MAILSTREAM *stream,long options) { /* return silently */ } /* Dummy ping mailbox * Accepts: MAIL stream * Returns: T if stream alive, else NIL */ long dummy_ping (MAILSTREAM *stream) { MAILSTREAM *test; if (time (0) >= /* time to do another test? */ ((time_t) (stream->gensym + (long) mail_parameters (NIL,GET_SNARFINTERVAL,NIL)))) { /* has mailbox format changed? */ if ((test = mail_open (NIL,stream->mailbox,OP_PROTOTYPE)) && (test->dtb != stream->dtb) && (test = mail_open (NIL,stream->mailbox,NIL))) { /* preserve some resources */ test->original_mailbox = stream->original_mailbox; stream->original_mailbox = NIL; test->sparep = stream->sparep; stream->sparep = NIL; test->sequence = stream->sequence; mail_close ((MAILSTREAM *) /* flush resources used by dummy stream */ memcpy (fs_get (sizeof (MAILSTREAM)),stream, sizeof (MAILSTREAM))); /* swap the streams */ memcpy (stream,test,sizeof (MAILSTREAM)); fs_give ((void **) &test);/* flush test now that copied */ /* make sure application knows */ mail_exists (stream,stream->recent = stream->nmsgs); } /* still hasn't changed */ else stream->gensym = time (0); } return T; } /* Dummy check mailbox * Accepts: MAIL stream * No-op for readonly files, since read/writer can expunge it from under us! */ void dummy_check (MAILSTREAM *stream) { dummy_ping (stream); /* invoke ping */ } /* Dummy expunge mailbox * Accepts: MAIL stream * sequence to expunge if non-NIL * expunge options * Returns: T, always */ long dummy_expunge (MAILSTREAM *stream,char *sequence,long options) { return LONGT; } /* Dummy copy message(s) * Accepts: MAIL stream * sequence * destination mailbox * options * Returns: T if copy successful, else NIL */ long dummy_copy (MAILSTREAM *stream,char *sequence,char *mailbox,long options) { if ((options & CP_UID) ? mail_uid_sequence (stream,sequence) : mail_sequence (stream,sequence)) fatal ("Impossible dummy_copy"); return NIL; } /* Dummy append message string * Accepts: mail stream * destination mailbox * append callback function * data for callback * Returns: T on success, NIL on failure */ long dummy_append (MAILSTREAM *stream,char *mailbox,append_t af,void *data) { struct stat sbuf; int fd = -1; int e; char tmp[MAILTMPLEN]; MAILSTREAM *ts = default_proto (T); /* append to INBOX? */ if (!compare_cstring (mailbox,"INBOX")) { /* yes, if no empty proto try creating */ if (!ts && !(*(ts = default_proto (NIL))->dtb->create) (ts,"INBOX")) ts = NIL; } else if (dummy_file (tmp,mailbox) && ((fd = open (tmp,O_RDONLY,NIL)) < 0)) { if ((e = errno) == ENOENT) /* failed, was it no such file? */ MM_NOTIFY (stream,"[TRYCREATE] Must create mailbox before append",NIL); sprintf (tmp,"%.80s: %.80s",strerror (e),mailbox); MM_LOG (tmp,ERROR); /* pass up error */ return NIL; /* always fails */ } else if (fd >= 0) { /* found file? */ fstat (fd,&sbuf); /* get its size */ close (fd); /* toss out the fd */ if (sbuf.st_size) ts = NIL; /* non-empty file? */ } if (ts) return (*ts->dtb->append) (stream,mailbox,af,data); sprintf (tmp,"Indeterminate mailbox format: %.80s",mailbox); MM_LOG (tmp,ERROR); return NIL; } /* Dummy mail generate file string * Accepts: temporary buffer to write into * mailbox name string * Returns: local file string or NIL if failure */ char *dummy_file (char *dst,char *name) { char *s = mailboxfile (dst,name); /* return our standard inbox */ return (s && !*s) ? strcpy (dst,sysinbox ()) : s; } /* Dummy canonicalize name * Accepts: buffer to write name * reference * pattern * Returns: T if success, NIL if failure */ long dummy_canonicalize (char *tmp,char *ref,char *pat) { unsigned long i; char *s; if (ref) { /* preliminary reference check */ if (*ref == '{') return NIL;/* remote reference not allowed */ else if (!*ref) ref = NIL; /* treat empty reference as no reference */ } switch (*pat) { case '#': /* namespace name */ if (mailboxfile (tmp,pat)) strcpy (tmp,pat); else return NIL; /* unknown namespace */ break; case '{': /* remote names not allowed */ return NIL; case '/': /* rooted name */ case '~': /* home directory name */ if (!ref || (*ref != '#')) {/* non-namespace reference? */ strcpy (tmp,pat); /* yes, ignore */ break; } /* fall through */ default: /* apply reference for all other names */ if (!ref) strcpy (tmp,pat); /* just copy if no namespace */ else if ((*ref != '#') || mailboxfile (tmp,ref)) { /* wants root of name? */ if (*pat == '/') strcpy (strchr (strcpy (tmp,ref),'/'),pat); /* otherwise just append */ else sprintf (tmp,"%s%s",ref,pat); } else return NIL; /* unknown namespace */ } /* count wildcards */ for (i = 0, s = tmp; *s; *s++) if ((*s == '*') || (*s == '%')) ++i; if (i > MAXWILDCARDS) { /* ridiculous wildcarding? */ MM_LOG ("Excessive wildcards in LIST/LSUB",ERROR); return NIL; } return T; } alpine-2.10+dfsg/imap/src/osdep/unix/ckp_ssn.c0000600000175000017500000000312611512502123022753 0ustar paulproteuspaulproteus/* ======================================================================== * Copyright 1988-2006 University of Washington * * Licensed under the Apache License, Version 2.0 (the "License"); * you may not use this file except in compliance with the License. * You may obtain a copy of the License at * * http://www.apache.org/licenses/LICENSE-2.0 * * * ======================================================================== */ /* * Program: Secure SUN-OS check password * * Author: Mark Crispin * Networks and Distributed Computing * Computing & Communications * University of Washington * Administration Building, AG-44 * Seattle, WA 98195 * Internet: MRC@CAC.Washington.EDU * * Date: 1 August 1988 * Last Edited: 30 August 2006 */ #include #include #include /* Check password * Accepts: login passwd struct * password string * argument count * argument vector * Returns: passwd struct if password validated, NIL otherwise */ struct passwd *checkpw (struct passwd *pw,char *pass,int argc,char *argv[]) { struct passwd_adjunct *pa; char *user = cpystr (pw->pw_name); /* validate user and password */ struct passwd *ret = ((pw->pw_passwd && pw->pw_passwd[0] && pw->pw_passwd[1] && !strcmp (pw->pw_passwd,(char *) crypt (pass,pw->pw_passwd))) || ((pa = getpwanam (pw->pw_name)) && pa->pwa_passwd && pa->pwa_passwd[0] && pa->pwa_passwd[1] && !strcmp (pa->pwa_passwd,(char *) crypt (pass,pa->pwa_passwd)))) ? getpwnam (user) : NIL; if (user) fs_give ((void **) &user); return ret; } alpine-2.10+dfsg/imap/src/osdep/unix/os_sun.c0000600000175000017500000000312311512502123022616 0ustar paulproteuspaulproteus/* ======================================================================== * Copyright 1988-2007 University of Washington * * Licensed under the Apache License, Version 2.0 (the "License"); * you may not use this file except in compliance with the License. * You may obtain a copy of the License at * * http://www.apache.org/licenses/LICENSE-2.0 * * * ======================================================================== */ /* * Program: Operating-system dependent routines -- SUN-OS version * * Author: Mark Crispin * Networks and Distributed Computing * Computing & Communications * University of Washington * Administration Building, AG-44 * Seattle, WA 98195 * Internet: MRC@CAC.Washington.EDU * * Date: 11 May 1989 * Last Edited: 16 August 2007 */ #include "tcp_unix.h" /* must be before osdep includes tcp.h */ #include "mail.h" #include "osdep.h" #include #include #include #include #include #include #include #include #include extern int errno; /* just in case */ #include #include "misc.h" extern int sys_nerr; extern char *sys_errlist[]; #define toint(c) ((c)-'0') #define isodigit(c) (((unsigned)(c)>=060)&((unsigned)(c)<=067)) #include "fs_unix.c" #include "ftl_unix.c" #include "nl_unix.c" #include "env_unix.c" #define fork vfork #include "tcp_unix.c" #include "gr_waitp.c" #include "memmove.c" #include "strerror.c" #define strstr Strstr /* override SUN's broken version */ #include "strstr.c" #include "strtoul.c" #include "tz_bsd.c" alpine-2.10+dfsg/imap/src/osdep/unix/os_drs.h0000600000175000017500000000265311512502123022615 0ustar paulproteuspaulproteus/* ======================================================================== * Copyright 1988-2006 University of Washington * * Licensed under the Apache License, Version 2.0 (the "License"); * you may not use this file except in compliance with the License. * You may obtain a copy of the License at * * http://www.apache.org/licenses/LICENSE-2.0 * * * ======================================================================== */ /* * Program: Operating-system dependent routines -- ICL DRS/NX version * * Author: Mark Crispin * Networks and Distributed Computing * Computing & Communications * University of Washington * Administration Building, AG-44 * Seattle, WA 98195 * Internet: MRC@CAC.Washington.EDU * * Date: 1 August 1988 * Last Edited: 15 September 2006 */ #include #include #include #include #include #include /* for struct tm */ #include #include #include #include #include #define random rand #define direct dirent long gethostid (void); typedef int (*select_t) (struct direct *name); typedef int (*compar_t) (void *d1,void *d2); int scandir (char *dirname,struct direct ***namelist,select_t select, compar_t compar); int alphasort (void *d1,void *d2); #include "env_unix.h" #include "fs.h" #include "ftl.h" #include "nl.h" #include "tcp.h" #include "flocksim.h" alpine-2.10+dfsg/imap/src/osdep/os2/0000700000175000017500000000000011512502151020664 5ustar paulproteuspaulproteusalpine-2.10+dfsg/imap/src/osdep/os2/env_os2.c0000600000175000017500000002016011512502123022403 0ustar paulproteuspaulproteus/* ======================================================================== * Copyright 1988-2006 University of Washington * * Licensed under the Apache License, Version 2.0 (the "License"); * you may not use this file except in compliance with the License. * You may obtain a copy of the License at * * http://www.apache.org/licenses/LICENSE-2.0 * * * ======================================================================== */ /* * Program: OS/2 environment routines * * Author: Mark Crispin * Networks and Distributed Computing * Computing & Communications * University of Washington * Administration Building, AG-44 * Seattle, WA 98195 * Internet: MRC@CAC.Washington.EDU * * Date: 1 August 1988 * Last Edited: 30 August 2006 */ static char *myLocalHost = NIL; /* local host name */ static char *myHomeDir = NIL; /* home directory name */ static char *myNewsrc = NIL; /* newsrc file name */ static short no822tztext = NIL; /* disable RFC [2]822 timezone text */ #include "write.c" /* include safe writing routines */ #include "pmatch.c" /* include wildcard pattern matcher */ /* Get all authenticators */ #include "auths.c" /* Environment manipulate parameters * Accepts: function code * function-dependent value * Returns: function-dependent return value */ void *env_parameters (long function,void *value) { void *ret = NIL; switch ((int) function) { case SET_HOMEDIR: myHomeDir = cpystr ((char *) value); case GET_HOMEDIR: ret = (void *) myHomeDir; break; case SET_LOCALHOST: myLocalHost = cpystr ((char *) value); case GET_LOCALHOST: ret = (void *) myLocalHost; break; case SET_NEWSRC: if (myNewsrc) fs_give ((void **) &myNewsrc); myNewsrc = cpystr ((char *) value); case GET_NEWSRC: if (!myNewsrc) { /* set news file name if not defined */ char tmp[MAILTMPLEN]; sprintf (tmp,"%s\\newsrc",myhomedir ()); myNewsrc = cpystr (tmp); } ret = (void *) myNewsrc; break; case SET_DISABLE822TZTEXT: no822tztext = value ? T : NIL; case GET_DISABLE822TZTEXT: ret = (void *) (no822tztext ? VOIDT : NIL); break; } return ret; } /* Write current time * Accepts: destination string * optional format of day-of-week prefix * format of date and time * flag whether to append symbolic timezone */ static void do_date (char *date,char *prefix,char *fmt,int suffix) { time_t tn = time (0); struct tm *t = gmtime (&tn); int zone = t->tm_hour * 60 + t->tm_min; int julian = t->tm_yday; t = localtime (&tn); /* get local time now */ /* minus UTC minutes since midnight */ zone = t->tm_hour * 60 + t->tm_min - zone; /* julian can be one of: * 36x local time is December 31, UTC is January 1, offset -24 hours * 1 local time is 1 day ahead of UTC, offset +24 hours * 0 local time is same day as UTC, no offset * -1 local time is 1 day behind UTC, offset -24 hours * -36x local time is January 1, UTC is December 31, offset +24 hours */ if (julian = t->tm_yday -julian) zone += ((julian < 0) == (abs (julian) == 1)) ? -24*60 : 24*60; if (prefix) { /* want day of week? */ sprintf (date,prefix,days[t->tm_wday]); date += strlen (date); /* make next sprintf append */ } /* output the date */ sprintf (date,fmt,t->tm_mday,months[t->tm_mon],t->tm_year+1900, t->tm_hour,t->tm_min,t->tm_sec,zone/60,abs (zone) % 60); if (suffix) { /* append timezone suffix if desired */ char *tz; tzset (); /* get timezone from TZ environment stuff */ tz = tzname[daylight ? (((struct tm *) t)->tm_isdst > 0) : 0]; if (tz && tz[0]) { char *s; for (s = tz; *s; s++) if (*s & 0x80) return; sprintf (date + strlen (date)," (%.50s)",tz); } } } /* Write current time in RFC 822 format * Accepts: destination string */ void rfc822_date (char *date) { do_date (date,"%s, ","%d %s %d %02d:%02d:%02d %+03d%02d", no822tztext ? NIL : T); } /* Write current time in fixed-width RFC 822 format * Accepts: destination string */ void rfc822_fixed_date (char *date) { do_date (date,NIL,"%02d %s %4d %02d:%02d:%02d %+03d%02d",NIL); } /* Write current time in internal format * Accepts: destination string */ void internal_date (char *date) { do_date (date,NIL,"%02d-%s-%d %02d:%02d:%02d %+03d%02d",NIL); } /* Return my home directory name * Returns: my home directory name */ char *myhomedir () { if (!myHomeDir) { /* get home directory name if not yet known */ char *s; if ((s = getenv ("PINEHOME")) || (s = getenv ("HOME")) || (s = getenv ("ETC"))) { myHomeDir = cpystr (s); while (s = strchr (myHomeDir,'/')) *s = '\\'; if ((s = strrchr (myHomeDir,'\\')) && !s[1]) *s = '\0'; } else myHomeDir = cpystr (""); } return myHomeDir; } /* Return mailbox file name * Accepts: destination buffer * mailbox name * Returns: file name */ char *mailboxfile (char *dst,char *name) { char *s; char *ext = (char *) mail_parameters (NIL,GET_EXTENSION,NIL); /* forbid extraneous extensions */ if ((s = strchr ((s = strrchr (name,'\\')) ? s : name,'.')) && ((ext = (char *) mail_parameters (NIL,GET_EXTENSION,NIL)) || strchr (s+1,'.'))) return NIL; /* absolute path name? */ if ((*name == '\\') || (name[1] == ':')) strcpy (dst,name); else sprintf (dst,"%s\\%s",myhomedir (),name); if (ext) sprintf (dst + strlen (dst),".%s",ext); return dst; } /* Lock file name * Accepts: return buffer for file name * file name * locking to be placed on file if non-NIL * Returns: file descriptor of lock or -1 if error */ int lockname (char *lock,char *fname,int op) { int ld; char c,*s; if (!((s = lockdir (lock,getenv ("TEMP"),NIL)) || (s = lockdir (lock,getenv ("TMP"),NIL)) || (s = lockdir (lock,getenv ("TMPDIR"),NIL)) || /* C:\TEMP is last resort */ (s = lockdir (lock,defaultDrive (),"TEMP")))) { mm_log ("Unable to find temporary directory",ERROR); return -1; } /* generate file name */ while (c = *fname++) switch (c) { case '/': case '\\': case ':': *s++ = '!'; /* convert bad chars to ! */ break; default: *s++ = c; break; } *s++ = c; /* tie off name */ /* get the lock */ if (((ld = open (lock,O_BINARY|O_RDWR|O_CREAT,S_IREAD|S_IWRITE)) >= 0) && op) flock (ld,op); /* apply locking function */ return ld; /* return locking file descriptor */ } /* Build lock directory, check to see if it exists * Accepts: return buffer for lock directory * first part of possible name * optional second part * Returns: pointer to end of buffer if buffer has a good name, else NIL */ char *lockdir (char *lock,char *first,char *last) { struct stat sbuf; char c,*s; if (first && *first) { /* first part must be non-NIL */ /* copy first part */ for (s = lock; *first; c = *s++ = *first++); if (last && *last) { /* copy last part if specified */ /* write trailing \ in case not in first */ if (c != '\\') *s++ = '\\'; while (*last) c = *s++ = *last++; } if (c == '\\') --s; /* delete trailing \ if any */ *s = '\0'; /* tie off name at this point */ return stat (lock,&sbuf) ? NIL : s; } return NIL; /* failed */ } /* Unlock file descriptor * Accepts: file descriptor * lock file name from lockfd() */ void unlockfd (int fd,char *lock) { flock (fd,LOCK_UN); /* unlock it */ close (fd); /* close it */ } /* Determine default prototype stream to user * Accepts: type (NIL for create, T for append) * Returns: default prototype stream */ MAILSTREAM *default_proto (long type) { extern MAILSTREAM DEFAULTPROTO; return &DEFAULTPROTO; /* return default driver's prototype */ } /* Global data */ static unsigned rndm = 0; /* initial `random' number */ /* Return random number */ long random () { if (!rndm) srand (rndm = (unsigned) time (0L)); return (long) rand (); } /* Emulator for BSD syslog() routine * Accepts: priority * message * parameters */ void syslog (int priority,const char *message,...) { } /* Emulator for BSD openlog() routine * Accepts: identity * options * facility */ void openlog (const char *ident,int logopt,int facility) { } alpine-2.10+dfsg/imap/src/osdep/os2/fs_os2.c0000600000175000017500000000260011512502123022222 0ustar paulproteuspaulproteus/* ======================================================================== * Copyright 1988-2006 University of Washington * * Licensed under the Apache License, Version 2.0 (the "License"); * you may not use this file except in compliance with the License. * You may obtain a copy of the License at * * http://www.apache.org/licenses/LICENSE-2.0 * * * ======================================================================== */ /* * Program: Free storage management routines * * Author: Mark Crispin * Networks and Distributed Computing * Computing & Communications * University of Washington * Administration Building, AG-44 * Seattle, WA 98195 * Internet: MRC@CAC.Washington.EDU * * Date: 1 August 1988 * Last Edited: 30 August 2006 */ /* Get a block of free storage * Accepts: size of desired block * Returns: free storage block */ void *fs_get (size_t size) { void *block = malloc (size ? size : (size_t) 1); if (!block) fatal ("Out of memory"); return (block); } /* Resize a block of free storage * Accepts: ** pointer to current block * new size */ void fs_resize (void **block,size_t size) { if (!(*block = realloc (*block,size ? size : (size_t) 1))) fatal ("Can't resize memory"); } /* Return a block of free storage * Accepts: ** pointer to free storage block */ void fs_give (void **block) { free (*block); *block = NIL; } alpine-2.10+dfsg/imap/src/osdep/os2/auths.cmd0000600000175000017500000000260211512502123022476 0ustar paulproteuspaulproteus/* rexx */ /* ======================================================================== * Copyright 1988-2006 University of Washington * * Licensed under the Apache License, Version 2.0 (the "License"); * you may not use this file except in compliance with the License. * You may obtain a copy of the License at * * http://www.apache.org/licenses/LICENSE-2.0 * * * ======================================================================== */ /* * Program: Authenticator Linkage Generator for OS/2 * * Author: Mark Crispin * Networks and Distributed Computing * Computing & Communications * University of Washington * Administration Building, AG-44 * Seattle, WA 98195 * Internet: MRC@CAC.Washington.EDU * * Date: 10 June 1999 * Last Edited: 30 August 2006 */ '@echo off' /* Erase old authenticators list */ 'if exist auths.c del auths.c' parse arg args n=words(args) a_file='auths.c' c_file='linkage.c' h_file='linkage.h' call stream a_file, 'C', 'open write' call stream c_file, 'C', 'open write' call stream h_file, 'C', 'open write' do i=1 to n arg=word(args,i) call lineout a_file, '#include "auth_'arg'.c"' call lineout h_file, 'extern AUTHENTICATOR auth_'arg';' call lineout c_file, ' auth_link (&auth_'arg'); /* link in the 'arg' authenticator */' end call stream h_file, 'C', 'close' call stream c_file, 'C', 'close' call stream a_file, 'C', 'close' exit 0 alpine-2.10+dfsg/imap/src/osdep/os2/dummy.h0000600000175000017500000000276411512502123022202 0ustar paulproteuspaulproteus/* ======================================================================== * Copyright 1988-2006 University of Washington * * Licensed under the Apache License, Version 2.0 (the "License"); * you may not use this file except in compliance with the License. * You may obtain a copy of the License at * * http://www.apache.org/licenses/LICENSE-2.0 * * * ======================================================================== */ /* * Program: Dummy routines * * Author: Mark Crispin * Networks and Distributed Computing * Computing & Communications * University of Washington * Administration Building, AG-44 * Seattle, WA 98195 * Internet: MRC@CAC.Washington.EDU * * Date: 9 May 1991 * Last Edited: 30 August 2006 */ /* Exported function prototypes */ void dummy_scan (MAILSTREAM *stream,char *ref,char *pat,char *contents); void dummy_list (MAILSTREAM *stream,char *ref,char *pat); void dummy_lsub (MAILSTREAM *stream,char *ref,char *pat); long scan_contents (DRIVER *dtb,char *name,char *contents, unsigned long csiz,unsigned long fsiz); long dummy_scan_contents (char *name,char *contents,unsigned long csiz, unsigned long fsiz); long dummy_create (MAILSTREAM *stream,char *mailbox); long dummy_create_path (MAILSTREAM *stream,char *path,long dirmode); long dummy_delete (MAILSTREAM *stream,char *mailbox); long dummy_rename (MAILSTREAM *stream,char *old,char *newname); char *dummy_file (char *dst,char *name); long dummy_canonicalize (char *tmp,char *ref,char *pat); alpine-2.10+dfsg/imap/src/osdep/os2/unixnt.c0000600000175000017500000023734611512502123022375 0ustar paulproteuspaulproteus/* ======================================================================== * Copyright 1988-2008 University of Washington * * Licensed under the Apache License, Version 2.0 (the "License"); * you may not use this file except in compliance with the License. * You may obtain a copy of the License at * * http://www.apache.org/licenses/LICENSE-2.0 * * * ======================================================================== */ /* * Program: UNIX mail routines * * Author: Mark Crispin * UW Technology * University of Washington * Seattle, WA 98195 * Internet: MRC@CAC.Washington.EDU * * Date: 20 December 1989 * Last Edited: 27 March 2008 */ /* DEDICATION * * This file is dedicated to my dog, Unix, also known as Yun-chan and * Unix J. Terwilliker Jehosophat Aloysius Monstrosity Animal Beast. Unix * passed away at the age of 11 1/2 on September 14, 1996, 12:18 PM PDT, after * a two-month bout with cirrhosis of the liver. * * He was a dear friend, and I miss him terribly. * * Lift a leg, Yunie. Luv ya forever!!!! */ #include #include #include extern int errno; /* just in case */ #include "mail.h" #include "osdep.h" #include #include #include #include #include "unixnt.h" #include "pseudo.h" #include "fdstring.h" #include "misc.h" #include "dummy.h" /* UNIX I/O stream local data */ typedef struct unix_local { unsigned int dirty : 1; /* disk copy needs updating */ unsigned int ddirty : 1; /* double-dirty, ping becomes checkpoint */ unsigned int pseudo : 1; /* uses a pseudo message */ unsigned int appending : 1; /* don't mark new messages as old */ int fd; /* mailbox file descriptor */ int ld; /* lock file descriptor */ char *lname; /* lock file name */ off_t filesize; /* file size parsed */ time_t filetime; /* last file time */ unsigned char *buf; /* temporary buffer */ unsigned long buflen; /* current size of temporary buffer */ unsigned long uid; /* current text uid */ SIZEDTEXT text; /* current text */ unsigned long textlen; /* current text length */ char *line; /* returned line */ char *linebuf; /* line readin buffer */ unsigned long linebuflen; /* current line readin buffer length */ } UNIXLOCAL; /* Convenient access to local data */ #define LOCAL ((UNIXLOCAL *) stream->local) /* UNIX protected file structure */ typedef struct unix_file { MAILSTREAM *stream; /* current stream */ off_t curpos; /* current file position */ off_t protect; /* protected position */ off_t filepos; /* current last written file position */ char *buf; /* overflow buffer */ size_t buflen; /* current overflow buffer length */ char *bufpos; /* current buffer position */ } UNIXFILE; /* Function prototypes */ DRIVER *unix_valid (char *name); void *unix_parameters (long function,void *value); void unix_scan (MAILSTREAM *stream,char *ref,char *pat,char *contents); void unix_list (MAILSTREAM *stream,char *ref,char *pat); void unix_lsub (MAILSTREAM *stream,char *ref,char *pat); long unix_create (MAILSTREAM *stream,char *mailbox); long unix_delete (MAILSTREAM *stream,char *mailbox); long unix_rename (MAILSTREAM *stream,char *old,char *newname); MAILSTREAM *unix_open (MAILSTREAM *stream); void unix_close (MAILSTREAM *stream,long options); char *unix_header (MAILSTREAM *stream,unsigned long msgno, unsigned long *length,long flags); long unix_text (MAILSTREAM *stream,unsigned long msgno,STRING *bs,long flags); char *unix_text_work (MAILSTREAM *stream,MESSAGECACHE *elt, unsigned long *length,long flags); void unix_flagmsg (MAILSTREAM *stream,MESSAGECACHE *elt); long unix_ping (MAILSTREAM *stream); void unix_check (MAILSTREAM *stream); long unix_expunge (MAILSTREAM *stream,char *sequence,long options); long unix_copy (MAILSTREAM *stream,char *sequence,char *mailbox,long options); long unix_append (MAILSTREAM *stream,char *mailbox,append_t af,void *data); int unix_collect_msg (MAILSTREAM *stream,FILE *sf,char *flags,char *date, STRING *msg); int unix_append_msgs (MAILSTREAM *stream,FILE *sf,FILE *df,SEARCHSET *set); void unix_abort (MAILSTREAM *stream); char *unix_file (char *dst,char *name); int unix_lock (char *file,int flags,int mode,char *lock,int op); void unix_unlock (int fd,MAILSTREAM *stream,char *lock); int unix_parse (MAILSTREAM *stream,char *lock,int op); char *unix_mbxline (MAILSTREAM *stream,STRING *bs,unsigned long *size); unsigned long unix_pseudo (MAILSTREAM *stream,char *hdr); unsigned long unix_xstatus (MAILSTREAM *stream,char *status,MESSAGECACHE *elt, unsigned long uid,long flag); long unix_rewrite (MAILSTREAM *stream,unsigned long *nexp,char *lock, long flags); long unix_extend (MAILSTREAM *stream,unsigned long size); void unix_write (UNIXFILE *f,char *s,unsigned long i); void unix_phys_write (UNIXFILE *f,char *buf,size_t size); /* UNIX mail routines */ /* Driver dispatch used by MAIL */ DRIVER unixdriver = { "unix", /* driver name */ /* driver flags */ DR_LOCAL|DR_MAIL|DR_NONEWMAILRONLY|DR_XPOINT, (DRIVER *) NIL, /* next driver */ unix_valid, /* mailbox is valid for us */ unix_parameters, /* manipulate parameters */ unix_scan, /* scan mailboxes */ unix_list, /* list mailboxes */ unix_lsub, /* list subscribed mailboxes */ NIL, /* subscribe to mailbox */ NIL, /* unsubscribe from mailbox */ unix_create, /* create mailbox */ unix_delete, /* delete mailbox */ unix_rename, /* rename mailbox */ mail_status_default, /* status of mailbox */ unix_open, /* open mailbox */ unix_close, /* close mailbox */ NIL, /* fetch message "fast" attributes */ NIL, /* fetch message flags */ NIL, /* fetch overview */ NIL, /* fetch message envelopes */ unix_header, /* fetch message header */ unix_text, /* fetch message text */ NIL, /* fetch partial message text */ NIL, /* unique identifier */ NIL, /* message number */ NIL, /* modify flags */ unix_flagmsg, /* per-message modify flags */ NIL, /* search for message based on criteria */ NIL, /* sort messages */ NIL, /* thread messages */ unix_ping, /* ping mailbox to see if still alive */ unix_check, /* check for new messages */ unix_expunge, /* expunge deleted messages */ unix_copy, /* copy messages to another mailbox */ unix_append, /* append string message to mailbox */ NIL /* garbage collect stream */ }; /* prototype stream */ MAILSTREAM unixproto = {&unixdriver}; /* driver parameters */ static long unix_fromwidget = T; /* UNIX mail validate mailbox * Accepts: mailbox name * Returns: our driver if name is valid, NIL otherwise */ DRIVER *unix_valid (char *name) { int fd; DRIVER *ret = NIL; int c,r; char tmp[MAILTMPLEN],file[MAILTMPLEN],*s,*t; struct stat sbuf; struct utimbuf times; errno = EINVAL; /* assume invalid argument */ /* must be non-empty file */ if ((t = dummy_file (file,name)) && !stat (t,&sbuf) && ((sbuf.st_mode & S_IFMT) == S_IFREG)) { if (!sbuf.st_size)errno = 0;/* empty file */ else if ((fd = open (file,O_BINARY|O_RDONLY,NIL)) >= 0) { memset (tmp,'\0',MAILTMPLEN); if (read (fd,tmp,MAILTMPLEN-1) <= 0) errno = -1; else { /* ignore leading whitespace */ for (s = tmp,c = '\n'; (*s == '\r') || (*s == '\n') || (*s == ' ') || (*s == '\t'); c = *s++); if (c == '\n') { /* at start of a line? */ VALID (s,t,r,c); /* yes, validate format */ if (r) ret = &unixdriver; else errno = -1; /* invalid format */ } } close (fd); /* close the file */ /* \Marked status? */ if ((sbuf.st_ctime > sbuf.st_atime) || (sbuf.st_mtime > sbuf.st_atime)) { /* yes, preserve atime and mtime */ times.actime = sbuf.st_atime; times.modtime = sbuf.st_mtime; utime (file,×); /* set the times */ } } } return ret; /* return what we should */ } /* UNIX manipulate driver parameters * Accepts: function code * function-dependent value * Returns: function-dependent return value */ void *unix_parameters (long function,void *value) { void *ret = NIL; switch ((int) function) { case SET_FROMWIDGET: unix_fromwidget = (long) value; case GET_FROMWIDGET: ret = (void *) unix_fromwidget; break; } return ret; } /* UNIX mail scan mailboxes * Accepts: mail stream * reference * pattern to search * string to scan */ void unix_scan (MAILSTREAM *stream,char *ref,char *pat,char *contents) { if (stream) dummy_scan (NIL,ref,pat,contents); } /* UNIX mail list mailboxes * Accepts: mail stream * reference * pattern to search */ void unix_list (MAILSTREAM *stream,char *ref,char *pat) { if (stream) dummy_list (NIL,ref,pat); } /* UNIX mail list subscribed mailboxes * Accepts: mail stream * reference * pattern to search */ void unix_lsub (MAILSTREAM *stream,char *ref,char *pat) { if (stream) dummy_lsub (NIL,ref,pat); } /* UNIX mail create mailbox * Accepts: MAIL stream * mailbox name to create * Returns: T on success, NIL on failure */ long unix_create (MAILSTREAM *stream,char *mailbox) { char *s,mbx[MAILTMPLEN],tmp[MAILTMPLEN]; long ret = NIL; int fd; time_t ti = time (0); if (!(s = dummy_file (mbx,mailbox))) { sprintf (tmp,"Can't create %.80s: invalid name",mailbox); mm_log (tmp,ERROR); } /* create underlying file */ else if (dummy_create_path (stream,s,NIL)) { if ((s = strrchr (s,'\\')) && !s[1]) ret = T; if ((fd = open (mbx,O_WRONLY|O_BINARY,NIL)) < 0) { sprintf (tmp,"Can't reopen mailbox node %.80s: %s",mbx,strerror (errno)); mm_log (tmp,ERROR); unlink (mbx); /* delete the file */ } else { /* initialize header */ memset (tmp,'\0',MAILTMPLEN); sprintf (tmp,"From %s %s",pseudo_from,ctime (&ti)); if (s = strpbrk (tmp,"\r\n")) *s = '\0'; strcat (tmp,"\r\nDate: "); rfc822_fixed_date (s = tmp + strlen (tmp)); sprintf (s += strlen (s), /* write the pseudo-header */ "\r\nFrom: %s <%s@%s>\r\nSubject: %s\r\nX-IMAP: %010lu 0000000000\r\nStatus: RO\r\n\r\n%s\r\n\r\n", pseudo_name,pseudo_from,mylocalhost (),pseudo_subject, (unsigned long) ti,pseudo_msg); if (write (fd,tmp,strlen (tmp)) > 0) { close (fd); /* close file */ ret = T; } else { sprintf (tmp,"Can't initialize mailbox node %.80s: %s",mbx, strerror (errno)); mm_log (tmp,ERROR); close (fd); /* close file before unlinking */ unlink (mbx); /* delete the file */ } } } return ret; } /* UNIX mail delete mailbox * Accepts: MAIL stream * mailbox name to delete * Returns: T on success, NIL on failure */ long unix_delete (MAILSTREAM *stream,char *mailbox) { return unix_rename (stream,mailbox,NIL); } /* UNIX mail rename mailbox * Accepts: MAIL stream * old mailbox name * new mailbox name (or NIL for delete) * Returns: T on success, NIL on failure */ long unix_rename (MAILSTREAM *stream,char *old,char *newname) { long ret = NIL; char c,*s = NIL; char tmp[MAILTMPLEN],file[MAILTMPLEN],lock[MAILTMPLEN],lockx[MAILTMPLEN]; int fd,ld; struct stat sbuf; mm_critical (stream); /* get the c-client lock */ if (!dummy_file (file,old) || (newname && (!(s = dummy_file (tmp,newname)) || ((s = strrchr (s,'\\')) && !s[1])))) sprintf (tmp,newname ? "Can't rename mailbox %.80s to %.80s: invalid name" : "Can't delete mailbox %.80s: invalid name", old,newname); else if ((ld = lockname (lock,file,NIL)) < 0) sprintf (tmp,"Can't get lock for mailbox %.80s",old); else { /* lock out other c-clients */ if (flock (ld,LOCK_EX|LOCK_NB)) { close (ld); /* couldn't lock, give up on it then */ sprintf (tmp,"Mailbox %.80s is in use by another process",old); } /* lock out non c-client applications */ else if ((fd = unix_lock (file,O_BINARY|O_RDWR,S_IREAD|S_IWRITE,lockx, LOCK_EX)) < 0) sprintf (tmp,"Can't lock mailbox %.80s: %s",old,strerror (errno)); else { unix_unlock(fd,NIL,lockx);/* pacify evil NTFS */ if (newname) { /* want rename? */ /* found superior to destination name? */ if ((s = strrchr (tmp,'\\')) && (s != tmp) && ((tmp[1] != ':') || (s != tmp + 2))) { c = s[1]; /* remember character after delimiter */ *s = s[1] = '\0'; /* tie off name at delimiter */ /* name doesn't exist, create it */ if (stat (tmp,&sbuf) || ((sbuf.st_mode & S_IFMT) != S_IFDIR)) { *s = '\\'; /* restore delimiter */ if (!dummy_create (stream,newname)) { flock (ld,LOCK_UN); close (ld); /* close c-client lock */ unlink (lock); /* and delete it */ mm_nocritical (stream); return NIL; /* couldn't create superior */ } } else *s = '\\'; /* restore delimiter */ s[1] = c; /* restore character after delimiter */ } if (rename (file,tmp)) sprintf (tmp,"Can't rename mailbox %.80s to %.80s: %s",old,newname, strerror (errno)); else ret = T; /* set success */ } else if (unlink (file)) /* want delete */ sprintf (tmp,"Can't delete mailbox %.80s: %s",old,strerror (errno)); else ret = T; /* set success */ flock (ld,LOCK_UN); /* release c-client lock */ close (ld); /* close c-client lock */ unlink (lock); /* and delete it */ } } mm_nocritical (stream); /* no longer critical */ if (!ret) mm_log (tmp,ERROR); /* log error */ return ret; /* return success or failure */ } /* UNIX mail open * Accepts: Stream to open * Returns: Stream on success, NIL on failure */ MAILSTREAM *unix_open (MAILSTREAM *stream) { int fd; char tmp[MAILTMPLEN]; /* return prototype for OP_PROTOTYPE call */ if (!stream) return &unixproto; if (stream->local) fatal ("unix recycle stream"); stream->local = memset (fs_get (sizeof (UNIXLOCAL)),0,sizeof (UNIXLOCAL)); /* note if an INBOX or not */ stream->inbox = !compare_cstring (stream->mailbox,"INBOX"); /* canonicalize the stream mailbox name */ if (!dummy_file (tmp,stream->mailbox)) { sprintf (tmp,"Can't open - invalid name: %.80s",stream->mailbox); mm_log (tmp,ERROR); return NIL; } /* flush old name */ fs_give ((void **) &stream->mailbox); /* save canonical name */ stream->mailbox = cpystr (tmp); LOCAL->fd = LOCAL->ld = -1; /* no file or state locking yet */ LOCAL->buf = (char *) fs_get ((LOCAL->buflen = CHUNKSIZE) + 1); LOCAL->text.data = (unsigned char *) fs_get (CHUNKSIZE); LOCAL->text.size = CHUNKSIZE - 1; LOCAL->linebuf = (char *) fs_get (CHUNKSIZE); LOCAL->linebuflen = CHUNKSIZE - 1; stream->sequence++; /* bump sequence number */ if (!stream->rdonly) { /* make lock for read/write access */ if ((fd = lockname (tmp,stream->mailbox,NIL)) < 0) mm_log ("Can't open mailbox lock, access is readonly",WARN); /* can get the lock? */ else if (flock (fd,LOCK_EX|LOCK_NB)) { if (!stream->silent) mm_log ("Mailbox is open by another process, access is readonly",WARN); close (fd); } else { /* got the lock, nobody else can alter state */ LOCAL->ld = fd; /* note lock's fd and name */ LOCAL->lname = cpystr (tmp); } } /* parse mailbox */ stream->nmsgs = stream->recent = 0; /* will we be able to get write access? */ if ((LOCAL->ld >= 0) && access (stream->mailbox,02) && (errno == EACCES)) { mm_log ("Can't get write access to mailbox, access is readonly",WARN); flock (LOCAL->ld,LOCK_UN); /* release the lock */ close (LOCAL->ld); /* close the lock file */ LOCAL->ld = -1; /* no more lock fd */ unlink (LOCAL->lname); /* delete it */ } /* reset UID validity */ stream->uid_validity = stream->uid_last = 0; if (stream->silent && !stream->rdonly && (LOCAL->ld < 0)) unix_abort (stream); /* abort if can't get RW silent stream */ /* parse mailbox */ else if (unix_parse (stream,tmp,LOCK_SH)) { unix_unlock (LOCAL->fd,stream,tmp); mail_unlock (stream); mm_nocritical (stream); /* done with critical */ } if (!LOCAL) return NIL; /* failure if stream died */ /* make sure upper level knows readonly */ stream->rdonly = (LOCAL->ld < 0); /* notify about empty mailbox */ if (!(stream->nmsgs || stream->silent)) mm_log ("Mailbox is empty",NIL); if (!stream->rdonly) { /* flags stick if readwrite */ stream->perm_seen = stream->perm_deleted = stream->perm_flagged = stream->perm_answered = stream->perm_draft = T; /* have permanent keywords */ stream->perm_user_flags = 0xffffffff; /* and maybe can create them too */ stream->kwd_create = stream->user_flags[NUSERFLAGS-1] ? NIL : T; } return stream; /* return stream alive to caller */ } /* UNIX mail close * Accepts: MAIL stream * close options */ void unix_close (MAILSTREAM *stream,long options) { int silent = stream->silent; stream->silent = T; /* go silent */ /* expunge if requested */ if (options & CL_EXPUNGE) unix_expunge (stream,NIL,NIL); /* else dump final checkpoint */ else if (LOCAL->dirty) unix_check (stream); stream->silent = silent; /* restore old silence state */ unix_abort (stream); /* now punt the file and local data */ } /* UNIX mail fetch message header * Accepts: MAIL stream * message # to fetch * pointer to returned header text length * option flags * Returns: message header in RFC822 format */ /* lines to filter from header */ static STRINGLIST *unix_hlines = NIL; char *unix_header (MAILSTREAM *stream,unsigned long msgno, unsigned long *length,long flags) { MESSAGECACHE *elt; unsigned char *s; *length = 0; /* default to empty */ if (flags & FT_UID) return "";/* UID call "impossible" */ elt = mail_elt (stream,msgno);/* get cache */ if (!unix_hlines) { /* once only code */ STRINGLIST *lines = unix_hlines = mail_newstringlist (); lines->text.size = strlen ((char *) (lines->text.data = (unsigned char *) "Status")); lines = lines->next = mail_newstringlist (); lines->text.size = strlen ((char *) (lines->text.data = (unsigned char *) "X-Status")); lines = lines->next = mail_newstringlist (); lines->text.size = strlen ((char *) (lines->text.data = (unsigned char *) "X-Keywords")); lines = lines->next = mail_newstringlist (); lines->text.size = strlen ((char *) (lines->text.data = (unsigned char *) "X-UID")); lines = lines->next = mail_newstringlist (); lines->text.size = strlen ((char *) (lines->text.data = (unsigned char *) "X-IMAP")); lines = lines->next = mail_newstringlist (); lines->text.size = strlen ((char *) (lines->text.data = (unsigned char *) "X-IMAPbase")); } /* go to header position */ lseek (LOCAL->fd,elt->private.special.offset + elt->private.msg.header.offset,L_SET); if (flags & FT_INTERNAL) { /* initial data OK? */ if (elt->private.msg.header.text.size > LOCAL->buflen) { fs_give ((void **) &LOCAL->buf); LOCAL->buf = (char *) fs_get ((LOCAL->buflen = elt->private.msg.header.text.size) + 1); } /* read message */ read (LOCAL->fd,LOCAL->buf,elt->private.msg.header.text.size); /* got text, tie off string */ LOCAL->buf[*length = elt->private.msg.header.text.size] = '\0'; } else { /* need to make a CRLF version */ read (LOCAL->fd,s = (char *) fs_get (elt->private.msg.header.text.size+1), elt->private.msg.header.text.size); /* tie off string, and convert to CRLF */ s[elt->private.msg.header.text.size] = '\0'; *length = unix_crlfcpy (&LOCAL->buf,&LOCAL->buflen,s, elt->private.msg.header.text.size); fs_give ((void **) &s); /* free readin buffer */ } *length = mail_filter (LOCAL->buf,*length,unix_hlines,FT_NOT); return LOCAL->buf; /* return processed copy */ } /* UNIX mail fetch message text * Accepts: MAIL stream * message # to fetch * pointer to returned stringstruct * option flags * Returns: T on success, NIL if failure */ long unix_text (MAILSTREAM *stream,unsigned long msgno,STRING *bs,long flags) { char *s; unsigned long i; MESSAGECACHE *elt; /* UID call "impossible" */ if (flags & FT_UID) return NIL; elt = mail_elt (stream,msgno);/* get cache element */ /* if message not seen */ if (!(flags & FT_PEEK) && !elt->seen) { /* mark message seen and dirty */ elt->seen = elt->private.dirty = LOCAL->dirty = T; mm_flags (stream,msgno); } s = unix_text_work (stream,elt,&i,flags); INIT (bs,mail_string,s,i); /* set up stringstruct */ return T; /* success */ } /* UNIX mail fetch message text worker routine * Accepts: MAIL stream * message cache element * pointer to returned header text length * option flags */ char *unix_text_work (MAILSTREAM *stream,MESSAGECACHE *elt, unsigned long *length,long flags) { FDDATA d; STRING bs; unsigned char c,*s,tmp[CHUNKSIZE]; /* go to text position */ lseek (LOCAL->fd,elt->private.special.offset + elt->private.msg.text.offset,L_SET); if (flags & FT_INTERNAL) { /* initial data OK? */ if (elt->private.msg.text.text.size > LOCAL->buflen) { fs_give ((void **) &LOCAL->buf); LOCAL->buf = (char *) fs_get ((LOCAL->buflen = elt->private.msg.text.text.size) + 1); } /* read message */ read (LOCAL->fd,LOCAL->buf,elt->private.msg.text.text.size); /* got text, tie off string */ LOCAL->buf[*length = elt->private.msg.text.text.size] = '\0'; return LOCAL->buf; } /* have it cached already? */ if (elt->private.uid != LOCAL->uid) { /* not cached, cache it now */ LOCAL->uid = elt->private.uid; /* is buffer big enough? */ if (elt->rfc822_size > LOCAL->text.size) { /* excessively conservative, but the right thing is too hard to do */ fs_give ((void **) &LOCAL->text.data); LOCAL->text.data = (unsigned char *) fs_get ((LOCAL->text.size = elt->rfc822_size) + 1); } d.fd = LOCAL->fd; /* yes, set up file descriptor */ d.pos = elt->private.special.offset + elt->private.msg.text.offset; d.chunk = tmp; /* initial buffer chunk */ d.chunksize = CHUNKSIZE; /* file chunk size */ INIT (&bs,fd_string,&d,elt->private.msg.text.text.size); for (s = (char *) LOCAL->text.data; SIZE (&bs);) switch (c = SNX (&bs)) { case '\r': /* carriage return seen */ *s++ = c; /* copy it and any succeeding LF */ if (SIZE (&bs) && (CHR (&bs) == '\n')) *s++ = SNX (&bs); break; case '\n': *s++ = '\r'; /* insert a CR */ default: *s++ = c; /* copy characters */ } *s = '\0'; /* tie off buffer */ /* calculate length of cached data */ LOCAL->textlen = s - LOCAL->text.data; } *length = LOCAL->textlen; /* return from cache */ return (char *) LOCAL->text.data; } /* UNIX per-message modify flag * Accepts: MAIL stream * message cache element */ void unix_flagmsg (MAILSTREAM *stream,MESSAGECACHE *elt) { /* only after finishing */ if (elt->valid) elt->private.dirty = LOCAL->dirty = T; } /* UNIX mail ping mailbox * Accepts: MAIL stream * Returns: T if stream alive, else NIL */ long unix_ping (MAILSTREAM *stream) { char lock[MAILTMPLEN]; struct stat sbuf; /* big no-op if not readwrite */ if (LOCAL && (LOCAL->ld >= 0) && !stream->lock) { if (stream->rdonly) { /* does he want to give up readwrite? */ /* checkpoint if we changed something */ if (LOCAL->dirty) unix_check (stream); flock (LOCAL->ld,LOCK_UN);/* release readwrite lock */ close (LOCAL->ld); /* close the readwrite lock file */ LOCAL->ld = -1; /* no more readwrite lock fd */ unlink (LOCAL->lname); /* delete the readwrite lock file */ } else { /* get current mailbox size */ if (LOCAL->fd >= 0) fstat (LOCAL->fd,&sbuf); else if (stat (stream->mailbox,&sbuf)) { sprintf (LOCAL->buf,"Mailbox stat failed, aborted: %s", strerror (errno)); MM_LOG (LOCAL->buf,ERROR); unix_abort (stream); return NIL; } /* parse if mailbox changed */ if ((LOCAL->ddirty || (sbuf.st_size != LOCAL->filesize)) && unix_parse (stream,lock,LOCK_EX)) { /* force checkpoint if double-dirty */ if (LOCAL->ddirty) unix_rewrite (stream,NIL,lock,NIL); /* unlock mailbox */ else unix_unlock (LOCAL->fd,stream,lock); mail_unlock (stream); /* and stream */ mm_nocritical (stream); /* done with critical */ } } } return LOCAL ? LONGT : NIL; /* return if still alive */ } /* UNIX mail check mailbox * Accepts: MAIL stream */ void unix_check (MAILSTREAM *stream) { char lock[MAILTMPLEN]; /* parse and lock mailbox */ if (LOCAL && (LOCAL->ld >= 0) && !stream->lock && unix_parse (stream,lock,LOCK_EX)) { /* any unsaved changes? */ if (LOCAL->dirty && unix_rewrite (stream,NIL,lock,NIL)) { if (!stream->silent) mm_log ("Checkpoint completed",NIL); } /* no checkpoint needed, just unlock */ else unix_unlock (LOCAL->fd,stream,lock); mail_unlock (stream); /* unlock the stream */ mm_nocritical (stream); /* done with critical */ } } /* UNIX mail expunge mailbox * Accepts: MAIL stream * sequence to expunge if non-NIL * expunge options * Returns: T, always */ long unix_expunge (MAILSTREAM *stream,char *sequence,long options) { long ret; unsigned long i; char lock[MAILTMPLEN]; char *msg = NIL; /* parse and lock mailbox */ if (ret = (sequence ? ((options & EX_UID) ? mail_uid_sequence (stream,sequence) : mail_sequence (stream,sequence)) : LONGT) && LOCAL && (LOCAL->ld >= 0) && !stream->lock && unix_parse (stream,lock,LOCK_EX)) { /* check expunged messages if not dirty */ for (i = 1; !LOCAL->dirty && (i <= stream->nmsgs); i++) { MESSAGECACHE *elt = mail_elt (stream,i); if (mail_elt (stream,i)->deleted) LOCAL->dirty = T; } if (!LOCAL->dirty) { /* not dirty and no expunged messages */ unix_unlock (LOCAL->fd,stream,lock); msg = "No messages deleted, so no update needed"; } else if (unix_rewrite (stream,&i,lock,sequence ? LONGT : NIL)) { if (i) sprintf (msg = LOCAL->buf,"Expunged %lu messages",i); else msg = "Mailbox checkpointed, but no messages expunged"; } /* rewrite failed */ else unix_unlock (LOCAL->fd,stream,lock); mail_unlock (stream); /* unlock the stream */ mm_nocritical (stream); /* done with critical */ if (msg && !stream->silent) mm_log (msg,NIL); } else if (!stream->silent) mm_log("Expunge ignored on readonly mailbox",WARN); return ret; } /* UNIX mail copy message(s) * Accepts: MAIL stream * sequence * destination mailbox * copy options * Returns: T if copy successful, else NIL */ long unix_copy (MAILSTREAM *stream,char *sequence,char *mailbox,long options) { struct stat sbuf; int fd; char *s,file[MAILTMPLEN],lock[MAILTMPLEN]; struct utimbuf times; unsigned long i,j; MESSAGECACHE *elt; long ret = T; mailproxycopy_t pc = (mailproxycopy_t) mail_parameters (stream,GET_MAILPROXYCOPY,NIL); copyuid_t cu = (copyuid_t) (mail_parameters (NIL,GET_USERHASNOLIFE,NIL) ? NIL : mail_parameters (NIL,GET_COPYUID,NIL)); SEARCHSET *source = cu ? mail_newsearchset () : NIL; SEARCHSET *dest = cu ? mail_newsearchset () : NIL; MAILSTREAM *tstream = NIL; if (!((options & CP_UID) ? mail_uid_sequence (stream,sequence) : mail_sequence (stream,sequence))) return NIL; /* make sure destination is valid */ if (!(unix_valid (mailbox) || !errno)) switch (errno) { case ENOENT: /* no such file? */ if (compare_cstring (mailbox,"INBOX")) { mm_notify (stream,"[TRYCREATE] Must create mailbox before copy",NIL); return NIL; } if (pc) return (*pc) (stream,sequence,mailbox,options); unix_create (NIL,"INBOX");/* create empty INBOX */ case EACCES: /* file protected */ sprintf (LOCAL->buf,"Can't access destination: %.80s",mailbox); MM_LOG (LOCAL->buf,ERROR); return NIL; case EINVAL: if (pc) return (*pc) (stream,sequence,mailbox,options); sprintf (LOCAL->buf,"Invalid UNIX-format mailbox name: %.80s",mailbox); mm_log (LOCAL->buf,ERROR); return NIL; default: if (pc) return (*pc) (stream,sequence,mailbox,options); sprintf (LOCAL->buf,"Not a UNIX-format mailbox: %.80s",mailbox); mm_log (LOCAL->buf,ERROR); return NIL; } /* try to open rewrite for UIDPLUS */ if ((tstream = mail_open_work (&unixdriver,NIL,mailbox, OP_SILENT|OP_NOKOD)) && tstream->rdonly) tstream = mail_close (tstream); if (cu && !tstream) { /* wanted a COPYUID? */ sprintf (LOCAL->buf,"Unable to write-open mailbox for COPYUID: %.80s", mailbox); MM_LOG (LOCAL->buf,WARN); cu = NIL; /* don't try to do COPYUID */ } LOCAL->buf[0] = '\0'; mm_critical (stream); /* go critical */ if ((fd = unix_lock (dummy_file (file,mailbox), O_BINARY|O_WRONLY|O_APPEND|O_CREAT,S_IREAD|S_IWRITE, lock,LOCK_EX)) < 0) { mm_nocritical (stream); /* done with critical */ sprintf (LOCAL->buf,"Can't open destination mailbox: %s",strerror (errno)); mm_log (LOCAL->buf,ERROR); /* log the error */ return NIL; /* failed */ } fstat (fd,&sbuf); /* get current file size */ /* write all requested messages to mailbox */ for (i = 1; ret && (i <= stream->nmsgs); i++) if ((elt = mail_elt (stream,i))->sequence) { lseek (LOCAL->fd,elt->private.special.offset,L_SET); read (LOCAL->fd,LOCAL->buf,elt->private.special.text.size); if (LOCAL->buf[(j = elt->private.special.text.size) - 2] != '\r') { LOCAL->buf[j - 1] = '\r'; LOCAL->buf[j++] = '\n'; } if (write (fd,LOCAL->buf,j) < 0) ret = NIL; else { /* internal header succeeded */ s = unix_header (stream,i,&j,NIL); /* header size, sans trailing newline */ if (j && (s[j - 4] == '\r')) j -= 2; if (write (fd,s,j) < 0) ret = NIL; else { /* message header succeeded */ j = tstream ? /* write UIDPLUS data if have readwrite */ unix_xstatus (stream,LOCAL->buf,elt,++(tstream->uid_last),LONGT) : unix_xstatus (stream,LOCAL->buf,elt,NIL,NIL); if (write (fd,LOCAL->buf,j) < 0) ret = NIL; else { /* message status succeeded */ s = unix_text_work (stream,elt,&j,NIL); if ((write (fd,s,j) < 0) || (write (fd,"\r\n",2) < 0)) ret = NIL; else if (cu) { /* need to pass back new UID? */ mail_append_set (source,mail_uid (stream,i)); mail_append_set (dest,tstream->uid_last); } } } } } if (!ret || fsync (fd)) { /* force out the update */ sprintf (LOCAL->buf,"Message copy failed: %s",strerror (errno)); ftruncate (fd,sbuf.st_size); ret = NIL; } /* force UIDVALIDITY assignment now */ if (tstream && !tstream->uid_validity) tstream->uid_validity = (unsigned long) time (0); /* return sets if doing COPYUID */ if (cu && ret) (*cu) (stream,mailbox,tstream->uid_validity,source,dest); else { /* flush any sets we may have built */ mail_free_searchset (&source); mail_free_searchset (&dest); } times.modtime = time (0); /* set mtime to now */ /* set atime to now-1 if successful copy */ if (ret) times.actime = times.modtime - 1; else times.actime = /* else preserve \Marked status */ ((sbuf.st_ctime > sbuf.st_atime) || (sbuf.st_mtime > sbuf.st_atime)) ? sbuf.st_atime : times.modtime; utime (file,×); /* set the times */ unix_unlock (fd,NIL,lock); /* unlock and close mailbox */ if (tstream) { /* update last UID if we can */ UNIXLOCAL * local = (UNIXLOCAL *) tstream->local; local->dirty = T; /* do a rewrite */ local->appending = T; /* but not at the cost of marking as old */ tstream = mail_close (tstream); } /* log the error */ if (!ret) mm_log (LOCAL->buf,ERROR); /* delete if requested message */ else if (options & CP_MOVE) for (i = 1; i <= stream->nmsgs; i++) if ((elt = mail_elt (stream,i))->sequence) elt->deleted = elt->private.dirty = LOCAL->dirty = T; mm_nocritical (stream); /* release critical */ return ret; } /* UNIX mail append message from stringstruct * Accepts: MAIL stream * destination mailbox * append callback * data for callback * Returns: T if append successful, else NIL */ #define BUFLEN 8*MAILTMPLEN long unix_append (MAILSTREAM *stream,char *mailbox,append_t af,void *data) { struct stat sbuf; int fd; unsigned long i; char *flags,*date,buf[BUFLEN],tmp[MAILTMPLEN],file[MAILTMPLEN], lock[MAILTMPLEN]; struct utimbuf times; FILE *sf,*df; MESSAGECACHE elt; STRING *message; unsigned long uidlocation = 0; appenduid_t au = (appenduid_t) (mail_parameters (NIL,GET_USERHASNOLIFE,NIL) ? NIL : mail_parameters (NIL,GET_APPENDUID,NIL)); SEARCHSET *dst = au ? mail_newsearchset () : NIL; long ret = LONGT; MAILSTREAM *tstream = NIL; if (!stream) { /* stream specified? */ stream = &unixproto; /* no, default stream to prototype */ for (i = 0; i < NUSERFLAGS && stream->user_flags[i]; ++i) fs_give ((void **) &stream->user_flags[i]); } if (!unix_valid (mailbox)) switch (errno) { case ENOENT: /* no such file? */ if (!compare_cstring (mailbox,"INBOX")) { mm_notify (stream,"[TRYCREATE] Must create mailbox before append",NIL); return NIL; } unix_create (NIL,"INBOX"); /* create empty INBOX */ case 0: /* merely empty file? */ tstream = stream; break; case EACCES: /* file protected */ sprintf (tmp,"Can't access destination: %.80s",mailbox); MM_LOG (tmp,ERROR); return NIL; case EINVAL: sprintf (tmp,"Invalid UNIX-format mailbox name: %.80s",mailbox); mm_log (tmp,ERROR); return NIL; default: sprintf (tmp,"Not a UNIX-format mailbox: %.80s",mailbox); mm_log (tmp,ERROR); return NIL; } /* get sniffing stream for keywords */ else if (!(tstream = mail_open (NIL,mailbox, OP_READONLY|OP_SILENT|OP_NOKOD|OP_SNIFF))) { sprintf (tmp,"Unable to examine mailbox for APPEND: %.80s",mailbox); MM_LOG (tmp,ERROR); return NIL; } /* get first message */ if (!(*af) (tstream,data,&flags,&date,&message)) return NIL; if (!(sf = tmpfile ())) { /* must have scratch file */ sprintf (tmp,".%lx.%lx",(unsigned long) time (0),(unsigned long)getpid ()); if (!stat (tmp,&sbuf) || !(sf = fopen (tmp,"wb+"))) { sprintf (tmp,"Unable to create scratch file: %.80s",strerror (errno)); mm_log (tmp,ERROR); return NIL; } unlink (tmp); } do { /* parse date */ if (!date) rfc822_date (date = tmp); if (!mail_parse_date (&elt,date)) { sprintf (tmp,"Bad date in append: %.80s",date); mm_log (tmp,ERROR); } else { /* user wants to suppress time zones? */ if (mail_parameters (NIL,GET_NOTIMEZONES,NIL)) { time_t when = mail_longdate (&elt); date = ctime (&when); /* use traditional date */ } /* use POSIX-style date */ else date = mail_cdate (tmp,&elt); if (!SIZE (message)) mm_log ("Append of zero-length message",ERROR); else if (!unix_collect_msg (tstream,sf,flags,date,message)) { sprintf (tmp,"Error writing scratch file: %.80s",strerror (errno)); mm_log (tmp,ERROR); } /* get next message */ else if ((*af) (tstream,data,&flags,&date,&message)) continue; } fclose (sf); /* punt scratch file */ return NIL; /* give up */ } while (message); /* until no more messages */ if (fflush (sf)) { sprintf (tmp,"Error finishing scratch file: %.80s",strerror (errno)); mm_log (tmp,ERROR); fclose (sf); /* punt scratch file */ return NIL; /* give up */ } i = ftell (sf); /* size of scratch file */ /* close sniffing stream */ if (tstream != stream) tstream = mail_close (tstream); mm_critical (stream); /* go critical */ /* try to open readwrite for UIDPLUS */ if ((tstream = mail_open_work (&unixdriver,NIL,mailbox, OP_SILENT|OP_NOKOD)) && tstream->rdonly) tstream = mail_close (tstream); if (au && !tstream) { /* wanted an APPENDUID? */ sprintf (tmp,"Unable to re-open mailbox for APPENDUID: %.80s",mailbox); MM_LOG (tmp,WARN); au = NIL; } if (((fd = unix_lock (dummy_file (file,mailbox), O_BINARY|O_WRONLY|O_APPEND|O_CREAT,S_IREAD|S_IWRITE, lock,LOCK_EX)) < 0) || !(df = fdopen (fd,"ab"))) { mm_nocritical (stream); /* done with critical */ sprintf (tmp,"Can't open append mailbox: %s",strerror (errno)); mm_log (tmp,ERROR); return NIL; } fstat (fd,&sbuf); /* get current file size */ rewind (sf); times.modtime = time (0); /* set mtime to now */ /* write all messages */ if (!unix_append_msgs (tstream,sf,df,au ? dst : NIL) || (fflush (df) == EOF) || fsync (fd)) { sprintf (buf,"Message append failed: %s",strerror (errno)); mm_log (buf,ERROR); ftruncate (fd,sbuf.st_size);/* revert file */ times.actime = /* preserve \Marked status */ ((sbuf.st_ctime > sbuf.st_atime) || (sbuf.st_mtime > sbuf.st_atime)) ? sbuf.st_atime : times.modtime; ret = NIL; /* return error */ } /* set atime to now-1 if successful copy */ else times.actime = times.modtime - 1; utime (file,×); /* set the times */ fclose (sf); /* done with scratch file */ /* force UIDVALIDITY assignment now */ if (tstream && !tstream->uid_validity) tstream->uid_validity = (unsigned long) time (0); /* return sets if doing APPENDUID */ if (au && ret) (*au) (mailbox,tstream->uid_validity,dst); else mail_free_searchset (&dst); flock (fd,LOCK_UN); /* unlock mailbox (can't use unix_unlock() */ if (lock && *lock) unlink (lock); fclose (df); /* close mailbox */ if (tstream) { /* update last UID if we can */ UNIXLOCAL * local = (UNIXLOCAL *) tstream->local; local->dirty = T; /* do a rewrite */ local->appending = T; /* but not at the cost of marking as old */ tstream = mail_close (tstream); } mm_nocritical (stream); /* release critical */ return ret; } /* Collect and write single message to append scratch file * Accepts: MAIL stream * scratch file * flags * date * message stringstruct * Returns: NIL if write error, else T */ int unix_collect_msg (MAILSTREAM *stream,FILE *sf,char *flags,char *date, STRING *msg) { unsigned char *s,*t; unsigned long uf; long f = mail_parse_flags (stream,flags,&uf); /* write metadata */ if (fprintf (sf,"%ld %lu ",f,SIZE (msg) + 2) < 0) return NIL; for (s = date; *s; *s++) switch (*s) { default: if (putc (*s,sf) == EOF) return NIL; case '\r': case '\n': break; } if (fputs ("\r\n",sf) == EOF) return NIL; while (uf) /* write user flags */ if ((s = stream->user_flags[find_rightmost_bit (&uf)]) && (fprintf (sf," %s",s) < 0)) return NIL; if (fputs ("\r\n",sf) == EOF) return NIL; while (SIZE (msg)) { /* copy text to scratch file */ for (s = (unsigned char *) msg->curpos, t = s + msg->cursize; s < t; ++s) if (!*s) *s = 0x80; /* disallow NUL */ /* write buffered text */ if (fwrite (msg->curpos,1,msg->cursize,sf) == msg->cursize) SETPOS (msg,GETPOS (msg) + msg->cursize); else return NIL; /* failed */ } /* write trailing CRLF and return */ return (fputs ("\r\n",sf) == EOF) ? NIL : T; } /* Append messages from scratch file to mailbox * Accepts: MAIL stream * source file * destination file * uidset to update if non-NIL * Returns: T if success, NIL if failure */ int unix_append_msgs (MAILSTREAM *stream,FILE *sf,FILE *df,SEARCHSET *set) { int ti,zn,c; long f; unsigned long i,j; char *x,tmp[MAILTMPLEN]; int hdrp = T; /* get message metadata line */ while (fgets (tmp,MAILTMPLEN,sf)) { if (!(isdigit (tmp[0]) && strchr (tmp,'\n'))) return NIL; f = strtol (tmp,&x,10); /* get flags */ if (!((*x++ == ' ') && isdigit (*x))) return NIL; i = strtoul (x,&x,10); /* get message size */ if ((*x++ != ' ') || /* build initial header */ (fprintf (df,"From %s@%s %sStatus: ",myusername(),mylocalhost(),x)<0)|| (f&fSEEN && (putc ('R',df) == EOF)) || (fputs ("\r\nX-Status: ",df) == EOF) || (f&fDELETED && (putc ('D',df) == EOF)) || (f&fFLAGGED && (putc ('F',df) == EOF)) || (f&fANSWERED && (putc ('A',df) == EOF)) || (f&fDRAFT && (putc ('T',df) == EOF)) || (fputs ("\r\nX-Keywords:",df) == EOF)) return NIL; /* copy keywords */ while ((c = getc (sf)) != '\n') switch (c) { case EOF: return NIL; default: if (putc (c,df) == EOF) return NIL; } if ((putc ('\n',df) == EOF) || (set && (fprintf (df,"X-UID: %lu\r\n",++(stream->uid_last)) < 0))) return NIL; for (c = '\n'; i && fgets (tmp,MAILTMPLEN,sf); c = tmp[j-1]) { /* get read line length */ if (i < (j = strlen (tmp))) fatal ("unix_append_msgs overrun"); i -= j; /* number of bytes left */ if (!j) continue; /* do nothing if line emptied */ /* complete line? */ if ((c == '\n')) switch (tmp[0]) { case 'F': /* possible "From " (case counts here) */ if ((j > 4) && (tmp[0] == 'F') && (tmp[1] == 'r') && (tmp[2] == 'o') && (tmp[3] == 'm') && (tmp[4] == ' ')) { if (!unix_fromwidget) { VALID (tmp,x,ti,zn);/* conditional, only write widget if */ if (!ti) break; /* it looks like a valid header */ } /* write the widget */ if (putc ('>',df) == EOF) return NIL; } break; case 'S': case 's': /* possible "Status:" */ if (hdrp && (j > 6) && ((tmp[1] == 't') || (tmp[1] == 'T')) && ((tmp[2] == 'a') || (tmp[2] == 'A')) && ((tmp[3] == 't') || (tmp[3] == 'T')) && ((tmp[4] == 'u') || (tmp[4] == 'U')) && ((tmp[5] == 's') || (tmp[5] == 'S')) && (tmp[6] == ':') && (fputs ("X-Original-",df) == EOF)) return NIL; break; case 'X': case 'x': /* possible X-??? header */ if (hdrp && (tmp[1] == '-') && /* possible X-UID: */ (((j > 5) && ((tmp[2] == 'U') || (tmp[2] == 'u')) && ((tmp[3] == 'I') || (tmp[3] == 'i')) && ((tmp[4] == 'D') || (tmp[4] == 'd')) && (tmp[5] == ':')) || /* possible X-IMAP: */ ((j > 6) && ((tmp[2] == 'I') || (tmp[2] == 'i')) && ((tmp[3] == 'M') || (tmp[3] == 'm')) && ((tmp[4] == 'A') || (tmp[4] == 'a')) && ((tmp[5] == 'P') || (tmp[5] == 'p')) && ((tmp[6] == ':') || /* or X-IMAPbase: */ ((j > 10) && ((tmp[6] == 'b') || (tmp[6] == 'B')) && ((tmp[7] == 'a') || (tmp[7] == 'A')) && ((tmp[8] == 's') || (tmp[8] == 'S')) && ((tmp[9] == 'e') || (tmp[9] == 'E')) && (tmp[10] == ':')))) || /* possible X-Status: */ ((j > 8) && ((tmp[2] == 'S') || (tmp[2] == 's')) && ((tmp[3] == 't') || (tmp[3] == 'T')) && ((tmp[4] == 'a') || (tmp[4] == 'A')) && ((tmp[5] == 't') || (tmp[5] == 'T')) && ((tmp[6] == 'u') || (tmp[6] == 'U')) && ((tmp[7] == 's') || (tmp[7] == 'S')) && (tmp[8] == ':')) || /* possible X-Keywords: */ ((j > 10) && ((tmp[2] == 'K') || (tmp[2] == 'k')) && ((tmp[3] == 'e') || (tmp[3] == 'E')) && ((tmp[4] == 'y') || (tmp[4] == 'Y')) && ((tmp[5] == 'w') || (tmp[5] == 'W')) && ((tmp[6] == 'o') || (tmp[6] == 'O')) && ((tmp[7] == 'r') || (tmp[7] == 'R')) && ((tmp[8] == 'd') || (tmp[8] == 'D')) && ((tmp[9] == 's') || (tmp[9] == 'S')) && (tmp[10] == ':'))) && (fputs ("X-Original-",df) == EOF)) return NIL; break; case '\n': /* blank line */ hdrp = NIL; break; default: /* nothing to do */ break; } /* just write the line */ if (fwrite (tmp,1,j,df) != j) return NIL; } if (i) return NIL; /* didn't read entire message */ /* update set */ if (stream) mail_append_set (set,stream->uid_last); } return T; } /* Internal routines */ /* UNIX mail abort stream * Accepts: MAIL stream */ void unix_abort (MAILSTREAM *stream) { if (LOCAL) { /* only if a file is open */ if (LOCAL->fd >= 0) close (LOCAL->fd); if (LOCAL->ld >= 0) { /* have a mailbox lock? */ flock (LOCAL->ld,LOCK_UN);/* yes, release the lock */ close (LOCAL->ld); /* close the lock file */ unlink (LOCAL->lname); /* and delete it */ } if (LOCAL->lname) fs_give ((void **) &LOCAL->lname); /* free local text buffers */ if (LOCAL->buf) fs_give ((void **) &LOCAL->buf); if (LOCAL->text.data) fs_give ((void **) &LOCAL->text.data); if (LOCAL->linebuf) fs_give ((void **) &LOCAL->linebuf); if (LOCAL->line) fs_give ((void **) &LOCAL->line); /* nuke the local data */ fs_give ((void **) &stream->local); stream->dtb = NIL; /* log out the DTB */ } } /* UNIX open and lock mailbox * Accepts: file name to open/lock * file open mode * destination buffer for lock file name * type of locking operation (LOCK_SH or LOCK_EX) */ int unix_lock (char *file,int flags,int mode,char *lock,int op) { int fd,ld,j; int i = LOCKTIMEOUT * 60 - 1; char tmp[MAILTMPLEN]; time_t t; struct stat sb; sprintf (lock,"%s.lock",file);/* build lock filename */ do { /* until OK or out of tries */ t = time (0); /* get the time now */ /* try to get the lock */ if ((ld = open(lock,O_BINARY|O_WRONLY|O_CREAT|O_EXCL,S_IREAD|S_IWRITE))>=0) close (ld); /* got it, close the lock file! */ else if (errno != EEXIST) { /* miscellaneous error */ sprintf (tmp,"Error creating %.80s: %s",lock,strerror (errno)); if (!(i%15)) mm_log (tmp,WARN); } /* lock exists, still active? */ else if (!stat (lock,&sb) && (t > sb.st_ctime + LOCKTIMEOUT * 60) && ((ld = open(lock,O_BINARY|O_WRONLY|O_CREAT,S_IREAD|S_IWRITE))>=0)) close (ld); /* got timed-out lock file */ else { /* active lock, try again */ if (!(i%15)) { sprintf (tmp,"Mailbox %.80s is locked, will override in %d seconds...", file,i); mm_log (tmp,WARN); } sleep (1); /* wait a second before next retry */ } } while (*lock && ld < 0 && i--); /* open file */ if ((fd = open (file,flags,mode)) >= 0) flock (fd,op); else { /* open failed */ j = errno; /* preserve error code */ if (*lock) unlink (lock); /* flush the lock file if any */ errno = j; /* restore error code */ } return fd; } /* UNIX unlock and close mailbox * Accepts: file descriptor * (optional) mailbox stream to check atime/mtime * (optional) lock file name */ void unix_unlock (int fd,MAILSTREAM *stream,char *lock) { if (stream) { /* need to muck with times? */ struct stat sbuf; struct utimbuf times; time_t now = time (0); fstat (fd,&sbuf); /* get file times */ if (LOCAL->ld >= 0) { /* yes, readwrite session? */ times.actime = now; /* set atime to now */ /* set mtime to (now - 1) if necessary */ times.modtime = (now > sbuf.st_mtime) ? sbuf.st_mtime : now - 1; } else if (stream->recent) { /* readonly with recent messages */ if ((sbuf.st_atime >= sbuf.st_mtime) || (sbuf.st_atime >= sbuf.st_ctime)) /* keep past mtime, whack back atime */ times.actime = (times.modtime = (sbuf.st_mtime < now) ? sbuf.st_mtime : now) - 1; else now = 0; /* no time change needed */ } /* readonly with no recent messages */ else if ((sbuf.st_atime < sbuf.st_mtime) || (sbuf.st_atime < sbuf.st_ctime)) { times.actime = now; /* set atime to now */ /* set mtime to (now - 1) if necessary */ times.modtime = (now > sbuf.st_mtime) ? sbuf.st_mtime : now - 1; } else now = 0; /* no time change needed */ /* set the times, note change */ if (now && !utime (stream->mailbox,×)) LOCAL->filetime = times.modtime; } flock (fd,LOCK_UN); /* release flock'ers */ if (!stream) close (fd); /* close the file if no stream */ /* flush the lock file if any */ if (lock && *lock) unlink (lock); } /* UNIX mail parse and lock mailbox * Accepts: MAIL stream * space to write lock file name * type of locking operation * Returns: T if parse OK, critical & mailbox is locked shared; NIL if failure */ int unix_parse (MAILSTREAM *stream,char *lock,int op) { int zn; unsigned long i,j,k,m; unsigned char c,*s,*t,*u,tmp[MAILTMPLEN],date[30]; int ti = 0,retain = T; unsigned long nmsgs = stream->nmsgs; unsigned long prevuid = nmsgs ? mail_elt (stream,nmsgs)->private.uid : 0; unsigned long recent = stream->recent; unsigned long oldnmsgs = stream->nmsgs; short silent = stream->silent; short pseudoseen = NIL; struct stat sbuf; STRING bs; FDDATA d; MESSAGECACHE *elt; mail_lock (stream); /* guard against recursion or pingers */ /* toss out previous descriptor */ if (LOCAL->fd >= 0) close (LOCAL->fd); mm_critical (stream); /* open and lock mailbox (shared OK) */ if ((LOCAL->fd = unix_lock (stream->mailbox, O_BINARY + ((LOCAL->ld >= 0) ? O_RDWR:O_RDONLY), NIL,lock,op)) < 0) { sprintf (tmp,"Mailbox open failed, aborted: %s",strerror (errno)); mm_log (tmp,ERROR); unix_abort (stream); mail_unlock (stream); mm_nocritical (stream); /* done with critical */ return NIL; } fstat (LOCAL->fd,&sbuf); /* get status */ /* validate change in size */ if (sbuf.st_size < LOCAL->filesize) { sprintf (tmp,"Mailbox shrank from %lu to %lu bytes, aborted", (unsigned long) LOCAL->filesize,(unsigned long) sbuf.st_size); mm_log (tmp,ERROR); /* this is pretty bad */ unix_unlock (LOCAL->fd,stream,lock); unix_abort (stream); mail_unlock (stream); mm_nocritical (stream); /* done with critical */ return NIL; } /* new data? */ else if (i = sbuf.st_size - LOCAL->filesize) { d.fd = LOCAL->fd; /* yes, set up file descriptor */ d.pos = LOCAL->filesize; /* get to that position in the file */ d.chunk = LOCAL->buf; /* initial buffer chunk */ d.chunksize = CHUNKSIZE; /* file chunk size */ INIT (&bs,fd_string,&d,i); /* initialize stringstruct */ /* skip leading whitespace for broken MTAs */ while (((c = CHR (&bs)) == '\n') || (c == '\r') || (c == ' ') || (c == '\t')) SNX (&bs); if (SIZE (&bs)) { /* read new data */ /* remember internal header position */ j = LOCAL->filesize + GETPOS (&bs); s = unix_mbxline (stream,&bs,&i); t = NIL,zn = 0; if (i) VALID (s,t,ti,zn); /* see if valid From line */ if (!ti) { /* someone pulled the rug from under us */ sprintf (tmp,"Unexpected changes to mailbox (try restarting): %.20s", (char *) s); mm_log (tmp,ERROR); unix_unlock (LOCAL->fd,stream,lock); unix_abort (stream); mail_unlock (stream); mm_nocritical (stream); /* done with critical */ return NIL; } stream->silent = T; /* quell main program new message events */ do { /* found a message */ /* instantiate first new message */ mail_exists (stream,++nmsgs); (elt = mail_elt (stream,nmsgs))->valid = T; recent++; /* assume recent by default */ elt->recent = T; /* note position/size of internal header */ elt->private.special.offset = j; elt->private.msg.header.offset = elt->private.special.text.size = i; /* generate plausible IMAPish date string */ date[2] = date[6] = date[20] = '-'; date[11] = ' '; date[14] = date[17] = ':'; /* dd */ date[0] = t[ti - 2]; date[1] = t[ti - 1]; /* mmm */ date[3] = t[ti - 6]; date[4] = t[ti - 5]; date[5] = t[ti - 4]; /* hh */ date[12] = t[ti + 1]; date[13] = t[ti + 2]; /* mm */ date[15] = t[ti + 4]; date[16] = t[ti + 5]; if (t[ti += 6] == ':') {/* ss */ date[18] = t[++ti]; date[19] = t[++ti]; ti++; /* move to space */ } else date[18] = date[19] = '0'; /* yy -- advance over timezone if necessary */ if (zn == ti) ti += (((t[zn+1] == '+') || (t[zn+1] == '-')) ? 6 : 4); date[7] = t[ti + 1]; date[8] = t[ti + 2]; date[9] = t[ti + 3]; date[10] = t[ti + 4]; /* zzz */ t = zn ? (t + zn + 1) : (unsigned char *) "LCL"; date[21] = *t++; date[22] = *t++; date[23] = *t++; if ((date[21] != '+') && (date[21] != '-')) date[24] = '\0'; else { /* numeric time zone */ date[24] = *t++; date[25] = *t++; date[26] = '\0'; date[20] = ' '; } /* set internal date */ if (!mail_parse_date (elt,date)) { sprintf (tmp,"Unable to parse internal date: %s",(char *) date); mm_log (tmp,WARN); } do { /* look for message body */ s = t = unix_mbxline (stream,&bs,&i); if (i) switch (*s) { /* check header lines */ case 'X': /* possible X-???: line */ if (s[1] == '-') { /* must be immediately followed by hyphen */ /* X-Status: becomes Status: in S case */ if (s[2] == 'S' && s[3] == 't' && s[4] == 'a' && s[5] == 't' && s[6] == 'u' && s[7] == 's' && s[8] == ':') s += 2; /* possible X-Keywords */ else if (s[2] == 'K' && s[3] == 'e' && s[4] == 'y' && s[5] == 'w' && s[6] == 'o' && s[7] == 'r' && s[8] == 'd' && s[9] == 's' && s[10] == ':') { SIZEDTEXT uf; retain = NIL; /* don't retain continuation */ s += 11; /* flush leading whitespace */ while (*s && (*s != '\n') && ((*s != '\r') || (s[1] != '\n'))){ while (*s == ' ') s++; /* find end of keyword */ if (!(u = strpbrk (s," \n\r"))) u = s + strlen (s); /* got a keyword? */ if ((k = (u - s)) && (k <= MAXUSERFLAG)) { uf.data = (unsigned char *) s; uf.size = k; for (j = 0; (j < NUSERFLAGS) && stream->user_flags[j]; ++j) if (!compare_csizedtext (stream->user_flags[j],&uf)) { elt->user_flags |= ((long) 1) << j; break; } } s = u; /* advance to next keyword */ } break; } /* possible X-IMAP */ else if ((s[2] == 'I') && (s[3] == 'M') && (s[4] == 'A') && (s[5] == 'P') && ((m = (s[6] == ':')) || ((s[6] == 'b') && (s[7] == 'a') && (s[8] == 's') && (s[9] == 'e') && (s[10] == ':')))) { retain = NIL; /* don't retain continuation */ if ((nmsgs == 1) && !stream->uid_validity) { /* advance to data */ s += m ? 7 : 11; /* flush whitespace */ while (*s == ' ') s++; j = 0; /* slurp UID validity */ /* found a digit? */ while (isdigit (*s)) { j *= 10; /* yes, add it in */ j += *s++ - '0'; } /* flush whitespace */ while (*s == ' ') s++; /* must have valid UID validity and UID last */ if (j && isdigit (*s)) { /* pseudo-header seen if X-IMAP */ if (m) pseudoseen = LOCAL->pseudo = T; /* save UID validity */ stream->uid_validity = j; j = 0; /* slurp UID last */ while (isdigit (*s)) { j *= 10; /* yes, add it in */ j += *s++ - '0'; } /* save UID last */ stream->uid_last = j; /* process keywords */ for (j = 0; (*s != '\n') && ((*s != '\r')||(s[1] != '\n')); s = u,j++) { /* flush leading whitespace */ while (*s == ' ') s++; u = strpbrk (s," \n\r"); /* got a keyword? */ if ((j < NUSERFLAGS) && (k = (u - s)) && (k <= MAXUSERFLAG)) { if (stream->user_flags[j]) fs_give ((void **) &stream->user_flags[j]); stream->user_flags[j] = (char *) fs_get (k + 1); strncpy (stream->user_flags[j],s,k); stream->user_flags[j][k] = '\0'; } } } } break; } /* possible X-UID */ else if (s[2] == 'U' && s[3] == 'I' && s[4] == 'D' && s[5] == ':') { retain = NIL; /* don't retain continuation */ /* only believe if have a UID validity */ if (stream->uid_validity && ((nmsgs > 1) || !pseudoseen)) { s += 6; /* advance to UID value */ /* flush whitespace */ while (*s == ' ') s++; j = 0; /* found a digit? */ while (isdigit (*s)) { j *= 10; /* yes, add it in */ j += *s++ - '0'; } /* flush remainder of line */ while (*s != '\n') s++; /* make sure not duplicated */ if (elt->private.uid) sprintf (tmp,"Message %lu UID %lu already has UID %lu", pseudoseen ? elt->msgno - 1 : elt->msgno, j,elt->private.uid); /* make sure UID doesn't go backwards */ else if (j <= prevuid) sprintf (tmp,"Message %lu UID %lu less than %lu", pseudoseen ? elt->msgno - 1 : elt->msgno, j,prevuid + 1); #if 0 /* this is currently broken by UIDPLUS */ /* or skip by mailbox's recorded last */ else if (j > stream->uid_last) sprintf (tmp,"Message %lu UID %lu greater than last %lu", pseudoseen ? elt->msgno - 1 : elt->msgno, j,stream->uid_last); #endif else { /* normal UID case */ prevuid = elt->private.uid = j; #if 1 /* temporary kludge for UIDPLUS */ if (prevuid > stream->uid_last) { stream->uid_last = prevuid; LOCAL->ddirty = LOCAL->dirty = T; } #endif break; /* exit this cruft */ } mm_log (tmp,WARN); /* invalidate UID validity */ stream->uid_validity = 0; elt->private.uid = 0; } break; } } /* otherwise fall into S case */ case 'S': /* possible Status: line */ if (s[0] == 'S' && s[1] == 't' && s[2] == 'a' && s[3] == 't' && s[4] == 'u' && s[5] == 's' && s[6] == ':') { retain = NIL; /* don't retain continuation */ s += 6; /* advance to status flags */ do switch (*s++) {/* parse flags */ case 'R': /* message read */ elt->seen = T; break; case 'O': /* message old */ if (elt->recent) { elt->recent = NIL; recent--; /* it really wasn't recent */ } break; case 'D': /* message deleted */ elt->deleted = T; break; case 'F': /* message flagged */ elt->flagged = T; break; case 'A': /* message answered */ elt->answered = T; break; case 'T': /* message is a draft */ elt->draft = T; break; default: /* some other crap */ break; } while (*s && (*s != '\n') && ((*s != '\r') || (s[1] != '\n'))); break; /* all done */ } /* otherwise fall into default case */ default: /* ordinary header line */ if ((*s == 'S') || (*s == 's') || (((*s == 'X') || (*s == 'x')) && (s[1] == '-'))) { unsigned char *e,*v; /* must match what mail_filter() does */ for (u = s,v = tmp,e = u + min (i,MAILTMPLEN - 1); (u < e) && ((c = (*u ? *u : (*u = ' '))) != ':') && ((c > ' ') || ((c != ' ') && (c != '\t') && (c != '\r') && (c != '\n'))); *v++ = *u++); *v = '\0'; /* tie off */ /* matches internal header? */ if (!compare_cstring (tmp,"STATUS") || !compare_cstring (tmp,"X-STATUS") || !compare_cstring (tmp,"X-KEYWORDS") || !compare_cstring (tmp,"X-UID") || !compare_cstring (tmp,"X-IMAP") || !compare_cstring (tmp,"X-IMAPBASE")) { char err[MAILTMPLEN]; sprintf (err,"Discarding bogus %s header in message %lu", (char *) tmp,elt->msgno); mm_log (err,WARN); retain = NIL; /* don't retain continuation */ break; /* different case or something */ } } /* retain or non-continuation? */ if (retain || ((*s != ' ') && (*s != '\t'))) { retain = T; /* retaining continuation now */ /* line length in CRLF format newline */ k = i + (((i < 2) || (s[i - 2] != '\r')) ? 1 : 0); /* header size */ elt->rfc822_size = elt->private.spare.data += k; } else { char err[MAILTMPLEN]; sprintf (err,"Discarding bogus continuation in msg %lu: %.80s", elt->msgno,(char *) s); if (u = strpbrk (err,"\r\n")) *u = '\0'; mm_log (err,WARN); break; /* different case or something */ } break; } } while (i && (*t != '\n') && ((*t != '\r') || (t[1] != '\n'))); /* "internal" header sans trailing newline */ if (i) elt->private.spare.data -= 2; /* assign a UID if none found */ if (((nmsgs > 1) || !pseudoseen) && !elt->private.uid) { prevuid = elt->private.uid = ++stream->uid_last; elt->private.dirty = T; LOCAL->ddirty = T; /* force update */ } else elt->private.dirty = elt->recent; /* note size of header, location of text */ elt->private.msg.header.text.size = (elt->private.msg.text.offset = (LOCAL->filesize + GETPOS (&bs)) - elt->private.special.offset) - elt->private.special.text.size; k = m = 0; /* no previous line size yet */ /* note current position */ j = LOCAL->filesize + GETPOS (&bs); if (i) do { /* look for next message */ s = unix_mbxline (stream,&bs,&i); if (i) { /* got new data? */ VALID (s,t,ti,zn); /* yes, parse line */ if (!ti) { /* not a header line, add it to message */ if (s[i - 1] == '\n') elt->rfc822_size += k = i + (m = (((i < 2) || s[i - 2] != '\r') ? 1 : 0)); else { /* file does not end with newline! */ elt->rfc822_size += i; k = m = 0; } /* update current position */ j = LOCAL->filesize + GETPOS (&bs); } } } while (i && !ti); /* until found a header */ elt->private.msg.text.text.size = j - (elt->private.special.offset + elt->private.msg.text.offset); if (k == 2) { /* last line was blank? */ elt->private.msg.text.text.size -= (m ? 1 : 2); elt->rfc822_size -= 2; } /* until end of buffer */ } while (!stream->sniff && i); if (pseudoseen) { /* flush pseudo-message if present */ /* decrement recent count */ if (mail_elt (stream,1)->recent) recent--; /* and the exists count */ mail_exists (stream,nmsgs--); mail_expunged(stream,1);/* fake an expunge of that message */ } /* need to start a new UID validity? */ if (!stream->uid_validity) { stream->uid_validity = (unsigned long) time (0); if (nmsgs) { /* don't bother if empty file */ /* make dirty to restart UID epoch */ LOCAL->ddirty = LOCAL->dirty = T; /* need to rewrite msg 1 if not pseudo */ if (!LOCAL->pseudo) mail_elt (stream,1)->private.dirty = T; mm_log ("Assigning new unique identifiers to all messages",NIL); } } stream->nmsgs = oldnmsgs; /* whack it back down */ stream->silent = silent; /* restore old silent setting */ /* notify upper level of new mailbox sizes */ mail_exists (stream,nmsgs); mail_recent (stream,recent); /* mark dirty so O flags are set */ if (recent) LOCAL->dirty = T; } } /* no change, don't babble if never got time */ else if (LOCAL->filetime && LOCAL->filetime != sbuf.st_mtime) mm_log ("New mailbox modification time but apparently no changes",WARN); /* update parsed file size and time */ LOCAL->filesize = sbuf.st_size; LOCAL->filetime = sbuf.st_mtime; return T; /* return the winnage */ } /* UNIX read line from mailbox * Accepts: mail stream * stringstruct * pointer to line size * Returns: pointer to input line */ char *unix_mbxline (MAILSTREAM *stream,STRING *bs,unsigned long *size) { unsigned long i,j,k,m; char *s,*t,*te; char *ret = ""; /* flush old buffer */ if (LOCAL->line) fs_give ((void **) &LOCAL->line); /* if buffer needs refreshing */ if (!bs->cursize) SETPOS (bs,GETPOS (bs)); if (SIZE (bs)) { /* find newline */ /* end of fast scan */ te = (t = (s = bs->curpos) + bs->cursize) - 12; while (s < te) if ((*s++ == '\n') || (*s++ == '\n') || (*s++ == '\n') || (*s++ == '\n') || (*s++ == '\n') || (*s++ == '\n') || (*s++ == '\n') || (*s++ == '\n') || (*s++ == '\n') || (*s++ == '\n') || (*s++ == '\n') || (*s++ == '\n')) { --s; /* back up */ break; /* exit loop */ } /* final character-at-a-time scan */ while ((s < t) && (*s != '\n')) ++s; /* difficult case if line spans buffer */ if ((i = s - bs->curpos) == bs->cursize) { /* have space in line buffer? */ if (i > LOCAL->linebuflen) { fs_give ((void **) &LOCAL->linebuf); LOCAL->linebuf = (char *) fs_get (LOCAL->linebuflen = i); } /* remember what we have so far */ memcpy (LOCAL->linebuf,bs->curpos,i); /* load next buffer */ SETPOS (bs,k = GETPOS (bs) + i); /* end of fast scan */ te = (t = (s = bs->curpos) + bs->cursize) - 12; /* fast scan in overlap buffer */ while (s < te) if ((*s++ == '\n') || (*s++ == '\n') || (*s++ == '\n') || (*s++ == '\n') || (*s++ == '\n') || (*s++ == '\n') || (*s++ == '\n') || (*s++ == '\n') || (*s++ == '\n') || (*s++ == '\n') || (*s++ == '\n') || (*s++ == '\n')) { --s; /* back up */ break; /* exit loop */ } /* final character-at-a-time scan */ while ((s < t) && (*s != '\n')) ++s; /* huge line? */ if ((j = s - bs->curpos) == bs->cursize) { SETPOS (bs,GETPOS (bs) + j); /* look for end of line (s-l-o-w!!) */ for (m = SIZE (bs); m && (SNX (bs) != '\n'); --m,++j); SETPOS (bs,k); /* go back to where it started */ } /* got size of data, make buffer for return */ ret = LOCAL->line = (char *) fs_get (i + j + 2); /* copy first chunk */ memcpy (ret,LOCAL->linebuf,i); while (j) { /* copy remainder */ if (!bs->cursize) SETPOS (bs,GETPOS (bs)); memcpy (ret + i,bs->curpos,k = min (j,bs->cursize)); i += k; /* account for this much read in */ j -= k; bs->curpos += k; /* increment new position */ bs->cursize -= k; /* eat that many bytes */ } if (!bs->cursize) SETPOS (bs,GETPOS (bs)); /* read newline at end */ if (SIZE (bs)) ret[i++] = SNX (bs); ret[i] = '\0'; /* makes debugging easier */ } else { /* this is easy */ ret = bs->curpos; /* string it at this position */ bs->curpos += ++i; /* increment new position */ bs->cursize -= i; /* eat that many bytes */ } *size = i; /* return that to user */ } else *size = 0; /* end of data, return empty */ return ret; } /* UNIX make pseudo-header * Accepts: MAIL stream * buffer to write pseudo-header * Returns: length of pseudo-header */ unsigned long unix_pseudo (MAILSTREAM *stream,char *hdr) { int i; char *s,*t,tmp[MAILTMPLEN]; time_t now = time(0); rfc822_fixed_date (tmp); sprintf (hdr,"From %s %.24s\r\nDate: %s\r\nFrom: %s <%s@%.80s>\r\nSubject: %s\r\nMessage-ID: <%lu@%.80s>\r\nX-IMAP: %010ld %010ld", pseudo_from,ctime (&now), tmp,pseudo_name,pseudo_from,mylocalhost (),pseudo_subject, (unsigned long) now,mylocalhost (),stream->uid_validity, stream->uid_last); for (t = hdr + strlen (hdr),i = 0; i < NUSERFLAGS; ++i) if (stream->user_flags[i]) sprintf (t += strlen (t)," %s",stream->user_flags[i]); strcpy (t += strlen (t),"\r\nStatus: RO\r\n\r\n"); for (s = pseudo_msg,t += strlen (t); *s; *t++ = *s++) if (*s == '\n') *t++ = '\r'; *t++ = '\r'; *t++ = '\n'; *t++ = '\r'; *t++ = '\n'; *t = '\0'; /* tie off pseudo header */ return t - hdr; /* return length of pseudo header */ } /* UNIX make status string * Accepts: MAIL stream * destination string to write * message cache entry * UID to write if non-zero (else use elt->private.uid) * non-zero flag to write UID (.LT. 0 to write UID base info too) * Returns: length of string */ unsigned long unix_xstatus (MAILSTREAM *stream,char *status,MESSAGECACHE *elt, unsigned long uid,long flag) { char *t,stack[64]; char *s = status; unsigned long n; unsigned long pad = 50; /* This used to use sprintf(), but thanks to certain cretinous C libraries with horribly slow implementations of sprintf() I had to change it to this mess. At least it should be fast. */ *s++ = 'S'; *s++ = 't'; *s++ = 'a'; *s++ = 't'; *s++ = 'u'; *s++ = 's'; *s++ = ':'; *s++ = ' '; if (elt->seen) *s++ = 'R'; /* only write O if have a UID */ if (flag && (!elt->recent || LOCAL->appending)) *s++ = 'O'; *s++ = '\r'; *s++ = '\n'; *s++ = 'X'; *s++ = '-'; *s++ = 'S'; *s++ = 't'; *s++ = 'a'; *s++ = 't'; *s++ = 'u'; *s++ = 's'; *s++ = ':'; *s++ = ' '; if (elt->deleted) *s++ = 'D'; if (elt->flagged) *s++ = 'F'; if (elt->answered) *s++ = 'A'; if (elt->draft) *s++ = 'T'; *s++ = '\r'; *s++ = '\n'; *s++ = 'X'; *s++ = '-'; *s++ = 'K'; *s++ = 'e'; *s++ = 'y'; *s++ = 'w'; *s++ = 'o'; *s++ = 'r'; *s++ = 'd'; *s++ = 's'; *s++ = ':'; if (n = elt->user_flags) do { *s++ = ' '; for (t = stream->user_flags[find_rightmost_bit (&n)]; *t; *s++ = *t++); } while (n); n = s - status; /* get size of stuff so far */ /* pad X-Keywords to make size constant */ if (n < pad) for (n = pad - n; n > 0; --n) *s++ = ' '; *s++ = '\r'; *s++ = '\n'; if (flag) { /* want to include UID? */ t = stack; /* push UID digits on the stack */ n = uid ? uid : elt->private.uid; do *t++ = (char) (n % 10) + '0'; while (n /= 10); *s++ = 'X'; *s++ = '-'; *s++ = 'U'; *s++ = 'I'; *s++ = 'D'; *s++ = ':'; *s++ = ' '; /* pop UID from stack */ while (t > stack) *s++ = *--t; *s++ = '\r'; *s++ = '\n'; } /* end of extended message status */ *s++ = '\r'; *s++ = '\n'; *s = '\0'; return s - status; /* return size of resulting string */ } /* Rewrite mailbox file * Accepts: MAIL stream, must be critical and locked * return pointer to number of expunged messages if want expunge * lock file name * expunge sequence, not deleted flag * Returns: T if success and mailbox unlocked, NIL if failure */ #define OVERFLOWBUFLEN 8192 /* initial overflow buffer length */ long unix_rewrite (MAILSTREAM *stream,unsigned long *nexp,char *lock, long flags) { MESSAGECACHE *elt; UNIXFILE f; char *s; struct utimbuf times; long ret,flag; unsigned long i,j; unsigned long recent = stream->recent; unsigned long size = LOCAL->pseudo ? unix_pseudo (stream,LOCAL->buf) : 0; if (nexp) *nexp = 0; /* initially nothing expunged */ /* calculate size of mailbox after rewrite */ for (i = 1,flag = LOCAL->pseudo ? 1 : -1; i <= stream->nmsgs; i++) { elt = mail_elt (stream,i); /* get cache */ if (!(nexp && elt->deleted && (flags ? elt->sequence : T))) { /* add RFC822 size of this message */ size += elt->private.special.text.size + elt->private.spare.data + unix_xstatus (stream,LOCAL->buf,elt,NIL,flag) + elt->private.msg.text.text.size + 2; flag = 1; /* only count X-IMAPbase once */ } } if (!size) { /* no messages and no pseudo, make one now */ size = unix_pseudo (stream,LOCAL->buf); LOCAL->pseudo = T; } /* extend the file as necessary */ if (ret = unix_extend (stream,size)) { /* Set up buffered I/O file structure * curpos current position being written through buffering * filepos current position being written physically to the disk * bufpos current position being written in the buffer * protect current maximum position that can be written to the disk * before buffering is forced * The code tries to buffer so that that disk is written in multiples of * OVERBLOWBUFLEN bytes. */ f.stream = stream; /* note mail stream */ f.curpos = f.filepos = 0; /* start of file */ f.protect = stream->nmsgs ? /* initial protection pointer */ mail_elt (stream,1)->private.special.offset : 8192; f.bufpos = f.buf = (char *) fs_get (f.buflen = OVERFLOWBUFLEN); if (LOCAL->pseudo) /* update pseudo-header */ unix_write (&f,LOCAL->buf,unix_pseudo (stream,LOCAL->buf)); /* loop through all messages */ for (i = 1,flag = LOCAL->pseudo ? 1 : -1; i <= stream->nmsgs;) { elt = mail_elt (stream,i);/* get cache */ /* expunge this message? */ if (nexp && elt->deleted && (flags ? elt->sequence : T)) { /* one less recent message */ if (elt->recent) --recent; mail_expunged(stream,i);/* notify upper levels */ ++*nexp; /* count up one more expunged message */ } else { /* preserve this message */ i++; /* advance to next message */ if ((flag < 0) || /* need to rewrite message? */ elt->private.dirty || (((unsigned long) f.curpos) != elt->private.special.offset) || (elt->private.msg.header.text.size != (elt->private.spare.data + unix_xstatus (stream,LOCAL->buf,elt,NIL,flag)))) { unsigned long newoffset = f.curpos; /* yes, seek to internal header */ lseek (LOCAL->fd,elt->private.special.offset,L_SET); read (LOCAL->fd,LOCAL->buf,elt->private.special.text.size); /* protection pointer moves to RFC822 header */ f.protect = elt->private.special.offset + elt->private.msg.header.offset; /* write internal header */ unix_write (&f,LOCAL->buf,elt->private.special.text.size); /* get RFC822 header */ s = unix_header (stream,elt->msgno,&j,NIL); /* in case this got decremented */ elt->private.msg.header.offset = elt->private.special.text.size; /* header size, sans trailing newline */ if ((j < 4) || (s[j - 4] == '\r')) j -= 2; if (j != elt->private.spare.data) fatal ("header size inconsistent"); /* protection pointer moves to RFC822 text */ f.protect = elt->private.special.offset + elt->private.msg.text.offset; unix_write (&f,s,j); /* write RFC822 header */ /* write status and UID */ unix_write (&f,LOCAL->buf, j = unix_xstatus (stream,LOCAL->buf,elt,NIL,flag)); flag = 1; /* only write X-IMAPbase once */ /* new file header size */ elt->private.msg.header.text.size = elt->private.spare.data + j; /* did text move? */ if (f.curpos != f.protect) { /* get message text */ s = unix_text_work (stream,elt,&j,FT_INTERNAL); /* can't happen it says here */ if (j > elt->private.msg.text.text.size) fatal ("text size inconsistent"); /* new text offset, status/UID may change it */ elt->private.msg.text.offset = f.curpos - newoffset; /* protection pointer moves to next message */ f.protect = (i <= stream->nmsgs) ? mail_elt (stream,i)->private.special.offset : (f.curpos + j + 2); unix_write (&f,s,j);/* write text */ /* write trailing newline */ unix_write (&f,"\r\n",2); } else { /* tie off header and status */ unix_write (&f,NIL,NIL); /* protection pointer moves to next message */ f.protect = (i <= stream->nmsgs) ? mail_elt (stream,i)->private.special.offset : size; /* locate end of message text */ j = f.filepos + elt->private.msg.text.text.size; /* trailing newline already there? */ if (f.protect == (off_t) (j + 2)) f.curpos = f.filepos = f.protect; else { /* trailing newline missing, write it */ f.curpos = f.filepos = j; unix_write (&f,"\r\n",2); } } /* new internal header offset */ elt->private.special.offset = newoffset; elt->private.dirty =NIL;/* message is now clean */ } else { /* no need to rewrite this message */ /* tie off previous message if needed */ unix_write (&f,NIL,NIL); /* protection pointer moves to next message */ f.protect = (i <= stream->nmsgs) ? mail_elt (stream,i)->private.special.offset : size; /* locate end of message text */ j = f.filepos + elt->private.special.text.size + elt->private.msg.header.text.size + elt->private.msg.text.text.size; /* trailing newline already there? */ if (f.protect == (off_t) (j + 2)) f.curpos = f.filepos = f.protect; else { /* trailing newline missing, write it */ f.curpos = f.filepos = j; unix_write (&f,"\r\n",2); } } } } unix_write (&f,NIL,NIL); /* tie off final message */ if (size != ((unsigned long) f.filepos)) fatal ("file size inconsistent"); fs_give ((void **) &f.buf); /* free buffer */ /* make sure tied off */ ftruncate (LOCAL->fd,LOCAL->filesize = size); fsync (LOCAL->fd); /* make sure the updates take */ if (size && (flag < 0)) fatal ("lost UID base information"); /* no longer dirty */ LOCAL->ddirty = LOCAL->dirty = NIL; /* notify upper level of new mailbox sizes */ mail_exists (stream,stream->nmsgs); mail_recent (stream,recent); /* set atime to now, mtime a second earlier */ times.modtime = (times.actime = time (0)) -1; /* set the times, note change */ if (!utime (stream->mailbox,×)) LOCAL->filetime = times.modtime; /* flush the lock file */ unix_unlock (LOCAL->fd,stream,lock); } return ret; /* return state from algorithm */ } /* Extend UNIX mailbox file * Accepts: MAIL stream * new desired size * Return: T if success, else NIL */ long unix_extend (MAILSTREAM *stream,unsigned long size) { unsigned long i = (size > ((unsigned long) LOCAL->filesize)) ? size - ((unsigned long) LOCAL->filesize) : 0; if (i) { /* does the mailbox need to grow? */ if (i > LOCAL->buflen) { /* make sure have enough space */ /* this user won the lottery all right */ fs_give ((void **) &LOCAL->buf); LOCAL->buf = (char *) fs_get ((LOCAL->buflen = i) + 1); } memset (LOCAL->buf,'\0',i); /* get a block of nulls */ while (T) { /* until write successful or punt */ lseek (LOCAL->fd,LOCAL->filesize,L_SET); if ((write (LOCAL->fd,LOCAL->buf,i) >= 0) && !fsync (LOCAL->fd)) break; else { long e = errno; /* note error before doing ftruncate */ ftruncate (LOCAL->fd,LOCAL->filesize); if (mm_diskerror (stream,e,NIL)) { fsync (LOCAL->fd); /* user chose to punt */ sprintf (LOCAL->buf,"Unable to extend mailbox: %s",strerror (e)); if (!stream->silent) mm_log (LOCAL->buf,ERROR); return NIL; } } } } return LONGT; } /* Write data to buffered file * Accepts: buffered file pointer * file data or NIL to indicate "flush buffer" * date size (ignored for "flush buffer") * Does not return until success */ void unix_write (UNIXFILE *f,char *buf,unsigned long size) { unsigned long i,j,k; if (buf) { /* doing buffered write? */ i = f->bufpos - f->buf; /* yes, get size of current buffer data */ /* yes, have space in current buffer chunk? */ if (j = i ? ((f->buflen - i) % OVERFLOWBUFLEN) : f->buflen) { /* yes, fill up buffer as much as we can */ memcpy (f->bufpos,buf,k = min (j,size)); f->bufpos += k; /* new buffer position */ f->curpos += k; /* new current position */ if (j -= k) return; /* all done if still have buffer free space */ buf += k; /* full, get new unwritten data pointer */ size -= k; /* new data size */ i += k; /* new buffer data size */ } /* This chunk of the buffer is full. See if can make some space by * writing to the disk, if there's enough unprotected space to do so. * Try to fill out any unaligned chunk, along with any subsequent full * chunks that will fit in unprotected space. */ /* any unprotected space we can write to? */ if (j = min (i,f->protect - f->filepos)) { /* yes, filepos not at chunk boundary? */ if ((k = f->filepos % OVERFLOWBUFLEN) && ((k = OVERFLOWBUFLEN - k) < j)) j -= k; /* yes, and can write out partial chunk */ else k = 0; /* no partial chunk to write */ /* if at least a chunk free, write that too */ if (j > OVERFLOWBUFLEN) k += j - (j % OVERFLOWBUFLEN); if (k) { /* write data if there is anything we can */ unix_phys_write (f,f->buf,k); /* slide buffer */ if (i -= k) memmove (f->buf,f->buf + k,i); f->bufpos = f->buf + i; /* new end of buffer */ } } /* Have flushed the buffer as best as possible. All done if no more * data to write. Otherwise, if the buffer is empty AND if the unwritten * data is larger than a chunk AND the unprotected space is also larger * than a chunk, then write as many chunks as we can directly from the * data. Buffer the rest, expanding the buffer as needed. */ if (size) { /* have more data that we need to buffer? */ /* can write any of it to disk instead? */ if ((f->bufpos == f->buf) && ((j = min (f->protect - f->filepos,size)) > OVERFLOWBUFLEN)) { /* write as much as we can right now */ unix_phys_write (f,buf,j -= (j % OVERFLOWBUFLEN)); buf += j; /* new data pointer */ size -= j; /* new data size */ f->curpos += j; /* advance current pointer */ } if (size) { /* still have data that we need to buffer? */ /* yes, need to expand the buffer? */ if ((i = ((f->bufpos + size) - f->buf)) > f->buflen) { /* note current position in buffer */ j = f->bufpos - f->buf; i += OVERFLOWBUFLEN; /* yes, grow another chunk */ fs_resize ((void **) &f->buf,f->buflen = i - (i % OVERFLOWBUFLEN)); /* in case buffer relocated */ f->bufpos = f->buf + j; } /* buffer remaining data */ memcpy (f->bufpos,buf,size); f->bufpos += size; /* new end of buffer */ f->curpos += size; /* advance current pointer */ } } } else { /* flush buffer to disk */ unix_phys_write (f,f->buf,i = f->bufpos - f->buf); f->bufpos = f->buf; /* reset buffer */ /* update positions */ f->curpos = f->protect = f->filepos; } } /* Physical disk write * Accepts: buffered file pointer * buffer address * buffer size * Does not return until success */ void unix_phys_write (UNIXFILE *f,char *buf,size_t size) { MAILSTREAM *stream = f->stream; /* write data at desired position */ while (size && ((lseek (LOCAL->fd,f->filepos,L_SET) < 0) || (write (LOCAL->fd,buf,size) < 0))) { int e; char tmp[MAILTMPLEN]; sprintf (tmp,"Unable to write to mailbox: %s",strerror (e = errno)); mm_log (tmp,ERROR); mm_diskerror (NIL,e,T); /* serious problem, must retry */ } f->filepos += size; /* update file position */ } alpine-2.10+dfsg/imap/src/osdep/os2/nl_os2.c0000600000175000017500000000331711512502123022231 0ustar paulproteuspaulproteus/* ======================================================================== * Copyright 1988-2006 University of Washington * * Licensed under the Apache License, Version 2.0 (the "License"); * you may not use this file except in compliance with the License. * You may obtain a copy of the License at * * http://www.apache.org/licenses/LICENSE-2.0 * * * ======================================================================== */ /* * Program: Windows/TOPS-20 newline routines * * Author: Mark Crispin * Networks and Distributed Computing * Computing & Communications * University of Washington * Administration Building, AG-44 * Seattle, WA 98195 * Internet: MRC@CAC.Washington.EDU * * Date: 1 August 1988 * Last Edited: 30 August 2006 */ /* Copy string with CRLF newlines * Accepts: destination string * pointer to size of destination string buffer * source string * length of source string * Returns: length of copied string */ unsigned long strcrlfcpy (unsigned char **dst,unsigned long *dstl, unsigned char *src,unsigned long srcl) { /* flush destination buffer if too small */ if (*dst && (srcl > *dstl)) fs_give ((void **) dst); if (!*dst) { /* make a new buffer if needed */ *dst = (char *) fs_get ((size_t) (*dstl = srcl) + 1); if (dstl) *dstl = srcl; /* return new buffer length to main program */ } /* copy strings */ if (srcl) memcpy (*dst,src,(size_t) srcl); *(*dst + srcl) = '\0'; /* tie off destination */ return srcl; /* return length */ } /* Length of string after strcrlfcpy applied * Accepts: source string * Returns: length of string */ unsigned long strcrlflen (STRING *s) { return SIZE (s); /* no-brainer on DOS! */ } alpine-2.10+dfsg/imap/src/osdep/os2/os_os2.h0000600000175000017500000000171311512502123022244 0ustar paulproteuspaulproteus/* ======================================================================== * Copyright 1988-2006 University of Washington * * Licensed under the Apache License, Version 2.0 (the "License"); * you may not use this file except in compliance with the License. * You may obtain a copy of the License at * * http://www.apache.org/licenses/LICENSE-2.0 * * * ======================================================================== */ /* * Program: Operating-system dependent routines -- OS/2 emx version * * Author: Mark Crispin * Networks and Distributed Computing * Computing & Communications * University of Washington * Administration Building, AG-44 * Seattle, WA 98195 * Internet: MRC@CAC.Washington.EDU * * Date: 14 March 1996 * Last Edited: 30 August 2006 */ #include #include #include #include #include "env_os2.h" #include "fs.h" #include "ftl.h" #include "nl.h" #include "tcp.h" alpine-2.10+dfsg/imap/src/osdep/os2/makefile.os20000600000175000017500000000576311512502123023102 0ustar paulproteuspaulproteus# ======================================================================== # Copyright 1988-2006 University of Washington # # Licensed under the Apache License, Version 2.0 (the "License"); # you may not use this file except in compliance with the License. # You may obtain a copy of the License at # # http://www.apache.org/licenses/LICENSE-2.0 # # # ======================================================================== # Program: Portable C client makefile -- OS/2 version # # Author: Mark Crispin # Networks and Distributed Computing # Computing & Communications # University of Washington # Administration Building, AG-44 # Seattle, WA 98195 # Internet: MRC@CAC.Washington.EDU # # Date: 11 May 1989 # Last Edited: 30 August 2006 EXTRAAUTHENTICATORS = EXTRADRIVERS = EXTRACFLAGS = DEFAULTAUTHENTICATORS = ext md5 pla log DRIVERS = imap nntp pop3 mbx mtx tenex unix DEFAULTDRIVER = mbx CFLAGS = -DOMF -DCHUNKSIZE=65536 -O2 -Zomf $(EXTRACFLAGS) CC = gcc CCLIENTLIB = cclient.lib all: $(CCLIENTLIB) .c.obj: $(CC) $(CFLAGS) -o $@ -c $*.c osdep.h: os_os2.h copy os_os2.h osdep.h drivers.cmd $(EXTRADRIVERS) $(DRIVERS) dummy auths.cmd $(EXTRAAUTHENTICATORS) $(DEFAULTAUTHENTICATORS) setproto.cmd $(DEFAULTDRIVER) mail.obj: mail.h misc.h osdep.h mail.c misc.obj: mail.h misc.h misc.c fdstring.obj: mail.h misc.h osdep.h fdstring.h fdstring.c flstring.obj: mail.h misc.h osdep.h flstring.h flstring.c netmsg.obj: mail.h misc.h netmsg.h osdep.h netmsg.c newsrc.obj: mail.h misc.h newsrc.h osdep.h newsrc.c rfc822.obj: mail.h rfc822.h misc.h rfc822.c smanager.obj: mail.h misc.h smanager.c utf8.obj: mail.h misc.h osdep.h utf8.h utf8aux.obj: mail.h misc.h osdep.h utf8.h imap4r1.obj: mail.h imap4r1.h misc.h osdep.h imap4r1.c nntp.obj: mail.h nntp.h smtp.h rfc822.h misc.h osdep.h nntp.c pop3.obj: mail.h rfc822.h misc.h osdep.h pop3.c smtp.obj: mail.h smtp.h rfc822.h misc.h osdep.h smtp.c os_os2.obj: mail.h osdep.h env_os2.h fs.h ftl.h nl.h tcp.h tcp_os2.h \ os_os2.c fs_os2.c ftl_os2.c nl_os2.c env_os2.c tcp_os2.c \ mailfile.h auth_md5.c auth_log.c pmatch.c write.c mbxnt.obj: mail.h misc.h osdep.h mbxnt.c mtxnt.obj: mail.h misc.h osdep.h mtxnt.c tenexnt.obj: mail.h misc.h osdep.h tenexnt.c unixnt.obj: mail.h unixnt.h pseudo.h misc.h osdep.h unixnt.c dummyos2.obj: mail.h dummy.h misc.h osdep.h dummyos2.c pseudo.obj: pseudo.h $(CCLIENTLIB): mail.obj misc.obj fdstring.obj flstring.obj netmsg.obj \ newsrc.obj rfc822.obj smanager.obj utf8.obj utf8aux.obj \ imap4r1.obj nntp.obj pop3.obj smtp.obj os_os2.obj \ mbxnt.obj mtxnt.obj tenexnt.obj unixnt.obj dummynt.obj pseudo.obj del $(CCLIENTLIB) LIB /NOLOGO /OUT:$(CCLIENTLIB) \ mail.obj misc.obj fdstring.obj flstring.obj netmsg.obj \ newsrc.obj rfc822.obj smanager.obj utf8.obj utf8aux.obj \ imap4r1.obj nntp.obj pop3.obj smtp.obj os_os2.obj \ mbxnt.obj mtxnt.obj tenexnt.obj unixnt.obj dummynt.obj pseudo.obj clean: del *.lib *.obj linkage.* osdep.* auths.c *.exe *.exp # A monument to a hack of long ago and far away... love: @echo not war? alpine-2.10+dfsg/imap/src/osdep/os2/pseudo.c0000600000175000017500000000236611512502123022337 0ustar paulproteuspaulproteus/* ======================================================================== * Copyright 1988-2006 University of Washington * * Licensed under the Apache License, Version 2.0 (the "License"); * you may not use this file except in compliance with the License. * You may obtain a copy of the License at * * http://www.apache.org/licenses/LICENSE-2.0 * * * ======================================================================== */ /* * Program: Pseudo Header Strings * * Author: Mark Crispin * Networks and Distributed Computing * Computing & Communications * University of Washington * Administration Building, AG-44 * Seattle, WA 98195 * Internet: MRC@CAC.Washington.EDU * * Date: 26 September 1996 * Last Edited: 30 August 2006 */ /* Local sites may wish to alter this text */ char *pseudo_from = "MAILER-DAEMON"; char *pseudo_name = "Mail System Internal Data"; char *pseudo_subject = "DON'T DELETE THIS MESSAGE -- FOLDER INTERNAL DATA"; char *pseudo_msg = "This text is part of the internal format of your mail folder, and is not\na real message. It is created automatically by the mail system software.\nIf deleted, important folder data will be lost, and it will be re-created\nwith the data reset to initial values." ; alpine-2.10+dfsg/imap/src/osdep/os2/dummyos2.c0000600000175000017500000005147711512502123022626 0ustar paulproteuspaulproteus/* ======================================================================== * Copyright 1988-2006 University of Washington * * Licensed under the Apache License, Version 2.0 (the "License"); * you may not use this file except in compliance with the License. * You may obtain a copy of the License at * * http://www.apache.org/licenses/LICENSE-2.0 * * * ======================================================================== */ /* * Program: Dummy routines for OS2 * * Author: Mark Crispin * Networks and Distributed Computing * Computing & Communications * University of Washington * Administration Building, AG-44 * Seattle, WA 98195 * Internet: MRC@CAC.Washington.EDU * * Date: 24 May 1993 * Last Edited: 30 August 2006 */ /* Thanks to Nicholas Sheppard for the original version */ #include #include #include #include #include #include #include #include #include #include #undef ADDRESS #include "mail.h" #include "osdep.h" #include "misc.h" #include "dummy.h" /* Function prototypes */ DRIVER *dummy_valid (char *name); void *dummy_parameters (long function,void *value); void dummy_list_work (MAILSTREAM *stream,char *dir,char *pat,char *contents, long level); long dummy_listed (MAILSTREAM *stream,char delimiter,char *name, long attributes,char *contents); long dummy_subscribe (MAILSTREAM *stream,char *mailbox); MAILSTREAM *dummy_open (MAILSTREAM *stream); void dummy_close (MAILSTREAM *stream,long options); long dummy_ping (MAILSTREAM *stream); void dummy_check (MAILSTREAM *stream); long dummy_expunge (MAILSTREAM *stream,char *sequence,long options); long dummy_copy (MAILSTREAM *stream,char *sequence,char *mailbox,long options); long dummy_append (MAILSTREAM *stream,char *mailbox,append_t af,void *data); /* Dummy routines */ /* Driver dispatch used by MAIL */ DRIVER dummydriver = { "dummy", /* driver name */ DR_LOCAL|DR_MAIL, /* driver flags */ (DRIVER *) NIL, /* next driver */ dummy_valid, /* mailbox is valid for us */ dummy_parameters, /* manipulate parameters */ dummy_scan, /* scan mailboxes */ dummy_list, /* list mailboxes */ dummy_lsub, /* list subscribed mailboxes */ dummy_subscribe, /* subscribe to mailbox */ NIL, /* unsubscribe from mailbox */ dummy_create, /* create mailbox */ dummy_delete, /* delete mailbox */ dummy_rename, /* rename mailbox */ mail_status_default, /* status of mailbox */ dummy_open, /* open mailbox */ dummy_close, /* close mailbox */ NIL, /* fetch message "fast" attributes */ NIL, /* fetch message flags */ NIL, /* fetch overview */ NIL, /* fetch message structure */ NIL, /* fetch header */ NIL, /* fetch text */ NIL, /* fetch message data */ NIL, /* unique identifier */ NIL, /* message number from UID */ NIL, /* modify flags */ NIL, /* per-message modify flags */ NIL, /* search for message based on criteria */ NIL, /* sort messages */ NIL, /* thread messages */ dummy_ping, /* ping mailbox to see if still alive */ dummy_check, /* check for new messages */ dummy_expunge, /* expunge deleted messages */ dummy_copy, /* copy messages to another mailbox */ dummy_append, /* append string message to mailbox */ NIL /* garbage collect stream */ }; /* prototype stream */ MAILSTREAM dummyproto = {&dummydriver}; /* Dummy validate mailbox * Accepts: mailbox name * Returns: our driver if name is valid, NIL otherwise */ DRIVER *dummy_valid (char *name) { char *s,*t,tmp[MAILTMPLEN]; struct stat sbuf; /* must be valid local mailbox */ if (name && *name && (*name != '{') && (s = mailboxfile (tmp,name))) { /* indeterminate INBOX */ if (!*s) return &dummydriver; /* remove trailing \ */ if ((t = strrchr (s,'\\')) && !t[1]) *t = '\0'; if (!stat (s,&sbuf)) switch (sbuf.st_mode & S_IFMT) { case S_IFREG: /* file */ case S_IFDIR: /* future use */ return &dummydriver; } } return NIL; } /* Dummy manipulate driver parameters * Accepts: function code * function-dependent value * Returns: function-dependent return value */ void *dummy_parameters (long function,void *value) { return NIL; } /* Dummy scan mailboxes * Accepts: mail stream * reference * pattern to search * string to scan */ void dummy_scan (MAILSTREAM *stream,char *ref,char *pat,char *contents) { char *s,test[MAILTMPLEN],file[MAILTMPLEN]; long i = 0; if (!pat || !*pat) { /* empty pattern? */ if (dummy_canonicalize (test,ref,"*")) { /* tie off name at root */ if (s = strchr (test,'\\')) *++s = '\0'; else test[0] = '\0'; dummy_listed (stream,'\\',test,LATT_NOSELECT,NIL); } } /* get canonical form of name */ else if (dummy_canonicalize (test,ref,pat)) { /* found any wildcards? */ if (s = strpbrk (test,"%*")) { /* yes, copy name up to that point */ strncpy (file,test,(size_t) (i = s - test)); file[i] = '\0'; /* tie off */ } else strcpy (file,test); /* use just that name then */ /* find directory name */ if (s = strrchr (file,'\\')) { *++s = '\0'; /* found, tie off at that point */ s = file; } /* silly case */ else if (file[0] == '#') s = file; /* do the work */ dummy_list_work (stream,s,test,contents,0); if (pmatch ("INBOX",test)) /* always an INBOX */ dummy_listed (stream,NIL,"INBOX",LATT_NOINFERIORS,contents); } } /* Dummy list mailboxes * Accepts: mail stream * reference * pattern to search */ void dummy_list (MAILSTREAM *stream,char *ref,char *pat) { dummy_scan (stream,ref,pat,NIL); } /* Dummy list subscribed mailboxes * Accepts: mail stream * reference * pattern to search */ void dummy_lsub (MAILSTREAM *stream,char *ref,char *pat) { void *sdb = NIL; char *s,*t,test[MAILTMPLEN]; int showuppers = pat[strlen (pat) - 1] == '%'; /* get canonical form of name */ if (dummy_canonicalize (test,ref,pat) && (s = sm_read (&sdb))) do if (*s != '{') { if (pmatch_full (s,test,'\\')) { if (pmatch (s,"INBOX")) mm_lsub (stream,NIL,s,LATT_NOINFERIORS); else mm_lsub (stream,'\\',s,NIL); } else while (showuppers && (t = strrchr (s,'\\'))) { *t = '\0'; /* tie off the name */ if (pmatch_full (s,test,'\\')) mm_lsub (stream,'\\',s,LATT_NOSELECT); } } while (s = sm_read (&sdb)); /* until no more subscriptions */ } /* Dummy subscribe to mailbox * Accepts: mail stream * mailbox to add to subscription list * Returns: T on success, NIL on failure */ long dummy_subscribe (MAILSTREAM *stream,char *mailbox) { char *s,tmp[MAILTMPLEN]; struct stat sbuf; /* must be valid local mailbox */ if ((s = mailboxfile (tmp,mailbox)) && *s && !stat (s,&sbuf) && ((sbuf.st_mode & S_IFMT) == S_IFREG)) return sm_subscribe (mailbox); sprintf (tmp,"Can't subscribe %.80s: not a mailbox",mailbox); mm_log (tmp,ERROR); return NIL; } /* Dummy list mailboxes worker routine * Accepts: mail stream * directory name to search * search pattern * string to scan * search level */ void dummy_list_work (MAILSTREAM *stream,char *dir,char *pat,char *contents, long level) { unsigned long i = 1; FILEFINDBUF3 f; HDIR hd = HDIR_CREATE; struct stat sbuf; char tmp[MAILTMPLEN]; /* punt if bogus name */ if (!mailboxdir (tmp,dir,NIL)) return; /* make directory wildcard */ strcat (tmp,(tmp[strlen (tmp) -1] == '\\') ? "*.*" : "\\*.*"); /* do nothing if can't open directory */ if (!DosFindFirst (tmp,&hd,FILE_NORMAL,&f,sizeof (f),&i,FIL_STANDARD)) { /* list it if not at top-level */ if (!level && dir && pmatch_full (dir,pat,'\\')) dummy_listed (stream,'\\',dir,LATT_NOSELECT,contents); /* scan directory */ if (!dir || dir[strlen (dir) -1] == '\\') do { if (((f.name[0] != '.') || (f.name[1] && ((f.name[1] != '.') || f.name[2]))) && (strlen (f.name) <= NETMAXMBX)) { /* see if name is useful */ if (dir) sprintf (tmp,"%s%s",dir,f.name); else strcpy (tmp,f.name); /* make sure useful and can get info */ if ((pmatch_full (tmp,pat,'\\') || pmatch_full (strcat (tmp,"\\"),pat,'\\') || dmatch (tmp,pat,'\\')) && mailboxdir (tmp,dir,f.name) && tmp[0] && !stat (tmp,&sbuf)) { /* now make name we'd return */ if (dir) sprintf (tmp,"%s%s",dir,f.name); else strcpy (tmp,f.name); /* only interested in file type */ switch (sbuf.st_mode & S_IFMT) { case S_IFDIR: /* directory? */ if (pmatch_full (tmp,pat,'\\')) { if (!dummy_listed (stream,'\\',tmp,LATT_NOSELECT,contents))break; strcat (tmp,"\\");/* set up for dmatch call */ } /* try again with trailing \ */ else if (pmatch_full (strcat (tmp,"\\"),pat,'\\') && !dummy_listed (stream,'\\',tmp,LATT_NOSELECT,contents)) break; if (dmatch (tmp,pat,'\\') && (level < (long) mail_parameters (NIL,GET_LISTMAXLEVEL,NIL))) dummy_list_work (stream,tmp,pat,contents,level+1); break; case S_IFREG: /* ordinary name */ if (pmatch_full (tmp,pat,'\\') && !pmatch ("INBOX",tmp)) dummy_listed (stream,'\\',tmp,LATT_NOINFERIORS,contents); break; } } } i = 1; } while (!DosFindNext (h,&f,sizeof (f),&i)); } } /* Mailbox found * Accepts: hierarchy delimiter * mailbox name * attributes * contents to search before calling mm_list() * Returns: T, always */ #define BUFSIZE 4*MAILTMPLEN long dummy_listed (MAILSTREAM *stream,char delimiter,char *name, long attributes,char *contents) { struct stat sbuf; int fd; long csiz,ssiz,bsiz; char *s,*buf,tmp[MAILTMPLEN]; if (contents) { /* want to search contents? */ /* forget it if can't select or open */ if ((attributes & LATT_NOSELECT) || !(csiz = strlen (contents)) || !(s = dummy_file (tmp,name)) || stat (s,&sbuf) || (csiz > sbuf.st_size) || ((fd = open (tmp,O_RDONLY,NIL)) < 0)) return T; /* get buffer including slop */ buf = (char *) fs_get (BUFSIZE + (ssiz = 4 * ((csiz / 4) + 1)) + 1); memset (buf,'\0',ssiz); /* no slop area the first time */ while (sbuf.st_size) { /* until end of file */ read (fd,buf+ssiz,bsiz = min (sbuf.st_size,BUFSIZE)); if (search ((unsigned char *) buf,bsiz+ssiz, (unsigned char *) contents,csiz)) break; memcpy (buf,buf+BUFSIZE,ssiz); sbuf.st_size -= bsiz; /* note that we read that much */ } fs_give ((void **) &buf); /* flush buffer */ close (fd); /* finished with file */ if (!sbuf.st_size) return T;/* not found */ } /* notify main program */ mm_list (stream,delimiter,name,attributes); return T; } /* Dummy create mailbox * Accepts: mail stream * mailbox name to create * Returns: T on success, NIL on failure */ long dummy_create (MAILSTREAM *stream,char *mailbox) { char tmp[MAILTMPLEN]; if (compare_cstring (mailbox,"INBOX") && dummy_file (tmp,mailbox)) return dummy_create_path (stream,tmp,NIL); sprintf (tmp,"Can't create %.80s: invalid name",mailbox); mm_log (tmp,ERROR); return NIL; } /* Dummy create path * Accepts: mail stream * path name to create * directory mode * Returns: T on success, NIL on failure */ long dummy_create_path (MAILSTREAM *stream,char *path,long dirmode) { struct stat sbuf; char c,*s,tmp[MAILTMPLEN]; int fd; long ret = NIL; char *t = strrchr (path,'\\'); char *pt = (path[1] == ':') ? path + 2 : path; int wantdir = t && !t[1]; if (wantdir) *t = '\0'; /* flush trailing delimiter for directory */ /* found superior to this name? */ if ((s = strrchr (pt,'\\')) && (s != pt)) { strncpy (tmp,path,(size_t) (s - path)); tmp[s - path] = '\0'; /* make directory name for stat */ c = *++s; /* tie off in case need to recurse */ *s = '\0'; /* name doesn't exist, create it */ if ((stat (tmp,&sbuf) || ((sbuf.st_mode & S_IFMT) != S_IFDIR)) && !dummy_create_path (stream,path,dirmode)) return NIL; *s = c; /* restore full name */ } if (wantdir) { /* want to create directory? */ ret = !mkdir (path); *t = '\\'; /* restore directory delimiter */ } /* create file */ else if ((fd = open (path,O_WRONLY|O_CREAT|O_EXCL,S_IREAD|S_IWRITE)) >= 0) ret = !close (fd); /* close file */ if (!ret) { /* error? */ sprintf (tmp,"Can't create mailbox node %.80s: %.80s",path, strerror (errno)); mm_log (tmp,ERROR); } return ret; /* return status */ } /* Dummy delete mailbox * Accepts: mail stream * mailbox name to delete * Returns: T on success, NIL on failure */ long dummy_delete (MAILSTREAM *stream,char *mailbox) { struct stat sbuf; char *s,tmp[MAILTMPLEN]; if (!(s = dummy_file (tmp,mailbox))) { sprintf (tmp,"Can't delete - invalid name: %.80s",s); mm_log (tmp,ERROR); } /* no trailing \ */ if ((s = strrchr (tmp,'\\')) && !s[1]) *s = '\0'; if (stat (tmp,&sbuf) || ((sbuf.st_mode & S_IFMT) == S_IFDIR) ? rmdir (tmp) : unlink (tmp)) { sprintf (tmp,"Can't delete mailbox %.80s: %.80s",mailbox,strerror (errno)); mm_log (tmp,ERROR); return NIL; } return T; /* return success */ } /* Mail rename mailbox * Accepts: mail stream * old mailbox name * new mailbox name * Returns: T on success, NIL on failure */ long dummy_rename (MAILSTREAM *stream,char *old,char *newname) { struct stat sbuf; char c,*s,tmp[MAILTMPLEN],mbx[MAILTMPLEN],oldname[MAILTMPLEN]; long ret = NIL; /* no trailing \ allowed */ if (!dummy_file (oldname,old) || !(s = dummy_file (mbx,newname)) || ((s = strrchr (s,'\\')) && !s[1])) { sprintf (mbx,"Can't rename %.80s to %.80s: invalid name",old,newname); mm_log (mbx,ERROR); return NIL; } /* found superior to destination name? */ if (s && (s != mbx) && ((mbx[1] != ':') || (s != mbx + 2))) { c = s[1]; /* remember character after delimiter */ *s = s[1] = '\0'; /* tie off name at delimiter */ /* name doesn't exist, create it */ if (stat (mbx,&sbuf) || ((sbuf.st_mode & S_IFMT) != S_IFDIR)) { *s = '\\'; /* restore delimiter */ if (!dummy_create (stream,mbx)) return NIL; } else *s = '\\'; /* restore delimiter */ s[1] = c; /* restore character after delimiter */ } /* rename of non-ex INBOX creates dest */ if (!compare_cstring (old,"INBOX") && stat (oldname,&sbuf)) return dummy_create (NIL,mbx); if (rename (oldname,mbx)) { sprintf (tmp,"Can't rename mailbox %.80s to %.80s: %.80s",old,newname, strerror (errno)); mm_log (tmp,ERROR); return NIL; } return LONGT; /* return success */ } /* Dummy open * Accepts: stream to open * Returns: stream on success, NIL on failure */ MAILSTREAM *dummy_open (MAILSTREAM *stream) { int fd; char err[MAILTMPLEN],tmp[MAILTMPLEN]; struct stat sbuf; /* OP_PROTOTYPE call */ if (!stream) return &dummyproto; err[0] = '\0'; /* no error message yet */ /* can we open the file? */ if (!dummy_file (tmp,stream->mailbox)) sprintf (err,"Can't open this name: %.80s",stream->mailbox); else if ((fd = open (tmp,O_RDONLY,NIL)) < 0) { /* no, error unless INBOX */ if (compare_cstring (stream->mailbox,"INBOX")) sprintf (err,"%.80s: %.80s",strerror (errno),stream->mailbox); } else { /* file had better be empty then */ fstat (fd,&sbuf); /* sniff at its size */ close (fd); if (sbuf.st_size) /* bogus format if non-empty */ sprintf (err,"%.80s (file %.80s) is not in valid mailbox format", stream->mailbox,tmp); } if (err[0]) { /* if an error happened */ mm_log (err,stream->silent ? WARN : ERROR); return NIL; } else if (!stream->silent) { /* only if silence not requested */ mail_exists (stream,0); /* say there are 0 messages */ mail_recent (stream,0); /* and certainly no recent ones! */ stream->uid_validity = time (0); } stream->inbox = T; /* note that it's an INBOX */ return stream; /* return success */ } /* Dummy close * Accepts: MAIL stream * options */ void dummy_close (MAILSTREAM *stream,long options) { /* return silently */ } /* Dummy ping mailbox * Accepts: MAIL stream * Returns: T if stream alive, else NIL */ long dummy_ping (MAILSTREAM *stream) { MAILSTREAM *test; /* time to do another test? */ if (time (0) >= ((time_t) (stream->gensym + 30))) { /* has mailbox format changed? */ if ((test = mail_open (NIL,stream->mailbox,OP_PROTOTYPE)) && (test->dtb != stream->dtb) && (test = mail_open (NIL,stream->mailbox,NIL))) { /* preserve some resources */ test->original_mailbox = stream->original_mailbox; stream->original_mailbox = NIL; test->sparep = stream->sparep; stream->sparep = NIL; test->sequence = stream->sequence; mail_close ((MAILSTREAM *) /* flush resources used by dummy stream */ memcpy (fs_get (sizeof (MAILSTREAM)),stream, sizeof (MAILSTREAM))); /* swap the streams */ memcpy (stream,test,sizeof (MAILSTREAM)); fs_give ((void **) &test);/* flush test now that copied */ /* make sure application knows */ mail_exists (stream,stream->recent = stream->nmsgs); } /* still hasn't changed */ else stream->gensym = time (0); } return T; } /* Dummy check mailbox * Accepts: MAIL stream * No-op for readonly files, since read/writer can expunge it from under us! */ void dummy_check (MAILSTREAM *stream) { dummy_ping (stream); /* invoke ping */ } /* Dummy expunge mailbox * Accepts: MAIL stream * sequence to expunge if non-NIL * expunge options * Returns: T, always */ long dummy_expunge (MAILSTREAM *stream,char *sequence,long options) { return LONGT; } /* Dummy copy message(s) * Accepts: MAIL stream * sequence * destination mailbox * options * Returns: T if copy successful, else NIL */ long dummy_copy (MAILSTREAM *stream,char *sequence,char *mailbox,long options) { if ((options & CP_UID) ? mail_uid_sequence (stream,sequence) : mail_sequence (stream,sequence)) fatal ("Impossible dummy_copy"); return NIL; } /* Dummy append message string * Accepts: mail stream * destination mailbox * append callback function * data for callback * Returns: T on success, NIL on failure */ long dummy_append (MAILSTREAM *stream,char *mailbox,append_t af,void *data) { struct stat sbuf; int fd = -1; int e; char tmp[MAILTMPLEN]; MAILSTREAM *ts = default_proto (T); if (compare_cstring (mailbox,"INBOX") && dummy_file (tmp,mailbox) && ((fd = open (tmp,O_RDONLY,NIL)) < 0)) { if ((e = errno) == ENOENT) /* failed, was it no such file? */ mm_notify (stream,"[TRYCREATE] Must create mailbox before append", (long) NIL); sprintf (tmp,"%.80s: %.80s",strerror (e),mailbox); mm_log (tmp,ERROR); /* pass up error */ return NIL; /* always fails */ } if (fd >= 0) { /* found file? */ fstat (fd,&sbuf); /* get its size */ close (fd); /* toss out the fd */ if (sbuf.st_size) ts = NIL; /* non-empty file? */ } if (ts) return (*ts->dtb->append) (stream,mailbox,af,data); sprintf (tmp,"Indeterminate mailbox format: %.80s",mailbox); mm_log (tmp,ERROR); return NIL; } /* Dummy mail generate file string * Accepts: temporary buffer to write into * mailbox name string * Returns: local file string or NIL if failure */ char *dummy_file (char *dst,char *name) { char *s = mailboxfile (dst,name); /* return our standard inbox */ return (s && !*s) ? strcpy (dst,sysinbox ()) : s; } /* Dummy canonicalize name * Accepts: buffer to write name * reference * pattern * Returns: T if success, NIL if failure */ long dummy_canonicalize (char *tmp,char *ref,char *pat) { unsigned long i; char *s,dev[4]; /* initially no device */ dev[0] = dev[1] = dev[2] = dev[3] = '\0'; if (ref) switch (*ref) { /* preliminary reference check */ case '{': /* remote names not allowed */ return NIL; /* disallowed */ case '\0': /* empty reference string */ break; default: /* all other names */ if (ref[1] == ':') { /* start with device name? */ dev[0] = *ref++; dev[1] = *ref++; } break; } if (pat[1] == ':') { /* device name in pattern? */ dev[0] = *pat++; dev[1] = *pat++; ref = NIL; /* ignore reference */ } switch (*pat) { case '#': /* namespace names */ if (mailboxfile (tmp,pat)) strcpy (tmp,pat); else return NIL; /* unknown namespace */ break; case '{': /* remote names not allowed */ return NIL; case '\\': /* rooted name */ ref = NIL; /* ignore reference */ break; } /* make sure device names are rooted */ if (dev[0] && (*(ref ? ref : pat) != '\\')) dev[2] = '\\'; /* build name */ sprintf (tmp,"%s%s%s",dev,ref ? ref : "",pat); ucase (tmp); /* force upper case */ /* count wildcards */ for (i = 0, s = tmp; *s; *s++) if ((*s == '*') || (*s == '%')) ++i; if (i > MAXWILDCARDS) { /* ridiculous wildcarding? */ MM_LOG ("Excessive wildcards in LIST/LSUB",ERROR); return NIL; } return T; } alpine-2.10+dfsg/imap/src/osdep/os2/unixnt.h0000600000175000017500000001506711512502123022374 0ustar paulproteuspaulproteus/* ======================================================================== * Copyright 1988-2006 University of Washington * * Licensed under the Apache License, Version 2.0 (the "License"); * you may not use this file except in compliance with the License. * You may obtain a copy of the License at * * http://www.apache.org/licenses/LICENSE-2.0 * * * ======================================================================== */ /* * Program: UNIX mail routines * * Author: Mark Crispin * Networks and Distributed Computing * Computing & Communications * University of Washington * Administration Building, AG-44 * Seattle, WA 98195 * Internet: MRC@CAC.Washington.EDU * * Date: 20 December 1989 * Last Edited: 30 August 2006 */ /* DEDICATION * * This file is dedicated to my dog, Unix, also known as Yun-chan and * Unix J. Terwilliker Jehosophat Aloysius Monstrosity Animal Beast. Unix * passed away at the age of 11 1/2 on September 14, 1996, 12:18 PM PDT, after * a two-month bout with cirrhosis of the liver. * * He was a dear friend, and I miss him terribly. * * Lift a leg, Yunie. Luv ya forever!!!! */ /* Validate line * Accepts: pointer to candidate string to validate as a From header * return pointer to end of date/time field * return pointer to offset from t of time (hours of ``mmm dd hh:mm'') * return pointer to offset from t of time zone (if non-zero) * Returns: t,ti,zn set if valid From string, else ti is NIL */ #define VALID(s,x,ti,zn) { \ ti = 0; \ if ((*s == 'F') && (s[1] == 'r') && (s[2] == 'o') && (s[3] == 'm') && \ (s[4] == ' ')) { \ for (x = s + 5; *x && *x != '\012'; x++); \ if (*x) { \ if (x[-1] == '\015') --x; \ if (x - s >= 41) { \ for (zn = -1; x[zn] != ' '; zn--); \ if ((x[zn-1] == 'm') && (x[zn-2] == 'o') && (x[zn-3] == 'r') && \ (x[zn-4] == 'f') && (x[zn-5] == ' ') && (x[zn-6] == 'e') && \ (x[zn-7] == 't') && (x[zn-8] == 'o') && (x[zn-9] == 'm') && \ (x[zn-10] == 'e') && (x[zn-11] == 'r') && (x[zn-12] == ' '))\ x += zn - 12; \ } \ if (x - s >= 27) { \ if (x[-5] == ' ') { \ if (x[-8] == ':') zn = 0,ti = -5; \ else if (x[-9] == ' ') ti = zn = -9; \ else if ((x[-11] == ' ') && ((x[-10]=='+') || (x[-10]=='-'))) \ ti = zn = -11; \ } \ else if (x[-4] == ' ') { \ if (x[-9] == ' ') zn = -4,ti = -9; \ } \ else if (x[-6] == ' ') { \ if ((x[-11] == ' ') && ((x[-5] == '+') || (x[-5] == '-'))) \ zn = -6,ti = -11; \ } \ if (ti && !((x[ti - 3] == ':') && \ (x[ti -= ((x[ti - 6] == ':') ? 9 : 6)] == ' ') && \ (x[ti - 3] == ' ') && (x[ti - 7] == ' ') && \ (x[ti - 11] == ' '))) ti = 0; \ } \ } \ } \ } /* You are not expected to understand this macro, but read the next page if * you are not faint of heart. * * Known formats to the VALID macro are: * From user Wed Dec 2 05:53 1992 * BSD From user Wed Dec 2 05:53:22 1992 * SysV From user Wed Dec 2 05:53 PST 1992 * rn From user Wed Dec 2 05:53:22 PST 1992 * From user Wed Dec 2 05:53 -0700 1992 * emacs From user Wed Dec 2 05:53:22 -0700 1992 * From user Wed Dec 2 05:53 1992 PST * From user Wed Dec 2 05:53:22 1992 PST * From user Wed Dec 2 05:53 1992 -0700 * Solaris From user Wed Dec 2 05:53:22 1992 -0700 * * Plus all of the above with `` remote from xxx'' after it. Thank you very * much, smail and Solaris, for making my life considerably more complicated. */ /* * What? You want to understand the VALID macro anyway? Alright, since you * insist. Actually, it isn't really all that difficult, provided that you * take it step by step. * * Line 1 Initializes the return ti value to failure (0); * Lines 2-3 Validates that the 1st-5th characters are ``From ''. * Lines 4-6 Validates that there is an end of line and points x at it. * Lines 7-14 First checks to see if the line is at least 41 characters long. * If so, it scans backwards to find the rightmost space. From * that point, it scans backwards to see if the string matches * `` remote from''. If so, it sets x to point to the space at * the start of the string. * Line 15 Makes sure that there are at least 27 characters in the line. * Lines 16-21 Checks if the date/time ends with the year (there is a space * five characters back). If there is a colon three characters * further back, there is no timezone field, so zn is set to 0 * and ti is set in front of the year. Otherwise, there must * either to be a space four characters back for a three-letter * timezone, or a space six characters back followed by a + or - * for a numeric timezone; in either case, zn and ti become the * offset of the space immediately before it. * Lines 22-24 Are the failure case for line 14. If there is a space four * characters back, it is a three-letter timezone; there must be a * space for the year nine characters back. zn is the zone * offset; ti is the offset of the space. * Lines 25-28 Are the failure case for line 20. If there is a space six * characters back, it is a numeric timezone; there must be a * space eleven characters back and a + or - five characters back. * zn is the zone offset; ti is the offset of the space. * Line 29-32 If ti is valid, make sure that the string before ti is of the * form www mmm dd hh:mm or www mmm dd hh:mm:ss, otherwise * invalidate ti. There must be a colon three characters back * and a space six or nine characters back (depending upon * whether or not the character six characters back is a colon). * There must be a space three characters further back (in front * of the day), one seven characters back (in front of the month), * and one eleven characters back (in front of the day of week). * ti is set to be the offset of the space before the time. * * Why a macro? It gets invoked a *lot* in a tight loop. On some of the * newer pipelined machines it is faster being open-coded than it would be if * subroutines are called. * * Why does it scan backwards from the end of the line, instead of doing the * much easier forward scan? There is no deterministic way to parse the * ``user'' field, because it may contain unquoted spaces! Yes, I tested it to * see if unquoted spaces were possible. They are, and I've encountered enough * evil mail to be totally unwilling to trust that ``it will never happen''. */ /* Build parameters */ #define KODRETRY 15 /* kiss-of-death retry in seconds */ #define LOCKTIMEOUT 5 /* lock timeout in minutes */ alpine-2.10+dfsg/imap/src/osdep/os2/ftl_os2.c0000600000175000017500000000167311512502123022410 0ustar paulproteuspaulproteus/* ======================================================================== * Copyright 1988-2006 University of Washington * * Licensed under the Apache License, Version 2.0 (the "License"); * you may not use this file except in compliance with the License. * You may obtain a copy of the License at * * http://www.apache.org/licenses/LICENSE-2.0 * * * ======================================================================== */ /* * Program: DOS/VMS/TOPS-20 crash management routines * * Author: Mark Crispin * Networks and Distributed Computing * Computing & Communications * University of Washington * Administration Building, AG-44 * Seattle, WA 98195 * Internet: MRC@CAC.Washington.EDU * * Date: 1 August 1988 * Last Edited: 30 August 2006 */ /* Report a fatal error * Accepts: string to output */ void fatal (char *string) { mm_fatal (string); /* pass up the string */ abort (); /* die horribly */ } alpine-2.10+dfsg/imap/src/osdep/os2/drivers.cmd0000600000175000017500000000242411512502123023032 0ustar paulproteuspaulproteus/* rexx */ /* ======================================================================== * Copyright 1988-2006 University of Washington * * Licensed under the Apache License, Version 2.0 (the "License"); * you may not use this file except in compliance with the License. * You may obtain a copy of the License at * * http://www.apache.org/licenses/LICENSE-2.0 * * * ======================================================================== */ /* * Program: Authenticator Linkage Generator for OS/2 * * Author: Mark Crispin * Networks and Distributed Computing * Computing & Communications * University of Washington * Administration Building, AG-44 * Seattle, WA 98195 * Internet: MRC@CAC.Washington.EDU * * Date: 10 June 1999 * Last Edited: 30 August 2006 */ '@echo off' /* Erase old authenticators list */ 'if exist linkage.h del linkage.h' 'if exist linkage.c del linkage.c' parse arg args n=words(args) c_file='linkage.c' h_file='linkage.h' call stream c_file, 'C', 'open write' call stream h_file, 'C', 'open write' do i=1 to n arg=word(args,i) call lineout h_file, 'extern DRIVER 'arg'driver;' call lineout c_file, ' mail_link (&'arg'driver); /* link in the 'arg' driver */' end call stream h_file, 'C', 'close' call stream c_file, 'C', 'close' exit 0 alpine-2.10+dfsg/imap/src/osdep/os2/pseudo.h0000600000175000017500000000150611512502123022337 0ustar paulproteuspaulproteus/* ======================================================================== * Copyright 1988-2006 University of Washington * * Licensed under the Apache License, Version 2.0 (the "License"); * you may not use this file except in compliance with the License. * You may obtain a copy of the License at * * http://www.apache.org/licenses/LICENSE-2.0 * * * ======================================================================== */ /* * Program: Pseudo Header Strings * * Author: Mark Crispin * Networks and Distributed Computing * Computing & Communications * University of Washington * Administration Building, AG-44 * Seattle, WA 98195 * Internet: MRC@CAC.Washington.EDU * * Date: 26 September 1996 * Last Edited: 30 August 2006 */ extern char *pseudo_from,*pseudo_name,*pseudo_subject,*pseudo_msg; alpine-2.10+dfsg/imap/src/osdep/os2/os_os2.c0000600000175000017500000000473311512502123022244 0ustar paulproteuspaulproteus/* ======================================================================== * Copyright 1988-2006 University of Washington * * Licensed under the Apache License, Version 2.0 (the "License"); * you may not use this file except in compliance with the License. * You may obtain a copy of the License at * * http://www.apache.org/licenses/LICENSE-2.0 * * * ======================================================================== */ /* * Program: Operating-system dependent routines -- OS/2 emx version * * Author: Mark Crispin * Networks and Distributed Computing * Computing & Communications * University of Washington * Administration Building, AG-44 * Seattle, WA 98195 * Internet: MRC@CAC.Washington.EDU * * Date: 14 March 1996 * Last Edited: 30 August 2006 */ #include #include #include #include #include #include #include #include #include #include #include extern int errno; /* just in case */ #include "tcp_os2.h" /* must be before osdep includes tcp.h */ #include "mail.h" #include "osdep.h" #include "misc.h" #include "fs_os2.c" #include "ftl_os2.c" #include "nl_os2.c" #include "env_os2.c" #include "tcp_os2.c" /* Return my local host name * Returns: my local host name */ char *mylocalhost (void) { if (!myLocalHost) { /* known yet? */ char *s,tmp[MAILTMPLEN]; struct hostent *he; /* could we get local id? */ gethostname (tmp,MAILTMPLEN-1); if (he = gethostbyname (lcase (tmp))) { if (he->h_name) s = he->h_name; else sprintf (s = tmp,"[%i.%i.%i.%i]",he->h_addr[0],he->h_addr[1], he->h_addr[2],he->h_addr[3]); } else s = "random-pc"; myLocalHost = cpystr (s); /* record for subsequent use */ } return myLocalHost; } /* Look up host address * Accepts: pointer to pointer to host name * socket address block * Returns: non-zero with host address in socket, official host name in host; * else NIL */ long lookuphost (char **host,struct sockaddr_in *sin) { long ret = -1; char tmp[MAILTMPLEN]; struct hostent *hn = gethostbyname (lcase (strcpy (tmp,*host))); if (!hn) return NIL; /* got a host name? */ *host = cpystr (hn->h_name); /* set official name */ /* copy host addresses */ memcpy (&sin->sin_addr,hn->h_addr,hn->h_length); return T; } /* * Emulator for BSD syslog() routine. */ void syslog (int priority,const char *message,...) { } alpine-2.10+dfsg/imap/src/osdep/os2/write.c0000600000175000017500000000336711512502123022174 0ustar paulproteuspaulproteus/* ======================================================================== * Copyright 1988-2006 University of Washington * * Licensed under the Apache License, Version 2.0 (the "License"); * you may not use this file except in compliance with the License. * You may obtain a copy of the License at * * http://www.apache.org/licenses/LICENSE-2.0 * * * ======================================================================== */ /* * Program: Write data, treating partial writes as an error * * Author: Mark Crispin * Networks and Distributed Computing * Computing & Communications * University of Washington * Administration Building, AG-44 * Seattle, WA 98195 * Internet: MRC@CAC.Washington.EDU * * Date: 26 May 1995 * Last Edited: 30 August 2006 */ /* The whole purpose of this unfortunate routine is to deal with DOS and * certain cretinous versions of UNIX which decided that the "bytes actually * written" return value from write() gave them license to use that for things * that are really errors, such as disk quota exceeded, maximum file size * exceeded, disk full, etc. * * BSD won't screw us this way on the local filesystem, but who knows what * some NFS-mounted filesystem will do. */ #undef write /* Write data to file * Accepts: file descriptor * I/O vector structure * number of vectors in structure * Returns: number of bytes written if successful, -1 if failure */ long maxposint = (long)((((unsigned long) 1) << ((sizeof(int) * 8) - 1)) - 1); long safe_write (int fd,char *buf,long nbytes) { long i,j; if (nbytes > 0) for (i = nbytes; i; i -= j,buf += j) { while (((j = write (fd,buf,(int) min (maxposint,i))) < 0) && (errno == EINTR)); if (j < 0) return j; } return nbytes; } alpine-2.10+dfsg/imap/src/osdep/os2/mbxnt.c0000600000175000017500000016000711512502123022165 0ustar paulproteuspaulproteus/* ======================================================================== * Copyright 1988-2007 University of Washington * * Licensed under the Apache License, Version 2.0 (the "License"); * you may not use this file except in compliance with the License. * You may obtain a copy of the License at * * http://www.apache.org/licenses/LICENSE-2.0 * * * ======================================================================== */ /* * Program: MBX mail routines * * Author: Mark Crispin * Networks and Distributed Computing * Computing & Communications * University of Washington * Administration Building, AG-44 * Seattle, WA 98195 * Internet: MRC@CAC.Washington.EDU * * Date: 3 October 1995 * Last Edited: 28 September 2007 */ /* FILE TIME SEMANTICS * * The atime is the last read time of the file. * The mtime is the last flags update time of the file. * The ctime is the last write time of the file. */ #include #include #include extern int errno; /* just in case */ #include "mail.h" #include "osdep.h" #include #include #include #include #include "misc.h" #include "dummy.h" #include "fdstring.h" /* Build parameters */ #define HDRSIZE 2048 /* MBX I/O stream local data */ typedef struct mbx_local { unsigned int flagcheck: 1; /* if ping should sweep for flags */ unsigned int expok: 1; /* if expunging OK in ping */ unsigned int expunged : 1; /* if one or more expunged messages */ int fd; /* file descriptor for I/O */ int ld; /* lock file descriptor */ int ffuserflag; /* first free user flag */ off_t filesize; /* file size parsed */ time_t filetime; /* last file time */ time_t lastsnarf; /* last snarf time */ unsigned char *buf; /* temporary buffer */ unsigned long buflen; /* current size of temporary buffer */ char lock[MAILTMPLEN]; /* buffer to write lock name */ } MBXLOCAL; /* Convenient access to local data */ #define LOCAL ((MBXLOCAL *) stream->local) /* Function prototypes */ DRIVER *mbx_valid (char *name); int mbx_isvalid (MAILSTREAM **stream,char *name,char *file,int *ld,char *lock, long flags); void *mbx_parameters (long function,void *value); void mbx_scan (MAILSTREAM *stream,char *ref,char *pat,char *contents); void mbx_list (MAILSTREAM *stream,char *ref,char *pat); void mbx_lsub (MAILSTREAM *stream,char *ref,char *pat); long mbx_create (MAILSTREAM *stream,char *mailbox); long mbx_delete (MAILSTREAM *stream,char *mailbox); long mbx_rename (MAILSTREAM *stream,char *old,char *newname); long mbx_status (MAILSTREAM *stream,char *mbx,long flags); MAILSTREAM *mbx_open (MAILSTREAM *stream); void mbx_close (MAILSTREAM *stream,long options); void mbx_abort (MAILSTREAM *stream); void mbx_flags (MAILSTREAM *stream,char *sequence,long flags); char *mbx_header (MAILSTREAM *stream,unsigned long msgno,unsigned long *length, long flags); long mbx_text (MAILSTREAM *stream,unsigned long msgno,STRING *bs,long flags); void mbx_flag (MAILSTREAM *stream,char *sequence,char *flag,long flags); void mbx_flagmsg (MAILSTREAM *stream,MESSAGECACHE *elt); long mbx_ping (MAILSTREAM *stream); void mbx_check (MAILSTREAM *stream); long mbx_expunge (MAILSTREAM *stream,char *sequence,long options); void mbx_snarf (MAILSTREAM *stream); long mbx_copy (MAILSTREAM *stream,char *sequence,char *mailbox,long options); long mbx_append (MAILSTREAM *stream,char *mailbox,append_t af,void *data); long mbx_parse (MAILSTREAM *stream); MESSAGECACHE *mbx_elt (MAILSTREAM *stream,unsigned long msgno,long expok); unsigned long mbx_read_flags (MAILSTREAM *stream,MESSAGECACHE *elt); void mbx_update_header (MAILSTREAM *stream); void mbx_update_status (MAILSTREAM *stream,unsigned long msgno,long flags); unsigned long mbx_hdrpos (MAILSTREAM *stream,unsigned long msgno, unsigned long *size,char **hdr); unsigned long mbx_rewrite (MAILSTREAM *stream,unsigned long *reclaimed, long flags); long mbx_flaglock (MAILSTREAM *stream); /* MBX mail routines */ /* Driver dispatch used by MAIL */ DRIVER mbxdriver = { "mbx", /* driver name */ DR_LOCAL|DR_MAIL|DR_CRLF|DR_LOCKING, /* driver flags */ (DRIVER *) NIL, /* next driver */ mbx_valid, /* mailbox is valid for us */ mbx_parameters, /* manipulate parameters */ mbx_scan, /* scan mailboxes */ mbx_list, /* list mailboxes */ mbx_lsub, /* list subscribed mailboxes */ NIL, /* subscribe to mailbox */ NIL, /* unsubscribe from mailbox */ mbx_create, /* create mailbox */ mbx_delete, /* delete mailbox */ mbx_rename, /* rename mailbox */ mail_status_default, /* status of mailbox */ mbx_open, /* open mailbox */ mbx_close, /* close mailbox */ mbx_flags, /* fetch message "fast" attributes */ mbx_flags, /* fetch message flags */ NIL, /* fetch overview */ NIL, /* fetch message envelopes */ mbx_header, /* fetch message header */ mbx_text, /* fetch message body */ NIL, /* fetch partial message text */ NIL, /* unique identifier */ NIL, /* message number */ mbx_flag, /* modify flags */ mbx_flagmsg, /* per-message modify flags */ NIL, /* search for message based on criteria */ NIL, /* sort messages */ NIL, /* thread messages */ mbx_ping, /* ping mailbox to see if still alive */ mbx_check, /* check for new messages */ mbx_expunge, /* expunge deleted messages */ mbx_copy, /* copy messages to another mailbox */ mbx_append, /* append string message to mailbox */ NIL /* garbage collect stream */ }; /* prototype stream */ MAILSTREAM mbxproto = {&mbxdriver}; /* MBX mail validate mailbox * Accepts: mailbox name * Returns: our driver if name is valid, NIL otherwise */ DRIVER *mbx_valid (char *name) { char tmp[MAILTMPLEN]; int fd = mbx_isvalid (NIL,name,tmp,NIL,NIL,NIL); if (fd < 0) return NIL; close (fd); /* don't need the fd now */ return &mbxdriver; } /* MBX mail test for valid mailbox * Accepts: returned stream with valid mailbox keywords * mailbox name * buffer to write file name * returned lock fd * returned lock name * RW flags or NIL for readonly * Returns: file descriptor if valid, NIL otherwise */ #define MBXISVALIDNOUID 0x1 /* RW, don't do UID action */ #define MBXISVALIDUID 0x2 /* RW, do UID action */ int mbx_isvalid (MAILSTREAM **stream,char *name,char *file,int *ld,char *lock, long flags) { int fd,upd; int ret = -1; unsigned long i; long j,k; off_t pos; char c,*s,*t,hdr[HDRSIZE]; struct stat sbuf; struct utimbuf times; int error = EINVAL; /* assume invalid argument */ if (ld) *ld = -1; /* initially no lock */ /* if file, get its status */ if ((s = dummy_file (file,name)) && !stat (s,&sbuf) && ((sbuf.st_mode & S_IFMT) == S_IFREG) && ((fd = open (file,(flags ? O_RDWR : O_RDONLY)|O_BINARY,NIL)) >= 0)) { error = -1; /* assume bogus format */ if (((((j = read (fd,hdr,HDRSIZE)) == HDRSIZE) && (hdr[0] == '*')) || /* locked, set byte 0 to "*", read rest */ ((j < 0) && (lseek (fd,1,L_SET) == 1) && (read (fd,hdr+1,HDRSIZE-1) == (HDRSIZE-1)) && (hdr[0] = '*'))) && (hdr[1] == 'm') && (hdr[2] == 'b') && (hdr[3] == 'x') && (hdr[4] == '*') && (hdr[5] == '\015') && (hdr[6] == '\012') && isxdigit (hdr[7]) && isxdigit (hdr[8]) && isxdigit (hdr[9]) && isxdigit (hdr[10]) && isxdigit (hdr[11]) && isxdigit (hdr[12]) && isxdigit (hdr[13]) && isxdigit (hdr[14]) && isxdigit (c = hdr[15]) && isxdigit (hdr[16]) && isxdigit (hdr[17]) && isxdigit (hdr[18]) && isxdigit (hdr[19]) && isxdigit (hdr[20]) && isxdigit (hdr[21]) && isxdigit (hdr[22]) && (hdr[23] == '\015') && (hdr[24] == '\012')) { ret = fd; /* mbx format */ if (stream) { /* lock if making a mini-stream */ if (flock (fd,LOCK_SH) || (flags && ((*ld = lockname (lock,file,LOCK_EX)) < 0))) ret = -1; /* reread data now that locked */ else if (lseek (fd,0,L_SET) || (read (fd,hdr+1,HDRSIZE-1) != (HDRSIZE-1))) ret = -1; else { *stream = (MAILSTREAM *) memset (fs_get (sizeof (MAILSTREAM)),0, sizeof (MAILSTREAM)); hdr[15] = '\0'; /* tie off UIDVALIDITY */ (*stream)->uid_validity = strtoul (hdr+7,NIL,16); hdr[15] = c; /* now get UIDLAST */ (*stream)->uid_last = strtoul (hdr+15,NIL,16); /* parse user flags */ for (i = 0, s = hdr + 25; (i < NUSERFLAGS) && (t = strchr (s,'\015')) && (t - s); i++, s = t + 2) { *t = '\0'; /* tie off flag */ if (strlen (s) <= MAXUSERFLAG) (*stream)->user_flags[i] = cpystr (s); } /* make sure have true UIDLAST */ if (flags & MBXISVALIDUID) { for (upd = NIL,pos = 2048, k = 0; pos < sbuf.st_size; pos += (j + k)) { /* read header for this message */ lseek (fd,pos,L_SET); if ((j = read (fd,hdr,64)) >= 0) { hdr[j] = '\0'; if ((s = strchr (hdr,'\015')) && (s[1] == '\012')) { *s = '\0'; k = s + 2 - hdr; if ((s = strchr (hdr,',')) && (j = strtol (s+1,&s,10)) && (*s == ';') && (s = strchr (s+1,'-'))) { /* get UID if there is any */ i = strtoul (++s,&t,16); if (!*t && (t == (s + 8)) && (i <= (*stream)->uid_last)) { if (!i) { lseek (fd,pos + s - hdr,L_SET); sprintf (hdr,"%08lx",++(*stream)->uid_last); write (fd,hdr,8); upd = T; } continue; } } } ret = -1; /* error, give up */ *stream = mail_close (*stream); pos = sbuf.st_size + 1; j = k = 0; } } if (upd) { /* need to update hdr with new UIDLAST? */ lseek (fd,15,L_SET); sprintf (hdr,"%08lx",(*stream)->uid_last); write (fd,hdr,8); } } } } } if (ret != fd) close (fd); /* close the file */ else lseek (fd,0,L_SET); /* else rewind to start */ /* \Marked status? */ if (sbuf.st_ctime > sbuf.st_atime) { /* preserve atime and mtime */ times.actime = sbuf.st_atime; times.modtime = sbuf.st_mtime; utime (file,×); /* set the times */ } } /* in case INBOX but not mbx format */ else if (((error = errno) == ENOENT) && !compare_cstring (name,"INBOX")) error = -1; if ((ret < 0) && ld && (*ld >= 0)) { unlockfd (*ld,lock); *ld = -1; } errno = error; /* return as last error */ return ret; /* return what we should */ } /* MBX manipulate driver parameters * Accepts: function code * function-dependent value * Returns: function-dependent return value */ void *mbx_parameters (long function,void *value) { void *ret = NIL; switch ((int) function) { case SET_ONETIMEEXPUNGEATPING: if (value) ((MBXLOCAL *) ((MAILSTREAM *) value)->local)->expok = T; case GET_ONETIMEEXPUNGEATPING: if (value) ret = (void *) (((MBXLOCAL *) ((MAILSTREAM *) value)->local)->expok ? VOIDT : NIL); break; } return ret; } /* MBX mail scan mailboxes * Accepts: mail stream * reference * pattern to search * string to scan */ void mbx_scan (MAILSTREAM *stream,char *ref,char *pat,char *contents) { if (stream) dummy_scan (NIL,ref,pat,contents); } /* MBX mail list mailboxes * Accepts: mail stream * reference * pattern to search */ void mbx_list (MAILSTREAM *stream,char *ref,char *pat) { if (stream) dummy_list (NIL,ref,pat); } /* MBX mail list subscribed mailboxes * Accepts: mail stream * reference * pattern to search */ void mbx_lsub (MAILSTREAM *stream,char *ref,char *pat) { if (stream) dummy_lsub (NIL,ref,pat); } /* MBX mail create mailbox * Accepts: MAIL stream * mailbox name to create * Returns: T on success, NIL on failure */ long mbx_create (MAILSTREAM *stream,char *mailbox) { char *s,mbx[MAILTMPLEN],tmp[HDRSIZE]; long ret = NIL; int i,fd; if (!(s = dummy_file (mbx,mailbox))) { sprintf (mbx,"Can't create %.80s: invalid name",mailbox); mm_log (mbx,ERROR); } /* create underlying file */ else if (dummy_create (stream,s)) { /* done if made directory */ if ((s = strrchr (s,'\\')) && !s[1]) return T; if ((fd = open (mbx,O_WRONLY|O_BINARY,NIL)) < 0) { sprintf (tmp,"Can't reopen mailbox node %.80s: %s",mbx,strerror (errno)); mm_log (tmp,ERROR); unlink (mbx); /* delete the file */ } else { memset (tmp,'\0',HDRSIZE);/* initialize header */ sprintf (s = tmp,"*mbx*\015\012%08lx00000000\015\012", (unsigned long) time (0)); for (i = 0; i < NUSERFLAGS; ++i) sprintf (s += strlen (s),"%s\015\012", (stream && stream->user_flags[i]) ? stream->user_flags[i] : ""); if (write (fd,tmp,HDRSIZE) != HDRSIZE) { sprintf (tmp,"Can't initialize mailbox node %.80s: %s", mbx,strerror (errno)); mm_log (tmp,ERROR); unlink (mbx); /* delete the file */ } else ret = T; /* success */ close (fd); /* close file */ } } return ret; } /* MBX mail delete mailbox * Accepts: MAIL stream * mailbox name to delete * Returns: T on success, NIL on failure */ long mbx_delete (MAILSTREAM *stream,char *mailbox) { return mbx_rename (stream,mailbox,NIL); } /* MBX mail rename mailbox * Accepts: MAIL stream * old mailbox name * new mailbox name (or NIL for delete) * Returns: T on success, NIL on failure */ long mbx_rename (MAILSTREAM *stream,char *old,char *newname) { long ret = LONGT; char c,*s,tmp[MAILTMPLEN],file[MAILTMPLEN],lock[MAILTMPLEN]; int fd,ld; struct stat sbuf; if (!dummy_file (file,old) || (newname && (!((s = mailboxfile (tmp,newname)) && *s) || ((s = strrchr (tmp,'\\')) && !s[1])))) { sprintf (tmp,newname ? "Can't rename mailbox %.80s to %.80s: invalid name" : "Can't delete mailbox %.80s: invalid name", old,newname); mm_log (tmp,ERROR); return NIL; } else if ((fd = open (file,O_RDWR|O_BINARY,NIL)) < 0) { sprintf (tmp,"Can't open mailbox %.80s: %s",old,strerror (errno)); mm_log (tmp,ERROR); return NIL; } /* get parse/append permission */ if ((ld = lockname (lock,file,LOCK_EX)) < 0) { mm_log ("Unable to lock rename mailbox",ERROR); return NIL; } /* lock out other users */ if (flock (fd,LOCK_EX|LOCK_NB)) { close (fd); /* couldn't lock, give up on it then */ sprintf (tmp,"Mailbox %.80s is in use by another process",old); mm_log (tmp,ERROR); unlockfd (ld,lock); /* release exclusive parse/append permission */ return NIL; } if (newname) { /* want rename? */ /* found superior to destination name? */ if ((s = strrchr (tmp,'\\')) && (s != tmp) && ((tmp[1] != ':') || (s != tmp + 2))) { c = s[1]; /* remember character after delimiter */ *s = s[1] = '\0'; /* tie off name at delimiter */ /* name doesn't exist, create it */ if (stat (tmp,&sbuf) || ((sbuf.st_mode & S_IFMT) != S_IFDIR)) { *s = '\\'; /* restore delimiter */ if (!dummy_create (stream,tmp)) ret = NIL; } else *s = '\\'; /* restore delimiter */ s[1] = c; /* restore character after delimiter */ } flock (fd,LOCK_UN); /* release lock on the file */ close (fd); /* pacify NTFS */ /* rename the file */ if (ret && rename (file,tmp)) { sprintf (tmp,"Can't rename mailbox %.80s to %.80s: %s",old,newname, strerror (errno)); mm_log (tmp,ERROR); ret = NIL; /* set failure */ } } else { flock (fd,LOCK_UN); /* release lock on the file */ close (fd); /* pacify NTFS */ if (unlink (file)) { sprintf (tmp,"Can't delete mailbox %.80s: %s",old,strerror (errno)); mm_log (tmp,ERROR); ret = NIL; /* set failure */ } } unlockfd (ld,lock); /* release exclusive parse/append permission */ /* recreate file if renamed INBOX */ if (ret && !compare_cstring (old,"INBOX")) mbx_create (NIL,"INBOX"); return ret; /* return success */ } /* MBX mail open * Accepts: stream to open * Returns: stream on success, NIL on failure */ MAILSTREAM *mbx_open (MAILSTREAM *stream) { int fd,ld; short silent; char tmp[MAILTMPLEN]; if (!stream) return &mbxproto;/* return prototype for OP_PROTOTYPE call */ if (stream->local) fatal ("mbx recycle stream"); /* canonicalize the mailbox name */ if (!dummy_file (tmp,stream->mailbox)) { sprintf (tmp,"Can't open - invalid name: %.80s",stream->mailbox); mm_log (tmp,ERROR); } if (stream->rdonly || (fd = open (tmp,O_RDWR|O_BINARY,NIL)) < 0) { if ((fd = open (tmp,O_RDONLY|O_BINARY,NIL)) < 0) { sprintf (tmp,"Can't open mailbox: %s",strerror (errno)); mm_log (tmp,ERROR); return NIL; } else if (!stream->rdonly) { /* got it, but readonly */ mm_log ("Can't get write access to mailbox, access is readonly",WARN); stream->rdonly = T; } } stream->local = memset (fs_get (sizeof (MBXLOCAL)),NIL,sizeof (MBXLOCAL)); LOCAL->fd = fd; /* bind the file */ LOCAL->ld = -1; /* no flaglock */ LOCAL->buf = (char *) fs_get (CHUNKSIZE); LOCAL->buflen = CHUNKSIZE - 1; /* note if an INBOX or not */ stream->inbox = !compare_cstring (stream->mailbox,"INBOX"); fs_give ((void **) &stream->mailbox); stream->mailbox = cpystr (tmp); /* get parse/append permission */ if ((ld = lockname (tmp,stream->mailbox,LOCK_EX)) < 0) { mm_log ("Unable to lock open mailbox",ERROR); return NIL; } flock (LOCAL->fd,LOCK_SH); /* lock the file */ unlockfd (ld,tmp); /* release shared parse permission */ LOCAL->filesize = HDRSIZE; /* initialize parsed file size */ LOCAL->filetime = 0; /* time not set up yet */ LOCAL->expok = LOCAL->flagcheck = NIL; stream->sequence++; /* bump sequence number */ /* parse mailbox */ stream->nmsgs = stream->recent = 0; silent = stream->silent; /* defer events */ stream->silent = T; if (mbx_ping (stream) && !stream->nmsgs) mm_log ("Mailbox is empty",(long) NIL); stream->silent = silent; /* now notify upper level */ mail_exists (stream,stream->nmsgs); mail_recent (stream,stream->recent); if (!LOCAL) return NIL; /* failure if stream died */ stream->perm_seen = stream->perm_deleted = stream->perm_flagged = stream->perm_answered = stream->perm_draft = stream->rdonly ? NIL : T; stream->perm_user_flags = stream->rdonly ? NIL : 0xffffffff; stream->kwd_create = (stream->user_flags[NUSERFLAGS-1] || stream->rdonly) ? NIL : T; /* can we create new user flags? */ return stream; /* return stream to caller */ } /* MBX mail close * Accepts: MAIL stream * close options */ void mbx_close (MAILSTREAM *stream,long options) { if (stream && LOCAL) { /* only if a file is open */ int silent = stream->silent; stream->silent = T; /* note this stream is dying */ /* do an expunge if requested */ if (options & CL_EXPUNGE) mbx_expunge (stream,NIL,NIL); else { /* otherwise do a checkpoint to purge */ LOCAL->expok = T; /* possible expunged messages */ mbx_ping (stream); } stream->silent = silent; /* restore previous status */ mbx_abort (stream); } } /* MBX mail abort stream * Accepts: MAIL stream */ void mbx_abort (MAILSTREAM *stream) { if (stream && LOCAL) { /* only if a file is open */ flock (LOCAL->fd,LOCK_UN); /* unlock local file */ close (LOCAL->fd); /* close the local file */ /* free local text buffer */ if (LOCAL->buf) fs_give ((void **) &LOCAL->buf); /* nuke the local data */ fs_give ((void **) &stream->local); stream->dtb = NIL; /* log out the DTB */ } } /* MBX mail fetch flags * Accepts: MAIL stream * sequence * option flags * Sniffs at file to see if some other process changed the flags */ void mbx_flags (MAILSTREAM *stream,char *sequence,long flags) { MESSAGECACHE *elt; unsigned long i; if (mbx_ping (stream) && /* ping mailbox, get new status for messages */ ((flags & FT_UID) ? mail_uid_sequence (stream,sequence) : mail_sequence (stream,sequence))) for (i = 1; i <= stream->nmsgs; i++) if ((elt = mail_elt (stream,i))->sequence && !elt->valid) mbx_elt (stream,i,NIL); } /* MBX mail fetch message header * Accepts: MAIL stream * message # to fetch * pointer to returned header text length * option flags * Returns: message header in RFC822 format */ char *mbx_header (MAILSTREAM *stream,unsigned long msgno,unsigned long *length, long flags) { unsigned long i; char *s; *length = 0; /* default to empty */ if (flags & FT_UID) return "";/* UID call "impossible" */ /* get header position, possibly header */ i = mbx_hdrpos (stream,msgno,length,&s); if (!s) { /* mbx_hdrpos() returned header? */ lseek (LOCAL->fd,i,L_SET); /* no, get to header position */ /* is buffer big enough? */ if (*length > LOCAL->buflen) { fs_give ((void **) &LOCAL->buf); LOCAL->buf = (char *) fs_get ((LOCAL->buflen = *length) + 1); } /* slurp the data */ read (LOCAL->fd,s = LOCAL->buf,*length); } s[*length] = '\0'; /* tie off string */ return s; } /* MBX mail fetch message text (body only) * Accepts: MAIL stream * message # to fetch * pointer to returned header text length * option flags * Returns: T on success, NIL on failure */ long mbx_text (MAILSTREAM *stream,unsigned long msgno,STRING *bs,long flags) { FDDATA d; unsigned long i,j; MESSAGECACHE *elt; /* UID call "impossible" */ if (flags & FT_UID) return NIL; /* get message status */ elt = mbx_elt (stream,msgno,NIL); /* if message not seen */ if (!(flags & FT_PEEK) && !elt->seen && mbx_flaglock (stream)) { elt->seen = T; /* mark message as seen */ /* recalculate status */ mbx_update_status (stream,msgno,NIL); mm_flags (stream,msgno); /* update flags */ mbx_flag (stream,NIL,NIL,NIL); } if (!LOCAL) return NIL; /* mbx_flaglock() could have aborted */ /* find header position */ i = mbx_hdrpos (stream,msgno,&j,NIL); d.fd = LOCAL->fd; /* set up file descriptor */ d.pos = i + j; d.chunk = LOCAL->buf; /* initial buffer chunk */ d.chunksize = CHUNKSIZE; INIT (bs,fd_string,&d,elt->rfc822_size - j); return LONGT; /* success */ } /* MBX mail modify flags * Accepts: MAIL stream * sequence * flag(s) * option flags * Unlocks flag lock */ void mbx_flag (MAILSTREAM *stream,char *sequence,char *flag,long flags) { struct utimbuf times; struct stat sbuf; /* make sure the update takes */ if (!stream->rdonly && LOCAL && (LOCAL->fd >= 0) && (LOCAL->ld >= 0)) { fsync (LOCAL->fd); fstat (LOCAL->fd,&sbuf); /* get current write time */ times.modtime = LOCAL->filetime = sbuf.st_mtime; /* update header */ if ((LOCAL->ffuserflag < NUSERFLAGS) && stream->user_flags[LOCAL->ffuserflag]) mbx_update_header (stream); times.actime = time (0); /* make sure read comes after all that */ utime (stream->mailbox,×); } if (LOCAL->ld >= 0) { /* unlock now */ unlockfd (LOCAL->ld,LOCAL->lock); LOCAL->ld = -1; } } /* MBX mail per-message modify flags * Accepts: MAIL stream * message cache element */ void mbx_flagmsg (MAILSTREAM *stream,MESSAGECACHE *elt) { if (mbx_flaglock (stream)) mbx_update_status (stream,elt->msgno,NIL); } /* MBX mail ping mailbox * Accepts: MAIL stream * Returns: T if stream still alive, NIL if not */ long mbx_ping (MAILSTREAM *stream) { unsigned long i,pos; long ret = NIL; int ld; char lock[MAILTMPLEN]; MESSAGECACHE *elt; struct stat sbuf; if (stream && LOCAL) { /* only if stream already open */ ret = LONGT; /* assume OK */ fstat (LOCAL->fd,&sbuf); /* get current file poop */ /* allow expunge if permitted at ping */ if (mail_parameters (NIL,GET_EXPUNGEATPING,NIL)) LOCAL->expok = T; /* if external modification */ if (LOCAL->filetime && (LOCAL->filetime < sbuf.st_mtime)) LOCAL->flagcheck = T; /* upgrade to flag checking */ /* new mail or flagcheck handling needed? */ if (((sbuf.st_size - LOCAL->filesize) || LOCAL->flagcheck || !stream->nmsgs) && ((ld = lockname (lock,stream->mailbox,LOCK_EX)) >= 0)) { if (!LOCAL->flagcheck) ret = mbx_parse (stream); /* sweep mailbox for changed message status */ else if (ret = mbx_parse (stream)) { unsigned long recent = 0; LOCAL->filetime = sbuf.st_mtime; for (i = 1; i <= stream->nmsgs; ) if (elt = mbx_elt (stream,i,LOCAL->expok)) { if (elt->recent) ++recent; ++i; } mail_recent (stream,recent); LOCAL->flagcheck = NIL; /* got all the updates */ } unlockfd (ld,lock); /* release shared parse/append permission */ } if (ret) { /* must still be alive */ if (!LOCAL->expunged) /* look for holes if none known yet */ for (i = 1, pos = HDRSIZE; !LOCAL->expunged && (i <= stream->nmsgs); i++, pos += elt->private.special.text.size + elt->rfc822_size) if ((elt = mail_elt (stream,i))->private.special.offset != pos) LOCAL->expunged = T;/* found a hole */ /* burp any holes */ if (LOCAL->expunged && !stream->rdonly) { if (mbx_rewrite (stream,&i,NIL)) fatal ("expunge on check"); if (i) { /* any space reclaimed? */ LOCAL->expunged = NIL;/* no more pending expunge */ sprintf (LOCAL->buf,"Reclaimed %lu bytes of expunged space",i); mm_log (LOCAL->buf,(long) NIL); } } LOCAL->expok = NIL; /* no more expok */ } } return ret; /* return result of the parse */ } /* MBX mail check mailbox (reparses status too) * Accepts: MAIL stream */ void mbx_check (MAILSTREAM *stream) { if (LOCAL) LOCAL->expok = T; /* mark that a check is desired */ if (mbx_ping (stream)) mm_log ("Check completed",(long) NIL); } /* MBX mail expunge mailbox * Accepts: MAIL stream * sequence to expunge if non-NIL * expunge options * Returns: T if success, NIL if failure */ long mbx_expunge (MAILSTREAM *stream,char *sequence,long options) { long ret; unsigned long nexp,reclaimed; if (ret = sequence ? ((options & EX_UID) ? mail_uid_sequence (stream,sequence) : mail_sequence (stream,sequence)) : LONGT) { if (!mbx_ping (stream)); /* do nothing if stream dead */ else if (stream->rdonly) /* won't do on readonly files! */ mm_log ("Expunge ignored on readonly mailbox",WARN); /* if expunged any messages */ else if (nexp = mbx_rewrite (stream,&reclaimed,sequence ? -1 : 1)) { sprintf (LOCAL->buf,"Expunged %lu messages",nexp); mm_log (LOCAL->buf,(long) NIL); } else if (reclaimed) { /* or if any prior expunged space reclaimed */ sprintf (LOCAL->buf,"Reclaimed %lu bytes of expunged space",reclaimed); mm_log (LOCAL->buf,(long) NIL); } else mm_log ("No messages deleted, so no update needed",(long) NIL); } return ret; } /* MBX mail copy message(s) * Accepts: MAIL stream * sequence * destination mailbox * copy options * Returns: T if success, NIL if failed */ long mbx_copy (MAILSTREAM *stream,char *sequence,char *mailbox,long options) { struct stat sbuf; struct utimbuf times; MESSAGECACHE *elt; unsigned long i,j,k,m; long ret = LONGT; int fd,ld; char *s,*t,file[MAILTMPLEN],lock[MAILTMPLEN]; mailproxycopy_t pc = (mailproxycopy_t) mail_parameters (stream,GET_MAILPROXYCOPY,NIL); copyuid_t cu = (copyuid_t) mail_parameters (NIL,GET_COPYUID,NIL); SEARCHSET *source = cu ? mail_newsearchset () : NIL; SEARCHSET *dest = cu ? mail_newsearchset () : NIL; MAILSTREAM *dstream = NIL; if (!((options & CP_UID) ? mail_uid_sequence (stream,sequence) : mail_sequence (stream,sequence))) return NIL; /* make sure valid mailbox */ if ((fd = mbx_isvalid (&dstream,mailbox,file,&ld,lock, cu ? MBXISVALIDUID : MBXISVALIDNOUID)) < 0) switch (errno) { case ENOENT: /* no such file? */ mm_notify (stream,"[TRYCREATE] Must create mailbox before copy",NIL); return NIL; case EACCES: /* file protected */ sprintf (LOCAL->buf,"Can't access destination: %.80s",mailbox); MM_LOG (LOCAL->buf,ERROR); return NIL; case EINVAL: if (pc) return (*pc) (stream,sequence,mailbox,options); sprintf (LOCAL->buf,"Invalid MBX-format mailbox name: %.80s",mailbox); mm_log (LOCAL->buf,ERROR); return NIL; default: if (pc) return (*pc) (stream,sequence,mailbox,options); sprintf (LOCAL->buf,"Not a MBX-format mailbox: %.80s",mailbox); mm_log (LOCAL->buf,ERROR); return NIL; } /* got file? */ if ((fd = open (dummy_file (file,mailbox),O_RDWR|O_CREAT|O_BINARY, S_IREAD|S_IWRITE)) < 0) { sprintf (LOCAL->buf,"Unable to open copy mailbox: %s",strerror (errno)); mm_log (LOCAL->buf,ERROR); return NIL; } mm_critical (stream); /* go critical */ fstat (fd,&sbuf); /* get current file size */ lseek (fd,sbuf.st_size,L_SET);/* move to end of file */ /* for each requested message */ for (i = 1; ret && (i <= stream->nmsgs); i++) if ((elt = mail_elt (stream,i))->sequence) { lseek (LOCAL->fd,elt->private.special.offset + elt->private.special.text.size,L_SET); mail_date(LOCAL->buf,elt);/* build target header */ /* get target keyword mask */ for (j = elt->user_flags, k = 0; j; ) if (s = stream->user_flags[find_rightmost_bit (&j)]) for (m = 0; (m < NUSERFLAGS) && (t = dstream->user_flags[m]); m++) if (!compare_cstring (s,t) && (k |= 1 << m)) break; sprintf (LOCAL->buf+strlen(LOCAL->buf),",%lu;%08lx%04x-%08lx\015\012", elt->rfc822_size,k,(unsigned) ((fSEEN * elt->seen) + (fDELETED * elt->deleted) + (fFLAGGED * elt->flagged) + (fANSWERED * elt->answered) + (fDRAFT * elt->draft)),cu ? ++dstream->uid_last : 0); /* write target header */ if (ret = (write (fd,LOCAL->buf,strlen (LOCAL->buf)) > 0)) { for (k = elt->rfc822_size; ret && (j = min (k,LOCAL->buflen)); k -= j){ read (LOCAL->fd,LOCAL->buf,j); ret = write (fd,LOCAL->buf,j) >= 0; } if (cu) { /* need to pass back new UID? */ mail_append_set (source,mail_uid (stream,i)); mail_append_set (dest,dstream->uid_last); } } } /* make sure all the updates take */ if (!(ret && (ret = !fsync (fd)))) { sprintf (LOCAL->buf,"Unable to write message: %s",strerror (errno)); mm_log (LOCAL->buf,ERROR); ftruncate (fd,sbuf.st_size); } if (cu && ret) { /* return sets if doing COPYUID */ (*cu) (stream,mailbox,dstream->uid_validity,source,dest); lseek (fd,15,L_SET); /* update UIDLAST */ sprintf (LOCAL->buf,"%08lx",dstream->uid_last); write (fd,LOCAL->buf,8); } else { /* flush any sets we may have built */ mail_free_searchset (&source); mail_free_searchset (&dest); } /* set atime to now-1 if successful copy */ if (ret) times.actime = time (0) - 1; /* else preserved \Marked status */ else times.actime = (sbuf.st_ctime > sbuf.st_atime) ? sbuf.st_atime : time (0); times.modtime = sbuf.st_mtime;/* preserve mtime */ utime (file,×); /* set the times */ close (fd); /* close the file */ mm_nocritical (stream); /* release critical */ unlockfd (ld,lock); /* release exclusive parse/append permission */ /* delete all requested messages */ if (ret && (options & CP_MOVE) && mbx_flaglock (stream)) { for (i = 1; i <= stream->nmsgs; i++) if (mail_elt (stream,i)->sequence) { /* mark message deleted */ mbx_elt (stream,i,NIL)->deleted = T; /* recalculate status */ mbx_update_status (stream,i,NIL); } /* update flags */ mbx_flag (stream,NIL,NIL,NIL); } if (dstream != stream) mail_close (dstream); return ret; } /* MBX mail append message from stringstruct * Accepts: MAIL stream * destination mailbox * append callback * data for callback * Returns: T if append successful, else NIL */ long mbx_append (MAILSTREAM *stream,char *mailbox,append_t af,void *data) { struct stat sbuf; int fd,ld; char *flags,*date,tmp[MAILTMPLEN],file[MAILTMPLEN],lock[MAILTMPLEN]; struct utimbuf times; FILE *df; MESSAGECACHE elt; long f; unsigned long i,uf; STRING *message; long ret = NIL; MAILSTREAM *dstream = NIL; appenduid_t au = (appenduid_t) mail_parameters (NIL,GET_APPENDUID,NIL); SEARCHSET *dst = au ? mail_newsearchset () : NIL; /* make sure valid mailbox */ /* make sure valid mailbox */ if ((fd = mbx_isvalid (&dstream,mailbox,file,&ld,lock, au ? MBXISVALIDUID : MBXISVALIDNOUID)) < 0) switch (errno) { case ENOENT: /* no such file? */ if (compare_cstring (mailbox,"INBOX")) { mm_notify (stream,"[TRYCREATE] Must create mailbox before append",NIL); return NIL; } /* can create INBOX here */ mbx_create (dstream = stream ? stream : &mbxproto,"INBOX"); if ((fd = mbx_isvalid (&dstream,mailbox,file,&ld,lock, au ? MBXISVALIDUID : MBXISVALIDNOUID)) < 0) break; case EACCES: /* file protected */ sprintf (tmp,"Can't access destination: %.80s",mailbox); MM_LOG (tmp,ERROR); return NIL; case EINVAL: sprintf (tmp,"Invalid MBX-format mailbox name: %.80s",mailbox); mm_log (tmp,ERROR); return NIL; default: sprintf (tmp,"Not a MBX-format mailbox: %.80s",mailbox); mm_log (tmp,ERROR); return NIL; } /* get first message */ if (!(*af) (dstream,data,&flags,&date,&message)) close (fd); else if (!(df = fdopen (fd,"r+b"))) { MM_LOG ("Unable to reopen append mailbox",ERROR); close (fd); } else { mm_critical (dstream); /* go critical */ fstat (fd,&sbuf); /* get current file size */ fseek (df,sbuf.st_size,SEEK_SET); errno = 0; for (ret = LONGT; ret && message; ) { if (!SIZE (message)) { /* guard against zero-length */ mm_log ("Append of zero-length message",ERROR); ret = NIL; break; } f = mail_parse_flags (dstream,flags,&uf); if (date) { /* parse date if given */ if (!mail_parse_date (&elt,date)) { sprintf (tmp,"Bad date in append: %.80s",date); mm_log (tmp,ERROR); ret = NIL; /* mark failure */ break; } mail_date (tmp,&elt); /* write preseved date */ } else internal_date (tmp); /* get current date in IMAP format */ /* write header */ if (fprintf (df,"%s,%lu;%08lx%04lx-%08lx\015\012",tmp,i = SIZE (message), uf,(unsigned long) f,au ? ++dstream->uid_last : 0) < 0) ret = NIL; else { /* write message */ size_t j; if (!message->cursize) SETPOS (message,GETPOS (message)); while (i && (j = fwrite (message->curpos,1,message->cursize,df))) { i -= j; SETPOS (message,GETPOS (message) + j); } /* get next message */ if (i || !(*af) (dstream,data,&flags,&date,&message)) ret = NIL; else if (au) mail_append_set (dst,dstream->uid_last); } } /* if error... */ if (!ret || (fflush (df) == EOF)) { /* revert file */ ftruncate (fd,sbuf.st_size); close (fd); /* make sure fclose() doesn't corrupt us */ if (errno) { sprintf (tmp,"Message append failed: %s",strerror (errno)); mm_log (tmp,ERROR); } ret = NIL; } if (au && ret) { /* return sets if doing APPENDUID */ (*au) (mailbox,dstream->uid_validity,dst); fseek (df,15,SEEK_SET); /* update UIDLAST */ fprintf (df,"%08lx",dstream->uid_last); } else mail_free_searchset (&dst); if (ret) times.actime = time (0) - 1; /* else preserve \Marked status */ else times.actime = (sbuf.st_ctime > sbuf.st_atime) ? sbuf.st_atime : time (0); /* preserve mtime */ times.modtime = sbuf.st_mtime; utime (file,×); /* set the times */ fclose (df); /* close the file */ mm_nocritical (dstream); /* release critical */ } unlockfd (ld,lock); /* release exclusive parse/append permission */ if (dstream != stream) mail_close (dstream); return ret; } /* Internal routines */ /* MBX mail parse mailbox * Accepts: MAIL stream * Returns: T if parse OK * NIL if failure, stream aborted */ long mbx_parse (MAILSTREAM *stream) { struct stat sbuf; MESSAGECACHE *elt = NIL; unsigned char c,*s,*t,*x; char tmp[MAILTMPLEN]; unsigned long i,j,k,m; off_t curpos = LOCAL->filesize; unsigned long nmsgs = stream->nmsgs; unsigned long recent = stream->recent; unsigned long lastuid = 0; short dirty = NIL; short added = NIL; short silent = stream->silent; short uidwarn = T; fstat (LOCAL->fd,&sbuf); /* get status */ if (sbuf.st_size < curpos) { /* sanity check */ sprintf (tmp,"Mailbox shrank from %lu to %lu!", (unsigned long) curpos,(unsigned long) sbuf.st_size); mm_log (tmp,ERROR); mbx_abort (stream); return NIL; } lseek (LOCAL->fd,0,L_SET); /* rewind file */ /* read internal header */ read (LOCAL->fd,LOCAL->buf,HDRSIZE); LOCAL->buf[HDRSIZE] = '\0'; /* tie off header */ c = LOCAL->buf[15]; /* save first character of last UID */ LOCAL->buf[15] = '\0'; /* parse UID validity */ stream->uid_validity = strtoul (LOCAL->buf + 7,NIL,16); LOCAL->buf[15] = c; /* restore first character of last UID */ /* parse last UID */ i = strtoul (LOCAL->buf + 15,NIL,16); stream->uid_last = stream->rdonly ? max (i,stream->uid_last) : i; /* parse user flags */ for (i = 0, s = LOCAL->buf + 25; (i < NUSERFLAGS) && (t = strchr (s,'\015')) && (t - s); i++, s = t + 2) { *t = '\0'; /* tie off flag */ if (!stream->user_flags[i] && (strlen (s) <= MAXUSERFLAG)) stream->user_flags[i] = cpystr (s); } LOCAL->ffuserflag = (int) i; /* first free user flag */ stream->silent = T; /* don't pass up mm_exists() events yet */ while (sbuf.st_size - curpos){/* while there is stuff to parse */ /* get to that position in the file */ lseek (LOCAL->fd,curpos,L_SET); if ((i = read (LOCAL->fd,LOCAL->buf,64)) <= 0) { sprintf (tmp,"Unable to read internal header at %lu, size = %lu: %s", (unsigned long) curpos,(unsigned long) sbuf.st_size, i ? strerror (errno) : "no data read"); mm_log (tmp,ERROR); mbx_abort (stream); return NIL; } LOCAL->buf[i] = '\0'; /* tie off buffer just in case */ if (!((s = strchr (LOCAL->buf,'\015')) && (s[1] == '\012'))) { sprintf (tmp,"Unable to find CRLF at %lu in %lu bytes, text: %.80s", (unsigned long) curpos,i,(char *) LOCAL->buf); mm_log (tmp,ERROR); mbx_abort (stream); return NIL; } *s = '\0'; /* tie off header line */ i = (s + 2) - LOCAL->buf; /* note start of text offset */ if (!((s = strchr (LOCAL->buf,',')) && (t = strchr (s+1,';')))) { sprintf (tmp,"Unable to parse internal header at %lu: %.80s", (unsigned long) curpos,(char *) LOCAL->buf); mm_log (tmp,ERROR); mbx_abort (stream); return NIL; } if (!(isxdigit (t[1]) && isxdigit (t[2]) && isxdigit (t[3]) && isxdigit (t[4]) && isxdigit (t[5]) && isxdigit (t[6]) && isxdigit (t[7]) && isxdigit (t[8]) && isxdigit (t[9]) && isxdigit (t[10]) && isxdigit (t[11]) && isxdigit (t[12]))) { sprintf (tmp,"Unable to parse message flags at %lu: %.80s", (unsigned long) curpos,(char *) LOCAL->buf); mm_log (tmp,ERROR); mbx_abort (stream); return NIL; } if ((t[13] != '-') || t[22] || !(isxdigit (t[14]) && isxdigit (t[15]) && isxdigit (t[16]) && isxdigit (t[17]) && isxdigit (t[18]) && isxdigit (t[19]) && isxdigit (t[20]) && isxdigit (t[21]))) { sprintf (tmp,"Unable to parse message UID at %lu: %.80s", (unsigned long) curpos,(char *) LOCAL->buf); mm_log (tmp,ERROR); mbx_abort (stream); return NIL; } *s++ = '\0'; *t++ = '\0'; /* break up fields */ /* get message size */ if (!(j = strtoul (s,(char **) &x,10)) && (!(x && *x))) { sprintf (tmp,"Unable to parse message size at %lu: %.80s,%.80s;%.80s", (unsigned long) curpos,(char *) LOCAL->buf,(char *) s, (char *) t); mm_log (tmp,ERROR); mbx_abort (stream); return NIL; } /* make sure didn't run off end of file */ if (((off_t) (curpos + i + j)) > sbuf.st_size) { sprintf (tmp,"Last message (at %lu) runs past end of file (%lu > %lu)", (unsigned long) curpos,(unsigned long) (curpos + i + j), (unsigned long) sbuf.st_size); mm_log (tmp,ERROR); mbx_abort (stream); return NIL; } /* parse UID */ if ((m = strtoul (t+13,NIL,16)) && ((m <= lastuid) || (m > stream->uid_last))) { if (uidwarn) { sprintf (tmp,"Invalid UID %08lx in message %lu, rebuilding UIDs", m,nmsgs+1); mm_log (tmp,WARN); uidwarn = NIL; /* restart UID validity */ stream->uid_validity = (unsigned long) time (0); } m = 0; /* lose this UID */ dirty = T; /* mark dirty, set new lastuid */ stream->uid_last = lastuid; } t[12] = '\0'; /* parse system flags */ if ((k = strtoul (t+8,NIL,16)) & fEXPUNGED) { if (m) lastuid = m; /* expunge message, update last UID seen */ else { /* no UID assigned? */ lastuid = ++stream->uid_last; dirty = T; } } else { /* not expunged, swell the cache */ added = T; /* note that a new message was added */ mail_exists (stream,++nmsgs); /* instantiate an elt for this message */ (elt = mail_elt (stream,nmsgs))->valid = T; /* parse the date */ if (!mail_parse_date (elt,LOCAL->buf)) { sprintf (tmp,"Unable to parse message date at %lu: %.80s", (unsigned long) curpos,(char *) LOCAL->buf); mm_log (tmp,ERROR); mbx_abort (stream); return NIL; } /* note file offset of header */ elt->private.special.offset = curpos; /* and internal header size */ elt->private.special.text.size = i; /* header size not known yet */ elt->private.msg.header.text.size = 0; elt->rfc822_size = j; /* note message size */ /* calculate system flags */ if (k & fSEEN) elt->seen = T; if (k & fDELETED) elt->deleted = T; if (k & fFLAGGED) elt->flagged = T; if (k & fANSWERED) elt->answered = T; if (k & fDRAFT) elt->draft = T; t[8] = '\0'; /* get user flags value */ elt->user_flags = strtoul (t,NIL,16); /* UID already assigned? */ if (!(elt->private.uid = m) || !(k & fOLD)) { elt->recent = T; /* no, mark as recent */ ++recent; /* count up a new recent message */ dirty = T; /* and must rewrite header */ /* assign new UID */ if (!elt->private.uid) elt->private.uid = ++stream->uid_last; mbx_update_status (stream,elt->msgno,NIL); } /* update last parsed UID */ lastuid = elt->private.uid; } curpos += i + j; /* update position */ } if (dirty && !stream->rdonly){/* update header */ mbx_update_header (stream); fsync (LOCAL->fd); /* make sure all the UID updates take */ } /* update parsed file size and time */ LOCAL->filesize = sbuf.st_size; fstat (LOCAL->fd,&sbuf); /* get status again to ensure time is right */ LOCAL->filetime = sbuf.st_mtime; if (added && !stream->rdonly){/* make sure atime updated */ struct utimbuf times; times.actime = time (0); times.modtime = LOCAL->filetime; utime (stream->mailbox,×); } stream->silent = silent; /* can pass up events now */ mail_exists (stream,nmsgs); /* notify upper level of new mailbox size */ mail_recent (stream,recent); /* and of change in recent messages */ return LONGT; /* return the winnage */ } /* MBX get cache element with status updating from file * Accepts: MAIL stream * message number * expunge OK flag * Returns: cache element */ MESSAGECACHE *mbx_elt (MAILSTREAM *stream,unsigned long msgno,long expok) { MESSAGECACHE *elt = mail_elt (stream,msgno); struct { /* old flags */ unsigned int seen : 1; unsigned int deleted : 1; unsigned int flagged : 1; unsigned int answered : 1; unsigned int draft : 1; unsigned long user_flags; } old; old.seen = elt->seen; old.deleted = elt->deleted; old.flagged = elt->flagged; old.answered = elt->answered; old.draft = elt->draft; old.user_flags = elt->user_flags; /* get new flags */ if (mbx_read_flags (stream,elt) && expok) { mail_expunged (stream,elt->msgno); return NIL; /* return this message was expunged */ } if ((old.seen != elt->seen) || (old.deleted != elt->deleted) || (old.flagged != elt->flagged) || (old.answered != elt->answered) || (old.draft != elt->draft) || (old.user_flags != elt->user_flags)) mm_flags (stream,msgno); /* let top level know */ return elt; } /* MBX read flags from file * Accepts: MAIL stream * cache element * Returns: non-NIL if message expunged */ unsigned long mbx_read_flags (MAILSTREAM *stream,MESSAGECACHE *elt) { unsigned long i; struct stat sbuf; fstat (LOCAL->fd,&sbuf); /* get status */ /* make sure file size is good */ if (sbuf.st_size < LOCAL->filesize) { sprintf (LOCAL->buf,"Mailbox shrank from %lu to %lu in flag read!", (unsigned long) LOCAL->filesize,(unsigned long) sbuf.st_size); fatal (LOCAL->buf); } /* set the seek pointer */ lseek (LOCAL->fd,(off_t) elt->private.special.offset + elt->private.special.text.size - 24,L_SET); /* read the new flags */ if (read (LOCAL->fd,LOCAL->buf,14) < 0) { sprintf (LOCAL->buf,"Unable to read new status: %s",strerror (errno)); fatal (LOCAL->buf); } if ((LOCAL->buf[0] != ';') || (LOCAL->buf[13] != '-')) { LOCAL->buf[14] = '\0'; /* tie off buffer for error message */ sprintf (LOCAL->buf+50,"Invalid flags for message %lu (%lu %lu): %s", elt->msgno,elt->private.special.offset, elt->private.special.text.size,(char *) LOCAL->buf); fatal (LOCAL->buf+50); } LOCAL->buf[13] = '\0'; /* tie off buffer */ /* calculate system flags */ i = strtoul (LOCAL->buf+9,NIL,16); elt->seen = i & fSEEN ? T : NIL; elt->deleted = i & fDELETED ? T : NIL; elt->flagged = i & fFLAGGED ? T : NIL; elt->answered = i & fANSWERED ? T : NIL; elt->draft = i & fDRAFT ? T : NIL; LOCAL->expunged |= i & fEXPUNGED ? T : NIL; LOCAL->buf[9] = '\0'; /* tie off flags */ /* get user flags value */ elt->user_flags = strtoul (LOCAL->buf+1,NIL,16); elt->valid = T; /* have valid flags now */ return i & fEXPUNGED; } /* MBX update header * Accepts: MAIL stream */ #define NTKLUDGEOFFSET 7 void mbx_update_header (MAILSTREAM *stream) { int i; char *s = LOCAL->buf; memset (s,'\0',HDRSIZE); /* initialize header */ sprintf (s,"*mbx*\015\012%08lx%08lx\015\012", stream->uid_validity,stream->uid_last); for (i = 0; (i < NUSERFLAGS) && stream->user_flags[i]; ++i) sprintf (s += strlen (s),"%s\015\012",stream->user_flags[i]); LOCAL->ffuserflag = i; /* first free user flag */ /* can we create more user flags? */ stream->kwd_create = (i < NUSERFLAGS) ? T : NIL; /* write reserved lines */ while (i++ < NUSERFLAGS) strcat (s,"\015\012"); while (T) { /* rewind file */ lseek (LOCAL->fd,NTKLUDGEOFFSET,L_SET); /* write new header */ if (write (LOCAL->fd,LOCAL->buf + NTKLUDGEOFFSET, HDRSIZE - NTKLUDGEOFFSET) > 0) break; mm_notify (stream,strerror (errno),WARN); mm_diskerror (stream,errno,T); } } /* MBX update status string * Accepts: MAIL stream * message number * flags */ void mbx_update_status (MAILSTREAM *stream,unsigned long msgno,long flags) { struct stat sbuf; MESSAGECACHE *elt = mail_elt (stream,msgno); /* readonly */ if (stream->rdonly || !elt->valid) mbx_read_flags (stream,elt); else { /* readwrite */ fstat (LOCAL->fd,&sbuf); /* get status */ /* make sure file size is good */ if (sbuf.st_size < LOCAL->filesize) { sprintf (LOCAL->buf,"Mailbox shrank from %lu to %lu in flag update!", (unsigned long) LOCAL->filesize,(unsigned long) sbuf.st_size); fatal (LOCAL->buf); } /* set the seek pointer */ lseek (LOCAL->fd,(off_t) elt->private.special.offset + elt->private.special.text.size - 24,L_SET); /* read the new flags */ if (read (LOCAL->fd,LOCAL->buf,14) < 0) { sprintf (LOCAL->buf,"Unable to read old status: %s",strerror (errno)); fatal (LOCAL->buf); } if ((LOCAL->buf[0] != ';') || (LOCAL->buf[13] != '-')) { LOCAL->buf[14] = '\0'; /* tie off buffer for error message */ sprintf (LOCAL->buf+50,"Invalid flags for message %lu (%lu %lu): %s", elt->msgno,elt->private.special.offset, elt->private.special.text.size,(char *) LOCAL->buf); fatal (LOCAL->buf+50); } /* print new flag string */ sprintf (LOCAL->buf,"%08lx%04x-%08lx",elt->user_flags,(unsigned) (((elt->deleted && flags) ? fEXPUNGED : (strtoul (LOCAL->buf+9,NIL,16)) & fEXPUNGED) + (fSEEN * elt->seen) + (fDELETED * elt->deleted) + (fFLAGGED * elt->flagged) + (fANSWERED * elt->answered) + (fDRAFT * elt->draft) + fOLD),elt->private.uid); while (T) { /* get to that place in the file */ lseek (LOCAL->fd,(off_t) elt->private.special.offset + elt->private.special.text.size - 23,L_SET); /* write new flags and UID */ if (write (LOCAL->fd,LOCAL->buf,21) > 0) break; mm_notify (stream,strerror (errno),WARN); mm_diskerror (stream,errno,T); } } } /* MBX locate header for a message * Accepts: MAIL stream * message number * pointer to returned header size * pointer to possible returned header * Returns: position of header in file */ #define HDRBUFLEN 16384 /* good enough for most headers */ #define SLOP 4 /* CR LF CR LF */ unsigned long mbx_hdrpos (MAILSTREAM *stream,unsigned long msgno, unsigned long *size,char **hdr) { unsigned long siz,done; long i; unsigned char *s,*t,*te; MESSAGECACHE *elt = mail_elt (stream,msgno); unsigned long ret = elt->private.special.offset + elt->private.special.text.size; if (hdr) *hdr = NIL; /* assume no header returned */ /* is header size known? */ if (*size = elt->private.msg.header.text.size) return ret; /* paranoia check */ if (LOCAL->buflen < (HDRBUFLEN + SLOP)) fatal ("LOCAL->buf smaller than HDRBUFLEN"); lseek (LOCAL->fd,ret,L_SET); /* get to header position */ /* read HDRBUFLEN chunks with 4 byte slop */ for (done = siz = 0, s = LOCAL->buf; (i = min ((long) (elt->rfc822_size - done),(long) HDRBUFLEN)) && (read (LOCAL->fd,s,i) == i); done += i, siz += (t - LOCAL->buf) - SLOP, s = LOCAL->buf + SLOP) { te = (t = s + i) - 12; /* calculate end of fast scan */ /* fast scan for CR */ for (s = LOCAL->buf; s < te;) if (((*s++ == '\015') || (*s++ == '\015') || (*s++ == '\015') || (*s++ == '\015') || (*s++ == '\015') || (*s++ == '\015') || (*s++ == '\015') || (*s++ == '\015') || (*s++ == '\015') || (*s++ == '\015') || (*s++ == '\015') || (*s++ == '\015')) && (*s == '\012') && (*++s == '\015') && (*++s == '\012')) { *size = elt->private.msg.header.text.size = siz + (++s - LOCAL->buf); if (hdr) *hdr = LOCAL->buf; return ret; } for (te = t - 3; (s < te);) /* final character-at-a-time scan */ if ((*s++ == '\015') && (*s == '\012') && (*++s == '\015') && (*++s == '\012')) { *size = elt->private.msg.header.text.size = siz + (++s - LOCAL->buf); if (hdr) *hdr = LOCAL->buf; return ret; } if (i <= SLOP) break; /* end of data */ /* slide over last 4 bytes */ memmove (LOCAL->buf,t - SLOP,SLOP); hdr = NIL; /* can't return header this way */ } /* not found: header consumes entire message */ elt->private.msg.header.text.size = *size = elt->rfc822_size; if (hdr) *hdr = LOCAL->buf; /* possibly return header too */ return ret; } /* MBX mail rewrite mailbox * Accepts: MAIL stream * pointer to return reclaimed size * flags (0 = no expunge, 1 = expunge deleted, -1 = expunge sequence) * Returns: number of expunged messages */ unsigned long mbx_rewrite (MAILSTREAM *stream,unsigned long *reclaimed, long flags) { struct utimbuf times; struct stat sbuf; off_t pos,ppos; int ld; unsigned long i,j,k,m,delta; unsigned long n = *reclaimed = 0; unsigned long recent = 0; char lock[MAILTMPLEN]; MESSAGECACHE *elt; /* get parse/append permission */ if ((ld = lockname (lock,stream->mailbox,LOCK_EX)) < 0) { mm_log ("Unable to lock expunge mailbox",ERROR); return 0; } fstat (LOCAL->fd,&sbuf); /* get current write time */ if (LOCAL->filetime && !LOCAL->flagcheck && (LOCAL->filetime < sbuf.st_mtime)) LOCAL->flagcheck = T; if (!mbx_parse (stream)) { /* make sure see any newly-arrived messages */ unlockfd (ld,lock); /* failed?? */ return 0; } if (LOCAL->flagcheck) { /* sweep flags if need flagcheck */ LOCAL->filetime = sbuf.st_mtime; for (i = 1; i <= stream->nmsgs; ++i) mbx_elt (stream,i,NIL); LOCAL->flagcheck = NIL; } /* get exclusive access */ if (!flock (LOCAL->fd,LOCK_EX|LOCK_NB)) { mm_critical (stream); /* go critical */ for (i = 1,delta = 0,pos = ppos = HDRSIZE; i <= stream->nmsgs; ) { /* note if message not at predicted location */ if (m = (elt = mbx_elt (stream,i,NIL))->private.special.offset - ppos) { ppos = elt->private.special.offset; *reclaimed += m; /* note reclaimed message space */ delta += m; /* and as expunge delta */ } /* number of bytes to smash or preserve */ ppos += (k = elt->private.special.text.size + elt->rfc822_size); /* if need to expunge this message*/ if (flags && elt->deleted && ((flags > 0) || elt->sequence)) { delta += k; /* number of bytes to delete */ mail_expunged(stream,i);/* notify upper levels */ n++; /* count up one more expunged message */ } else { /* preserved message */ i++; /* count this message */ if (elt->recent) ++recent; if (delta) { /* moved, note first byte to preserve */ j = elt->private.special.offset; do { /* read from source position */ m = min (k,LOCAL->buflen); lseek (LOCAL->fd,j,L_SET); read (LOCAL->fd,LOCAL->buf,m); pos = j - delta; /* write to destination position */ while (T) { lseek (LOCAL->fd,pos,L_SET); if (write (LOCAL->fd,LOCAL->buf,m) > 0) break; mm_notify (stream,strerror (errno),WARN); mm_diskerror (stream,errno,T); } pos += m; /* new position */ j += m; /* next chunk, perhaps */ } while (k -= m); /* until done */ /* note the new address of this text */ elt->private.special.offset -= delta; } /* preserved but no deleted messages yet */ else pos = elt->private.special.offset + k; } } /* deltaed file size match position? */ if (m = (LOCAL->filesize -= delta) - pos) { *reclaimed += m; /* probably an fEXPUNGED msg */ LOCAL->filesize = pos; /* set correct size */ } /* truncate file after last message */ ftruncate (LOCAL->fd,LOCAL->filesize); fsync (LOCAL->fd); /* force disk update */ mm_nocritical (stream); /* release critical */ flock (LOCAL->fd,LOCK_SH); /* allow sharers again */ } else { /* can't get exclusive */ flock (LOCAL->fd,LOCK_SH); /* recover previous shared mailbox lock */ /* do hide-expunge when shared */ if (flags) for (i = 1; i <= stream->nmsgs; ) { if (elt = mbx_elt (stream,i,T)) { /* make the message invisible */ if (elt->deleted && ((flags > 0) || elt->sequence)) { mbx_update_status (stream,elt->msgno,LONGT); /* notify upper levels */ mail_expunged (stream,i); n++; /* count up one more expunged message */ } else { i++; /* preserved message */ if (elt->recent) ++recent; } } else n++; /* count up one more expunged message */ } fsync (LOCAL->fd); /* force disk update */ } fstat (LOCAL->fd,&sbuf); /* get new write time */ times.modtime = LOCAL->filetime = sbuf.st_mtime; times.actime = time (0); /* reset atime to now */ utime (stream->mailbox,×); unlockfd (ld,lock); /* release exclusive parse/append permission */ /* notify upper level of new mailbox size */ mail_exists (stream,stream->nmsgs); mail_recent (stream,recent); return n; /* return number of expunged messages */ } /* MBX mail lock for flag updating * Accepts: stream * Returns: T if successful, NIL if failure */ long mbx_flaglock (MAILSTREAM *stream) { struct stat sbuf; unsigned long i; int ld; char lock[MAILTMPLEN]; /* no-op if readonly or already locked */ if (!stream->rdonly && LOCAL && (LOCAL->fd >= 0) && (LOCAL->ld < 0)) { /* lock now */ if ((ld = lockname (lock,stream->mailbox,LOCK_EX)) < 0) return NIL; if (!LOCAL->flagcheck) { /* don't do this if flagcheck already needed */ if (LOCAL->filetime) { /* know previous time? */ fstat (LOCAL->fd,&sbuf);/* get current write time */ if (LOCAL->filetime < sbuf.st_mtime) LOCAL->flagcheck = T; LOCAL->filetime = 0; /* don't do this test for any other messages */ } if (!mbx_parse (stream)) {/* parse mailbox */ unlockfd (ld,lock); /* shouldn't happen */ return NIL; } if (LOCAL->flagcheck) /* invalidate cache if flagcheck */ for (i = 1; i <= stream->nmsgs; ++i) mail_elt (stream,i)->valid = NIL; } LOCAL->ld = ld; /* copy to stream for subsequent calls */ memcpy (LOCAL->lock,lock,MAILTMPLEN); } return LONGT; } alpine-2.10+dfsg/imap/src/osdep/os2/setproto.cmd0000600000175000017500000000171611512502123023236 0ustar paulproteuspaulproteus/* rexx */ /* ======================================================================== * Copyright 1988-2006 University of Washington * * Licensed under the Apache License, Version 2.0 (the "License"); * you may not use this file except in compliance with the License. * You may obtain a copy of the License at * * http://www.apache.org/licenses/LICENSE-2.0 * * * ======================================================================== */ /* * Program: Set default prototype for OS/2 * * Author: Mark Crispin * Networks and Distributed Computing * Computing & Communications * University of Washington * Administration Building, AG-44 * Seattle, WA 98195 * Internet: MRC@CAC.Washington.EDU * * Date: 10 June 1999 * Last Edited: 30 August 2006 */ '@echo off' parse arg default args h_file='linkage.h' call stream h_file, 'C', 'open write' call lineout h_file, '#define DEFAULTPROTO' default'proto' call stream h_file, 'C', 'close' exit 0 alpine-2.10+dfsg/imap/src/osdep/os2/tcp_os2.c0000600000175000017500000002710711512502123022411 0ustar paulproteuspaulproteus/* ======================================================================== * Copyright 1988-2008 University of Washington * * Licensed under the Apache License, Version 2.0 (the "License"); * you may not use this file except in compliance with the License. * You may obtain a copy of the License at * * http://www.apache.org/licenses/LICENSE-2.0 * * * ======================================================================== */ /* * Program: MS-DOS TCP/IP routines * * Author: Mark Crispin * Networks and Distributed Computing * Computing & Communications * University of Washington * Administration Building, AG-44 * Seattle, WA 98195 * Internet: MRC@CAC.Washington.EDU * * Date: 11 April 1989 * Last Edited: 13 January 2008 */ static tcptimeout_t tmoh = NIL; /* TCP timeout handler routine */ static long ttmo_read = 0; /* TCP timeouts, in seconds */ static long ttmo_write = 0; static char *tcp_getline_work (TCPSTREAM *stream,unsigned long *size, long *contd); /* TCP/IP manipulate parameters * Accepts: function code * function-dependent value * Returns: function-dependent return value */ void *tcp_parameters (long function,void *value) { void *ret = NIL; switch ((int) function) { case SET_TIMEOUT: tmoh = (tcptimeout_t) value; case GET_TIMEOUT: ret = (void *) tmoh; break; case SET_READTIMEOUT: ttmo_read = (long) value; case GET_READTIMEOUT: ret = (void *) ttmo_read; break; case SET_WRITETIMEOUT: ttmo_write = (long) value; case GET_WRITETIMEOUT: ret = (void *) ttmo_write; break; } return ret; } /* TCP/IP open * Accepts: host name * contact service name * contact port number * Returns: TCP/IP stream if success else NIL */ TCPSTREAM *tcp_open (char *host,char *service,unsigned long port) { TCPSTREAM *stream = NIL; struct sockaddr_in sin; int sock; char *s,tmp[MAILTMPLEN]; port &= 0xffff; /* erase flags */ /* The domain literal form is used (rather than simply the dotted decimal as with other Unix programs) because it has to be a valid "host name" in mailsystem terminology. */ sin.sin_family = AF_INET; /* family is always Internet */ /* look like domain literal? */ if (host[0] == '[' && host[(strlen (host))-1] == ']') { strcpy (tmp,host+1); /* yes, copy number part */ tmp[strlen (tmp)-1] = '\0'; if ((sin.sin_addr.s_addr = inet_addr (tmp)) == -1) { sprintf (tmp,"Bad format domain-literal: %.80s",host); mm_log (tmp,ERROR); return NIL; } } /* look up host name */ else if (!lookuphost (&host,&sin)) { sprintf (tmp,"Host not found: %s",host); mm_log (tmp,ERROR); return NIL; } /* copy port number in network format */ if (!(sin.sin_port = htons (port))) fatal ("Bad port argument to tcp_open"); /* get a TCP stream */ if ((sock = socket (sin.sin_family,SOCK_STREAM,0)) < 0) { sprintf (tmp,"Unable to create TCP socket (%d)",errno); mm_log (tmp,ERROR); fs_give ((void **) &host); return NIL; } #if 0 /* needed? */ else if (sock >= FD_SETSIZE) {/* unselectable sockets are useless */ sprintf (tmp,"Unable to create selectable TCP socket (%d >= %d)", sock,FD_SETSIZE); close (sock); errno = ENOBUFS; /* just in case */ return NIL; } #endif /* open connection */ if (connect (sock,(struct sockaddr *) &sin,sizeof (sin)) < 0) { switch (errno) { /* analyze error */ case ECONNREFUSED: s = "Refused"; break; case ENOBUFS: s = "Insufficient system resources"; break; case ETIMEDOUT: s = "Timed out"; break; default: s = "Unknown error"; break; } sprintf (tmp,"Can't connect to %.80s,%ld: %s (%d)",host,port,s,errno); mm_log (tmp,ERROR); close (sock); fs_give ((void **) &host); return NIL; } /* create TCP/IP stream */ stream = (TCPSTREAM *) fs_get (sizeof (TCPSTREAM)); stream->host = host; /* official host name */ stream->localhost = cpystr (mylocalhost ()); stream->port = port; /* port number */ stream->tcps = sock; /* init socket */ stream->ictr = 0; /* init input counter */ return stream; /* return success */ } /* TCP/IP authenticated open * Accepts: NETMBX specifier * service name * returned user name buffer * Returns: TCP/IP stream if success else NIL */ TCPSTREAM *tcp_aopen (NETMBX *mb,char *service,char *usrbuf) { return NIL; /* always NIL on DOS */ } /* TCP receive line * Accepts: TCP stream * Returns: text line string or NIL if failure */ char *tcp_getline (TCPSTREAM *stream) { unsigned long n,contd; char *ret = tcp_getline_work (stream,&n,&contd); if (ret && contd) { /* got a line needing continuation? */ STRINGLIST *stl = mail_newstringlist (); STRINGLIST *stc = stl; do { /* collect additional lines */ stc->text.data = (unsigned char *) ret; stc->text.size = n; stc = stc->next = mail_newstringlist (); ret = tcp_getline_work (stream,&n,&contd); } while (ret && contd); if (ret) { /* stash final part of line on list */ stc->text.data = (unsigned char *) ret; stc->text.size = n; /* determine how large a buffer we need */ for (n = 0, stc = stl; stc; stc = stc->next) n += stc->text.size; ret = fs_get (n + 1); /* copy parts into buffer */ for (n = 0, stc = stl; stc; n += stc->text.size, stc = stc->next) memcpy (ret + n,stc->text.data,stc->text.size); ret[n] = '\0'; } mail_free_stringlist (&stl);/* either way, done with list */ } return ret; } /* TCP receive line or partial line * Accepts: TCP stream * pointer to return size * pointer to return continuation flag * Returns: text line string, size and continuation flag, or NIL if failure */ static char *tcp_getline_work (TCPSTREAM *stream,unsigned long *size, long *contd) { unsigned long n; char *s,*ret,c,d; *contd = NIL; /* assume no continuation */ /* make sure have data */ if (!tcp_getdata (stream)) return NIL; for (s = stream->iptr, n = 0, c = '\0'; stream->ictr--; n++, c = d) { d = *stream->iptr++; /* slurp another character */ if ((c == '\015') && (d == '\012')) { ret = (char *) fs_get (n--); memcpy (ret,s,*size = n); /* copy into a free storage string */ ret[n] = '\0'; /* tie off string with null */ return ret; } } /* copy partial string from buffer */ memcpy ((ret = (char *) fs_get (n)),s,*size = n); /* get more data from the net */ if (!tcp_getdata (stream)) fs_give ((void **) &ret); /* special case of newline broken by buffer */ else if ((c == '\015') && (*stream->iptr == '\012')) { stream->iptr++; /* eat the line feed */ stream->ictr--; ret[*size = --n] = '\0'; /* tie off string with null */ } else *contd = LONGT; /* continuation needed */ return ret; } /* TCP/IP receive buffer * Accepts: TCP/IP stream * size in bytes * buffer to read into * Returns: T if success, NIL otherwise */ long tcp_getbuffer (TCPSTREAM *stream,unsigned long size,char *buffer) { unsigned long n; char *bufptr = buffer; while (size > 0) { /* until request satisfied */ if (!tcp_getdata (stream)) return NIL; n = min (size,stream->ictr);/* number of bytes to transfer */ /* do the copy */ memcpy (bufptr,stream->iptr,n); bufptr += n; /* update pointer */ stream->iptr +=n; size -= n; /* update # of bytes to do */ stream->ictr -=n; } bufptr[0] = '\0'; /* tie off string */ return T; } /* TCP/IP receive data * Accepts: TCP/IP stream * Returns: T if success, NIL otherwise */ long tcp_getdata (TCPSTREAM *stream) { int i; fd_set fds,efds; struct timeval tmo; time_t t = time (0); if (stream->tcps < 0) return NIL; while (stream->ictr < 1) { /* if nothing in the buffer */ time_t tl = time (0); /* start of request */ tmo.tv_sec = ttmo_read; /* read timeout */ tmo.tv_usec = 0; FD_ZERO (&fds); /* initialize selection vector */ FD_ZERO (&efds); /* handle errors too */ FD_SET (stream->tcps,&fds);/* set bit in selection vector */ FD_SET(stream->tcps,&efds);/* set bit in error selection vector */ errno = NIL; /* block and read */ while (((i = select (stream->tcps+1,&fds,0,&efds,ttmo_read ? &tmo : 0))<0) && (errno == EINTR)); if (!i) { /* timeout? */ time_t tc = time (0); if (tmoh && ((*tmoh) (tc - t,tc - tl))) continue; else return tcp_abort (stream); } else if (i < 0) return tcp_abort (stream); while (((i = read (stream->tcps,stream->ibuf,BUFLEN)) < 0) && (errno == EINTR)); if (i < 1) return tcp_abort (stream); stream->iptr = stream->ibuf;/* point at TCP buffer */ stream->ictr = i; /* set new byte count */ } return T; } /* TCP/IP send string as record * Accepts: TCP/IP stream * string pointer * Returns: T if success else NIL */ long tcp_soutr (TCPSTREAM *stream,char *string) { return tcp_sout (stream,string,(unsigned long) strlen (string)); } /* TCP/IP send string * Accepts: TCP/IP stream * string pointer * byte count * Returns: T if success else NIL */ long tcp_sout (TCPSTREAM *stream,char *string,unsigned long size) { int i; fd_set fds; struct timeval tmo; time_t t = time (0); if (stream->tcps < 0) return NIL; while (size > 0) { /* until request satisfied */ time_t tl = time (0); /* start of request */ tmo.tv_sec = ttmo_write; /* write timeout */ tmo.tv_usec = 0; FD_ZERO (&fds); /* initialize selection vector */ FD_SET (stream->tcps,&fds);/* set bit in selection vector */ errno = NIL; /* block and write */ while (((i = select (stream->tcps+1,0,&fds,0,ttmo_write ? &tmo : 0)) < 0) && (errno == EINTR)); if (!i) { /* timeout? */ time_t tc = time (0); if (tmoh && ((*tmoh) (tc - t,tc - tl))) continue; else return tcp_abort (stream); } else if (i < 0) return tcp_abort (stream); while (((i = write (stream->tcps,string,size)) < 0) && (errno == EINTR)); if (i < 0) return tcp_abort (stream); size -= i; /* how much we sent */ string += i; } return T; /* all done */ } /* TCP/IP close * Accepts: TCP/IP stream */ void tcp_close (TCPSTREAM *stream) { tcp_abort (stream); /* nuke the socket */ /* flush host names */ fs_give ((void **) &stream->host); fs_give ((void **) &stream->localhost); fs_give ((void **) &stream); /* flush the stream */ } /* TCP/IP abort stream * Accepts: TCP/IP stream * Returns: NIL always */ long tcp_abort (TCPSTREAM *stream) { if (stream->tcps >= 0) close (stream->tcps); stream->tcps = -1; return NIL; } /* TCP/IP get host name * Accepts: TCP/IP stream * Returns: host name for this stream */ char *tcp_host (TCPSTREAM *stream) { return stream->host; /* return host name */ } /* TCP/IP get remote host name * Accepts: TCP/IP stream * Returns: host name for this stream */ char *tcp_remotehost (TCPSTREAM *stream) { return stream->host; /* all we can do for now */ } /* TCP/IP return port for this stream * Accepts: TCP/IP stream * Returns: port number for this stream */ unsigned long tcp_port (TCPSTREAM *stream) { return stream->port; /* return port number */ } /* TCP/IP get local host name * Accepts: TCP/IP stream * Returns: local host name */ char *tcp_localhost (TCPSTREAM *stream) { return stream->localhost; /* return local host name */ } /* TCP/IP return canonical form of host name * Accepts: host name * Returns: canonical form of host name */ char *tcp_canonical (char *name) { return name; } /* TCP/IP get client host name (server calls only) * Returns: client host name */ char *tcp_clienthost () { return "UNKNOWN"; } alpine-2.10+dfsg/imap/src/osdep/os2/tcp_os2.h0000600000175000017500000000247611512502123022420 0ustar paulproteuspaulproteus/* ======================================================================== * Copyright 1988-2006 University of Washington * * Licensed under the Apache License, Version 2.0 (the "License"); * you may not use this file except in compliance with the License. * You may obtain a copy of the License at * * http://www.apache.org/licenses/LICENSE-2.0 * * * ======================================================================== */ /* * Program: OS2 routines * * Author: Mark Crispin * Networks and Distributed Computing * Computing & Communications * University of Washington * Administration Building, AG-44 * Seattle, WA 98195 * Internet: MRC@CAC.Washington.EDU * * Date: 11 April 1989 * Last Edited: 30 August 2006 */ /* TCP input buffer -- must be large enough to prevent overflow */ #define BUFLEN 8192 /* TCP I/O stream (must be before osdep.h is included) */ #define TCPSTREAM struct tcp_stream TCPSTREAM { char *host; /* host name */ unsigned long port; /* port number */ char *localhost; /* local host name */ int tcps; /* tcp socket */ long ictr; /* input counter */ char *iptr; /* input pointer */ char ibuf[BUFLEN]; /* input buffer */ }; /* Local function prototypes */ long lookuphost (char **host,struct sockaddr_in *sin); long tcp_abort (TCPSTREAM *stream); alpine-2.10+dfsg/imap/src/osdep/os2/env_os2.h0000600000175000017500000000371211512502123022414 0ustar paulproteuspaulproteus/* ======================================================================== * Copyright 1988-2006 University of Washington * * Licensed under the Apache License, Version 2.0 (the "License"); * you may not use this file except in compliance with the License. * You may obtain a copy of the License at * * http://www.apache.org/licenses/LICENSE-2.0 * * * ======================================================================== */ /* * Program: OS/2 environment routines * * Author: Mark Crispin * Networks and Distributed Computing * Computing & Communications * University of Washington * Administration Building, AG-44 * Seattle, WA 98195 * Internet: MRC@CAC.Washington.EDU * * Date: 14 March 1996 * Last Edited: 30 August 2006 */ /* Function prototypes */ #include "env.h" long random (void); /* syslog() emulation */ #define LOG_MAIL (2<<3) /* mail system */ #define LOG_DAEMON (3<<3) /* system daemons */ #define LOG_AUTH (4<<3) /* security/authorization messages */ #define LOG_EMERG 0 /* system is unusable */ #define LOG_ALERT 1 /* action must be taken immediately */ #define LOG_CRIT 2 /* critical conditions */ #define LOG_ERR 3 /* error conditions */ #define LOG_WARNING 4 /* warning conditions */ #define LOG_NOTICE 5 /* normal but signification condition */ #define LOG_INFO 6 /* informational */ #define LOG_DEBUG 7 /* debug-level messages */ #define LOG_PID 0x01 /* log the pid with each message */ #define LOG_CONS 0x02 /* log on the console if errors in sending */ #define LOG_ODELAY 0x04 /* delay open until syslog() is called */ #define LOG_NDELAY 0x08 /* don't delay open */ #define LOG_NOWAIT 0x10 /* if forking to log on console, don't wait() */ void openlog (const char *ident,int logopt,int facility); void syslog (int priority,const char *message,...); void rfc822_fixed_date (char *date); int lockname (char *lock,char *fname,int op); char *lockdir (char *lock,char *first,char *last); void unlockfd (int fd,char *lock); alpine-2.10+dfsg/imap/src/osdep/os2/pmatch.c0000600000175000017500000000545411512502123022315 0ustar paulproteuspaulproteus/* ======================================================================== * Copyright 1988-2006 University of Washington * * Licensed under the Apache License, Version 2.0 (the "License"); * you may not use this file except in compliance with the License. * You may obtain a copy of the License at * * http://www.apache.org/licenses/LICENSE-2.0 * * * ======================================================================== */ /* * Program: IMAP Wildcard Matching Routines (case-independent) * * Author: Mark Crispin * Networks and Distributed Computing * Computing & Communications * University of Washington * Administration Building, AG-44 * Seattle, WA 98195 * Internet: MRC@CAC.Washington.EDU * * Date: 15 June 2000 * Last Edited: 30 August 2006 */ /* Wildcard pattern match * Accepts: base string * pattern string * delimiter character * Returns: T if pattern matches base, else NIL */ long pmatch_full (unsigned char *s,unsigned char *pat,unsigned char delim) { switch (*pat) { case '%': /* non-recursive */ /* % at end, OK if no inferiors */ if (!pat[1]) return (delim && strchr (s,delim)) ? NIL : T; /* scan remainder of string until delimiter */ do if (pmatch_full (s,pat+1,delim)) return T; while ((*s != delim) && *s++); break; case '*': /* match 0 or more characters */ if (!pat[1]) return T; /* * at end, unconditional match */ /* scan remainder of string */ do if (pmatch_full (s,pat+1,delim)) return T; while (*s++); break; case '\0': /* end of pattern */ return *s ? NIL : T; /* success if also end of base */ default: /* match this character */ return compare_uchar (*pat,*s) ? NIL : pmatch_full (s+1,pat+1,delim); } return NIL; } /* Directory pattern match * Accepts: base string * pattern string * delimiter character * Returns: T if base is a matching directory of pattern, else NIL */ long dmatch (unsigned char *s,unsigned char *pat,unsigned char delim) { switch (*pat) { case '%': /* non-recursive */ if (!*s) return T; /* end of base means have a subset match */ if (!*++pat) return NIL; /* % at end, no inferiors permitted */ /* scan remainder of string until delimiter */ do if (dmatch (s,pat,delim)) return T; while ((*s != delim) && *s++); if (*s && !s[1]) return T; /* ends with delimiter, must be subset */ return dmatch (s,pat,delim);/* do new scan */ case '*': /* match 0 or more characters */ return T; /* unconditional match */ case '\0': /* end of pattern */ break; default: /* match this character */ if (*s) return compare_uchar (*pat,*s) ? NIL : dmatch (s+1,pat+1,delim); /* end of base, return if at delimiter */ else if (*pat == delim) return T; break; } return NIL; } alpine-2.10+dfsg/imap/src/osdep/os2/mtxnt.c0000600000175000017500000011753411512502123022216 0ustar paulproteuspaulproteus/* ======================================================================== * Copyright 1988-2007 University of Washington * * Licensed under the Apache License, Version 2.0 (the "License"); * you may not use this file except in compliance with the License. * You may obtain a copy of the License at * * http://www.apache.org/licenses/LICENSE-2.0 * * * ======================================================================== */ /* * Program: MTX mail routines * * Author: Mark Crispin * Networks and Distributed Computing * Computing & Communications * University of Washington * Administration Building, AG-44 * Seattle, WA 98195 * Internet: MRC@CAC.Washington.EDU * * Date: 22 May 1990 * Last Edited: 15 June 2007 */ /* FILE TIME SEMANTICS * * The atime is the last read time of the file. * The mtime is the last flags update time of the file. * The ctime is the last write time of the file. */ #include #include #include extern int errno; /* just in case */ #include "mail.h" #include "osdep.h" #include #include #include #include #include "misc.h" #include "dummy.h" #include "fdstring.h" /* MTX I/O stream local data */ typedef struct mtx_local { unsigned int shouldcheck: 1; /* if ping should do a check instead */ unsigned int mustcheck: 1; /* if ping must do a check instead */ int fd; /* file descriptor for I/O */ off_t filesize; /* file size parsed */ time_t filetime; /* last file time */ time_t lastsnarf; /* last snarf time */ unsigned char *buf; /* temporary buffer */ unsigned long buflen; /* current size of temporary buffer */ } MTXLOCAL; /* Convenient access to local data */ #define LOCAL ((MTXLOCAL *) stream->local) /* Function prototypes */ DRIVER *mtx_valid (char *name); int mtx_isvalid (char *name,char *file); void *mtx_parameters (long function,void *value); void mtx_scan (MAILSTREAM *stream,char *ref,char *pat,char *contents); void mtx_list (MAILSTREAM *stream,char *ref,char *pat); void mtx_lsub (MAILSTREAM *stream,char *ref,char *pat); long mtx_create (MAILSTREAM *stream,char *mailbox); long mtx_delete (MAILSTREAM *stream,char *mailbox); long mtx_rename (MAILSTREAM *stream,char *old,char *newname); long mtx_status (MAILSTREAM *stream,char *mbx,long flags); MAILSTREAM *mtx_open (MAILSTREAM *stream); void mtx_close (MAILSTREAM *stream,long options); void mtx_flags (MAILSTREAM *stream,char *sequence,long flags); char *mtx_header (MAILSTREAM *stream,unsigned long msgno, unsigned long *length,long flags); long mtx_text (MAILSTREAM *stream,unsigned long msgno,STRING *bs,long flags); void mtx_flag (MAILSTREAM *stream,char *sequence,char *flag,long flags); void mtx_flagmsg (MAILSTREAM *stream,MESSAGECACHE *elt); long mtx_ping (MAILSTREAM *stream); void mtx_check (MAILSTREAM *stream); void mtx_snarf (MAILSTREAM *stream); long mtx_expunge (MAILSTREAM *stream,char *sequence,long options); long mtx_copy (MAILSTREAM *stream,char *sequence,char *mailbox,long options); long mtx_append (MAILSTREAM *stream,char *mailbox,append_t af,void *data); long mtx_parse (MAILSTREAM *stream); MESSAGECACHE *mtx_elt (MAILSTREAM *stream,unsigned long msgno); void mtx_read_flags (MAILSTREAM *stream,MESSAGECACHE *elt); void mtx_update_status (MAILSTREAM *stream,unsigned long msgno,long syncflag); unsigned long mtx_hdrpos (MAILSTREAM *stream,unsigned long msgno, unsigned long *size); /* MTX mail routines */ /* Driver dispatch used by MAIL */ DRIVER mtxdriver = { "mtx", /* driver name */ /* driver flags */ DR_LOCAL|DR_MAIL|DR_CRLF|DR_NOSTICKY, (DRIVER *) NIL, /* next driver */ mtx_valid, /* mailbox is valid for us */ mtx_parameters, /* manipulate parameters */ mtx_scan, /* scan mailboxes */ mtx_list, /* list mailboxes */ mtx_lsub, /* list subscribed mailboxes */ NIL, /* subscribe to mailbox */ NIL, /* unsubscribe from mailbox */ mtx_create, /* create mailbox */ mtx_delete, /* delete mailbox */ mtx_rename, /* rename mailbox */ mail_status_default, /* status of mailbox */ mtx_open, /* open mailbox */ mtx_close, /* close mailbox */ mtx_flags, /* fetch message "fast" attributes */ mtx_flags, /* fetch message flags */ NIL, /* fetch overview */ NIL, /* fetch message envelopes */ mtx_header, /* fetch message header */ mtx_text, /* fetch message body */ NIL, /* fetch partial message text */ NIL, /* unique identifier */ NIL, /* message number */ mtx_flag, /* modify flags */ mtx_flagmsg, /* per-message modify flags */ NIL, /* search for message based on criteria */ NIL, /* sort messages */ NIL, /* thread messages */ mtx_ping, /* ping mailbox to see if still alive */ mtx_check, /* check for new messages */ mtx_expunge, /* expunge deleted messages */ mtx_copy, /* copy messages to another mailbox */ mtx_append, /* append string message to mailbox */ NIL /* garbage collect stream */ }; /* prototype stream */ MAILSTREAM mtxproto = {&mtxdriver}; /* MTX mail validate mailbox * Accepts: mailbox name * Returns: our driver if name is valid, NIL otherwise */ DRIVER *mtx_valid (char *name) { char tmp[MAILTMPLEN]; return mtx_isvalid (name,tmp) ? &mtxdriver : NIL; } /* MTX mail test for valid mailbox * Accepts: mailbox name * buffer to return file name * Returns: T if valid, NIL otherwise */ int mtx_isvalid (char *name,char *file) { int fd; int ret = NIL; char *s,tmp[MAILTMPLEN]; struct stat sbuf; struct utimbuf times; errno = EINVAL; /* assume invalid argument */ /* if file, get its status */ if ((s = dummy_file (file,name)) && !stat (s,&sbuf) && ((sbuf.st_mode & S_IFMT) == S_IFREG)) { if (!sbuf.st_size)errno = 0;/* empty file */ else if ((fd = open (file,O_BINARY|O_RDONLY,NIL)) >= 0) { memset (tmp,'\0',MAILTMPLEN); if ((read (fd,tmp,64) >= 0) && (s = strchr (tmp,'\015')) && (s[1] == '\012')) { /* valid format? */ *s = '\0'; /* tie off header */ /* must begin with dd-mmm-yy" */ ret = (((tmp[2] == '-' && tmp[6] == '-') || (tmp[1] == '-' && tmp[5] == '-')) && (s = strchr (tmp+18,',')) && strchr (s+2,';')) ? T : NIL; } else errno = -1; /* bogus format */ close (fd); /* close the file */ /* \Marked status? */ if (sbuf.st_ctime > sbuf.st_atime) { /* preserve atime and mtime */ times.actime = sbuf.st_atime; times.modtime = sbuf.st_mtime; utime (file,×); /* set the times */ } } } /* in case INBOX but not mtx format */ else if ((errno == ENOENT) && !compare_cstring (name,"INBOX")) errno = -1; return ret; /* return what we should */ } /* MTX manipulate driver parameters * Accepts: function code * function-dependent value * Returns: function-dependent return value */ void *mtx_parameters (long function,void *value) { return NIL; } /* MTX mail scan mailboxes * Accepts: mail stream * reference * pattern to search * string to scan */ void mtx_scan (MAILSTREAM *stream,char *ref,char *pat,char *contents) { if (stream) dummy_scan (NIL,ref,pat,contents); } /* MTX mail list mailboxes * Accepts: mail stream * reference * pattern to search */ void mtx_list (MAILSTREAM *stream,char *ref,char *pat) { if (stream) dummy_list (NIL,ref,pat); } /* MTX mail list subscribed mailboxes * Accepts: mail stream * reference * pattern to search */ void mtx_lsub (MAILSTREAM *stream,char *ref,char *pat) { if (stream) dummy_lsub (NIL,ref,pat); } /* MTX mail create mailbox * Accepts: MAIL stream * mailbox name to create * Returns: T on success, NIL on failure */ long mtx_create (MAILSTREAM *stream,char *mailbox) { char *s,mbx[MAILTMPLEN]; if (s = dummy_file (mbx,mailbox)) return dummy_create (stream,s); sprintf (mbx,"Can't create %.80s: invalid name",mailbox); mm_log (mbx,ERROR); return NIL; } /* MTX mail delete mailbox * Accepts: MAIL stream * mailbox name to delete * Returns: T on success, NIL on failure */ long mtx_delete (MAILSTREAM *stream,char *mailbox) { return mtx_rename (stream,mailbox,NIL); } /* MTX mail rename mailbox * Accepts: MAIL stream * old mailbox name * new mailbox name (or NIL for delete) * Returns: T on success, NIL on failure */ long mtx_rename (MAILSTREAM *stream,char *old,char *newname) { long ret = LONGT; char c,*s,tmp[MAILTMPLEN],file[MAILTMPLEN],lock[MAILTMPLEN]; int fd,ld; struct stat sbuf; if (!dummy_file (file,old) || (newname && (!((s = mailboxfile (tmp,newname)) && *s) || ((s = strrchr (tmp,'\\')) && !s[1])))) { sprintf (tmp,newname ? "Can't rename mailbox %.80s to %.80s: invalid name" : "Can't delete mailbox %.80s: invalid name", old,newname); mm_log (tmp,ERROR); return NIL; } if ((fd = open (file,O_BINARY|O_RDWR,NIL)) < 0) { sprintf (tmp,"Can't open mailbox %.80s: %s",old,strerror (errno)); mm_log (tmp,ERROR); return NIL; } /* get exclusive parse/append permission */ if ((ld = lockname (lock,file,LOCK_EX)) < 0) { mm_log ("Unable to lock rename mailbox",ERROR); return NIL; } /* lock out other users */ if (flock (fd,LOCK_EX|LOCK_NB)) { close (fd); /* couldn't lock, give up on it then */ sprintf (tmp,"Mailbox %.80s is in use by another process",old); mm_log (tmp,ERROR); unlockfd (ld,lock); /* release exclusive parse/append permission */ return NIL; } if (newname) { /* want rename? */ /* found superior to destination name? */ if ((s = strrchr (tmp,'\\')) && (s != tmp) && ((tmp[1] != ':') || (s != tmp + 2))) { c = s[1]; /* remember character after delimiter */ *s = s[1] = '\0'; /* tie off name at delimiter */ /* name doesn't exist, create it */ if (stat (tmp,&sbuf) || ((sbuf.st_mode & S_IFMT) != S_IFDIR)) { *s = '\\'; /* restore delimiter */ if (!dummy_create (stream,tmp)) ret = NIL; } else *s = '\\'; /* restore delimiter */ s[1] = c; /* restore character after delimiter */ } flock (fd,LOCK_UN); /* release lock on the file */ close (fd); /* pacify NTFS */ /* rename the file */ if (ret && rename (file,tmp)) { sprintf (tmp,"Can't rename mailbox %.80s to %.80s: %s",old,newname, strerror (errno)); mm_log (tmp,ERROR); ret = NIL; /* set failure */ } } else { flock (fd,LOCK_UN); /* release lock on the file */ close (fd); /* pacify NTFS */ if (unlink (file)) { sprintf (tmp,"Can't delete mailbox %.80s: %.80s",old,strerror (errno)); mm_log (tmp,ERROR); ret = NIL; /* set failure */ } } unlockfd (ld,lock); /* release exclusive parse/append permission */ return ret; /* return success */ } /* MTX mail open * Accepts: stream to open * Returns: stream on success, NIL on failure */ MAILSTREAM *mtx_open (MAILSTREAM *stream) { int fd,ld; char tmp[MAILTMPLEN]; /* return prototype for OP_PROTOTYPE call */ if (!stream) return &mtxproto; if (stream->local) fatal ("mtx recycle stream"); /* canonicalize the mailbox name */ if (!dummy_file (tmp,stream->mailbox)) { sprintf (tmp,"Can't open - invalid name: %.80s",stream->mailbox); mm_log (tmp,ERROR); } if (stream->rdonly || (fd = open (tmp,O_BINARY|O_RDWR,NIL)) < 0) { if ((fd = open (tmp,O_BINARY|O_RDONLY,NIL)) < 0) { sprintf (tmp,"Can't open mailbox: %.80s",strerror (errno)); mm_log (tmp,ERROR); return NIL; } else if (!stream->rdonly) { /* got it, but readonly */ mm_log ("Can't get write access to mailbox, access is readonly",WARN); stream->rdonly = T; } } stream->local = fs_get (sizeof (MTXLOCAL)); LOCAL->fd = fd; /* bind the file */ LOCAL->buf = (char *) fs_get (CHUNKSIZE); LOCAL->buflen = CHUNKSIZE - 1; /* note if an INBOX or not */ stream->inbox = !compare_cstring (stream->mailbox,"INBOX"); fs_give ((void **) &stream->mailbox); stream->mailbox = cpystr (tmp); /* get shared parse permission */ if ((ld = lockname (tmp,stream->mailbox,LOCK_SH)) < 0) { mm_log ("Unable to lock open mailbox",ERROR); return NIL; } flock (LOCAL->fd,LOCK_SH); /* lock the file */ unlockfd (ld,tmp); /* release shared parse permission */ LOCAL->filesize = 0; /* initialize parsed file size */ LOCAL->filetime = 0; /* time not set up yet */ LOCAL->mustcheck = LOCAL->shouldcheck = NIL; stream->sequence++; /* bump sequence number */ stream->uid_validity = (unsigned long) time (0); /* parse mailbox */ stream->nmsgs = stream->recent = 0; if (mtx_ping (stream) && !stream->nmsgs) mm_log ("Mailbox is empty",(long) NIL); if (!LOCAL) return NIL; /* failure if stream died */ stream->perm_seen = stream->perm_deleted = stream->perm_flagged = stream->perm_answered = stream->perm_draft = stream->rdonly ? NIL : T; stream->perm_user_flags = stream->rdonly ? NIL : 0xffffffff; return stream; /* return stream to caller */ } /* MTX mail close * Accepts: MAIL stream * close options */ void mtx_close (MAILSTREAM *stream,long options) { if (stream && LOCAL) { /* only if a file is open */ int silent = stream->silent; stream->silent = T; /* note this stream is dying */ if (options & CL_EXPUNGE) mtx_expunge (stream,NIL,NIL); stream->silent = silent; /* restore previous status */ flock (LOCAL->fd,LOCK_UN); /* unlock local file */ close (LOCAL->fd); /* close the local file */ /* free local text buffer */ if (LOCAL->buf) fs_give ((void **) &LOCAL->buf); /* nuke the local data */ fs_give ((void **) &stream->local); stream->dtb = NIL; /* log out the DTB */ } } /* MTX mail fetch flags * Accepts: MAIL stream * sequence * option flags * Sniffs at file to see if some other process changed the flags */ void mtx_flags (MAILSTREAM *stream,char *sequence,long flags) { unsigned long i; if (mtx_ping (stream) && /* ping mailbox, get new status for messages */ ((flags & FT_UID) ? mail_uid_sequence (stream,sequence) : mail_sequence (stream,sequence))) for (i = 1; i <= stream->nmsgs; i++) if (mail_elt (stream,i)->sequence) mtx_elt (stream,i); } /* MTX mail fetch message header * Accepts: MAIL stream * message # to fetch * pointer to returned header text length * option flags * Returns: message header in RFC822 format */ char *mtx_header (MAILSTREAM *stream,unsigned long msgno,unsigned long *length, long flags) { *length = 0; /* default to empty */ if (flags & FT_UID) return "";/* UID call "impossible" */ /* get to header position */ lseek (LOCAL->fd,mtx_hdrpos (stream,msgno,length),L_SET); /* is buffer big enough? */ if (*length > LOCAL->buflen) { fs_give ((void **) &LOCAL->buf); LOCAL->buf = (char *) fs_get ((LOCAL->buflen = *length) + 1); } LOCAL->buf[*length] = '\0'; /* tie off string */ /* slurp the data */ read (LOCAL->fd,LOCAL->buf,*length); return LOCAL->buf; } /* MTX mail fetch message text (body only) * Accepts: MAIL stream * message # to fetch * pointer to returned header text length * option flags * Returns: T, always */ long mtx_text (MAILSTREAM *stream,unsigned long msgno,STRING *bs,long flags) { FDDATA d; unsigned long i,j; MESSAGECACHE *elt; /* UID call "impossible" */ if (flags & FT_UID) return NIL; elt = mtx_elt (stream,msgno); /* get message status */ /* if message not seen */ if (!(flags & FT_PEEK) && !elt->seen) { elt->seen = T; /* mark message as seen */ /* recalculate status */ mtx_update_status (stream,msgno,NIL); mm_flags (stream,msgno); } /* find header position */ i = mtx_hdrpos (stream,msgno,&j); d.fd = LOCAL->fd; /* set up file descriptor */ d.pos = i + j; d.chunk = LOCAL->buf; /* initial buffer chunk */ d.chunksize = CHUNKSIZE; INIT (bs,fd_string,&d,elt->rfc822_size - j); return T; /* success */ } /* MTX mail modify flags * Accepts: MAIL stream * sequence * flag(s) * option flags */ void mtx_flag (MAILSTREAM *stream,char *sequence,char *flag,long flags) { struct utimbuf times; struct stat sbuf; if (!stream->rdonly) { /* make sure the update takes */ fsync (LOCAL->fd); fstat (LOCAL->fd,&sbuf); /* get current write time */ times.modtime = LOCAL->filetime = sbuf.st_mtime; times.actime = time (0); /* make sure read comes after all that */ utime (stream->mailbox,×); } } /* MTX mail per-message modify flags * Accepts: MAIL stream * message cache element */ void mtx_flagmsg (MAILSTREAM *stream,MESSAGECACHE *elt) { struct stat sbuf; /* maybe need to do a checkpoint? */ if (LOCAL->filetime && !LOCAL->shouldcheck) { fstat (LOCAL->fd,&sbuf); /* get current write time */ if (LOCAL->filetime < sbuf.st_mtime) LOCAL->shouldcheck = T; LOCAL->filetime = 0; /* don't do this test for any other messages */ } /* recalculate status */ mtx_update_status (stream,elt->msgno,NIL); } /* MTX mail ping mailbox * Accepts: MAIL stream * Returns: T if stream still alive, NIL if not */ long mtx_ping (MAILSTREAM *stream) { unsigned long i = 1; long r = T; int ld; char lock[MAILTMPLEN]; struct stat sbuf; if (stream && LOCAL) { /* only if stream already open */ fstat (LOCAL->fd,&sbuf); /* get current file poop */ if (LOCAL->filetime && !(LOCAL->mustcheck || LOCAL->shouldcheck) && (LOCAL->filetime < sbuf.st_mtime)) LOCAL->shouldcheck = T; /* check for changed message status */ if (LOCAL->mustcheck || LOCAL->shouldcheck) { LOCAL->filetime = sbuf.st_mtime; if (LOCAL->shouldcheck) /* babble when we do this unilaterally */ mm_notify (stream,"[CHECK] Checking for flag updates",NIL); while (i <= stream->nmsgs) mtx_elt (stream,i++); LOCAL->mustcheck = LOCAL->shouldcheck = NIL; } /* get shared parse/append permission */ if ((sbuf.st_size != LOCAL->filesize) && ((ld = lockname (lock,stream->mailbox,LOCK_SH)) >= 0)) { /* parse resulting mailbox */ r = (mtx_parse (stream)) ? T : NIL; unlockfd (ld,lock); /* release shared parse/append permission */ } } return r; /* return result of the parse */ } /* MTX mail check mailbox (reparses status too) * Accepts: MAIL stream */ void mtx_check (MAILSTREAM *stream) { /* mark that a check is desired */ if (LOCAL) LOCAL->mustcheck = T; if (mtx_ping (stream)) mm_log ("Check completed",(long) NIL); } /* MTX mail expunge mailbox * sequence to expunge if non-NIL * expunge options * Returns: T, always */ long mtx_expunge (MAILSTREAM *stream,char *sequence,long options) { long ret; struct utimbuf times; struct stat sbuf; off_t pos = 0; int ld; unsigned long i = 1; unsigned long j,k,m,recent; unsigned long n = 0; unsigned long delta = 0; char lock[MAILTMPLEN]; MESSAGECACHE *elt; if (!(ret = (sequence ? ((options & EX_UID) ? mail_uid_sequence (stream,sequence) : mail_sequence (stream,sequence)) : LONGT) && mtx_ping (stream))); /* parse sequence if given, ping stream */ else if (stream->rdonly) mm_log ("Expunge ignored on readonly mailbox",WARN); else { if (LOCAL->filetime && !LOCAL->shouldcheck) { fstat (LOCAL->fd,&sbuf); /* get current write time */ if (LOCAL->filetime < sbuf.st_mtime) LOCAL->shouldcheck = T; } /* get exclusive parse/append permission */ if ((ld = lockname (lock,stream->mailbox,LOCK_EX)) < 0) mm_log ("Unable to lock expunge mailbox",ERROR); /* make sure see any newly-arrived messages */ else if (!mtx_parse (stream)); /* get exclusive access */ else if (flock (LOCAL->fd,LOCK_EX|LOCK_NB)) { flock (LOCAL->fd,LOCK_SH);/* recover previous lock */ mm_log ("Can't expunge because mailbox is in use by another process", ERROR); unlockfd (ld,lock); /* release exclusive parse/append permission */ } else { mm_critical (stream); /* go critical */ recent = stream->recent; /* get recent now that pinged and locked */ /* for each message */ while (i <= stream->nmsgs) { /* get cache element */ elt = mtx_elt (stream,i); /* number of bytes to smash or preserve */ k = elt->private.special.text.size + elt->rfc822_size; /* if need to expunge this message */ if (elt->deleted && (sequence ? elt->sequence : T)) { /* if recent, note one less recent message */ if (elt->recent) --recent; delta += k; /* number of bytes to delete */ /* notify upper levels */ mail_expunged (stream,i); n++; /* count up one more expunged message */ } else if (i++ && delta) {/* preserved message */ /* first byte to preserve */ j = elt->private.special.offset; do { /* read from source position */ m = min (k,LOCAL->buflen); lseek (LOCAL->fd,j,L_SET); read (LOCAL->fd,LOCAL->buf,m); pos = j - delta; /* write to destination position */ while (T) { lseek (LOCAL->fd,pos,L_SET); if (write (LOCAL->fd,LOCAL->buf,m) > 0) break; mm_notify (stream,strerror (errno),WARN); mm_diskerror (stream,errno,T); } pos += m; /* new position */ j += m; /* next chunk, perhaps */ } while (k -= m); /* until done */ /* note the new address of this text */ elt->private.special.offset -= delta; } /* preserved but no deleted messages */ else pos = elt->private.special.offset + k; } if (n) { /* truncate file after last message */ if (pos != (LOCAL->filesize -= delta)) { sprintf (LOCAL->buf, "Calculated size mismatch %lu != %lu, delta = %lu", (unsigned long) pos,(unsigned long) LOCAL->filesize,delta); mm_log (LOCAL->buf,WARN); LOCAL->filesize = pos;/* fix it then */ } ftruncate (LOCAL->fd,LOCAL->filesize); sprintf (LOCAL->buf,"Expunged %lu messages",n); /* output the news */ mm_log (LOCAL->buf,(long) NIL); } else mm_log ("No messages deleted, so no update needed",(long) NIL); fsync (LOCAL->fd); /* force disk update */ fstat (LOCAL->fd,&sbuf); /* get new write time */ times.modtime = LOCAL->filetime = sbuf.st_mtime; times.actime = time (0); /* reset atime to now */ utime (stream->mailbox,×); mm_nocritical (stream); /* release critical */ /* notify upper level of new mailbox size */ mail_exists (stream,stream->nmsgs); mail_recent (stream,recent); flock (LOCAL->fd,LOCK_SH);/* allow sharers again */ unlockfd (ld,lock); /* release exclusive parse/append permission */ } } return ret; } /* MTX mail copy message(s) * Accepts: MAIL stream * sequence * destination mailbox * copy options * Returns: T if success, NIL if failed */ long mtx_copy (MAILSTREAM *stream,char *sequence,char *mailbox,long options) { struct stat sbuf; struct utimbuf times; MESSAGECACHE *elt; unsigned long i,j,k; long ret = LONGT; int fd,ld; char file[MAILTMPLEN],lock[MAILTMPLEN]; mailproxycopy_t pc = (mailproxycopy_t) mail_parameters (stream,GET_MAILPROXYCOPY,NIL); /* make sure valid mailbox */ if (!mtx_isvalid (mailbox,file)) switch (errno) { case ENOENT: /* no such file? */ mm_notify (stream,"[TRYCREATE] Must create mailbox before copy",NIL); return NIL; case 0: /* merely empty file? */ break; case EACCES: /* file protected */ sprintf (LOCAL->buf,"Can't access destination: %.80s",mailbox); MM_LOG (LOCAL->buf,ERROR); return NIL; case EINVAL: if (pc) return (*pc) (stream,sequence,mailbox,options); sprintf (LOCAL->buf,"Invalid MTX-format mailbox name: %.80s",mailbox); mm_log (LOCAL->buf,ERROR); return NIL; default: if (pc) return (*pc) (stream,sequence,mailbox,options); sprintf (LOCAL->buf,"Not a MTX-format mailbox: %.80s",mailbox); mm_log (LOCAL->buf,ERROR); return NIL; } if (!((options & CP_UID) ? mail_uid_sequence (stream,sequence) : mail_sequence (stream,sequence))) return NIL; /* got file? */ if ((fd = open (file,O_BINARY|O_RDWR|O_CREAT,S_IREAD|S_IWRITE)) < 0) { sprintf (LOCAL->buf,"Unable to open copy mailbox: %.80s",strerror (errno)); mm_log (LOCAL->buf,ERROR); return NIL; } mm_critical (stream); /* go critical */ /* get exclusive parse/append permission */ if (flock (fd,LOCK_SH) || ((ld = lockname (lock,file,LOCK_EX)) < 0)) { mm_log ("Unable to lock copy mailbox",ERROR); mm_nocritical (stream); return NIL; } fstat (fd,&sbuf); /* get current file size */ lseek (fd,sbuf.st_size,L_SET);/* move to end of file */ /* for each requested message */ for (i = 1; ret && (i <= stream->nmsgs); i++) if ((elt = mail_elt (stream,i))->sequence) { lseek (LOCAL->fd,elt->private.special.offset,L_SET); /* number of bytes to copy */ k = elt->private.special.text.size + elt->rfc822_size; do { /* read from source position */ j = min (k,LOCAL->buflen); read (LOCAL->fd,LOCAL->buf,j); if (write (fd,LOCAL->buf,j) < 0) ret = NIL; } while (ret && (k -= j));/* until done */ } /* make sure all the updates take */ if (!(ret && (ret = !fsync (fd)))) { sprintf (LOCAL->buf,"Unable to write message: %s",strerror (errno)); mm_log (LOCAL->buf,ERROR); ftruncate (fd,sbuf.st_size); } /* set atime to now-1 if successful copy */ if (ret) times.actime = time (0) - 1; /* else preserved \Marked status */ else times.actime = (sbuf.st_ctime > sbuf.st_atime) ? sbuf.st_atime : time (0); times.modtime = sbuf.st_mtime;/* preserve mtime */ utime (file,×); /* set the times */ unlockfd (ld,lock); /* release exclusive parse/append permission */ close (fd); /* close the file */ mm_nocritical (stream); /* release critical */ /* delete all requested messages */ if (ret && (options & CP_MOVE)) { for (i = 1; i <= stream->nmsgs; i++) if ((elt = mtx_elt (stream,i))->sequence) { elt->deleted = T; /* mark message deleted */ /* recalculate status */ mtx_update_status (stream,i,NIL); } if (!stream->rdonly) { /* make sure the update takes */ fsync (LOCAL->fd); fstat (LOCAL->fd,&sbuf); /* get current write time */ times.modtime = LOCAL->filetime = sbuf.st_mtime; times.actime = time (0); /* make sure atime remains greater */ utime (stream->mailbox,×); } } if (ret && mail_parameters (NIL,GET_COPYUID,NIL)) mm_log ("Can not return meaningful COPYUID with this mailbox format",WARN); return ret; } /* MTX mail append message from stringstruct * Accepts: MAIL stream * destination mailbox * append callback * data for callback * Returns: T if append successful, else NIL */ long mtx_append (MAILSTREAM *stream,char *mailbox,append_t af,void *data) { struct stat sbuf; int fd,ld,c; char *flags,*date,tmp[MAILTMPLEN],file[MAILTMPLEN],lock[MAILTMPLEN]; struct utimbuf times; FILE *df; MESSAGECACHE elt; long f; unsigned long i,uf; STRING *message; long ret = LONGT; /* default stream to prototype */ if (!stream) stream = &mtxproto; /* make sure valid mailbox */ if (!mtx_isvalid (mailbox,file)) switch (errno) { case ENOENT: /* no such file? */ if (!compare_cstring (mailbox,"INBOX")) mtx_create (NIL,"INBOX"); else { mm_notify (stream,"[TRYCREATE] Must create mailbox before append",NIL); return NIL; } /* falls through */ case 0: /* merely empty file? */ break; case EACCES: /* file protected */ sprintf (tmp,"Can't access destination: %.80s",mailbox); MM_LOG (tmp,ERROR); return NIL; case EINVAL: sprintf (tmp,"Invalid MTX-format mailbox name: %.80s",mailbox); mm_log (tmp,ERROR); return NIL; default: sprintf (tmp,"Not a MTX-format mailbox: %.80s",mailbox); mm_log (tmp,ERROR); return NIL; } /* get first message */ if (!(*af) (stream,data,&flags,&date,&message)) return NIL; /* open destination mailbox */ if (((fd = open (file,O_BINARY|O_WRONLY|O_APPEND|O_CREAT,S_IREAD|S_IWRITE)) < 0) || !(df = fdopen (fd,"ab"))) { sprintf (tmp,"Can't open append mailbox: %s",strerror (errno)); mm_log (tmp,ERROR); return NIL; } /* get parse/append permission */ if (flock (fd,LOCK_SH) || ((ld = lockname (lock,file,LOCK_EX)) < 0)) { mm_log ("Unable to lock append mailbox",ERROR); close (fd); return NIL; } mm_critical (stream); /* go critical */ fstat (fd,&sbuf); /* get current file size */ errno = 0; do { /* parse flags */ if (!SIZE (message)) { /* guard against zero-length */ mm_log ("Append of zero-length message",ERROR); ret = NIL; break; } f = mail_parse_flags (stream,flags,&i); /* reverse bits (dontcha wish we had CIRC?) */ for (uf = 0; i; uf |= 1 << (29 - find_rightmost_bit (&i))); if (date) { /* parse date if given */ if (!mail_parse_date (&elt,date)) { sprintf (tmp,"Bad date in append: %.80s",date); mm_log (tmp,ERROR); ret = NIL; /* mark failure */ break; } mail_date (tmp,&elt); /* write preseved date */ } else internal_date (tmp); /* get current date in IMAP format */ /* write header */ if (fprintf (df,"%s,%lu;%010lo%02lo\015\012",tmp,i = SIZE (message),uf, (unsigned long) f) < 0) ret = NIL; else { /* write message */ if (i) do c = 0xff & SNX (message); while ((putc (c,df) != EOF) && --i); /* get next message */ if (i || !(*af) (stream,data,&flags,&date,&message)) ret = NIL; } } while (ret && message); /* if error... */ if (!ret || (fflush (df) == EOF)) { ftruncate (fd,sbuf.st_size);/* revert file */ close (fd); /* make sure fclose() doesn't corrupt us */ if (errno) { sprintf (tmp,"Message append failed: %s",strerror (errno)); mm_log (tmp,ERROR); } ret = NIL; } if (ret) times.actime = time (0) - 1; /* else preserved \Marked status */ else times.actime = (sbuf.st_ctime > sbuf.st_atime) ? sbuf.st_atime : time (0); times.modtime = sbuf.st_mtime;/* preserve mtime */ utime (file,×); /* set the times */ fclose (df); /* close the file */ unlockfd (ld,lock); /* release exclusive parse/append permission */ mm_nocritical (stream); /* release critical */ if (ret && mail_parameters (NIL,GET_APPENDUID,NIL)) mm_log ("Can not return meaningful APPENDUID with this mailbox format", WARN); return ret; } /* Internal routines */ /* MTX mail parse mailbox * Accepts: MAIL stream * Returns: T if parse OK * NIL if failure, stream aborted */ long mtx_parse (MAILSTREAM *stream) { struct stat sbuf; MESSAGECACHE *elt = NIL; unsigned char c,*s,*t,*x; char tmp[MAILTMPLEN]; unsigned long i,j; long curpos = LOCAL->filesize; long nmsgs = stream->nmsgs; long recent = stream->recent; short added = NIL; short silent = stream->silent; fstat (LOCAL->fd,&sbuf); /* get status */ if (sbuf.st_size < curpos) { /* sanity check */ sprintf (tmp,"Mailbox shrank from %ld to %ld!",curpos,sbuf.st_size); mm_log (tmp,ERROR); mtx_close (stream,NIL); return NIL; } stream->silent = T; /* don't pass up mm_exists() events yet */ while (sbuf.st_size - curpos){/* while there is stuff to parse */ /* get to that position in the file */ lseek (LOCAL->fd,curpos,L_SET); if ((i = read (LOCAL->fd,LOCAL->buf,64)) <= 0) { sprintf (tmp,"Unable to read internal header at %lu, size = %lu: %s", (unsigned long) curpos,(unsigned long) sbuf.st_size, i ? strerror (errno) : "no data read"); mm_log (tmp,ERROR); mtx_close (stream,NIL); return NIL; } LOCAL->buf[i] = '\0'; /* tie off buffer just in case */ if (!((s = strchr (LOCAL->buf,'\015')) && (s[1] == '\012'))) { sprintf (tmp,"Unable to find CRLF at %lu in %lu bytes, text: %s", (unsigned long) curpos,i,(char *) LOCAL->buf); mm_log (tmp,ERROR); mtx_close (stream,NIL); return NIL; } *s = '\0'; /* tie off header line */ i = (s + 2) - LOCAL->buf; /* note start of text offset */ if (!((s = strchr (LOCAL->buf,',')) && (t = strchr (s+1,';')))) { sprintf (tmp,"Unable to parse internal header at %lu: %s", (unsigned long) curpos,(char *) LOCAL->buf); mm_log (tmp,ERROR); mtx_close (stream,NIL); return NIL; } *s++ = '\0'; *t++ = '\0'; /* tie off fields */ added = T; /* note that a new message was added */ /* swell the cache */ mail_exists (stream,++nmsgs); /* instantiate an elt for this message */ (elt = mail_elt (stream,nmsgs))->valid = T; elt->private.uid = ++stream->uid_last; /* note file offset of header */ elt->private.special.offset = curpos; /* in case error */ elt->private.special.text.size = 0; /* header size not known yet */ elt->private.msg.header.text.size = 0; x = s; /* parse the header components */ if (mail_parse_date (elt,LOCAL->buf) && (elt->rfc822_size = strtoul (s,(char **) &s,10)) && (!(s && *s)) && isdigit (t[0]) && isdigit (t[1]) && isdigit (t[2]) && isdigit (t[3]) && isdigit (t[4]) && isdigit (t[5]) && isdigit (t[6]) && isdigit (t[7]) && isdigit (t[8]) && isdigit (t[9]) && isdigit (t[10]) && isdigit (t[11]) && !t[12]) elt->private.special.text.size = i; else { /* oops */ sprintf (tmp,"Unable to parse internal header elements at %ld: %s,%s;%s", curpos,(char *) LOCAL->buf,(char *) x,(char *) t); mm_log (tmp,ERROR); mtx_close (stream,NIL); return NIL; } /* make sure didn't run off end of file */ if ((curpos += (elt->rfc822_size + i)) > sbuf.st_size) { sprintf (tmp,"Last message (at %lu) runs past end of file (%lu > %lu)", elt->private.special.offset,(unsigned long) curpos, (unsigned long) sbuf.st_size); mm_log (tmp,ERROR); mtx_close (stream,NIL); return NIL; } c = t[10]; /* remember first system flags byte */ t[10] = '\0'; /* tie off flags */ j = strtoul (t,NIL,8); /* get user flags value */ t[10] = c; /* restore first system flags byte */ /* set up all valid user flags (reversed!) */ while (j) if (((i = 29 - find_rightmost_bit (&j)) < NUSERFLAGS) && stream->user_flags[i]) elt->user_flags |= 1 << i; /* calculate system flags */ if ((j = ((t[10]-'0') * 8) + t[11]-'0') & fSEEN) elt->seen = T; if (j & fDELETED) elt->deleted = T; if (j & fFLAGGED) elt->flagged = T; if (j & fANSWERED) elt->answered = T; if (j & fDRAFT) elt->draft = T; if (!(j & fOLD)) { /* newly arrived message? */ elt->recent = T; recent++; /* count up a new recent message */ /* mark it as old */ mtx_update_status (stream,nmsgs,NIL); } } fsync (LOCAL->fd); /* make sure all the fOLD flags take */ /* update parsed file size and time */ LOCAL->filesize = sbuf.st_size; fstat (LOCAL->fd,&sbuf); /* get status again to ensure time is right */ LOCAL->filetime = sbuf.st_mtime; if (added && !stream->rdonly){/* make sure atime updated */ struct utimbuf times; times.actime = time (0); times.modtime = LOCAL->filetime; utime (stream->mailbox,×); } stream->silent = silent; /* can pass up events now */ mail_exists (stream,nmsgs); /* notify upper level of new mailbox size */ mail_recent (stream,recent); /* and of change in recent messages */ return LONGT; /* return the winnage */ } /* MTX get cache element with status updating from file * Accepts: MAIL stream * message number * Returns: cache element */ MESSAGECACHE *mtx_elt (MAILSTREAM *stream,unsigned long msgno) { MESSAGECACHE *elt = mail_elt (stream,msgno); struct { /* old flags */ unsigned int seen : 1; unsigned int deleted : 1; unsigned int flagged : 1; unsigned int answered : 1; unsigned int draft : 1; unsigned long user_flags; } old; old.seen = elt->seen; old.deleted = elt->deleted; old.flagged = elt->flagged; old.answered = elt->answered; old.draft = elt->draft; old.user_flags = elt->user_flags; mtx_read_flags (stream,elt); if ((old.seen != elt->seen) || (old.deleted != elt->deleted) || (old.flagged != elt->flagged) || (old.answered != elt->answered) || (old.draft != elt->draft) || (old.user_flags != elt->user_flags)) mm_flags (stream,msgno); /* let top level know */ return elt; } /* MTX read flags from file * Accepts: MAIL stream * Returns: cache element */ void mtx_read_flags (MAILSTREAM *stream,MESSAGECACHE *elt) { unsigned long i,j; /* noop if readonly and have valid flags */ if (stream->rdonly && elt->valid) return; /* set the seek pointer */ lseek (LOCAL->fd,(off_t) elt->private.special.offset + elt->private.special.text.size - 14,L_SET); /* read the new flags */ if (read (LOCAL->fd,LOCAL->buf,12) < 0) { sprintf (LOCAL->buf,"Unable to read new status: %s",strerror (errno)); fatal (LOCAL->buf); } /* calculate system flags */ i = (((LOCAL->buf[10]-'0') * 8) + LOCAL->buf[11]-'0'); elt->seen = i & fSEEN ? T : NIL; elt->deleted = i & fDELETED ? T : NIL; elt->flagged = i & fFLAGGED ? T : NIL; elt->answered = i & fANSWERED ? T : NIL; elt->draft = i & fDRAFT ? T : NIL; LOCAL->buf[10] = '\0'; /* tie off flags */ j = strtoul(LOCAL->buf,NIL,8);/* get user flags value */ /* set up all valid user flags (reversed!) */ while (j) if (((i = 29 - find_rightmost_bit (&j)) < NUSERFLAGS) && stream->user_flags[i]) elt->user_flags |= 1 << i; elt->valid = T; /* have valid flags now */ } /* MTX update status string * Accepts: MAIL stream * message number * flag saying whether or not to sync */ void mtx_update_status (MAILSTREAM *stream,unsigned long msgno,long syncflag) { struct utimbuf times; struct stat sbuf; MESSAGECACHE *elt = mail_elt (stream,msgno); unsigned long j,k = 0; /* readonly */ if (stream->rdonly || !elt->valid) mtx_read_flags (stream,elt); else { /* readwrite */ j = elt->user_flags; /* get user flags */ /* reverse bits (dontcha wish we had CIRC?) */ while (j) k |= 1 << (29 - find_rightmost_bit (&j)); /* print new flag string */ sprintf (LOCAL->buf,"%010lo%02o",k,(unsigned) (fOLD + (fSEEN * elt->seen) + (fDELETED * elt->deleted) + (fFLAGGED * elt->flagged) + (fANSWERED * elt->answered) + (fDRAFT * elt->draft))); while (T) { /* get to that place in the file */ lseek (LOCAL->fd,(off_t) elt->private.special.offset + elt->private.special.text.size - 14,L_SET); /* write new flags */ if (write (LOCAL->fd,LOCAL->buf,12) > 0) break; mm_notify (stream,strerror (errno),WARN); mm_diskerror (stream,errno,T); } if (syncflag) { /* sync if requested */ fsync (LOCAL->fd); fstat (LOCAL->fd,&sbuf); /* get new write time */ times.modtime = LOCAL->filetime = sbuf.st_mtime; times.actime = time (0); /* make sure read is later */ utime (stream->mailbox,×); } } } /* MTX locate header for a message * Accepts: MAIL stream * message number * pointer to returned header size * Returns: position of header in file */ unsigned long mtx_hdrpos (MAILSTREAM *stream,unsigned long msgno, unsigned long *size) { unsigned long siz; long i = 0; int q = 0; char *s,tmp[MAILTMPLEN]; MESSAGECACHE *elt = mtx_elt (stream,msgno); unsigned long ret = elt->private.special.offset + elt->private.special.text.size; /* is header size known? */ if (!(*size = elt->private.msg.header.text.size)) { lseek (LOCAL->fd,ret,L_SET);/* get to header position */ /* search message for CRLF CRLF */ for (siz = 1,s = tmp; siz <= elt->rfc822_size; siz++) { /* read another buffer as necessary */ if ((--i <= 0) && /* buffer empty? */ (read (LOCAL->fd,s = tmp, i = min (elt->rfc822_size - siz,(long) MAILTMPLEN)) < 0)) return ret; /* I/O error? */ switch (q) { /* sniff at buffer */ case 0: /* first character */ q = (*s++ == '\015') ? 1 : 0; break; case 1: /* second character */ q = (*s++ == '\012') ? 2 : 0; break; case 2: /* third character */ q = (*s++ == '\015') ? 3 : 0; break; case 3: /* fourth character */ if (*s++ == '\012') { /* have the sequence? */ /* yes, note for later */ elt->private.msg.header.text.size = *size = siz; return ret; } q = 0; /* lost... */ break; } } /* header consumes entire message */ elt->private.msg.header.text.size = *size = elt->rfc822_size; } return ret; } alpine-2.10+dfsg/imap/src/osdep/os2/tenexnt.c0000600000175000017500000012575111512502123022531 0ustar paulproteuspaulproteus/* ======================================================================== * Copyright 1988-2007 University of Washington * * Licensed under the Apache License, Version 2.0 (the "License"); * you may not use this file except in compliance with the License. * You may obtain a copy of the License at * * http://www.apache.org/licenses/LICENSE-2.0 * * * ======================================================================== */ /* * Program: Tenex mail routines * * Author: Mark Crispin * Networks and Distributed Computing * Computing & Communications * University of Washington * Administration Building, AG-44 * Seattle, WA 98195 * Internet: MRC@CAC.Washington.EDU * * Date: 22 May 1990 * Last Edited: 18 June 2007 */ /* FILE TIME SEMANTICS * * The atime is the last read time of the file. * The mtime is the last flags update time of the file. * The ctime is the last write time of the file. * * TEXT SIZE SEMANTICS * * Most of the text sizes are in internal (LF-only) form, except for the * msg.text size. Beware. */ #include #include #include extern int errno; /* just in case */ #include "mail.h" #include "osdep.h" #include #include #include #include #include "misc.h" #include "dummy.h" /* TENEX I/O stream local data */ typedef struct tenex_local { unsigned int shouldcheck: 1; /* if ping should do a check instead */ unsigned int mustcheck: 1; /* if ping must do a check instead */ int fd; /* file descriptor for I/O */ off_t filesize; /* file size parsed */ time_t filetime; /* last file time */ time_t lastsnarf; /* local snarf time */ unsigned char *buf; /* temporary buffer */ unsigned long buflen; /* current size of temporary buffer */ unsigned long uid; /* current text uid */ SIZEDTEXT text; /* current text */ } TENEXLOCAL; /* Convenient access to local data */ #define LOCAL ((TENEXLOCAL *) stream->local) /* Function prototypes */ DRIVER *tenex_valid (char *name); int tenex_isvalid (char *name,char *file); void *tenex_parameters (long function,void *value); void tenex_scan (MAILSTREAM *stream,char *ref,char *pat,char *contents); void tenex_list (MAILSTREAM *stream,char *ref,char *pat); void tenex_lsub (MAILSTREAM *stream,char *ref,char *pat); long tenex_create (MAILSTREAM *stream,char *mailbox); long tenex_delete (MAILSTREAM *stream,char *mailbox); long tenex_rename (MAILSTREAM *stream,char *old,char *newname); long tenex_status (MAILSTREAM *stream,char *mbx,long flags); MAILSTREAM *tenex_open (MAILSTREAM *stream); void tenex_close (MAILSTREAM *stream,long options); void tenex_fast (MAILSTREAM *stream,char *sequence,long flags); void tenex_flags (MAILSTREAM *stream,char *sequence,long flags); char *tenex_header (MAILSTREAM *stream,unsigned long msgno, unsigned long *length,long flags); long tenex_text (MAILSTREAM *stream,unsigned long msgno,STRING *bs,long flags); void tenex_flag (MAILSTREAM *stream,char *sequence,char *flag,long flags); void tenex_flagmsg (MAILSTREAM *stream,MESSAGECACHE *elt); long tenex_ping (MAILSTREAM *stream); void tenex_check (MAILSTREAM *stream); void tenex_snarf (MAILSTREAM *stream); long tenex_expunge (MAILSTREAM *stream,char *sequence,long options); long tenex_copy (MAILSTREAM *stream,char *sequence,char *mailbox,long options); long tenex_append (MAILSTREAM *stream,char *mailbox,append_t af,void *data); unsigned long tenex_size (MAILSTREAM *stream,unsigned long m); long tenex_parse (MAILSTREAM *stream); MESSAGECACHE *tenex_elt (MAILSTREAM *stream,unsigned long msgno); void tenex_read_flags (MAILSTREAM *stream,MESSAGECACHE *elt); void tenex_update_status (MAILSTREAM *stream,unsigned long msgno, long syncflag); unsigned long tenex_hdrpos (MAILSTREAM *stream,unsigned long msgno, unsigned long *size); /* Tenex mail routines */ /* Driver dispatch used by MAIL */ DRIVER tenexdriver = { "tenex", /* driver name */ DR_LOCAL|DR_MAIL, /* driver flags */ (DRIVER *) NIL, /* next driver */ tenex_valid, /* mailbox is valid for us */ tenex_parameters, /* manipulate parameters */ tenex_scan, /* scan mailboxes */ tenex_list, /* list mailboxes */ tenex_lsub, /* list subscribed mailboxes */ NIL, /* subscribe to mailbox */ NIL, /* unsubscribe from mailbox */ tenex_create, /* create mailbox */ tenex_delete, /* delete mailbox */ tenex_rename, /* rename mailbox */ mail_status_default, /* status of mailbox */ tenex_open, /* open mailbox */ tenex_close, /* close mailbox */ tenex_flags, /* fetch message "fast" attributes */ tenex_flags, /* fetch message flags */ NIL, /* fetch overview */ NIL, /* fetch message envelopes */ tenex_header, /* fetch message header */ tenex_text, /* fetch message body */ NIL, /* fetch partial message text */ NIL, /* unique identifier */ NIL, /* message number */ tenex_flag, /* modify flags */ tenex_flagmsg, /* per-message modify flags */ NIL, /* search for message based on criteria */ NIL, /* sort messages */ NIL, /* thread messages */ tenex_ping, /* ping mailbox to see if still alive */ tenex_check, /* check for new messages */ tenex_expunge, /* expunge deleted messages */ tenex_copy, /* copy messages to another mailbox */ tenex_append, /* append string message to mailbox */ NIL /* garbage collect stream */ }; /* prototype stream */ MAILSTREAM tenexproto = {&tenexdriver}; /* Tenex mail validate mailbox * Accepts: mailbox name * Returns: our driver if name is valid, NIL otherwise */ DRIVER *tenex_valid (char *name) { char tmp[MAILTMPLEN]; return tenex_isvalid (name,tmp) ? &tenexdriver : NIL; } /* Tenex mail test for valid mailbox * Accepts: mailbox name * buffer to return file name * Returns: T if valid, NIL otherwise */ int tenex_isvalid (char *name,char *file) { int fd; int ret = NIL; char *s,tmp[MAILTMPLEN]; struct stat sbuf; struct utimbuf times; errno = EINVAL; /* assume invalid argument */ /* if file, get its status */ if ((s = dummy_file (file,name)) && !stat (s,&sbuf) && ((sbuf.st_mode & S_IFMT) == S_IFREG)) { if (!sbuf.st_size)errno = 0;/* empty file */ else if ((fd = open (file,O_BINARY|O_RDONLY,NIL)) >= 0) { memset (tmp,'\0',MAILTMPLEN); if ((read (fd,tmp,64) >= 0) && (s = strchr (tmp,'\012')) && (s[-1] != '\015')) { /* valid format? */ *s = '\0'; /* tie off header */ /* must begin with dd-mmm-yy" */ ret = (((tmp[2] == '-' && tmp[6] == '-') || (tmp[1] == '-' && tmp[5] == '-')) && (s = strchr (tmp+18,',')) && strchr (s+2,';')) ? T : NIL; } else errno = -1; /* bogus format */ close (fd); /* close the file */ /* \Marked status? */ if (sbuf.st_ctime > sbuf.st_atime) { /* preserve atime and mtime */ times.actime = sbuf.st_atime; times.modtime = sbuf.st_mtime; utime (file,×); /* set the times */ } } } /* in case INBOX but not tenex format */ else if ((errno == ENOENT) && !compare_cstring (name,"INBOX")) errno = -1; return ret; /* return what we should */ } /* Tenex manipulate driver parameters * Accepts: function code * function-dependent value * Returns: function-dependent return value */ void *tenex_parameters (long function,void *value) { return NIL; } /* Tenex mail scan mailboxes * Accepts: mail stream * reference * pattern to search * string to scan */ void tenex_scan (MAILSTREAM *stream,char *ref,char *pat,char *contents) { if (stream) dummy_scan (NIL,ref,pat,contents); } /* Tenex mail list mailboxes * Accepts: mail stream * reference * pattern to search */ void tenex_list (MAILSTREAM *stream,char *ref,char *pat) { if (stream) dummy_list (NIL,ref,pat); } /* Tenex mail list subscribed mailboxes * Accepts: mail stream * reference * pattern to search */ void tenex_lsub (MAILSTREAM *stream,char *ref,char *pat) { if (stream) dummy_lsub (NIL,ref,pat); } /* Tenex mail create mailbox * Accepts: MAIL stream * mailbox name to create * Returns: T on success, NIL on failure */ long tenex_create (MAILSTREAM *stream,char *mailbox) { char *s,mbx[MAILTMPLEN]; if (s = dummy_file (mbx,mailbox)) return dummy_create (stream,s); sprintf (mbx,"Can't create %.80s: invalid name",mailbox); mm_log (mbx,ERROR); return NIL; } /* Tenex mail delete mailbox * Accepts: MAIL stream * mailbox name to delete * Returns: T on success, NIL on failure */ long tenex_delete (MAILSTREAM *stream,char *mailbox) { return tenex_rename (stream,mailbox,NIL); } /* Tenex mail rename mailbox * Accepts: MAIL stream * old mailbox name * new mailbox name (or NIL for delete) * Returns: T on success, NIL on failure */ long tenex_rename (MAILSTREAM *stream,char *old,char *newname) { long ret = LONGT; char c,*s,tmp[MAILTMPLEN],file[MAILTMPLEN],lock[MAILTMPLEN]; int fd,ld; struct stat sbuf; if (!dummy_file (file,old) || (newname && (!((s = mailboxfile (tmp,newname)) && *s) || ((s = strrchr (tmp,'\\')) && !s[1])))) { sprintf (tmp,newname ? "Can't rename mailbox %.80s to %.80s: invalid name" : "Can't delete mailbox %.80s: invalid name", old,newname); mm_log (tmp,ERROR); return NIL; } else if ((fd = open (file,O_BINARY|O_RDWR,NIL)) < 0) { sprintf (tmp,"Can't open mailbox %.80s: %s",old,strerror (errno)); mm_log (tmp,ERROR); return NIL; } /* get exclusive parse/append permission */ if ((ld = lockname (lock,file,LOCK_EX)) < 0) { mm_log ("Unable to lock rename mailbox",ERROR); return NIL; } /* lock out other users */ if (flock (fd,LOCK_EX|LOCK_NB)) { close (fd); /* couldn't lock, give up on it then */ sprintf (tmp,"Mailbox %.80s is in use by another process",old); mm_log (tmp,ERROR); unlockfd (ld,lock); /* release exclusive parse/append permission */ return NIL; } if (newname) { /* want rename? */ /* found superior to destination name? */ if ((s = strrchr (tmp,'\\')) && (s != tmp) && ((tmp[1] != ':') || (s != tmp + 2))) { c = s[1]; /* remember character after delimiter */ *s = s[1] = '\0'; /* tie off name at delimiter */ /* name doesn't exist, create it */ if (stat (tmp,&sbuf) || ((sbuf.st_mode & S_IFMT) != S_IFDIR)) { *s = '\\'; /* restore delimiter */ if (!dummy_create (stream,tmp)) ret = NIL; } else *s = '\\'; /* restore delimiter */ s[1] = c; /* restore character after delimiter */ } flock (fd,LOCK_UN); /* release lock on the file */ close (fd); /* pacify NTFS */ /* rename the file */ if (ret && rename (file,tmp)) { sprintf (tmp,"Can't rename mailbox %.80s to %.80s: %s",old,newname, strerror (errno)); mm_log (tmp,ERROR); ret = NIL; /* set failure */ } } else { flock (fd,LOCK_UN); /* release lock on the file */ close (fd); /* pacify NTFS */ if (unlink (file)) { sprintf (tmp,"Can't delete mailbox %.80s: %.80s",old,strerror (errno)); mm_log (tmp,ERROR); ret = NIL; /* set failure */ } } unlockfd (ld,lock); /* release exclusive parse/append permission */ return ret; /* return success */ } /* Tenex mail open * Accepts: stream to open * Returns: stream on success, NIL on failure */ MAILSTREAM *tenex_open (MAILSTREAM *stream) { int fd,ld; char tmp[MAILTMPLEN]; /* return prototype for OP_PROTOTYPE call */ if (!stream) return &tenexproto; if (stream->local) fatal ("tenex recycle stream"); /* canonicalize the mailbox name */ if (!dummy_file (tmp,stream->mailbox)) { sprintf (tmp,"Can't open - invalid name: %.80s",stream->mailbox); mm_log (tmp,ERROR); } if (stream->rdonly || (fd = open (tmp,O_BINARY|O_RDWR,NIL)) < 0) { if ((fd = open (tmp,O_BINARY|O_RDONLY,NIL)) < 0) { sprintf (tmp,"Can't open mailbox: %.80s",strerror (errno)); mm_log (tmp,ERROR); return NIL; } else if (!stream->rdonly) { /* got it, but readonly */ mm_log ("Can't get write access to mailbox, access is readonly",WARN); stream->rdonly = T; } } stream->local = fs_get (sizeof (TENEXLOCAL)); LOCAL->fd = fd; /* bind the file */ LOCAL->buf = (char *) fs_get (CHUNKSIZE); LOCAL->buflen = CHUNKSIZE - 1; LOCAL->text.data = (unsigned char *) fs_get (CHUNKSIZE); LOCAL->text.size = CHUNKSIZE - 1; /* note if an INBOX or not */ stream->inbox = !compare_cstring (stream->mailbox,"INBOX"); fs_give ((void **) &stream->mailbox); stream->mailbox = cpystr (tmp); /* get shared parse permission */ if ((ld = lockname (tmp,stream->mailbox,LOCK_SH)) < 0) { mm_log ("Unable to lock open mailbox",ERROR); return NIL; } flock (LOCAL->fd,LOCK_SH); /* lock the file */ unlockfd (ld,tmp); /* release shared parse permission */ LOCAL->filesize = 0; /* initialize parsed file size */ LOCAL->filetime = 0; /* time not set up yet */ LOCAL->mustcheck = LOCAL->shouldcheck = NIL; stream->sequence++; /* bump sequence number */ stream->uid_validity = (unsigned long) time (0); /* parse mailbox */ stream->nmsgs = stream->recent = 0; if (tenex_ping (stream) && !stream->nmsgs) mm_log ("Mailbox is empty",(long) NIL); if (!LOCAL) return NIL; /* failure if stream died */ stream->perm_seen = stream->perm_deleted = stream->perm_flagged = stream->perm_answered = stream->perm_draft = stream->rdonly ? NIL : T; stream->perm_user_flags = stream->rdonly ? NIL : 0xffffffff; return stream; /* return stream to caller */ } /* Tenex mail close * Accepts: MAIL stream * close options */ void tenex_close (MAILSTREAM *stream,long options) { if (stream && LOCAL) { /* only if a file is open */ int silent = stream->silent; stream->silent = T; /* note this stream is dying */ if (options & CL_EXPUNGE) tenex_expunge (stream,NIL,NIL); stream->silent = silent; /* restore previous status */ flock (LOCAL->fd,LOCK_UN); /* unlock local file */ close (LOCAL->fd); /* close the local file */ /* free local text buffer */ if (LOCAL->buf) fs_give ((void **) &LOCAL->buf); if (LOCAL->text.data) fs_give ((void **) &LOCAL->text.data); /* nuke the local data */ fs_give ((void **) &stream->local); stream->dtb = NIL; /* log out the DTB */ } } /* Tenex mail fetch flags * Accepts: MAIL stream * sequence * option flags * Sniffs at file to get flags */ void tenex_flags (MAILSTREAM *stream,char *sequence,long flags) { STRING bs; MESSAGECACHE *elt; unsigned long i; if (stream && LOCAL && ((flags & FT_UID) ? mail_uid_sequence (stream,sequence) : mail_sequence (stream,sequence))) for (i = 1; i <= stream->nmsgs; i++) if ((elt = mail_elt (stream,i))->sequence) { if (!elt->rfc822_size) { /* have header size yet? */ lseek (LOCAL->fd,elt->private.special.offset + elt->private.special.text.size,L_SET); /* resize bigbuf if necessary */ if (LOCAL->buflen < elt->private.msg.full.text.size) { fs_give ((void **) &LOCAL->buf); LOCAL->buflen = elt->private.msg.full.text.size; LOCAL->buf = (char *) fs_get (LOCAL->buflen + 1); } /* tie off string */ LOCAL->buf[elt->private.msg.full.text.size] = '\0'; /* read in the message */ read (LOCAL->fd,LOCAL->buf,elt->private.msg.full.text.size); INIT (&bs,mail_string,(void *) LOCAL->buf, elt->private.msg.full.text.size); /* calculate its CRLF size */ elt->rfc822_size = unix_crlflen (&bs); } tenex_elt (stream,i); /* get current flags from file */ } } /* TENEX mail fetch message header * Accepts: MAIL stream * message # to fetch * pointer to returned header text length * option flags * Returns: message header in RFC822 format */ char *tenex_header (MAILSTREAM *stream,unsigned long msgno, unsigned long *length,long flags) { char *s; unsigned long i; *length = 0; /* default to empty */ if (flags & FT_UID) return "";/* UID call "impossible" */ /* get to header position */ lseek (LOCAL->fd,tenex_hdrpos (stream,msgno,&i),L_SET); if (flags & FT_INTERNAL) { if (i > LOCAL->buflen) { /* resize if not enough space */ fs_give ((void **) &LOCAL->buf); LOCAL->buf = (char *) fs_get (LOCAL->buflen = i + 1); } /* slurp the data */ read (LOCAL->fd,LOCAL->buf,*length = i); } else { s = (char *) fs_get (i + 1);/* get readin buffer */ s[i] = '\0'; /* tie off string */ read (LOCAL->fd,s,i); /* slurp the data */ /* make CRLF copy of string */ *length = unix_crlfcpy (&LOCAL->buf,&LOCAL->buflen,s,i); fs_give ((void **) &s); /* free readin buffer */ } return LOCAL->buf; } /* TENEX mail fetch message text (body only) * Accepts: MAIL stream * message # to fetch * pointer to returned stringstruct * option flags * Returns: T, always */ long tenex_text (MAILSTREAM *stream,unsigned long msgno,STRING *bs,long flags) { char *s; unsigned long i,j; MESSAGECACHE *elt; /* UID call "impossible" */ if (flags & FT_UID) return NIL; /* get message status */ elt = tenex_elt (stream,msgno); /* if message not seen */ if (!(flags & FT_PEEK) && !elt->seen) { elt->seen = T; /* mark message as seen */ /* recalculate status */ tenex_update_status (stream,msgno,T); mm_flags (stream,msgno); } if (flags & FT_INTERNAL) { /* if internal representation wanted */ /* find header position */ i = tenex_hdrpos (stream,msgno,&j); if (i > LOCAL->buflen) { /* resize if not enough space */ fs_give ((void **) &LOCAL->buf); LOCAL->buf = (char *) fs_get (LOCAL->buflen = i + 1); } /* go to text position */ lseek (LOCAL->fd,i + j,L_SET); /* slurp the data */ if (read (LOCAL->fd,LOCAL->buf,i) != (long) i) return NIL; /* set up stringstruct for internal */ INIT (bs,mail_string,LOCAL->buf,i); } else { /* normal form, previous text cached? */ if (elt->private.uid == LOCAL->uid) i = elt->private.msg.text.text.size; else { /* not cached, cache it now */ LOCAL->uid = elt->private.uid; /* find header position */ i = tenex_hdrpos (stream,msgno,&j); /* go to text position */ lseek (LOCAL->fd,i + j,L_SET); s = (char *) fs_get ((i = tenex_size (stream,msgno) - j) + 1); s[i] = '\0'; /* tie off string */ read (LOCAL->fd,s,i); /* slurp the data */ /* make CRLF copy of string */ i = elt->private.msg.text.text.size = strcrlfcpy (&LOCAL->text.data,&LOCAL->text.size,s,i); fs_give ((void **) &s); /* free readin buffer */ } /* set up stringstruct */ INIT (bs,mail_string,LOCAL->text.data,i); } return T; /* success */ } /* Tenex mail modify flags * Accepts: MAIL stream * sequence * flag(s) * option flags */ void tenex_flag (MAILSTREAM *stream,char *sequence,char *flag,long flags) { struct utimbuf times; struct stat sbuf; if (!stream->rdonly) { /* make sure the update takes */ fsync (LOCAL->fd); fstat (LOCAL->fd,&sbuf); /* get current write time */ times.modtime = LOCAL->filetime = sbuf.st_mtime; times.actime = time (0); /* make sure read comes after all that */ utime (stream->mailbox,×); } } /* Tenex mail per-message modify flags * Accepts: MAIL stream * message cache element */ void tenex_flagmsg (MAILSTREAM *stream,MESSAGECACHE *elt) { struct stat sbuf; /* maybe need to do a checkpoint? */ if (LOCAL->filetime && !LOCAL->shouldcheck) { fstat (LOCAL->fd,&sbuf); /* get current write time */ if (LOCAL->filetime < sbuf.st_mtime) LOCAL->shouldcheck = T; LOCAL->filetime = 0; /* don't do this test for any other messages */ } /* recalculate status */ tenex_update_status (stream,elt->msgno,NIL); } /* Tenex mail ping mailbox * Accepts: MAIL stream * Returns: T if stream still alive, NIL if not */ long tenex_ping (MAILSTREAM *stream) { unsigned long i = 1; long r = T; int ld; char lock[MAILTMPLEN]; struct stat sbuf; if (stream && LOCAL) { /* only if stream already open */ fstat (LOCAL->fd,&sbuf); /* get current file poop */ if (LOCAL->filetime && !(LOCAL->mustcheck || LOCAL->shouldcheck) && (LOCAL->filetime < sbuf.st_mtime)) LOCAL->shouldcheck = T; /* check for changed message status */ if (LOCAL->mustcheck || LOCAL->shouldcheck) { LOCAL->filetime = sbuf.st_mtime; if (LOCAL->shouldcheck) /* babble when we do this unilaterally */ mm_notify (stream,"[CHECK] Checking for flag updates",NIL); while (i <= stream->nmsgs) tenex_elt (stream,i++); LOCAL->mustcheck = LOCAL->shouldcheck = NIL; } /* get shared parse/append permission */ if ((sbuf.st_size != LOCAL->filesize) && ((ld = lockname (lock,stream->mailbox,LOCK_SH)) >= 0)) { /* parse resulting mailbox */ r = (tenex_parse (stream)) ? T : NIL; unlockfd (ld,lock); /* release shared parse/append permission */ } } return r; /* return result of the parse */ } /* Tenex mail check mailbox (reparses status too) * Accepts: MAIL stream */ void tenex_check (MAILSTREAM *stream) { /* mark that a check is desired */ if (LOCAL) LOCAL->mustcheck = T; if (tenex_ping (stream)) mm_log ("Check completed",(long) NIL); } /* Tenex mail expunge mailbox * sequence to expunge if non-NIL * expunge options * Returns: T, always */ long tenex_expunge (MAILSTREAM *stream,char *sequence,long options) { long ret; struct utimbuf times; struct stat sbuf; off_t pos = 0; int ld; unsigned long i = 1; unsigned long j,k,m,recent; unsigned long n = 0; unsigned long delta = 0; char lock[MAILTMPLEN]; MESSAGECACHE *elt; if (!(ret = (sequence ? ((options & EX_UID) ? mail_uid_sequence (stream,sequence) : mail_sequence (stream,sequence)) : LONGT) && tenex_ping (stream))); /* parse sequence if given, ping stream */ else if (stream->rdonly) mm_log ("Expunge ignored on readonly mailbox",WARN); else { if (LOCAL->filetime && !LOCAL->shouldcheck) { fstat (LOCAL->fd,&sbuf); /* get current write time */ if (LOCAL->filetime < sbuf.st_mtime) LOCAL->shouldcheck = T; } /* get exclusive access */ if ((ld = lockname (lock,stream->mailbox,LOCK_EX)) < 0) mm_log ("Unable to lock expunge mailbox",ERROR); /* make sure see any newly-arrived messages */ else if (!tenex_parse (stream)); /* get exclusive access */ else if (flock (LOCAL->fd,LOCK_EX|LOCK_NB)) { flock (LOCAL->fd,LOCK_SH);/* recover previous lock */ mm_log ("Can't expunge because mailbox is in use by another process", ERROR); unlockfd (ld,lock); /* release exclusive parse/append permission */ } else { mm_critical (stream); /* go critical */ recent = stream->recent; /* get recent now that pinged and locked */ /* for each message */ while (i <= stream->nmsgs) { /* get cache element */ elt = tenex_elt (stream,i); /* number of bytes to smash or preserve */ k = elt->private.special.text.size + tenex_size (stream,i); /* if need to expunge this message */ if (elt->deleted && (sequence ? elt->sequence : T)) { /* if recent, note one less recent message */ if (elt->recent) --recent; delta += k; /* number of bytes to delete */ /* notify upper levels */ mail_expunged (stream,i); n++; /* count up one more expunged message */ } else if (i++ && delta) {/* preserved message */ /* first byte to preserve */ j = elt->private.special.offset; do { /* read from source position */ m = min (k,LOCAL->buflen); lseek (LOCAL->fd,j,L_SET); read (LOCAL->fd,LOCAL->buf,m); pos = j - delta; /* write to destination position */ while (T) { lseek (LOCAL->fd,pos,L_SET); if (write (LOCAL->fd,LOCAL->buf,m) > 0) break; mm_notify (stream,strerror (errno),WARN); mm_diskerror (stream,errno,T); } pos += m; /* new position */ j += m; /* next chunk, perhaps */ } while (k -= m); /* until done */ /* note the new address of this text */ elt->private.special.offset -= delta; } /* preserved but no deleted messages */ else pos = elt->private.special.offset + k; } if (n) { /* truncate file after last message */ if (pos != (LOCAL->filesize -= delta)) { sprintf (LOCAL->buf, "Calculated size mismatch %lu != %lu, delta = %lu", (unsigned long) pos,(unsigned long) LOCAL->filesize,delta); mm_log (LOCAL->buf,WARN); LOCAL->filesize = pos;/* fix it then */ } ftruncate (LOCAL->fd,LOCAL->filesize); sprintf (LOCAL->buf,"Expunged %lu messages",n); /* output the news */ mm_log (LOCAL->buf,(long) NIL); } else mm_log ("No messages deleted, so no update needed",(long) NIL); fsync (LOCAL->fd); /* force disk update */ fstat (LOCAL->fd,&sbuf); /* get new write time */ times.modtime = LOCAL->filetime = sbuf.st_mtime; times.actime = time (0); /* reset atime to now */ utime (stream->mailbox,×); mm_nocritical (stream); /* release critical */ /* notify upper level of new mailbox size */ mail_exists (stream,stream->nmsgs); mail_recent (stream,recent); flock (LOCAL->fd,LOCK_SH);/* allow sharers again */ unlockfd (ld,lock); /* release exclusive parse/append permission */ } } return ret; } /* Tenex mail copy message(s) * Accepts: MAIL stream * sequence * destination mailbox * copy options * Returns: T if success, NIL if failed */ long tenex_copy (MAILSTREAM *stream,char *sequence,char *mailbox,long options) { struct stat sbuf; struct utimbuf times; MESSAGECACHE *elt; unsigned long i,j,k; long ret = LONGT; int fd,ld; char file[MAILTMPLEN],lock[MAILTMPLEN]; mailproxycopy_t pc = (mailproxycopy_t) mail_parameters (stream,GET_MAILPROXYCOPY,NIL); /* make sure valid mailbox */ if (!tenex_isvalid (mailbox,file)) switch (errno) { case ENOENT: /* no such file? */ mm_notify (stream,"[TRYCREATE] Must create mailbox before copy",NIL); return NIL; case 0: /* merely empty file? */ break; case EACCES: /* file protected */ sprintf (LOCAL->buf,"Can't access destination: %.80s",mailbox); MM_LOG (LOCAL->buf,ERROR); return NIL; case EINVAL: if (pc) return (*pc) (stream,sequence,mailbox,options); sprintf (LOCAL->buf,"Invalid Tenex-format mailbox name: %.80s",mailbox); mm_log (LOCAL->buf,ERROR); return NIL; default: if (pc) return (*pc) (stream,sequence,mailbox,options); sprintf (LOCAL->buf,"Not a Tenex-format mailbox: %.80s",mailbox); mm_log (LOCAL->buf,ERROR); return NIL; } if (!((options & CP_UID) ? mail_uid_sequence (stream,sequence) : mail_sequence (stream,sequence))) return NIL; /* got file? */ if ((fd = open (file,O_BINARY|O_RDWR|O_CREAT,S_IREAD|S_IWRITE)) < 0) { sprintf (LOCAL->buf,"Unable to open copy mailbox: %.80s",strerror (errno)); mm_log (LOCAL->buf,ERROR); return NIL; } mm_critical (stream); /* go critical */ /* get exclusive parse/append permission */ if (flock (fd,LOCK_SH) || ((ld = lockname (lock,file,LOCK_EX)) < 0)) { mm_log ("Unable to lock copy mailbox",ERROR); mm_nocritical (stream); return NIL; } fstat (fd,&sbuf); /* get current file size */ lseek (fd,sbuf.st_size,L_SET);/* move to end of file */ /* for each requested message */ for (i = 1; ret && (i <= stream->nmsgs); i++) if ((elt = mail_elt (stream,i))->sequence) { lseek (LOCAL->fd,elt->private.special.offset,L_SET); /* number of bytes to copy */ k = elt->private.special.text.size + tenex_size (stream,i); do { /* read from source position */ j = min (k,LOCAL->buflen); read (LOCAL->fd,LOCAL->buf,j); if (write (fd,LOCAL->buf,j) < 0) ret = NIL; } while (ret && (k -= j));/* until done */ } /* delete all requested messages */ if (ret && (options & CP_MOVE)) { sprintf (LOCAL->buf,"Unable to write message: %s",strerror (errno)); mm_log (LOCAL->buf,ERROR); ftruncate (fd,sbuf.st_size); } /* set atime to now-1 if successful copy */ if (ret) times.actime = time (0) - 1; /* else preserved \Marked status */ else times.actime = (sbuf.st_ctime > sbuf.st_atime) ? sbuf.st_atime : time (0); times.modtime = sbuf.st_mtime;/* preserve mtime */ utime (file,×); /* set the times */ unlockfd (ld,lock); /* release exclusive parse/append permission */ close (fd); /* close the file */ mm_nocritical (stream); /* release critical */ /* delete all requested messages */ if (ret && (options & CP_MOVE)) { for (i = 1; i <= stream->nmsgs; i++) if ((elt = tenex_elt (stream,i))->sequence) { elt->deleted = T; /* mark message deleted */ /* recalculate status */ tenex_update_status (stream,i,NIL); } if (!stream->rdonly) { /* make sure the update takes */ fsync (LOCAL->fd); fstat (LOCAL->fd,&sbuf); /* get current write time */ times.modtime = LOCAL->filetime = sbuf.st_mtime; times.actime = time (0); /* make sure atime remains greater */ utime (stream->mailbox,×); } } if (ret && mail_parameters (NIL,GET_COPYUID,NIL)) mm_log ("Can not return meaningful COPYUID with this mailbox format",WARN); return ret; } /* Tenex mail append message from stringstruct * Accepts: MAIL stream * destination mailbox * append callback * data for callback * Returns: T if append successful, else NIL */ long tenex_append (MAILSTREAM *stream,char *mailbox,append_t af,void *data) { struct stat sbuf; int fd,ld,c; char *flags,*date,tmp[MAILTMPLEN],file[MAILTMPLEN],lock[MAILTMPLEN]; struct utimbuf times; FILE *df; MESSAGECACHE elt; long f; unsigned long i,j,uf,size; STRING *message; long ret = LONGT; /* default stream to prototype */ if (!stream) stream = &tenexproto; /* make sure valid mailbox */ if (!tenex_isvalid (mailbox,file)) switch (errno) { case ENOENT: /* no such file? */ if (!compare_cstring (mailbox,"INBOX")) tenex_create (NIL,"INBOX"); else { mm_notify (stream,"[TRYCREATE] Must create mailbox before append",NIL); return NIL; } /* falls through */ case 0: /* merely empty file? */ break; case EACCES: /* file protected */ sprintf (tmp,"Can't access destination: %.80s",mailbox); MM_LOG (tmp,ERROR); return NIL; case EINVAL: sprintf (tmp,"Invalid TENEX-format mailbox name: %.80s",mailbox); mm_log (tmp,ERROR); return NIL; default: sprintf (tmp,"Not a TENEX-format mailbox: %.80s",mailbox); mm_log (tmp,ERROR); return NIL; } /* get first message */ if (!(*af) (stream,data,&flags,&date,&message)) return NIL; /* open destination mailbox */ if (((fd = open (file,O_BINARY|O_WRONLY|O_APPEND|O_CREAT,S_IREAD|S_IWRITE)) < 0) || !(df = fdopen (fd,"ab"))) { sprintf (tmp,"Can't open append mailbox: %s",strerror (errno)); mm_log (tmp,ERROR); return NIL; } /* get parse/append permission */ if (flock (fd,LOCK_SH) || ((ld = lockname (lock,file,LOCK_EX)) < 0)) { mm_log ("Unable to lock append mailbox",ERROR); close (fd); return NIL; } mm_critical (stream); /* go critical */ fstat (fd,&sbuf); /* get current file size */ errno = 0; do { /* parse flags */ if (!SIZE (message)) { /* guard against zero-length */ mm_log ("Append of zero-length message",ERROR); ret = NIL; break; } f = mail_parse_flags (stream,flags,&i); /* reverse bits (dontcha wish we had CIRC?) */ for (uf = 0; i; uf |= 1 << (29 - find_rightmost_bit (&i))); if (date) { /* parse date if given */ if (!mail_parse_date (&elt,date)) { sprintf (tmp,"Bad date in append: %.80s",date); mm_log (tmp,ERROR); ret = NIL; /* mark failure */ break; } mail_date (tmp,&elt); /* write preseved date */ } else internal_date (tmp); /* get current date in IMAP format */ i = GETPOS (message); /* remember current position */ for (j = SIZE (message), size = 0; j; --j) if (SNX (message) != '\015') ++size; SETPOS (message,i); /* restore position */ /* write header */ if (fprintf (df,"%s,%lu;%010lo%02lo\n",tmp,size,uf,(unsigned long) f) < 0) ret = NIL; else { /* write message */ while (size) if ((c = 0xff & SNX (message)) != '\015') { if (putc (c,df) != EOF) --size; else break; } /* get next message */ if (size || !(*af) (stream,data,&flags,&date,&message)) ret = NIL; } } while (ret && message); /* if error... */ if (!ret || (fflush (df) == EOF)) { ftruncate (fd,sbuf.st_size);/* revert file */ close (fd); /* make sure fclose() doesn't corrupt us */ if (errno) { sprintf (tmp,"Message append failed: %s",strerror (errno)); mm_log (tmp,ERROR); } ret = NIL; } if (ret) times.actime = time (0) - 1; /* else preserved \Marked status */ else times.actime = (sbuf.st_ctime > sbuf.st_atime) ? sbuf.st_atime : time (0); times.modtime = sbuf.st_mtime;/* preserve mtime */ utime (file,×); /* set the times */ fclose (df); /* close the file */ unlockfd (ld,lock); /* release exclusive parse/append permission */ mm_nocritical (stream); /* release critical */ if (ret && mail_parameters (NIL,GET_APPENDUID,NIL)) mm_log ("Can not return meaningful APPENDUID with this mailbox format", WARN); return ret; } /* Internal routines */ /* Tenex mail return internal message size in bytes * Accepts: MAIL stream * message # * Returns: internal size of message */ unsigned long tenex_size (MAILSTREAM *stream,unsigned long m) { MESSAGECACHE *elt = mail_elt (stream,m); return ((m < stream->nmsgs) ? mail_elt (stream,m+1)->private.special.offset : LOCAL->filesize) - (elt->private.special.offset + elt->private.special.text.size); } /* Tenex mail parse mailbox * Accepts: MAIL stream * Returns: T if parse OK * NIL if failure, stream aborted */ long tenex_parse (MAILSTREAM *stream) { struct stat sbuf; MESSAGECACHE *elt = NIL; unsigned char c,*s,*t,*x; char tmp[MAILTMPLEN]; unsigned long i,j; long curpos = LOCAL->filesize; long nmsgs = stream->nmsgs; long recent = stream->recent; short added = NIL; short silent = stream->silent; fstat (LOCAL->fd,&sbuf); /* get status */ if (sbuf.st_size < curpos) { /* sanity check */ sprintf (tmp,"Mailbox shrank from %ld to %ld!",curpos,sbuf.st_size); mm_log (tmp,ERROR); tenex_close (stream,NIL); return NIL; } stream->silent = T; /* don't pass up mm_exists() events yet */ while (sbuf.st_size - curpos){/* while there is stuff to parse */ /* get to that position in the file */ lseek (LOCAL->fd,curpos,L_SET); if ((i = read (LOCAL->fd,LOCAL->buf,64)) <= 0) { sprintf (tmp,"Unable to read internal header at %lu, size = %lu: %s", (unsigned long) curpos,(unsigned long) sbuf.st_size, i ? strerror (errno) : "no data read"); mm_log (tmp,ERROR); tenex_close (stream,NIL); return NIL; } LOCAL->buf[i] = '\0'; /* tie off buffer just in case */ if (!(s = strchr (LOCAL->buf,'\012'))) { sprintf (tmp,"Unable to find newline at %lu in %lu bytes, text: %s", (unsigned long) curpos,i,(char *) LOCAL->buf); mm_log (tmp,ERROR); tenex_close (stream,NIL); return NIL; } *s = '\0'; /* tie off header line */ i = (s + 1) - LOCAL->buf; /* note start of text offset */ if (!((s = strchr (LOCAL->buf,',')) && (t = strchr (s+1,';')))) { sprintf (tmp,"Unable to parse internal header at %lu: %s", (unsigned long) curpos,(char *) LOCAL->buf); mm_log (tmp,ERROR); tenex_close (stream,NIL); return NIL; } *s++ = '\0'; *t++ = '\0'; /* tie off fields */ added = T; /* note that a new message was added */ /* swell the cache */ mail_exists (stream,++nmsgs); /* instantiate an elt for this message */ (elt = mail_elt (stream,nmsgs))->valid = T; elt->private.uid = ++stream->uid_last; /* note file offset of header */ elt->private.special.offset = curpos; /* in case error */ elt->private.special.text.size = 0; /* header size not known yet */ elt->private.msg.header.text.size = 0; x = s; /* parse the header components */ if (mail_parse_date (elt,LOCAL->buf) && (elt->private.msg.full.text.size = strtoul (s,(char **) &s,10)) && (!(s && *s)) && isdigit (t[0]) && isdigit (t[1]) && isdigit (t[2]) && isdigit (t[3]) && isdigit (t[4]) && isdigit (t[5]) && isdigit (t[6]) && isdigit (t[7]) && isdigit (t[8]) && isdigit (t[9]) && isdigit (t[10]) && isdigit (t[11]) && !t[12]) elt->private.special.text.size = i; else { /* oops */ sprintf (tmp,"Unable to parse internal header elements at %ld: %s,%s;%s", curpos,(char *) LOCAL->buf,(char *) x,(char *) t); mm_log (tmp,ERROR); tenex_close (stream,NIL); return NIL; } /* make sure didn't run off end of file */ if ((curpos += (elt->private.msg.full.text.size + i)) > sbuf.st_size) { sprintf (tmp,"Last message (at %lu) runs past end of file (%lu > %lu)", elt->private.special.offset,(unsigned long) curpos, (unsigned long) sbuf.st_size); mm_log (tmp,ERROR); tenex_close (stream,NIL); return NIL; } c = t[10]; /* remember first system flags byte */ t[10] = '\0'; /* tie off flags */ j = strtoul (t,NIL,8); /* get user flags value */ t[10] = c; /* restore first system flags byte */ /* set up all valid user flags (reversed!) */ while (j) if (((i = 29 - find_rightmost_bit (&j)) < NUSERFLAGS) && stream->user_flags[i]) elt->user_flags |= 1 << i; /* calculate system flags */ if ((j = ((t[10]-'0') * 8) + t[11]-'0') & fSEEN) elt->seen = T; if (j & fDELETED) elt->deleted = T; if (j & fFLAGGED) elt->flagged = T; if (j & fANSWERED) elt->answered = T; if (j & fDRAFT) elt->draft = T; if (!(j & fOLD)) { /* newly arrived message? */ elt->recent = T; recent++; /* count up a new recent message */ /* mark it as old */ tenex_update_status (stream,nmsgs,NIL); } } fsync (LOCAL->fd); /* make sure all the fOLD flags take */ /* update parsed file size and time */ LOCAL->filesize = sbuf.st_size; fstat (LOCAL->fd,&sbuf); /* get status again to ensure time is right */ LOCAL->filetime = sbuf.st_mtime; if (added && !stream->rdonly){/* make sure atime updated */ struct utimbuf times; times.actime = time (0); times.modtime = LOCAL->filetime; utime (stream->mailbox,×); } stream->silent = silent; /* can pass up events now */ mail_exists (stream,nmsgs); /* notify upper level of new mailbox size */ mail_recent (stream,recent); /* and of change in recent messages */ return LONGT; /* return the winnage */ } /* Tenex get cache element with status updating from file * Accepts: MAIL stream * message number * Returns: cache element */ MESSAGECACHE *tenex_elt (MAILSTREAM *stream,unsigned long msgno) { MESSAGECACHE *elt = mail_elt (stream,msgno); struct { /* old flags */ unsigned int seen : 1; unsigned int deleted : 1; unsigned int flagged : 1; unsigned int answered : 1; unsigned int draft : 1; unsigned long user_flags; } old; old.seen = elt->seen; old.deleted = elt->deleted; old.flagged = elt->flagged; old.answered = elt->answered; old.draft = elt->draft; old.user_flags = elt->user_flags; tenex_read_flags (stream,elt); if ((old.seen != elt->seen) || (old.deleted != elt->deleted) || (old.flagged != elt->flagged) || (old.answered != elt->answered) || (old.draft != elt->draft) || (old.user_flags != elt->user_flags)) mm_flags (stream,msgno); /* let top level know */ return elt; } /* Tenex read flags from file * Accepts: MAIL stream * Returns: cache element */ void tenex_read_flags (MAILSTREAM *stream,MESSAGECACHE *elt) { unsigned long i,j; /* noop if readonly and have valid flags */ if (stream->rdonly && elt->valid) return; /* set the seek pointer */ lseek (LOCAL->fd,(off_t) elt->private.special.offset + elt->private.special.text.size - 13,L_SET); /* read the new flags */ if (read (LOCAL->fd,LOCAL->buf,12) < 0) { sprintf (LOCAL->buf,"Unable to read new status: %s",strerror (errno)); fatal (LOCAL->buf); } /* calculate system flags */ i = (((LOCAL->buf[10]-'0') * 8) + LOCAL->buf[11]-'0'); elt->seen = i & fSEEN ? T : NIL; elt->deleted = i & fDELETED ? T : NIL; elt->flagged = i & fFLAGGED ? T : NIL; elt->answered = i & fANSWERED ? T : NIL; elt->draft = i & fDRAFT ? T : NIL; LOCAL->buf[10] = '\0'; /* tie off flags */ j = strtoul(LOCAL->buf,NIL,8);/* get user flags value */ /* set up all valid user flags (reversed!) */ while (j) if (((i = 29 - find_rightmost_bit (&j)) < NUSERFLAGS) && stream->user_flags[i]) elt->user_flags |= 1 << i; elt->valid = T; /* have valid flags now */ } /* Tenex update status string * Accepts: MAIL stream * message number * flag saying whether or not to sync */ void tenex_update_status (MAILSTREAM *stream,unsigned long msgno,long syncflag) { struct utimbuf times; struct stat sbuf; MESSAGECACHE *elt = mail_elt (stream,msgno); unsigned long j,k = 0; /* readonly */ if (stream->rdonly || !elt->valid) tenex_read_flags (stream,elt); else { /* readwrite */ j = elt->user_flags; /* get user flags */ /* reverse bits (dontcha wish we had CIRC?) */ while (j) k |= 1 << (29 - find_rightmost_bit (&j)); /* print new flag string */ sprintf (LOCAL->buf,"%010lo%02o",k,(unsigned) (fOLD + (fSEEN * elt->seen) + (fDELETED * elt->deleted) + (fFLAGGED * elt->flagged) + (fANSWERED * elt->answered) + (fDRAFT * elt->draft))); while (T) { /* get to that place in the file */ lseek (LOCAL->fd,(off_t) elt->private.special.offset + elt->private.special.text.size - 13,L_SET); /* write new flags */ if (write (LOCAL->fd,LOCAL->buf,12) > 0) break; mm_notify (stream,strerror (errno),WARN); mm_diskerror (stream,errno,T); } if (syncflag) { /* sync if requested */ fsync (LOCAL->fd); fstat (LOCAL->fd,&sbuf); /* get new write time */ times.modtime = LOCAL->filetime = sbuf.st_mtime; times.actime = time (0); /* make sure read is later */ utime (stream->mailbox,×); } } } /* Tenex locate header for a message * Accepts: MAIL stream * message number * pointer to returned header size * Returns: position of header in file */ unsigned long tenex_hdrpos (MAILSTREAM *stream,unsigned long msgno, unsigned long *size) { unsigned long siz; long i = 0; char c = '\0'; char *s = NIL; MESSAGECACHE *elt = tenex_elt (stream,msgno); unsigned long ret = elt->private.special.offset + elt->private.special.text.size; unsigned long msiz = tenex_size (stream,msgno); /* is header size known? */ if (!(*size = elt->private.msg.header.text.size)) { lseek (LOCAL->fd,ret,L_SET);/* get to header position */ /* search message for LF LF */ for (siz = 0; siz < msiz; siz++) { if (--i <= 0) /* read another buffer as necessary */ read (LOCAL->fd,s = LOCAL->buf,i = min (msiz-siz,(long) MAILTMPLEN)); /* two newline sequence? */ if ((c == '\012') && (*s == '\012')) { /* yes, note for later */ elt->private.msg.header.text.size = (*size = siz + 1); return ret; /* return to caller */ } else c = *s++; /* next character */ } /* header consumes entire message */ elt->private.msg.header.text.size = *size = msiz; } return ret; } alpine-2.10+dfsg/imap/src/osdep/nt/0000700000175000017500000000000012074110156020606 5ustar paulproteuspaulproteusalpine-2.10+dfsg/imap/src/osdep/nt/mkautaux.bat0000700000175000017500000000222611512502123023135 0ustar paulproteuspaulproteus@ECHO OFF REM ======================================================================== REM Copyright 1988-2006 University of Washington REM REM Licensed under the Apache License, Version 2.0 (the "License"); REM you may not use this file except in compliance with the License. REM You may obtain a copy of the License at REM REM http://www.apache.org/licenses/LICENSE-2.0 REM REM REM ======================================================================== REM Program: Authenticator Linkage Generator auxillary for NT/Win9x REM REM Author: Mark Crispin REM Networks and Distributed Computing REM Computing & Communications REM University of Washington REM Administration Building, AG-44 REM Seattle, WA 98195 REM Internet: MRC@CAC.Washington.EDU REM REM Date: 6 December 1995 REM Last Edited:30 August 2006 ECHO extern AUTHENTICATOR auth_%1; >> LINKAGE.H REM Note the introduction of the caret to quote the ampersand in NT if "%OS%" == "Windows_NT" ECHO auth_link (^&auth_%1); /* link in the %1 authenticator */ >> LINKAGE.C if "%OS%" == "" ECHO auth_link (&auth_%1); /* link in the %1 authenticator */ >> LINKAGE.C ECHO #include "auth_%1.c" >> AUTHS.C alpine-2.10+dfsg/imap/src/osdep/nt/ftl_nt.c0000600000175000017500000000167311512502123022244 0ustar paulproteuspaulproteus/* ======================================================================== * Copyright 1988-2006 University of Washington * * Licensed under the Apache License, Version 2.0 (the "License"); * you may not use this file except in compliance with the License. * You may obtain a copy of the License at * * http://www.apache.org/licenses/LICENSE-2.0 * * * ======================================================================== */ /* * Program: DOS/VMS/TOPS-20 crash management routines * * Author: Mark Crispin * Networks and Distributed Computing * Computing & Communications * University of Washington * Administration Building, AG-44 * Seattle, WA 98195 * Internet: MRC@CAC.Washington.EDU * * Date: 1 August 1988 * Last Edited: 30 August 2006 */ /* Report a fatal error * Accepts: string to output */ void fatal (char *string) { mm_fatal (string); /* pass up the string */ abort (); /* die horribly */ } alpine-2.10+dfsg/imap/src/osdep/nt/os_w2k.c0000600000175000017500000000243611512502123022160 0ustar paulproteuspaulproteus/* ======================================================================== * Copyright 1988-2006 University of Washington * * Licensed under the Apache License, Version 2.0 (the "License"); * you may not use this file except in compliance with the License. * You may obtain a copy of the License at * * http://www.apache.org/licenses/LICENSE-2.0 * * * ======================================================================== */ /* * Program: Operating-system dependent routines -- Windows 2000 version * * Author: Mark Crispin * Networks and Distributed Computing * Computing & Communications * University of Washington * Administration Building, AG-44 * Seattle, WA 98195 * Internet: MRC@CAC.Washington.EDU * * Date: 11 April 1989 * Last Edited: 30 August 2006 */ #include "tcp_nt.h" /* must be before osdep includes tcp.h */ #undef ERROR /* quell conflicting def warning */ #include "mail.h" #include "osdep.h" #include #include #include #include #include #include #include "misc.h" #include "mailfile.h" #include "fs_nt.c" #include "ftl_nt.c" #include "nl_nt.c" #include "yunchan.c" #include "kerb_w2k.c" #include "tcp_nt.c" /* must be before env_nt.c */ #include "env_nt.c" #include "ssl_w2k.c" alpine-2.10+dfsg/imap/src/osdep/nt/fdstring.h0000600000175000017500000000205711512502123022600 0ustar paulproteuspaulproteus/* ======================================================================== * Copyright 1988-2006 University of Washington * * Licensed under the Apache License, Version 2.0 (the "License"); * you may not use this file except in compliance with the License. * You may obtain a copy of the License at * * http://www.apache.org/licenses/LICENSE-2.0 * * * ======================================================================== */ /* * Program: File descriptor string routines * * Author: Mark Crispin * Networks and Distributed Computing * Computing & Communications * University of Washington * Administration Building, AG-44 * Seattle, WA 98195 * Internet: MRC@CAC.Washington.EDU * * Date: 15 April 1997 * Last Edited: 30 August 2006 */ /* Driver-dependent data passed to init method */ typedef struct fd_data { int fd; /* file descriptor */ unsigned long pos; /* initial position */ char *chunk; /* I/O buffer chunk */ unsigned long chunksize; /* I/O buffer chunk length */ } FDDATA; extern STRINGDRIVER fd_string; alpine-2.10+dfsg/imap/src/osdep/nt/dummy.h0000600000175000017500000000276411512502123022120 0ustar paulproteuspaulproteus/* ======================================================================== * Copyright 1988-2006 University of Washington * * Licensed under the Apache License, Version 2.0 (the "License"); * you may not use this file except in compliance with the License. * You may obtain a copy of the License at * * http://www.apache.org/licenses/LICENSE-2.0 * * * ======================================================================== */ /* * Program: Dummy routines * * Author: Mark Crispin * Networks and Distributed Computing * Computing & Communications * University of Washington * Administration Building, AG-44 * Seattle, WA 98195 * Internet: MRC@CAC.Washington.EDU * * Date: 9 May 1991 * Last Edited: 30 August 2006 */ /* Exported function prototypes */ void dummy_scan (MAILSTREAM *stream,char *ref,char *pat,char *contents); void dummy_list (MAILSTREAM *stream,char *ref,char *pat); void dummy_lsub (MAILSTREAM *stream,char *ref,char *pat); long scan_contents (DRIVER *dtb,char *name,char *contents, unsigned long csiz,unsigned long fsiz); long dummy_scan_contents (char *name,char *contents,unsigned long csiz, unsigned long fsiz); long dummy_create (MAILSTREAM *stream,char *mailbox); long dummy_create_path (MAILSTREAM *stream,char *path,long dirmode); long dummy_delete (MAILSTREAM *stream,char *mailbox); long dummy_rename (MAILSTREAM *stream,char *old,char *newname); char *dummy_file (char *dst,char *name); long dummy_canonicalize (char *tmp,char *ref,char *pat); alpine-2.10+dfsg/imap/src/osdep/nt/ssl_old.c0000600000175000017500000004631611512502123022420 0ustar paulproteuspaulproteus/* ======================================================================== * Copyright 1988-2008 University of Washington * * Licensed under the Apache License, Version 2.0 (the "License"); * you may not use this file except in compliance with the License. * You may obtain a copy of the License at * * http://www.apache.org/licenses/LICENSE-2.0 * * * ======================================================================== */ /* * Program: SSL authentication/encryption module for Windows 9x and NT * * Author: Mark Crispin * Networks and Distributed Computing * Computing & Communications * University of Washington * Administration Building, AG-44 * Seattle, WA 98195 * Internet: MRC@CAC.Washington.EDU * * Date: 22 September 1998 * Last Edited: 13 January 2008 */ #define SECURITY_WIN32 #include #if(_WIN32_WINNT < 0x0400) typedef unsigned int ALG_ID; #else #include ALGIDDEF #endif #include #include /* in case a binary runs on Windows 2000 */ #ifndef ISC_REQ_MANUAL_CRED_VALIDATION #define ISC_REQ_MANUAL_CRED_VALIDATION 0x00080000 #endif #ifndef SEC_E_UNTRUSTED_ROOT #define SEC_E_UNTRUSTED_ROOT ((HRESULT) 0x80090325L) #endif #ifndef SEC_E_CERT_EXPIRED #define SEC_E_CERT_EXPIRED ((HRESULT) 0x80090328L) #endif #define SSLBUFLEN 8192 /* SSL I/O stream */ typedef struct ssl_stream { TCPSTREAM *tcpstream; /* TCP stream */ CredHandle cred; /* SSL credentials */ CtxtHandle context; /* SSL context */ /* stream encryption sizes */ SecPkgContext_StreamSizes sizes; size_t bufsize; int ictr; /* input counter */ char *iptr; /* input pointer */ int iextractr; /* extra input counter */ char *iextraptr; /* extra input pointer */ char *ibuf; /* input buffer */ char *obuf; /* output buffer */ } SSLSTREAM; #include "sslio.h" /* Function prototypes */ static SSLSTREAM *ssl_start(TCPSTREAM *tstream,char *host,unsigned long flags); static char *ssl_analyze_status (SECURITY_STATUS err,char *buf); static char *ssl_getline_work (SSLSTREAM *stream,unsigned long *size, long *contd); static long ssl_abort (SSLSTREAM *stream); /* Secure Sockets Layer network driver dispatch */ static struct ssl_driver ssldriver = { ssl_open, /* open connection */ ssl_aopen, /* open preauthenticated connection */ ssl_getline, /* get a line */ ssl_getbuffer, /* get a buffer */ ssl_soutr, /* output pushed data */ ssl_sout, /* output string */ ssl_close, /* close connection */ ssl_host, /* return host name */ ssl_remotehost, /* return remote host name */ ssl_port, /* return port number */ ssl_localhost /* return local host name */ }; /* security function table */ static SecurityFunctionTable *sft = NIL; static unsigned long ssltsz = 0;/* SSL maximum token length */ /* One-time SSL initialization */ static int sslonceonly = 0; void ssl_onceonlyinit (void) { if (!sslonceonly++) { /* only need to call it once */ HINSTANCE lib; FARPROC pi; ULONG np; SecPkgInfo *pp; int i; /* get security library */ if (((lib = LoadLibrary ("schannel.dll")) || (lib = LoadLibrary ("security.dll"))) && (pi = GetProcAddress (lib,SECURITY_ENTRYPOINT)) && (sft = (SecurityFunctionTable *) pi ()) && !(sft->EnumerateSecurityPackages (&np,&pp))) { /* look for an SSL package */ for (i = 0; (i < (int) np); i++) if (!strcmp (pp[i].Name,UNISP_NAME)) { /* note maximum token size and name */ ssltsz = pp[i].cbMaxToken; /* apply runtime linkage */ mail_parameters (NIL,SET_SSLDRIVER,(void *) &ssldriver); mail_parameters (NIL,SET_SSLSTART,(void *) ssl_start); return; /* all done */ } } } } /* SSL open * Accepts: host name * contact service name * contact port number * Returns: SSL stream if success else NIL */ SSLSTREAM *ssl_open (char *host,char *service,unsigned long port) { TCPSTREAM *stream = tcp_open (host,service,port); return stream ? ssl_start (stream,host,port) : NIL; } /* SSL authenticated open * Accepts: host name * service name * returned user name buffer * Returns: SSL stream if success else NIL */ SSLSTREAM *ssl_aopen (NETMBX *mb,char *service,char *usrbuf) { return NIL; /* don't use this mechanism with SSL */ } /* Start SSL/TLS negotiations * Accepts: open TCP stream of session * user's host name * flags * Returns: SSL stream if success else NIL */ static SSLSTREAM *ssl_start (TCPSTREAM *tstream,char *host,unsigned long flags) { SECURITY_STATUS e; ULONG a; TimeStamp t; SecBuffer ibuf[2],obuf[1]; SecBufferDesc ibufs,obufs; char tmp[MAILTMPLEN]; char *reason = NIL; ULONG req = ISC_REQ_REPLAY_DETECT | ISC_REQ_SEQUENCE_DETECT | ISC_REQ_CONFIDENTIALITY | ISC_REQ_USE_SESSION_KEY | ISC_REQ_ALLOCATE_MEMORY | ISC_REQ_STREAM | ISC_REQ_EXTENDED_ERROR + ((flags & NET_NOVALIDATECERT) ? ISC_REQ_MANUAL_CRED_VALIDATION : ISC_REQ_MUTUAL_AUTH); SCHANNEL_CRED tlscred; char *buf = (char *) fs_get (ssltsz); unsigned long size = 0; sslfailure_t sf = (sslfailure_t) mail_parameters (NIL,GET_SSLFAILURE,NIL); SSLSTREAM *stream = (SSLSTREAM *) memset (fs_get (sizeof (SSLSTREAM)),0, sizeof (SSLSTREAM)); stream->tcpstream = tstream; /* bind TCP stream */ /* initialize TLS credential */ memset (&tlscred,0,sizeof (SCHANNEL_CRED)); tlscred.dwVersion = SCHANNEL_CRED_VERSION; tlscred.grbitEnabledProtocols = SP_PROT_TLS1; /* acquire credentials */ if (sft->AcquireCredentialsHandle (NIL,UNISP_NAME,SECPKG_CRED_OUTBOUND,NIL,(flags & NET_TLSCLIENT) ? &tlscred : NIL,NIL,NIL,&stream->cred,&t) != SEC_E_OK) reason = "Acquire credentials handle failed"; else while (!reason) { /* negotiate security context */ /* initialize buffers */ ibuf[0].cbBuffer = size; ibuf[0].pvBuffer = buf; ibuf[1].cbBuffer = 0; ibuf[1].pvBuffer = NIL; obuf[0].cbBuffer = 0; obuf[0].pvBuffer = NIL; ibuf[0].BufferType = obuf[0].BufferType = SECBUFFER_TOKEN; ibuf[1].BufferType = SECBUFFER_EMPTY; /* initialize buffer descriptors */ ibufs.ulVersion = obufs.ulVersion = SECBUFFER_VERSION; ibufs.cBuffers = 2; obufs.cBuffers = 1; ibufs.pBuffers = ibuf; obufs.pBuffers = obuf; /* negotiate security */ e = sft->InitializeSecurityContext (&stream->cred,size ? &stream->context : NIL,host,req,0, SECURITY_NETWORK_DREP,size? &ibufs:NIL,0,&stream->context,&obufs,&a,&t); /* have an output buffer we need to send? */ if (obuf[0].pvBuffer && obuf[0].cbBuffer) { if (!tcp_sout (stream->tcpstream,obuf[0].pvBuffer,obuf[0].cbBuffer)) reason = "Unexpected TCP output disconnect"; /* free the buffer */ sft->FreeContextBuffer (obuf[0].pvBuffer); } if (!reason) switch (e) { /* negotiation state */ case SEC_I_INCOMPLETE_CREDENTIALS: break; /* server wants client auth */ case SEC_I_CONTINUE_NEEDED: if (size) { /* continue, read any data? */ /* yes, anything regurgiated back to us? */ if (ibuf[1].BufferType == SECBUFFER_EXTRA) { /* yes, set this as the new data */ memmove (buf,buf + size - ibuf[1].cbBuffer,ibuf[1].cbBuffer); size = ibuf[1].cbBuffer; break; } size = 0; /* otherwise, read more stuff from server */ } case SEC_E_INCOMPLETE_MESSAGE: /* need to read more data from server */ if (!tcp_getdata (stream->tcpstream)) reason = "Unexpected TCP input disconnect"; else { memcpy (buf+size,stream->tcpstream->iptr,stream->tcpstream->ictr); size += stream->tcpstream->ictr; /* empty it from TCP's buffers */ stream->tcpstream->iptr += stream->tcpstream->ictr; stream->tcpstream->ictr = 0; } break; case SEC_E_OK: /* success, any data to be regurgitated? */ if (ibuf[1].BufferType == SECBUFFER_EXTRA) { /* yes, set this as the new data */ memmove (stream->tcpstream->iptr = stream->tcpstream->ibuf, buf + size - ibuf[1].cbBuffer,ibuf[1].cbBuffer); stream->tcpstream->ictr = ibuf[1].cbBuffer; } if (reason = ssl_analyze_status (sft->QueryContextAttributes (&stream->context,SECPKG_ATTR_STREAM_SIZES,&stream->sizes),buf)) break; /* error getting sizes */ fs_give ((void **) &buf); /* flush temporary buffer */ /* make maximum-sized buffers */ stream->bufsize = stream->sizes.cbHeader + stream->sizes.cbMaximumMessage + stream->sizes.cbTrailer; if (stream->sizes.cbMaximumMessage < SSLBUFLEN) fatal ("cbMaximumMessage is less than SSLBUFLEN!"); else if (stream->sizes.cbMaximumMessage < 16384) { sprintf (tmp,"WINDOWS BUG: cbMaximumMessage = %ld, should be 16384", (long) stream->sizes.cbMaximumMessage); mm_log (tmp,NIL); } stream->ibuf = (char *) fs_get (stream->bufsize); stream->obuf = (char *) fs_get (stream->bufsize); return stream; default: reason = ssl_analyze_status (e,buf); } } ssl_close (stream); /* failed to do SSL */ stream = NIL; /* no stream returned */ fs_give ((void **) &buf); /* flush temporary buffer */ switch (*reason) { /* analyze reason */ case '*': /* certificate failure */ ++reason; /* skip over certificate failure indication */ /* pass to error callback */ if (sf) (*sf) (host,reason,flags); else { /* no error callback, build error message */ sprintf (tmp,"Certificate failure for %.80s: %.512s",host,reason); mm_log (tmp,ERROR); } case '\0': /* user answered no to certificate callback */ if (flags & NET_TRYSSL) /* return dummy stream to stop tryssl */ stream = (SSLSTREAM *) memset (fs_get (sizeof (SSLSTREAM)),0, sizeof (SSLSTREAM)); break; default: /* non-certificate failure */ if (flags & NET_TRYSSL); /* no error output if tryssl */ /* pass to error callback */ else if (sf) (*sf) (host,reason,flags); else { /* no error callback, build error message */ sprintf (tmp,"TLS/SSL failure for %.80s: %.512s",host,reason); mm_log (tmp,ERROR); } break; } return stream; } /* Generate error text from SSL error code * Accepts: SSL status * scratch buffer * Returns: text if error status, else NIL */ static char *ssl_analyze_status (SECURITY_STATUS err,char *buf) { switch (err) { case SEC_E_OK: /* no error */ case SEC_I_CONTINUE_NEEDED: case SEC_I_INCOMPLETE_CREDENTIALS: case SEC_E_INCOMPLETE_MESSAGE: return NIL; case SEC_E_NO_AUTHENTICATING_AUTHORITY: return "*No authority could be contacted for authentication"; case SEC_E_WRONG_PRINCIPAL: return "*Server name does not match certificate"; case SEC_E_UNTRUSTED_ROOT: return "*Self-signed certificate or untrusted authority"; case SEC_E_CERT_EXPIRED: return "*Certificate has expired"; case SEC_E_INVALID_TOKEN: return "Invalid token, probably not an SSL server"; case SEC_E_UNSUPPORTED_FUNCTION: return "SSL not supported on this machine - upgrade your system software"; } sprintf (buf,"Unexpected SChannel error %lx - report this",err); return buf; } /* SSL receive line * Accepts: SSL stream * Returns: text line string or NIL if failure */ char *ssl_getline (SSLSTREAM *stream) { unsigned long n,contd; char *ret = ssl_getline_work (stream,&n,&contd); if (ret && contd) { /* got a line needing continuation? */ STRINGLIST *stl = mail_newstringlist (); STRINGLIST *stc = stl; do { /* collect additional lines */ stc->text.data = (unsigned char *) ret; stc->text.size = n; stc = stc->next = mail_newstringlist (); ret = ssl_getline_work (stream,&n,&contd); } while (ret && contd); if (ret) { /* stash final part of line on list */ stc->text.data = (unsigned char *) ret; stc->text.size = n; /* determine how large a buffer we need */ for (n = 0, stc = stl; stc; stc = stc->next) n += stc->text.size; ret = fs_get (n + 1); /* copy parts into buffer */ for (n = 0, stc = stl; stc; n += stc->text.size, stc = stc->next) memcpy (ret + n,stc->text.data,stc->text.size); ret[n] = '\0'; } mail_free_stringlist (&stl);/* either way, done with list */ } return ret; } /* SSL receive line or partial line * Accepts: SSL stream * pointer to return size * pointer to return continuation flag * Returns: text line string, size and continuation flag, or NIL if failure */ static char *ssl_getline_work (SSLSTREAM *stream,unsigned long *size, long *contd) { unsigned long n; char *s,*ret,c,d; *contd = NIL; /* assume no continuation */ /* make sure have data */ if (!ssl_getdata (stream)) return NIL; for (s = stream->iptr, n = 0, c = '\0'; stream->ictr--; n++, c = d) { d = *stream->iptr++; /* slurp another character */ if ((c == '\015') && (d == '\012')) { ret = (char *) fs_get (n--); memcpy (ret,s,*size = n); /* copy into a free storage string */ ret[n] = '\0'; /* tie off string with null */ return ret; } } /* copy partial string from buffer */ memcpy ((ret = (char *) fs_get (n)),s,*size = n); /* get more data from the net */ if (!ssl_getdata (stream)) fs_give ((void **) &ret); /* special case of newline broken by buffer */ else if ((c == '\015') && (*stream->iptr == '\012')) { stream->iptr++; /* eat the line feed */ stream->ictr--; ret[*size = --n] = '\0'; /* tie off string with null */ } else *contd = LONGT; /* continuation needed */ return ret; } /* SSL receive buffer * Accepts: SSL stream * size in bytes * buffer to read into * Returns: T if success, NIL otherwise */ long ssl_getbuffer (SSLSTREAM *stream,unsigned long size,char *buffer) { unsigned long n; while (size > 0) { /* until request satisfied */ if (!ssl_getdata (stream)) return NIL; n = min (size,stream->ictr);/* number of bytes to transfer */ /* do the copy */ memcpy (buffer,stream->iptr,n); buffer += n; /* update pointer */ stream->iptr += n; size -= n; /* update # of bytes to do */ stream->ictr -= n; } buffer[0] = '\0'; /* tie off string */ return T; } /* SSL receive data * Accepts: TCP/IP stream * Returns: T if success, NIL otherwise */ long ssl_getdata (SSLSTREAM *stream) { while (stream->ictr < 1) { /* decrypted buffer empty? */ SECURITY_STATUS status; SecBuffer buf[4]; SecBufferDesc msg; size_t i; size_t n = 0; /* initially no bytes to decrypt */ do { /* yes, make sure have data from TCP */ if (stream->iextractr) { /* have previous unread data? */ memcpy (stream->ibuf + n,stream->iextraptr,stream->iextractr); n += stream->iextractr; /* update number of bytes read */ stream->iextractr = 0; /* no more extra data */ } else { /* read from TCP */ if (!tcp_getdata (stream->tcpstream)) return ssl_abort (stream); /* maximum amount of data to copy */ if (!(i = min (stream->bufsize - n,stream->tcpstream->ictr))) fatal ("incomplete SecBuffer exceeds maximum buffer size"); /* do the copy */ memcpy (stream->ibuf + n,stream->tcpstream->iptr,i); stream->tcpstream->iptr += i; stream->tcpstream->ictr -= i; n += i; /* update number of bytes to decrypt */ } buf[0].cbBuffer = n; /* first SecBuffer gets data */ buf[0].pvBuffer = stream->ibuf; buf[0].BufferType = SECBUFFER_DATA; /* subsequent ones are for spares */ buf[1].BufferType = buf[2].BufferType = buf[3].BufferType = SECBUFFER_EMPTY; msg.ulVersion = SECBUFFER_VERSION; msg.cBuffers = 4; /* number of SecBuffers */ msg.pBuffers = buf; /* first SecBuffer */ } while ((status = ((DECRYPT_MESSAGE_FN) sft->Reserved4) (&stream->context,&msg,0,NIL)) == SEC_E_INCOMPLETE_MESSAGE); switch (status) { case SEC_E_OK: /* won */ case SEC_I_RENEGOTIATE: /* won but lost it after this buffer */ /* hunt for a buffer */ for (i = 0; (i < 4) && (buf[i].BufferType != SECBUFFER_DATA) ; i++); if (i < 4) { /* found a buffer? */ /* yes, set up pointer and counter */ stream->iptr = buf[i].pvBuffer; stream->ictr = buf[i].cbBuffer; /* any unprocessed data? */ while (++i < 4) if (buf[i].BufferType == SECBUFFER_EXTRA) { /* yes, note for next time around */ stream->iextraptr = buf[i].pvBuffer; stream->iextractr = buf[i].cbBuffer; } } break; default: /* anything else means we've lost */ return ssl_abort (stream); } } return LONGT; } /* SSL send string as record * Accepts: SSL stream * string pointer * Returns: T if success else NIL */ long ssl_soutr (SSLSTREAM *stream,char *string) { return ssl_sout (stream,string,(unsigned long) strlen (string)); } /* SSL send string * Accepts: SSL stream * string pointer * byte count * Returns: T if success else NIL */ long ssl_sout (SSLSTREAM *stream,char *string,unsigned long size) { SecBuffer buf[4]; SecBufferDesc msg; char *s = stream->ibuf; size_t n = 0; while (size) { /* until satisfied request */ /* header */ buf[0].BufferType = SECBUFFER_STREAM_HEADER; memset (buf[0].pvBuffer = stream->obuf,0, buf[0].cbBuffer = stream->sizes.cbHeader); /* message (up to maximum size) */ buf[1].BufferType = SECBUFFER_DATA; memcpy (buf[1].pvBuffer = stream->obuf + stream->sizes.cbHeader,string, buf[1].cbBuffer = min (size,SSLBUFLEN)); /* trailer */ buf[2].BufferType = SECBUFFER_STREAM_TRAILER; memset (buf[2].pvBuffer = ((char *) buf[1].pvBuffer) + buf[1].cbBuffer,0, buf[2].cbBuffer = stream->sizes.cbTrailer); /* spare */ buf[3].BufferType = SECBUFFER_EMPTY; msg.ulVersion = SECBUFFER_VERSION; msg.cBuffers = 4; /* number of SecBuffers */ msg.pBuffers = buf; /* first SecBuffer */ string += buf[1].cbBuffer; size -= buf[1].cbBuffer; /* this many bytes processed */ /* encrypt and send message */ if ((((ENCRYPT_MESSAGE_FN) sft->Reserved3) (&stream->context,0,&msg,NIL) != SEC_E_OK) || !tcp_sout (stream->tcpstream,stream->obuf, buf[0].cbBuffer + buf[1].cbBuffer + buf[2].cbBuffer)) return ssl_abort (stream);/* encryption or sending failed */ } return LONGT; } /* SSL close * Accepts: SSL stream */ void ssl_close (SSLSTREAM *stream) { ssl_abort (stream); /* nuke the stream */ fs_give ((void **) &stream); /* flush the stream */ } /* SSL abort stream * Accepts: SSL stream * Returns: NIL always */ static long ssl_abort (SSLSTREAM *stream) { if (stream->tcpstream) { /* close TCP stream */ sft->DeleteSecurityContext (&stream->context); sft->FreeCredentialHandle (&stream->cred); tcp_close (stream->tcpstream); stream->tcpstream = NIL; } if (stream->ibuf) fs_give ((void **) &stream->ibuf); if (stream->obuf) fs_give ((void **) &stream->obuf); return NIL; } /* SSL get host name * Accepts: SSL stream * Returns: host name for this stream */ char *ssl_host (SSLSTREAM *stream) { return tcp_host (stream->tcpstream); } /* SSL get remote host name * Accepts: SSL stream * Returns: host name for this stream */ char *ssl_remotehost (SSLSTREAM *stream) { return tcp_remotehost (stream->tcpstream); } /* SSL return port for this stream * Accepts: SSL stream * Returns: port number for this stream */ unsigned long ssl_port (SSLSTREAM *stream) { return tcp_port (stream->tcpstream); } /* SSL get local host name * Accepts: SSL stream * Returns: local host name */ char *ssl_localhost (SSLSTREAM *stream) { return tcp_localhost (stream->tcpstream); } #include "ssl_none.c" /* currently no server support */ alpine-2.10+dfsg/imap/src/osdep/nt/unixnt.c0000600000175000017500000023734611512502123022313 0ustar paulproteuspaulproteus/* ======================================================================== * Copyright 1988-2008 University of Washington * * Licensed under the Apache License, Version 2.0 (the "License"); * you may not use this file except in compliance with the License. * You may obtain a copy of the License at * * http://www.apache.org/licenses/LICENSE-2.0 * * * ======================================================================== */ /* * Program: UNIX mail routines * * Author: Mark Crispin * UW Technology * University of Washington * Seattle, WA 98195 * Internet: MRC@CAC.Washington.EDU * * Date: 20 December 1989 * Last Edited: 27 March 2008 */ /* DEDICATION * * This file is dedicated to my dog, Unix, also known as Yun-chan and * Unix J. Terwilliker Jehosophat Aloysius Monstrosity Animal Beast. Unix * passed away at the age of 11 1/2 on September 14, 1996, 12:18 PM PDT, after * a two-month bout with cirrhosis of the liver. * * He was a dear friend, and I miss him terribly. * * Lift a leg, Yunie. Luv ya forever!!!! */ #include #include #include extern int errno; /* just in case */ #include "mail.h" #include "osdep.h" #include #include #include #include #include "unixnt.h" #include "pseudo.h" #include "fdstring.h" #include "misc.h" #include "dummy.h" /* UNIX I/O stream local data */ typedef struct unix_local { unsigned int dirty : 1; /* disk copy needs updating */ unsigned int ddirty : 1; /* double-dirty, ping becomes checkpoint */ unsigned int pseudo : 1; /* uses a pseudo message */ unsigned int appending : 1; /* don't mark new messages as old */ int fd; /* mailbox file descriptor */ int ld; /* lock file descriptor */ char *lname; /* lock file name */ off_t filesize; /* file size parsed */ time_t filetime; /* last file time */ unsigned char *buf; /* temporary buffer */ unsigned long buflen; /* current size of temporary buffer */ unsigned long uid; /* current text uid */ SIZEDTEXT text; /* current text */ unsigned long textlen; /* current text length */ char *line; /* returned line */ char *linebuf; /* line readin buffer */ unsigned long linebuflen; /* current line readin buffer length */ } UNIXLOCAL; /* Convenient access to local data */ #define LOCAL ((UNIXLOCAL *) stream->local) /* UNIX protected file structure */ typedef struct unix_file { MAILSTREAM *stream; /* current stream */ off_t curpos; /* current file position */ off_t protect; /* protected position */ off_t filepos; /* current last written file position */ char *buf; /* overflow buffer */ size_t buflen; /* current overflow buffer length */ char *bufpos; /* current buffer position */ } UNIXFILE; /* Function prototypes */ DRIVER *unix_valid (char *name); void *unix_parameters (long function,void *value); void unix_scan (MAILSTREAM *stream,char *ref,char *pat,char *contents); void unix_list (MAILSTREAM *stream,char *ref,char *pat); void unix_lsub (MAILSTREAM *stream,char *ref,char *pat); long unix_create (MAILSTREAM *stream,char *mailbox); long unix_delete (MAILSTREAM *stream,char *mailbox); long unix_rename (MAILSTREAM *stream,char *old,char *newname); MAILSTREAM *unix_open (MAILSTREAM *stream); void unix_close (MAILSTREAM *stream,long options); char *unix_header (MAILSTREAM *stream,unsigned long msgno, unsigned long *length,long flags); long unix_text (MAILSTREAM *stream,unsigned long msgno,STRING *bs,long flags); char *unix_text_work (MAILSTREAM *stream,MESSAGECACHE *elt, unsigned long *length,long flags); void unix_flagmsg (MAILSTREAM *stream,MESSAGECACHE *elt); long unix_ping (MAILSTREAM *stream); void unix_check (MAILSTREAM *stream); long unix_expunge (MAILSTREAM *stream,char *sequence,long options); long unix_copy (MAILSTREAM *stream,char *sequence,char *mailbox,long options); long unix_append (MAILSTREAM *stream,char *mailbox,append_t af,void *data); int unix_collect_msg (MAILSTREAM *stream,FILE *sf,char *flags,char *date, STRING *msg); int unix_append_msgs (MAILSTREAM *stream,FILE *sf,FILE *df,SEARCHSET *set); void unix_abort (MAILSTREAM *stream); char *unix_file (char *dst,char *name); int unix_lock (char *file,int flags,int mode,char *lock,int op); void unix_unlock (int fd,MAILSTREAM *stream,char *lock); int unix_parse (MAILSTREAM *stream,char *lock,int op); char *unix_mbxline (MAILSTREAM *stream,STRING *bs,unsigned long *size); unsigned long unix_pseudo (MAILSTREAM *stream,char *hdr); unsigned long unix_xstatus (MAILSTREAM *stream,char *status,MESSAGECACHE *elt, unsigned long uid,long flag); long unix_rewrite (MAILSTREAM *stream,unsigned long *nexp,char *lock, long flags); long unix_extend (MAILSTREAM *stream,unsigned long size); void unix_write (UNIXFILE *f,char *s,unsigned long i); void unix_phys_write (UNIXFILE *f,char *buf,size_t size); /* UNIX mail routines */ /* Driver dispatch used by MAIL */ DRIVER unixdriver = { "unix", /* driver name */ /* driver flags */ DR_LOCAL|DR_MAIL|DR_NONEWMAILRONLY|DR_XPOINT, (DRIVER *) NIL, /* next driver */ unix_valid, /* mailbox is valid for us */ unix_parameters, /* manipulate parameters */ unix_scan, /* scan mailboxes */ unix_list, /* list mailboxes */ unix_lsub, /* list subscribed mailboxes */ NIL, /* subscribe to mailbox */ NIL, /* unsubscribe from mailbox */ unix_create, /* create mailbox */ unix_delete, /* delete mailbox */ unix_rename, /* rename mailbox */ mail_status_default, /* status of mailbox */ unix_open, /* open mailbox */ unix_close, /* close mailbox */ NIL, /* fetch message "fast" attributes */ NIL, /* fetch message flags */ NIL, /* fetch overview */ NIL, /* fetch message envelopes */ unix_header, /* fetch message header */ unix_text, /* fetch message text */ NIL, /* fetch partial message text */ NIL, /* unique identifier */ NIL, /* message number */ NIL, /* modify flags */ unix_flagmsg, /* per-message modify flags */ NIL, /* search for message based on criteria */ NIL, /* sort messages */ NIL, /* thread messages */ unix_ping, /* ping mailbox to see if still alive */ unix_check, /* check for new messages */ unix_expunge, /* expunge deleted messages */ unix_copy, /* copy messages to another mailbox */ unix_append, /* append string message to mailbox */ NIL /* garbage collect stream */ }; /* prototype stream */ MAILSTREAM unixproto = {&unixdriver}; /* driver parameters */ static long unix_fromwidget = T; /* UNIX mail validate mailbox * Accepts: mailbox name * Returns: our driver if name is valid, NIL otherwise */ DRIVER *unix_valid (char *name) { int fd; DRIVER *ret = NIL; int c,r; char tmp[MAILTMPLEN],file[MAILTMPLEN],*s,*t; struct stat sbuf; struct utimbuf times; errno = EINVAL; /* assume invalid argument */ /* must be non-empty file */ if ((t = dummy_file (file,name)) && !stat (t,&sbuf) && ((sbuf.st_mode & S_IFMT) == S_IFREG)) { if (!sbuf.st_size)errno = 0;/* empty file */ else if ((fd = open (file,O_BINARY|O_RDONLY,NIL)) >= 0) { memset (tmp,'\0',MAILTMPLEN); if (read (fd,tmp,MAILTMPLEN-1) <= 0) errno = -1; else { /* ignore leading whitespace */ for (s = tmp,c = '\n'; (*s == '\r') || (*s == '\n') || (*s == ' ') || (*s == '\t'); c = *s++); if (c == '\n') { /* at start of a line? */ VALID (s,t,r,c); /* yes, validate format */ if (r) ret = &unixdriver; else errno = -1; /* invalid format */ } } close (fd); /* close the file */ /* \Marked status? */ if ((sbuf.st_ctime > sbuf.st_atime) || (sbuf.st_mtime > sbuf.st_atime)) { /* yes, preserve atime and mtime */ times.actime = sbuf.st_atime; times.modtime = sbuf.st_mtime; utime (file,×); /* set the times */ } } } return ret; /* return what we should */ } /* UNIX manipulate driver parameters * Accepts: function code * function-dependent value * Returns: function-dependent return value */ void *unix_parameters (long function,void *value) { void *ret = NIL; switch ((int) function) { case SET_FROMWIDGET: unix_fromwidget = (long) value; case GET_FROMWIDGET: ret = (void *) unix_fromwidget; break; } return ret; } /* UNIX mail scan mailboxes * Accepts: mail stream * reference * pattern to search * string to scan */ void unix_scan (MAILSTREAM *stream,char *ref,char *pat,char *contents) { if (stream) dummy_scan (NIL,ref,pat,contents); } /* UNIX mail list mailboxes * Accepts: mail stream * reference * pattern to search */ void unix_list (MAILSTREAM *stream,char *ref,char *pat) { if (stream) dummy_list (NIL,ref,pat); } /* UNIX mail list subscribed mailboxes * Accepts: mail stream * reference * pattern to search */ void unix_lsub (MAILSTREAM *stream,char *ref,char *pat) { if (stream) dummy_lsub (NIL,ref,pat); } /* UNIX mail create mailbox * Accepts: MAIL stream * mailbox name to create * Returns: T on success, NIL on failure */ long unix_create (MAILSTREAM *stream,char *mailbox) { char *s,mbx[MAILTMPLEN],tmp[MAILTMPLEN]; long ret = NIL; int fd; time_t ti = time (0); if (!(s = dummy_file (mbx,mailbox))) { sprintf (tmp,"Can't create %.80s: invalid name",mailbox); mm_log (tmp,ERROR); } /* create underlying file */ else if (dummy_create_path (stream,s,NIL)) { if ((s = strrchr (s,'\\')) && !s[1]) ret = T; if ((fd = open (mbx,O_WRONLY|O_BINARY,NIL)) < 0) { sprintf (tmp,"Can't reopen mailbox node %.80s: %s",mbx,strerror (errno)); mm_log (tmp,ERROR); unlink (mbx); /* delete the file */ } else { /* initialize header */ memset (tmp,'\0',MAILTMPLEN); sprintf (tmp,"From %s %s",pseudo_from,ctime (&ti)); if (s = strpbrk (tmp,"\r\n")) *s = '\0'; strcat (tmp,"\r\nDate: "); rfc822_fixed_date (s = tmp + strlen (tmp)); sprintf (s += strlen (s), /* write the pseudo-header */ "\r\nFrom: %s <%s@%s>\r\nSubject: %s\r\nX-IMAP: %010lu 0000000000\r\nStatus: RO\r\n\r\n%s\r\n\r\n", pseudo_name,pseudo_from,mylocalhost (),pseudo_subject, (unsigned long) ti,pseudo_msg); if (write (fd,tmp,strlen (tmp)) > 0) { close (fd); /* close file */ ret = T; } else { sprintf (tmp,"Can't initialize mailbox node %.80s: %s",mbx, strerror (errno)); mm_log (tmp,ERROR); close (fd); /* close file before unlinking */ unlink (mbx); /* delete the file */ } } } return ret; } /* UNIX mail delete mailbox * Accepts: MAIL stream * mailbox name to delete * Returns: T on success, NIL on failure */ long unix_delete (MAILSTREAM *stream,char *mailbox) { return unix_rename (stream,mailbox,NIL); } /* UNIX mail rename mailbox * Accepts: MAIL stream * old mailbox name * new mailbox name (or NIL for delete) * Returns: T on success, NIL on failure */ long unix_rename (MAILSTREAM *stream,char *old,char *newname) { long ret = NIL; char c,*s = NIL; char tmp[MAILTMPLEN],file[MAILTMPLEN],lock[MAILTMPLEN],lockx[MAILTMPLEN]; int fd,ld; struct stat sbuf; mm_critical (stream); /* get the c-client lock */ if (!dummy_file (file,old) || (newname && (!(s = dummy_file (tmp,newname)) || ((s = strrchr (s,'\\')) && !s[1])))) sprintf (tmp,newname ? "Can't rename mailbox %.80s to %.80s: invalid name" : "Can't delete mailbox %.80s: invalid name", old,newname); else if ((ld = lockname (lock,file,NIL)) < 0) sprintf (tmp,"Can't get lock for mailbox %.80s",old); else { /* lock out other c-clients */ if (flock (ld,LOCK_EX|LOCK_NB)) { close (ld); /* couldn't lock, give up on it then */ sprintf (tmp,"Mailbox %.80s is in use by another process",old); } /* lock out non c-client applications */ else if ((fd = unix_lock (file,O_BINARY|O_RDWR,S_IREAD|S_IWRITE,lockx, LOCK_EX)) < 0) sprintf (tmp,"Can't lock mailbox %.80s: %s",old,strerror (errno)); else { unix_unlock(fd,NIL,lockx);/* pacify evil NTFS */ if (newname) { /* want rename? */ /* found superior to destination name? */ if ((s = strrchr (tmp,'\\')) && (s != tmp) && ((tmp[1] != ':') || (s != tmp + 2))) { c = s[1]; /* remember character after delimiter */ *s = s[1] = '\0'; /* tie off name at delimiter */ /* name doesn't exist, create it */ if (stat (tmp,&sbuf) || ((sbuf.st_mode & S_IFMT) != S_IFDIR)) { *s = '\\'; /* restore delimiter */ if (!dummy_create (stream,newname)) { flock (ld,LOCK_UN); close (ld); /* close c-client lock */ unlink (lock); /* and delete it */ mm_nocritical (stream); return NIL; /* couldn't create superior */ } } else *s = '\\'; /* restore delimiter */ s[1] = c; /* restore character after delimiter */ } if (rename (file,tmp)) sprintf (tmp,"Can't rename mailbox %.80s to %.80s: %s",old,newname, strerror (errno)); else ret = T; /* set success */ } else if (unlink (file)) /* want delete */ sprintf (tmp,"Can't delete mailbox %.80s: %s",old,strerror (errno)); else ret = T; /* set success */ flock (ld,LOCK_UN); /* release c-client lock */ close (ld); /* close c-client lock */ unlink (lock); /* and delete it */ } } mm_nocritical (stream); /* no longer critical */ if (!ret) mm_log (tmp,ERROR); /* log error */ return ret; /* return success or failure */ } /* UNIX mail open * Accepts: Stream to open * Returns: Stream on success, NIL on failure */ MAILSTREAM *unix_open (MAILSTREAM *stream) { int fd; char tmp[MAILTMPLEN]; /* return prototype for OP_PROTOTYPE call */ if (!stream) return &unixproto; if (stream->local) fatal ("unix recycle stream"); stream->local = memset (fs_get (sizeof (UNIXLOCAL)),0,sizeof (UNIXLOCAL)); /* note if an INBOX or not */ stream->inbox = !compare_cstring (stream->mailbox,"INBOX"); /* canonicalize the stream mailbox name */ if (!dummy_file (tmp,stream->mailbox)) { sprintf (tmp,"Can't open - invalid name: %.80s",stream->mailbox); mm_log (tmp,ERROR); return NIL; } /* flush old name */ fs_give ((void **) &stream->mailbox); /* save canonical name */ stream->mailbox = cpystr (tmp); LOCAL->fd = LOCAL->ld = -1; /* no file or state locking yet */ LOCAL->buf = (char *) fs_get ((LOCAL->buflen = CHUNKSIZE) + 1); LOCAL->text.data = (unsigned char *) fs_get (CHUNKSIZE); LOCAL->text.size = CHUNKSIZE - 1; LOCAL->linebuf = (char *) fs_get (CHUNKSIZE); LOCAL->linebuflen = CHUNKSIZE - 1; stream->sequence++; /* bump sequence number */ if (!stream->rdonly) { /* make lock for read/write access */ if ((fd = lockname (tmp,stream->mailbox,NIL)) < 0) mm_log ("Can't open mailbox lock, access is readonly",WARN); /* can get the lock? */ else if (flock (fd,LOCK_EX|LOCK_NB)) { if (!stream->silent) mm_log ("Mailbox is open by another process, access is readonly",WARN); close (fd); } else { /* got the lock, nobody else can alter state */ LOCAL->ld = fd; /* note lock's fd and name */ LOCAL->lname = cpystr (tmp); } } /* parse mailbox */ stream->nmsgs = stream->recent = 0; /* will we be able to get write access? */ if ((LOCAL->ld >= 0) && access (stream->mailbox,02) && (errno == EACCES)) { mm_log ("Can't get write access to mailbox, access is readonly",WARN); flock (LOCAL->ld,LOCK_UN); /* release the lock */ close (LOCAL->ld); /* close the lock file */ LOCAL->ld = -1; /* no more lock fd */ unlink (LOCAL->lname); /* delete it */ } /* reset UID validity */ stream->uid_validity = stream->uid_last = 0; if (stream->silent && !stream->rdonly && (LOCAL->ld < 0)) unix_abort (stream); /* abort if can't get RW silent stream */ /* parse mailbox */ else if (unix_parse (stream,tmp,LOCK_SH)) { unix_unlock (LOCAL->fd,stream,tmp); mail_unlock (stream); mm_nocritical (stream); /* done with critical */ } if (!LOCAL) return NIL; /* failure if stream died */ /* make sure upper level knows readonly */ stream->rdonly = (LOCAL->ld < 0); /* notify about empty mailbox */ if (!(stream->nmsgs || stream->silent)) mm_log ("Mailbox is empty",NIL); if (!stream->rdonly) { /* flags stick if readwrite */ stream->perm_seen = stream->perm_deleted = stream->perm_flagged = stream->perm_answered = stream->perm_draft = T; /* have permanent keywords */ stream->perm_user_flags = 0xffffffff; /* and maybe can create them too */ stream->kwd_create = stream->user_flags[NUSERFLAGS-1] ? NIL : T; } return stream; /* return stream alive to caller */ } /* UNIX mail close * Accepts: MAIL stream * close options */ void unix_close (MAILSTREAM *stream,long options) { int silent = stream->silent; stream->silent = T; /* go silent */ /* expunge if requested */ if (options & CL_EXPUNGE) unix_expunge (stream,NIL,NIL); /* else dump final checkpoint */ else if (LOCAL->dirty) unix_check (stream); stream->silent = silent; /* restore old silence state */ unix_abort (stream); /* now punt the file and local data */ } /* UNIX mail fetch message header * Accepts: MAIL stream * message # to fetch * pointer to returned header text length * option flags * Returns: message header in RFC822 format */ /* lines to filter from header */ static STRINGLIST *unix_hlines = NIL; char *unix_header (MAILSTREAM *stream,unsigned long msgno, unsigned long *length,long flags) { MESSAGECACHE *elt; unsigned char *s; *length = 0; /* default to empty */ if (flags & FT_UID) return "";/* UID call "impossible" */ elt = mail_elt (stream,msgno);/* get cache */ if (!unix_hlines) { /* once only code */ STRINGLIST *lines = unix_hlines = mail_newstringlist (); lines->text.size = strlen ((char *) (lines->text.data = (unsigned char *) "Status")); lines = lines->next = mail_newstringlist (); lines->text.size = strlen ((char *) (lines->text.data = (unsigned char *) "X-Status")); lines = lines->next = mail_newstringlist (); lines->text.size = strlen ((char *) (lines->text.data = (unsigned char *) "X-Keywords")); lines = lines->next = mail_newstringlist (); lines->text.size = strlen ((char *) (lines->text.data = (unsigned char *) "X-UID")); lines = lines->next = mail_newstringlist (); lines->text.size = strlen ((char *) (lines->text.data = (unsigned char *) "X-IMAP")); lines = lines->next = mail_newstringlist (); lines->text.size = strlen ((char *) (lines->text.data = (unsigned char *) "X-IMAPbase")); } /* go to header position */ lseek (LOCAL->fd,elt->private.special.offset + elt->private.msg.header.offset,L_SET); if (flags & FT_INTERNAL) { /* initial data OK? */ if (elt->private.msg.header.text.size > LOCAL->buflen) { fs_give ((void **) &LOCAL->buf); LOCAL->buf = (char *) fs_get ((LOCAL->buflen = elt->private.msg.header.text.size) + 1); } /* read message */ read (LOCAL->fd,LOCAL->buf,elt->private.msg.header.text.size); /* got text, tie off string */ LOCAL->buf[*length = elt->private.msg.header.text.size] = '\0'; } else { /* need to make a CRLF version */ read (LOCAL->fd,s = (char *) fs_get (elt->private.msg.header.text.size+1), elt->private.msg.header.text.size); /* tie off string, and convert to CRLF */ s[elt->private.msg.header.text.size] = '\0'; *length = unix_crlfcpy (&LOCAL->buf,&LOCAL->buflen,s, elt->private.msg.header.text.size); fs_give ((void **) &s); /* free readin buffer */ } *length = mail_filter (LOCAL->buf,*length,unix_hlines,FT_NOT); return LOCAL->buf; /* return processed copy */ } /* UNIX mail fetch message text * Accepts: MAIL stream * message # to fetch * pointer to returned stringstruct * option flags * Returns: T on success, NIL if failure */ long unix_text (MAILSTREAM *stream,unsigned long msgno,STRING *bs,long flags) { char *s; unsigned long i; MESSAGECACHE *elt; /* UID call "impossible" */ if (flags & FT_UID) return NIL; elt = mail_elt (stream,msgno);/* get cache element */ /* if message not seen */ if (!(flags & FT_PEEK) && !elt->seen) { /* mark message seen and dirty */ elt->seen = elt->private.dirty = LOCAL->dirty = T; mm_flags (stream,msgno); } s = unix_text_work (stream,elt,&i,flags); INIT (bs,mail_string,s,i); /* set up stringstruct */ return T; /* success */ } /* UNIX mail fetch message text worker routine * Accepts: MAIL stream * message cache element * pointer to returned header text length * option flags */ char *unix_text_work (MAILSTREAM *stream,MESSAGECACHE *elt, unsigned long *length,long flags) { FDDATA d; STRING bs; unsigned char c,*s,tmp[CHUNKSIZE]; /* go to text position */ lseek (LOCAL->fd,elt->private.special.offset + elt->private.msg.text.offset,L_SET); if (flags & FT_INTERNAL) { /* initial data OK? */ if (elt->private.msg.text.text.size > LOCAL->buflen) { fs_give ((void **) &LOCAL->buf); LOCAL->buf = (char *) fs_get ((LOCAL->buflen = elt->private.msg.text.text.size) + 1); } /* read message */ read (LOCAL->fd,LOCAL->buf,elt->private.msg.text.text.size); /* got text, tie off string */ LOCAL->buf[*length = elt->private.msg.text.text.size] = '\0'; return LOCAL->buf; } /* have it cached already? */ if (elt->private.uid != LOCAL->uid) { /* not cached, cache it now */ LOCAL->uid = elt->private.uid; /* is buffer big enough? */ if (elt->rfc822_size > LOCAL->text.size) { /* excessively conservative, but the right thing is too hard to do */ fs_give ((void **) &LOCAL->text.data); LOCAL->text.data = (unsigned char *) fs_get ((LOCAL->text.size = elt->rfc822_size) + 1); } d.fd = LOCAL->fd; /* yes, set up file descriptor */ d.pos = elt->private.special.offset + elt->private.msg.text.offset; d.chunk = tmp; /* initial buffer chunk */ d.chunksize = CHUNKSIZE; /* file chunk size */ INIT (&bs,fd_string,&d,elt->private.msg.text.text.size); for (s = (char *) LOCAL->text.data; SIZE (&bs);) switch (c = SNX (&bs)) { case '\r': /* carriage return seen */ *s++ = c; /* copy it and any succeeding LF */ if (SIZE (&bs) && (CHR (&bs) == '\n')) *s++ = SNX (&bs); break; case '\n': *s++ = '\r'; /* insert a CR */ default: *s++ = c; /* copy characters */ } *s = '\0'; /* tie off buffer */ /* calculate length of cached data */ LOCAL->textlen = s - LOCAL->text.data; } *length = LOCAL->textlen; /* return from cache */ return (char *) LOCAL->text.data; } /* UNIX per-message modify flag * Accepts: MAIL stream * message cache element */ void unix_flagmsg (MAILSTREAM *stream,MESSAGECACHE *elt) { /* only after finishing */ if (elt->valid) elt->private.dirty = LOCAL->dirty = T; } /* UNIX mail ping mailbox * Accepts: MAIL stream * Returns: T if stream alive, else NIL */ long unix_ping (MAILSTREAM *stream) { char lock[MAILTMPLEN]; struct stat sbuf; /* big no-op if not readwrite */ if (LOCAL && (LOCAL->ld >= 0) && !stream->lock) { if (stream->rdonly) { /* does he want to give up readwrite? */ /* checkpoint if we changed something */ if (LOCAL->dirty) unix_check (stream); flock (LOCAL->ld,LOCK_UN);/* release readwrite lock */ close (LOCAL->ld); /* close the readwrite lock file */ LOCAL->ld = -1; /* no more readwrite lock fd */ unlink (LOCAL->lname); /* delete the readwrite lock file */ } else { /* get current mailbox size */ if (LOCAL->fd >= 0) fstat (LOCAL->fd,&sbuf); else if (stat (stream->mailbox,&sbuf)) { sprintf (LOCAL->buf,"Mailbox stat failed, aborted: %s", strerror (errno)); MM_LOG (LOCAL->buf,ERROR); unix_abort (stream); return NIL; } /* parse if mailbox changed */ if ((LOCAL->ddirty || (sbuf.st_size != LOCAL->filesize)) && unix_parse (stream,lock,LOCK_EX)) { /* force checkpoint if double-dirty */ if (LOCAL->ddirty) unix_rewrite (stream,NIL,lock,NIL); /* unlock mailbox */ else unix_unlock (LOCAL->fd,stream,lock); mail_unlock (stream); /* and stream */ mm_nocritical (stream); /* done with critical */ } } } return LOCAL ? LONGT : NIL; /* return if still alive */ } /* UNIX mail check mailbox * Accepts: MAIL stream */ void unix_check (MAILSTREAM *stream) { char lock[MAILTMPLEN]; /* parse and lock mailbox */ if (LOCAL && (LOCAL->ld >= 0) && !stream->lock && unix_parse (stream,lock,LOCK_EX)) { /* any unsaved changes? */ if (LOCAL->dirty && unix_rewrite (stream,NIL,lock,NIL)) { if (!stream->silent) mm_log ("Checkpoint completed",NIL); } /* no checkpoint needed, just unlock */ else unix_unlock (LOCAL->fd,stream,lock); mail_unlock (stream); /* unlock the stream */ mm_nocritical (stream); /* done with critical */ } } /* UNIX mail expunge mailbox * Accepts: MAIL stream * sequence to expunge if non-NIL * expunge options * Returns: T, always */ long unix_expunge (MAILSTREAM *stream,char *sequence,long options) { long ret; unsigned long i; char lock[MAILTMPLEN]; char *msg = NIL; /* parse and lock mailbox */ if (ret = (sequence ? ((options & EX_UID) ? mail_uid_sequence (stream,sequence) : mail_sequence (stream,sequence)) : LONGT) && LOCAL && (LOCAL->ld >= 0) && !stream->lock && unix_parse (stream,lock,LOCK_EX)) { /* check expunged messages if not dirty */ for (i = 1; !LOCAL->dirty && (i <= stream->nmsgs); i++) { MESSAGECACHE *elt = mail_elt (stream,i); if (mail_elt (stream,i)->deleted) LOCAL->dirty = T; } if (!LOCAL->dirty) { /* not dirty and no expunged messages */ unix_unlock (LOCAL->fd,stream,lock); msg = "No messages deleted, so no update needed"; } else if (unix_rewrite (stream,&i,lock,sequence ? LONGT : NIL)) { if (i) sprintf (msg = LOCAL->buf,"Expunged %lu messages",i); else msg = "Mailbox checkpointed, but no messages expunged"; } /* rewrite failed */ else unix_unlock (LOCAL->fd,stream,lock); mail_unlock (stream); /* unlock the stream */ mm_nocritical (stream); /* done with critical */ if (msg && !stream->silent) mm_log (msg,NIL); } else if (!stream->silent) mm_log("Expunge ignored on readonly mailbox",WARN); return ret; } /* UNIX mail copy message(s) * Accepts: MAIL stream * sequence * destination mailbox * copy options * Returns: T if copy successful, else NIL */ long unix_copy (MAILSTREAM *stream,char *sequence,char *mailbox,long options) { struct stat sbuf; int fd; char *s,file[MAILTMPLEN],lock[MAILTMPLEN]; struct utimbuf times; unsigned long i,j; MESSAGECACHE *elt; long ret = T; mailproxycopy_t pc = (mailproxycopy_t) mail_parameters (stream,GET_MAILPROXYCOPY,NIL); copyuid_t cu = (copyuid_t) (mail_parameters (NIL,GET_USERHASNOLIFE,NIL) ? NIL : mail_parameters (NIL,GET_COPYUID,NIL)); SEARCHSET *source = cu ? mail_newsearchset () : NIL; SEARCHSET *dest = cu ? mail_newsearchset () : NIL; MAILSTREAM *tstream = NIL; if (!((options & CP_UID) ? mail_uid_sequence (stream,sequence) : mail_sequence (stream,sequence))) return NIL; /* make sure destination is valid */ if (!(unix_valid (mailbox) || !errno)) switch (errno) { case ENOENT: /* no such file? */ if (compare_cstring (mailbox,"INBOX")) { mm_notify (stream,"[TRYCREATE] Must create mailbox before copy",NIL); return NIL; } if (pc) return (*pc) (stream,sequence,mailbox,options); unix_create (NIL,"INBOX");/* create empty INBOX */ case EACCES: /* file protected */ sprintf (LOCAL->buf,"Can't access destination: %.80s",mailbox); MM_LOG (LOCAL->buf,ERROR); return NIL; case EINVAL: if (pc) return (*pc) (stream,sequence,mailbox,options); sprintf (LOCAL->buf,"Invalid UNIX-format mailbox name: %.80s",mailbox); mm_log (LOCAL->buf,ERROR); return NIL; default: if (pc) return (*pc) (stream,sequence,mailbox,options); sprintf (LOCAL->buf,"Not a UNIX-format mailbox: %.80s",mailbox); mm_log (LOCAL->buf,ERROR); return NIL; } /* try to open rewrite for UIDPLUS */ if ((tstream = mail_open_work (&unixdriver,NIL,mailbox, OP_SILENT|OP_NOKOD)) && tstream->rdonly) tstream = mail_close (tstream); if (cu && !tstream) { /* wanted a COPYUID? */ sprintf (LOCAL->buf,"Unable to write-open mailbox for COPYUID: %.80s", mailbox); MM_LOG (LOCAL->buf,WARN); cu = NIL; /* don't try to do COPYUID */ } LOCAL->buf[0] = '\0'; mm_critical (stream); /* go critical */ if ((fd = unix_lock (dummy_file (file,mailbox), O_BINARY|O_WRONLY|O_APPEND|O_CREAT,S_IREAD|S_IWRITE, lock,LOCK_EX)) < 0) { mm_nocritical (stream); /* done with critical */ sprintf (LOCAL->buf,"Can't open destination mailbox: %s",strerror (errno)); mm_log (LOCAL->buf,ERROR); /* log the error */ return NIL; /* failed */ } fstat (fd,&sbuf); /* get current file size */ /* write all requested messages to mailbox */ for (i = 1; ret && (i <= stream->nmsgs); i++) if ((elt = mail_elt (stream,i))->sequence) { lseek (LOCAL->fd,elt->private.special.offset,L_SET); read (LOCAL->fd,LOCAL->buf,elt->private.special.text.size); if (LOCAL->buf[(j = elt->private.special.text.size) - 2] != '\r') { LOCAL->buf[j - 1] = '\r'; LOCAL->buf[j++] = '\n'; } if (write (fd,LOCAL->buf,j) < 0) ret = NIL; else { /* internal header succeeded */ s = unix_header (stream,i,&j,NIL); /* header size, sans trailing newline */ if (j && (s[j - 4] == '\r')) j -= 2; if (write (fd,s,j) < 0) ret = NIL; else { /* message header succeeded */ j = tstream ? /* write UIDPLUS data if have readwrite */ unix_xstatus (stream,LOCAL->buf,elt,++(tstream->uid_last),LONGT) : unix_xstatus (stream,LOCAL->buf,elt,NIL,NIL); if (write (fd,LOCAL->buf,j) < 0) ret = NIL; else { /* message status succeeded */ s = unix_text_work (stream,elt,&j,NIL); if ((write (fd,s,j) < 0) || (write (fd,"\r\n",2) < 0)) ret = NIL; else if (cu) { /* need to pass back new UID? */ mail_append_set (source,mail_uid (stream,i)); mail_append_set (dest,tstream->uid_last); } } } } } if (!ret || fsync (fd)) { /* force out the update */ sprintf (LOCAL->buf,"Message copy failed: %s",strerror (errno)); ftruncate (fd,sbuf.st_size); ret = NIL; } /* force UIDVALIDITY assignment now */ if (tstream && !tstream->uid_validity) tstream->uid_validity = (unsigned long) time (0); /* return sets if doing COPYUID */ if (cu && ret) (*cu) (stream,mailbox,tstream->uid_validity,source,dest); else { /* flush any sets we may have built */ mail_free_searchset (&source); mail_free_searchset (&dest); } times.modtime = time (0); /* set mtime to now */ /* set atime to now-1 if successful copy */ if (ret) times.actime = times.modtime - 1; else times.actime = /* else preserve \Marked status */ ((sbuf.st_ctime > sbuf.st_atime) || (sbuf.st_mtime > sbuf.st_atime)) ? sbuf.st_atime : times.modtime; utime (file,×); /* set the times */ unix_unlock (fd,NIL,lock); /* unlock and close mailbox */ if (tstream) { /* update last UID if we can */ UNIXLOCAL * local = (UNIXLOCAL *) tstream->local; local->dirty = T; /* do a rewrite */ local->appending = T; /* but not at the cost of marking as old */ tstream = mail_close (tstream); } /* log the error */ if (!ret) mm_log (LOCAL->buf,ERROR); /* delete if requested message */ else if (options & CP_MOVE) for (i = 1; i <= stream->nmsgs; i++) if ((elt = mail_elt (stream,i))->sequence) elt->deleted = elt->private.dirty = LOCAL->dirty = T; mm_nocritical (stream); /* release critical */ return ret; } /* UNIX mail append message from stringstruct * Accepts: MAIL stream * destination mailbox * append callback * data for callback * Returns: T if append successful, else NIL */ #define BUFLEN 8*MAILTMPLEN long unix_append (MAILSTREAM *stream,char *mailbox,append_t af,void *data) { struct stat sbuf; int fd; unsigned long i; char *flags,*date,buf[BUFLEN],tmp[MAILTMPLEN],file[MAILTMPLEN], lock[MAILTMPLEN]; struct utimbuf times; FILE *sf,*df; MESSAGECACHE elt; STRING *message; unsigned long uidlocation = 0; appenduid_t au = (appenduid_t) (mail_parameters (NIL,GET_USERHASNOLIFE,NIL) ? NIL : mail_parameters (NIL,GET_APPENDUID,NIL)); SEARCHSET *dst = au ? mail_newsearchset () : NIL; long ret = LONGT; MAILSTREAM *tstream = NIL; if (!stream) { /* stream specified? */ stream = &unixproto; /* no, default stream to prototype */ for (i = 0; i < NUSERFLAGS && stream->user_flags[i]; ++i) fs_give ((void **) &stream->user_flags[i]); } if (!unix_valid (mailbox)) switch (errno) { case ENOENT: /* no such file? */ if (!compare_cstring (mailbox,"INBOX")) { mm_notify (stream,"[TRYCREATE] Must create mailbox before append",NIL); return NIL; } unix_create (NIL,"INBOX"); /* create empty INBOX */ case 0: /* merely empty file? */ tstream = stream; break; case EACCES: /* file protected */ sprintf (tmp,"Can't access destination: %.80s",mailbox); MM_LOG (tmp,ERROR); return NIL; case EINVAL: sprintf (tmp,"Invalid UNIX-format mailbox name: %.80s",mailbox); mm_log (tmp,ERROR); return NIL; default: sprintf (tmp,"Not a UNIX-format mailbox: %.80s",mailbox); mm_log (tmp,ERROR); return NIL; } /* get sniffing stream for keywords */ else if (!(tstream = mail_open (NIL,mailbox, OP_READONLY|OP_SILENT|OP_NOKOD|OP_SNIFF))) { sprintf (tmp,"Unable to examine mailbox for APPEND: %.80s",mailbox); MM_LOG (tmp,ERROR); return NIL; } /* get first message */ if (!(*af) (tstream,data,&flags,&date,&message)) return NIL; if (!(sf = tmpfile ())) { /* must have scratch file */ sprintf (tmp,".%lx.%lx",(unsigned long) time (0),(unsigned long)getpid ()); if (!stat (tmp,&sbuf) || !(sf = fopen (tmp,"wb+"))) { sprintf (tmp,"Unable to create scratch file: %.80s",strerror (errno)); mm_log (tmp,ERROR); return NIL; } unlink (tmp); } do { /* parse date */ if (!date) rfc822_date (date = tmp); if (!mail_parse_date (&elt,date)) { sprintf (tmp,"Bad date in append: %.80s",date); mm_log (tmp,ERROR); } else { /* user wants to suppress time zones? */ if (mail_parameters (NIL,GET_NOTIMEZONES,NIL)) { time_t when = mail_longdate (&elt); date = ctime (&when); /* use traditional date */ } /* use POSIX-style date */ else date = mail_cdate (tmp,&elt); if (!SIZE (message)) mm_log ("Append of zero-length message",ERROR); else if (!unix_collect_msg (tstream,sf,flags,date,message)) { sprintf (tmp,"Error writing scratch file: %.80s",strerror (errno)); mm_log (tmp,ERROR); } /* get next message */ else if ((*af) (tstream,data,&flags,&date,&message)) continue; } fclose (sf); /* punt scratch file */ return NIL; /* give up */ } while (message); /* until no more messages */ if (fflush (sf)) { sprintf (tmp,"Error finishing scratch file: %.80s",strerror (errno)); mm_log (tmp,ERROR); fclose (sf); /* punt scratch file */ return NIL; /* give up */ } i = ftell (sf); /* size of scratch file */ /* close sniffing stream */ if (tstream != stream) tstream = mail_close (tstream); mm_critical (stream); /* go critical */ /* try to open readwrite for UIDPLUS */ if ((tstream = mail_open_work (&unixdriver,NIL,mailbox, OP_SILENT|OP_NOKOD)) && tstream->rdonly) tstream = mail_close (tstream); if (au && !tstream) { /* wanted an APPENDUID? */ sprintf (tmp,"Unable to re-open mailbox for APPENDUID: %.80s",mailbox); MM_LOG (tmp,WARN); au = NIL; } if (((fd = unix_lock (dummy_file (file,mailbox), O_BINARY|O_WRONLY|O_APPEND|O_CREAT,S_IREAD|S_IWRITE, lock,LOCK_EX)) < 0) || !(df = fdopen (fd,"ab"))) { mm_nocritical (stream); /* done with critical */ sprintf (tmp,"Can't open append mailbox: %s",strerror (errno)); mm_log (tmp,ERROR); return NIL; } fstat (fd,&sbuf); /* get current file size */ rewind (sf); times.modtime = time (0); /* set mtime to now */ /* write all messages */ if (!unix_append_msgs (tstream,sf,df,au ? dst : NIL) || (fflush (df) == EOF) || fsync (fd)) { sprintf (buf,"Message append failed: %s",strerror (errno)); mm_log (buf,ERROR); ftruncate (fd,sbuf.st_size);/* revert file */ times.actime = /* preserve \Marked status */ ((sbuf.st_ctime > sbuf.st_atime) || (sbuf.st_mtime > sbuf.st_atime)) ? sbuf.st_atime : times.modtime; ret = NIL; /* return error */ } /* set atime to now-1 if successful copy */ else times.actime = times.modtime - 1; utime (file,×); /* set the times */ fclose (sf); /* done with scratch file */ /* force UIDVALIDITY assignment now */ if (tstream && !tstream->uid_validity) tstream->uid_validity = (unsigned long) time (0); /* return sets if doing APPENDUID */ if (au && ret) (*au) (mailbox,tstream->uid_validity,dst); else mail_free_searchset (&dst); flock (fd,LOCK_UN); /* unlock mailbox (can't use unix_unlock() */ if (lock && *lock) unlink (lock); fclose (df); /* close mailbox */ if (tstream) { /* update last UID if we can */ UNIXLOCAL * local = (UNIXLOCAL *) tstream->local; local->dirty = T; /* do a rewrite */ local->appending = T; /* but not at the cost of marking as old */ tstream = mail_close (tstream); } mm_nocritical (stream); /* release critical */ return ret; } /* Collect and write single message to append scratch file * Accepts: MAIL stream * scratch file * flags * date * message stringstruct * Returns: NIL if write error, else T */ int unix_collect_msg (MAILSTREAM *stream,FILE *sf,char *flags,char *date, STRING *msg) { unsigned char *s,*t; unsigned long uf; long f = mail_parse_flags (stream,flags,&uf); /* write metadata */ if (fprintf (sf,"%ld %lu ",f,SIZE (msg) + 2) < 0) return NIL; for (s = date; *s; *s++) switch (*s) { default: if (putc (*s,sf) == EOF) return NIL; case '\r': case '\n': break; } if (fputs ("\r\n",sf) == EOF) return NIL; while (uf) /* write user flags */ if ((s = stream->user_flags[find_rightmost_bit (&uf)]) && (fprintf (sf," %s",s) < 0)) return NIL; if (fputs ("\r\n",sf) == EOF) return NIL; while (SIZE (msg)) { /* copy text to scratch file */ for (s = (unsigned char *) msg->curpos, t = s + msg->cursize; s < t; ++s) if (!*s) *s = 0x80; /* disallow NUL */ /* write buffered text */ if (fwrite (msg->curpos,1,msg->cursize,sf) == msg->cursize) SETPOS (msg,GETPOS (msg) + msg->cursize); else return NIL; /* failed */ } /* write trailing CRLF and return */ return (fputs ("\r\n",sf) == EOF) ? NIL : T; } /* Append messages from scratch file to mailbox * Accepts: MAIL stream * source file * destination file * uidset to update if non-NIL * Returns: T if success, NIL if failure */ int unix_append_msgs (MAILSTREAM *stream,FILE *sf,FILE *df,SEARCHSET *set) { int ti,zn,c; long f; unsigned long i,j; char *x,tmp[MAILTMPLEN]; int hdrp = T; /* get message metadata line */ while (fgets (tmp,MAILTMPLEN,sf)) { if (!(isdigit (tmp[0]) && strchr (tmp,'\n'))) return NIL; f = strtol (tmp,&x,10); /* get flags */ if (!((*x++ == ' ') && isdigit (*x))) return NIL; i = strtoul (x,&x,10); /* get message size */ if ((*x++ != ' ') || /* build initial header */ (fprintf (df,"From %s@%s %sStatus: ",myusername(),mylocalhost(),x)<0)|| (f&fSEEN && (putc ('R',df) == EOF)) || (fputs ("\r\nX-Status: ",df) == EOF) || (f&fDELETED && (putc ('D',df) == EOF)) || (f&fFLAGGED && (putc ('F',df) == EOF)) || (f&fANSWERED && (putc ('A',df) == EOF)) || (f&fDRAFT && (putc ('T',df) == EOF)) || (fputs ("\r\nX-Keywords:",df) == EOF)) return NIL; /* copy keywords */ while ((c = getc (sf)) != '\n') switch (c) { case EOF: return NIL; default: if (putc (c,df) == EOF) return NIL; } if ((putc ('\n',df) == EOF) || (set && (fprintf (df,"X-UID: %lu\r\n",++(stream->uid_last)) < 0))) return NIL; for (c = '\n'; i && fgets (tmp,MAILTMPLEN,sf); c = tmp[j-1]) { /* get read line length */ if (i < (j = strlen (tmp))) fatal ("unix_append_msgs overrun"); i -= j; /* number of bytes left */ if (!j) continue; /* do nothing if line emptied */ /* complete line? */ if ((c == '\n')) switch (tmp[0]) { case 'F': /* possible "From " (case counts here) */ if ((j > 4) && (tmp[0] == 'F') && (tmp[1] == 'r') && (tmp[2] == 'o') && (tmp[3] == 'm') && (tmp[4] == ' ')) { if (!unix_fromwidget) { VALID (tmp,x,ti,zn);/* conditional, only write widget if */ if (!ti) break; /* it looks like a valid header */ } /* write the widget */ if (putc ('>',df) == EOF) return NIL; } break; case 'S': case 's': /* possible "Status:" */ if (hdrp && (j > 6) && ((tmp[1] == 't') || (tmp[1] == 'T')) && ((tmp[2] == 'a') || (tmp[2] == 'A')) && ((tmp[3] == 't') || (tmp[3] == 'T')) && ((tmp[4] == 'u') || (tmp[4] == 'U')) && ((tmp[5] == 's') || (tmp[5] == 'S')) && (tmp[6] == ':') && (fputs ("X-Original-",df) == EOF)) return NIL; break; case 'X': case 'x': /* possible X-??? header */ if (hdrp && (tmp[1] == '-') && /* possible X-UID: */ (((j > 5) && ((tmp[2] == 'U') || (tmp[2] == 'u')) && ((tmp[3] == 'I') || (tmp[3] == 'i')) && ((tmp[4] == 'D') || (tmp[4] == 'd')) && (tmp[5] == ':')) || /* possible X-IMAP: */ ((j > 6) && ((tmp[2] == 'I') || (tmp[2] == 'i')) && ((tmp[3] == 'M') || (tmp[3] == 'm')) && ((tmp[4] == 'A') || (tmp[4] == 'a')) && ((tmp[5] == 'P') || (tmp[5] == 'p')) && ((tmp[6] == ':') || /* or X-IMAPbase: */ ((j > 10) && ((tmp[6] == 'b') || (tmp[6] == 'B')) && ((tmp[7] == 'a') || (tmp[7] == 'A')) && ((tmp[8] == 's') || (tmp[8] == 'S')) && ((tmp[9] == 'e') || (tmp[9] == 'E')) && (tmp[10] == ':')))) || /* possible X-Status: */ ((j > 8) && ((tmp[2] == 'S') || (tmp[2] == 's')) && ((tmp[3] == 't') || (tmp[3] == 'T')) && ((tmp[4] == 'a') || (tmp[4] == 'A')) && ((tmp[5] == 't') || (tmp[5] == 'T')) && ((tmp[6] == 'u') || (tmp[6] == 'U')) && ((tmp[7] == 's') || (tmp[7] == 'S')) && (tmp[8] == ':')) || /* possible X-Keywords: */ ((j > 10) && ((tmp[2] == 'K') || (tmp[2] == 'k')) && ((tmp[3] == 'e') || (tmp[3] == 'E')) && ((tmp[4] == 'y') || (tmp[4] == 'Y')) && ((tmp[5] == 'w') || (tmp[5] == 'W')) && ((tmp[6] == 'o') || (tmp[6] == 'O')) && ((tmp[7] == 'r') || (tmp[7] == 'R')) && ((tmp[8] == 'd') || (tmp[8] == 'D')) && ((tmp[9] == 's') || (tmp[9] == 'S')) && (tmp[10] == ':'))) && (fputs ("X-Original-",df) == EOF)) return NIL; break; case '\n': /* blank line */ hdrp = NIL; break; default: /* nothing to do */ break; } /* just write the line */ if (fwrite (tmp,1,j,df) != j) return NIL; } if (i) return NIL; /* didn't read entire message */ /* update set */ if (stream) mail_append_set (set,stream->uid_last); } return T; } /* Internal routines */ /* UNIX mail abort stream * Accepts: MAIL stream */ void unix_abort (MAILSTREAM *stream) { if (LOCAL) { /* only if a file is open */ if (LOCAL->fd >= 0) close (LOCAL->fd); if (LOCAL->ld >= 0) { /* have a mailbox lock? */ flock (LOCAL->ld,LOCK_UN);/* yes, release the lock */ close (LOCAL->ld); /* close the lock file */ unlink (LOCAL->lname); /* and delete it */ } if (LOCAL->lname) fs_give ((void **) &LOCAL->lname); /* free local text buffers */ if (LOCAL->buf) fs_give ((void **) &LOCAL->buf); if (LOCAL->text.data) fs_give ((void **) &LOCAL->text.data); if (LOCAL->linebuf) fs_give ((void **) &LOCAL->linebuf); if (LOCAL->line) fs_give ((void **) &LOCAL->line); /* nuke the local data */ fs_give ((void **) &stream->local); stream->dtb = NIL; /* log out the DTB */ } } /* UNIX open and lock mailbox * Accepts: file name to open/lock * file open mode * destination buffer for lock file name * type of locking operation (LOCK_SH or LOCK_EX) */ int unix_lock (char *file,int flags,int mode,char *lock,int op) { int fd,ld,j; int i = LOCKTIMEOUT * 60 - 1; char tmp[MAILTMPLEN]; time_t t; struct stat sb; sprintf (lock,"%s.lock",file);/* build lock filename */ do { /* until OK or out of tries */ t = time (0); /* get the time now */ /* try to get the lock */ if ((ld = open(lock,O_BINARY|O_WRONLY|O_CREAT|O_EXCL,S_IREAD|S_IWRITE))>=0) close (ld); /* got it, close the lock file! */ else if (errno != EEXIST) { /* miscellaneous error */ sprintf (tmp,"Error creating %.80s: %s",lock,strerror (errno)); if (!(i%15)) mm_log (tmp,WARN); } /* lock exists, still active? */ else if (!stat (lock,&sb) && (t > sb.st_ctime + LOCKTIMEOUT * 60) && ((ld = open(lock,O_BINARY|O_WRONLY|O_CREAT,S_IREAD|S_IWRITE))>=0)) close (ld); /* got timed-out lock file */ else { /* active lock, try again */ if (!(i%15)) { sprintf (tmp,"Mailbox %.80s is locked, will override in %d seconds...", file,i); mm_log (tmp,WARN); } sleep (1); /* wait a second before next retry */ } } while (*lock && ld < 0 && i--); /* open file */ if ((fd = open (file,flags,mode)) >= 0) flock (fd,op); else { /* open failed */ j = errno; /* preserve error code */ if (*lock) unlink (lock); /* flush the lock file if any */ errno = j; /* restore error code */ } return fd; } /* UNIX unlock and close mailbox * Accepts: file descriptor * (optional) mailbox stream to check atime/mtime * (optional) lock file name */ void unix_unlock (int fd,MAILSTREAM *stream,char *lock) { if (stream) { /* need to muck with times? */ struct stat sbuf; struct utimbuf times; time_t now = time (0); fstat (fd,&sbuf); /* get file times */ if (LOCAL->ld >= 0) { /* yes, readwrite session? */ times.actime = now; /* set atime to now */ /* set mtime to (now - 1) if necessary */ times.modtime = (now > sbuf.st_mtime) ? sbuf.st_mtime : now - 1; } else if (stream->recent) { /* readonly with recent messages */ if ((sbuf.st_atime >= sbuf.st_mtime) || (sbuf.st_atime >= sbuf.st_ctime)) /* keep past mtime, whack back atime */ times.actime = (times.modtime = (sbuf.st_mtime < now) ? sbuf.st_mtime : now) - 1; else now = 0; /* no time change needed */ } /* readonly with no recent messages */ else if ((sbuf.st_atime < sbuf.st_mtime) || (sbuf.st_atime < sbuf.st_ctime)) { times.actime = now; /* set atime to now */ /* set mtime to (now - 1) if necessary */ times.modtime = (now > sbuf.st_mtime) ? sbuf.st_mtime : now - 1; } else now = 0; /* no time change needed */ /* set the times, note change */ if (now && !utime (stream->mailbox,×)) LOCAL->filetime = times.modtime; } flock (fd,LOCK_UN); /* release flock'ers */ if (!stream) close (fd); /* close the file if no stream */ /* flush the lock file if any */ if (lock && *lock) unlink (lock); } /* UNIX mail parse and lock mailbox * Accepts: MAIL stream * space to write lock file name * type of locking operation * Returns: T if parse OK, critical & mailbox is locked shared; NIL if failure */ int unix_parse (MAILSTREAM *stream,char *lock,int op) { int zn; unsigned long i,j,k,m; unsigned char c,*s,*t,*u,tmp[MAILTMPLEN],date[30]; int ti = 0,retain = T; unsigned long nmsgs = stream->nmsgs; unsigned long prevuid = nmsgs ? mail_elt (stream,nmsgs)->private.uid : 0; unsigned long recent = stream->recent; unsigned long oldnmsgs = stream->nmsgs; short silent = stream->silent; short pseudoseen = NIL; struct stat sbuf; STRING bs; FDDATA d; MESSAGECACHE *elt; mail_lock (stream); /* guard against recursion or pingers */ /* toss out previous descriptor */ if (LOCAL->fd >= 0) close (LOCAL->fd); mm_critical (stream); /* open and lock mailbox (shared OK) */ if ((LOCAL->fd = unix_lock (stream->mailbox, O_BINARY + ((LOCAL->ld >= 0) ? O_RDWR:O_RDONLY), NIL,lock,op)) < 0) { sprintf (tmp,"Mailbox open failed, aborted: %s",strerror (errno)); mm_log (tmp,ERROR); unix_abort (stream); mail_unlock (stream); mm_nocritical (stream); /* done with critical */ return NIL; } fstat (LOCAL->fd,&sbuf); /* get status */ /* validate change in size */ if (sbuf.st_size < LOCAL->filesize) { sprintf (tmp,"Mailbox shrank from %lu to %lu bytes, aborted", (unsigned long) LOCAL->filesize,(unsigned long) sbuf.st_size); mm_log (tmp,ERROR); /* this is pretty bad */ unix_unlock (LOCAL->fd,stream,lock); unix_abort (stream); mail_unlock (stream); mm_nocritical (stream); /* done with critical */ return NIL; } /* new data? */ else if (i = sbuf.st_size - LOCAL->filesize) { d.fd = LOCAL->fd; /* yes, set up file descriptor */ d.pos = LOCAL->filesize; /* get to that position in the file */ d.chunk = LOCAL->buf; /* initial buffer chunk */ d.chunksize = CHUNKSIZE; /* file chunk size */ INIT (&bs,fd_string,&d,i); /* initialize stringstruct */ /* skip leading whitespace for broken MTAs */ while (((c = CHR (&bs)) == '\n') || (c == '\r') || (c == ' ') || (c == '\t')) SNX (&bs); if (SIZE (&bs)) { /* read new data */ /* remember internal header position */ j = LOCAL->filesize + GETPOS (&bs); s = unix_mbxline (stream,&bs,&i); t = NIL,zn = 0; if (i) VALID (s,t,ti,zn); /* see if valid From line */ if (!ti) { /* someone pulled the rug from under us */ sprintf (tmp,"Unexpected changes to mailbox (try restarting): %.20s", (char *) s); mm_log (tmp,ERROR); unix_unlock (LOCAL->fd,stream,lock); unix_abort (stream); mail_unlock (stream); mm_nocritical (stream); /* done with critical */ return NIL; } stream->silent = T; /* quell main program new message events */ do { /* found a message */ /* instantiate first new message */ mail_exists (stream,++nmsgs); (elt = mail_elt (stream,nmsgs))->valid = T; recent++; /* assume recent by default */ elt->recent = T; /* note position/size of internal header */ elt->private.special.offset = j; elt->private.msg.header.offset = elt->private.special.text.size = i; /* generate plausible IMAPish date string */ date[2] = date[6] = date[20] = '-'; date[11] = ' '; date[14] = date[17] = ':'; /* dd */ date[0] = t[ti - 2]; date[1] = t[ti - 1]; /* mmm */ date[3] = t[ti - 6]; date[4] = t[ti - 5]; date[5] = t[ti - 4]; /* hh */ date[12] = t[ti + 1]; date[13] = t[ti + 2]; /* mm */ date[15] = t[ti + 4]; date[16] = t[ti + 5]; if (t[ti += 6] == ':') {/* ss */ date[18] = t[++ti]; date[19] = t[++ti]; ti++; /* move to space */ } else date[18] = date[19] = '0'; /* yy -- advance over timezone if necessary */ if (zn == ti) ti += (((t[zn+1] == '+') || (t[zn+1] == '-')) ? 6 : 4); date[7] = t[ti + 1]; date[8] = t[ti + 2]; date[9] = t[ti + 3]; date[10] = t[ti + 4]; /* zzz */ t = zn ? (t + zn + 1) : (unsigned char *) "LCL"; date[21] = *t++; date[22] = *t++; date[23] = *t++; if ((date[21] != '+') && (date[21] != '-')) date[24] = '\0'; else { /* numeric time zone */ date[24] = *t++; date[25] = *t++; date[26] = '\0'; date[20] = ' '; } /* set internal date */ if (!mail_parse_date (elt,date)) { sprintf (tmp,"Unable to parse internal date: %s",(char *) date); mm_log (tmp,WARN); } do { /* look for message body */ s = t = unix_mbxline (stream,&bs,&i); if (i) switch (*s) { /* check header lines */ case 'X': /* possible X-???: line */ if (s[1] == '-') { /* must be immediately followed by hyphen */ /* X-Status: becomes Status: in S case */ if (s[2] == 'S' && s[3] == 't' && s[4] == 'a' && s[5] == 't' && s[6] == 'u' && s[7] == 's' && s[8] == ':') s += 2; /* possible X-Keywords */ else if (s[2] == 'K' && s[3] == 'e' && s[4] == 'y' && s[5] == 'w' && s[6] == 'o' && s[7] == 'r' && s[8] == 'd' && s[9] == 's' && s[10] == ':') { SIZEDTEXT uf; retain = NIL; /* don't retain continuation */ s += 11; /* flush leading whitespace */ while (*s && (*s != '\n') && ((*s != '\r') || (s[1] != '\n'))){ while (*s == ' ') s++; /* find end of keyword */ if (!(u = strpbrk (s," \n\r"))) u = s + strlen (s); /* got a keyword? */ if ((k = (u - s)) && (k <= MAXUSERFLAG)) { uf.data = (unsigned char *) s; uf.size = k; for (j = 0; (j < NUSERFLAGS) && stream->user_flags[j]; ++j) if (!compare_csizedtext (stream->user_flags[j],&uf)) { elt->user_flags |= ((long) 1) << j; break; } } s = u; /* advance to next keyword */ } break; } /* possible X-IMAP */ else if ((s[2] == 'I') && (s[3] == 'M') && (s[4] == 'A') && (s[5] == 'P') && ((m = (s[6] == ':')) || ((s[6] == 'b') && (s[7] == 'a') && (s[8] == 's') && (s[9] == 'e') && (s[10] == ':')))) { retain = NIL; /* don't retain continuation */ if ((nmsgs == 1) && !stream->uid_validity) { /* advance to data */ s += m ? 7 : 11; /* flush whitespace */ while (*s == ' ') s++; j = 0; /* slurp UID validity */ /* found a digit? */ while (isdigit (*s)) { j *= 10; /* yes, add it in */ j += *s++ - '0'; } /* flush whitespace */ while (*s == ' ') s++; /* must have valid UID validity and UID last */ if (j && isdigit (*s)) { /* pseudo-header seen if X-IMAP */ if (m) pseudoseen = LOCAL->pseudo = T; /* save UID validity */ stream->uid_validity = j; j = 0; /* slurp UID last */ while (isdigit (*s)) { j *= 10; /* yes, add it in */ j += *s++ - '0'; } /* save UID last */ stream->uid_last = j; /* process keywords */ for (j = 0; (*s != '\n') && ((*s != '\r')||(s[1] != '\n')); s = u,j++) { /* flush leading whitespace */ while (*s == ' ') s++; u = strpbrk (s," \n\r"); /* got a keyword? */ if ((j < NUSERFLAGS) && (k = (u - s)) && (k <= MAXUSERFLAG)) { if (stream->user_flags[j]) fs_give ((void **) &stream->user_flags[j]); stream->user_flags[j] = (char *) fs_get (k + 1); strncpy (stream->user_flags[j],s,k); stream->user_flags[j][k] = '\0'; } } } } break; } /* possible X-UID */ else if (s[2] == 'U' && s[3] == 'I' && s[4] == 'D' && s[5] == ':') { retain = NIL; /* don't retain continuation */ /* only believe if have a UID validity */ if (stream->uid_validity && ((nmsgs > 1) || !pseudoseen)) { s += 6; /* advance to UID value */ /* flush whitespace */ while (*s == ' ') s++; j = 0; /* found a digit? */ while (isdigit (*s)) { j *= 10; /* yes, add it in */ j += *s++ - '0'; } /* flush remainder of line */ while (*s != '\n') s++; /* make sure not duplicated */ if (elt->private.uid) sprintf (tmp,"Message %lu UID %lu already has UID %lu", pseudoseen ? elt->msgno - 1 : elt->msgno, j,elt->private.uid); /* make sure UID doesn't go backwards */ else if (j <= prevuid) sprintf (tmp,"Message %lu UID %lu less than %lu", pseudoseen ? elt->msgno - 1 : elt->msgno, j,prevuid + 1); #if 0 /* this is currently broken by UIDPLUS */ /* or skip by mailbox's recorded last */ else if (j > stream->uid_last) sprintf (tmp,"Message %lu UID %lu greater than last %lu", pseudoseen ? elt->msgno - 1 : elt->msgno, j,stream->uid_last); #endif else { /* normal UID case */ prevuid = elt->private.uid = j; #if 1 /* temporary kludge for UIDPLUS */ if (prevuid > stream->uid_last) { stream->uid_last = prevuid; LOCAL->ddirty = LOCAL->dirty = T; } #endif break; /* exit this cruft */ } mm_log (tmp,WARN); /* invalidate UID validity */ stream->uid_validity = 0; elt->private.uid = 0; } break; } } /* otherwise fall into S case */ case 'S': /* possible Status: line */ if (s[0] == 'S' && s[1] == 't' && s[2] == 'a' && s[3] == 't' && s[4] == 'u' && s[5] == 's' && s[6] == ':') { retain = NIL; /* don't retain continuation */ s += 6; /* advance to status flags */ do switch (*s++) {/* parse flags */ case 'R': /* message read */ elt->seen = T; break; case 'O': /* message old */ if (elt->recent) { elt->recent = NIL; recent--; /* it really wasn't recent */ } break; case 'D': /* message deleted */ elt->deleted = T; break; case 'F': /* message flagged */ elt->flagged = T; break; case 'A': /* message answered */ elt->answered = T; break; case 'T': /* message is a draft */ elt->draft = T; break; default: /* some other crap */ break; } while (*s && (*s != '\n') && ((*s != '\r') || (s[1] != '\n'))); break; /* all done */ } /* otherwise fall into default case */ default: /* ordinary header line */ if ((*s == 'S') || (*s == 's') || (((*s == 'X') || (*s == 'x')) && (s[1] == '-'))) { unsigned char *e,*v; /* must match what mail_filter() does */ for (u = s,v = tmp,e = u + min (i,MAILTMPLEN - 1); (u < e) && ((c = (*u ? *u : (*u = ' '))) != ':') && ((c > ' ') || ((c != ' ') && (c != '\t') && (c != '\r') && (c != '\n'))); *v++ = *u++); *v = '\0'; /* tie off */ /* matches internal header? */ if (!compare_cstring (tmp,"STATUS") || !compare_cstring (tmp,"X-STATUS") || !compare_cstring (tmp,"X-KEYWORDS") || !compare_cstring (tmp,"X-UID") || !compare_cstring (tmp,"X-IMAP") || !compare_cstring (tmp,"X-IMAPBASE")) { char err[MAILTMPLEN]; sprintf (err,"Discarding bogus %s header in message %lu", (char *) tmp,elt->msgno); mm_log (err,WARN); retain = NIL; /* don't retain continuation */ break; /* different case or something */ } } /* retain or non-continuation? */ if (retain || ((*s != ' ') && (*s != '\t'))) { retain = T; /* retaining continuation now */ /* line length in CRLF format newline */ k = i + (((i < 2) || (s[i - 2] != '\r')) ? 1 : 0); /* header size */ elt->rfc822_size = elt->private.spare.data += k; } else { char err[MAILTMPLEN]; sprintf (err,"Discarding bogus continuation in msg %lu: %.80s", elt->msgno,(char *) s); if (u = strpbrk (err,"\r\n")) *u = '\0'; mm_log (err,WARN); break; /* different case or something */ } break; } } while (i && (*t != '\n') && ((*t != '\r') || (t[1] != '\n'))); /* "internal" header sans trailing newline */ if (i) elt->private.spare.data -= 2; /* assign a UID if none found */ if (((nmsgs > 1) || !pseudoseen) && !elt->private.uid) { prevuid = elt->private.uid = ++stream->uid_last; elt->private.dirty = T; LOCAL->ddirty = T; /* force update */ } else elt->private.dirty = elt->recent; /* note size of header, location of text */ elt->private.msg.header.text.size = (elt->private.msg.text.offset = (LOCAL->filesize + GETPOS (&bs)) - elt->private.special.offset) - elt->private.special.text.size; k = m = 0; /* no previous line size yet */ /* note current position */ j = LOCAL->filesize + GETPOS (&bs); if (i) do { /* look for next message */ s = unix_mbxline (stream,&bs,&i); if (i) { /* got new data? */ VALID (s,t,ti,zn); /* yes, parse line */ if (!ti) { /* not a header line, add it to message */ if (s[i - 1] == '\n') elt->rfc822_size += k = i + (m = (((i < 2) || s[i - 2] != '\r') ? 1 : 0)); else { /* file does not end with newline! */ elt->rfc822_size += i; k = m = 0; } /* update current position */ j = LOCAL->filesize + GETPOS (&bs); } } } while (i && !ti); /* until found a header */ elt->private.msg.text.text.size = j - (elt->private.special.offset + elt->private.msg.text.offset); if (k == 2) { /* last line was blank? */ elt->private.msg.text.text.size -= (m ? 1 : 2); elt->rfc822_size -= 2; } /* until end of buffer */ } while (!stream->sniff && i); if (pseudoseen) { /* flush pseudo-message if present */ /* decrement recent count */ if (mail_elt (stream,1)->recent) recent--; /* and the exists count */ mail_exists (stream,nmsgs--); mail_expunged(stream,1);/* fake an expunge of that message */ } /* need to start a new UID validity? */ if (!stream->uid_validity) { stream->uid_validity = (unsigned long) time (0); if (nmsgs) { /* don't bother if empty file */ /* make dirty to restart UID epoch */ LOCAL->ddirty = LOCAL->dirty = T; /* need to rewrite msg 1 if not pseudo */ if (!LOCAL->pseudo) mail_elt (stream,1)->private.dirty = T; mm_log ("Assigning new unique identifiers to all messages",NIL); } } stream->nmsgs = oldnmsgs; /* whack it back down */ stream->silent = silent; /* restore old silent setting */ /* notify upper level of new mailbox sizes */ mail_exists (stream,nmsgs); mail_recent (stream,recent); /* mark dirty so O flags are set */ if (recent) LOCAL->dirty = T; } } /* no change, don't babble if never got time */ else if (LOCAL->filetime && LOCAL->filetime != sbuf.st_mtime) mm_log ("New mailbox modification time but apparently no changes",WARN); /* update parsed file size and time */ LOCAL->filesize = sbuf.st_size; LOCAL->filetime = sbuf.st_mtime; return T; /* return the winnage */ } /* UNIX read line from mailbox * Accepts: mail stream * stringstruct * pointer to line size * Returns: pointer to input line */ char *unix_mbxline (MAILSTREAM *stream,STRING *bs,unsigned long *size) { unsigned long i,j,k,m; char *s,*t,*te; char *ret = ""; /* flush old buffer */ if (LOCAL->line) fs_give ((void **) &LOCAL->line); /* if buffer needs refreshing */ if (!bs->cursize) SETPOS (bs,GETPOS (bs)); if (SIZE (bs)) { /* find newline */ /* end of fast scan */ te = (t = (s = bs->curpos) + bs->cursize) - 12; while (s < te) if ((*s++ == '\n') || (*s++ == '\n') || (*s++ == '\n') || (*s++ == '\n') || (*s++ == '\n') || (*s++ == '\n') || (*s++ == '\n') || (*s++ == '\n') || (*s++ == '\n') || (*s++ == '\n') || (*s++ == '\n') || (*s++ == '\n')) { --s; /* back up */ break; /* exit loop */ } /* final character-at-a-time scan */ while ((s < t) && (*s != '\n')) ++s; /* difficult case if line spans buffer */ if ((i = s - bs->curpos) == bs->cursize) { /* have space in line buffer? */ if (i > LOCAL->linebuflen) { fs_give ((void **) &LOCAL->linebuf); LOCAL->linebuf = (char *) fs_get (LOCAL->linebuflen = i); } /* remember what we have so far */ memcpy (LOCAL->linebuf,bs->curpos,i); /* load next buffer */ SETPOS (bs,k = GETPOS (bs) + i); /* end of fast scan */ te = (t = (s = bs->curpos) + bs->cursize) - 12; /* fast scan in overlap buffer */ while (s < te) if ((*s++ == '\n') || (*s++ == '\n') || (*s++ == '\n') || (*s++ == '\n') || (*s++ == '\n') || (*s++ == '\n') || (*s++ == '\n') || (*s++ == '\n') || (*s++ == '\n') || (*s++ == '\n') || (*s++ == '\n') || (*s++ == '\n')) { --s; /* back up */ break; /* exit loop */ } /* final character-at-a-time scan */ while ((s < t) && (*s != '\n')) ++s; /* huge line? */ if ((j = s - bs->curpos) == bs->cursize) { SETPOS (bs,GETPOS (bs) + j); /* look for end of line (s-l-o-w!!) */ for (m = SIZE (bs); m && (SNX (bs) != '\n'); --m,++j); SETPOS (bs,k); /* go back to where it started */ } /* got size of data, make buffer for return */ ret = LOCAL->line = (char *) fs_get (i + j + 2); /* copy first chunk */ memcpy (ret,LOCAL->linebuf,i); while (j) { /* copy remainder */ if (!bs->cursize) SETPOS (bs,GETPOS (bs)); memcpy (ret + i,bs->curpos,k = min (j,bs->cursize)); i += k; /* account for this much read in */ j -= k; bs->curpos += k; /* increment new position */ bs->cursize -= k; /* eat that many bytes */ } if (!bs->cursize) SETPOS (bs,GETPOS (bs)); /* read newline at end */ if (SIZE (bs)) ret[i++] = SNX (bs); ret[i] = '\0'; /* makes debugging easier */ } else { /* this is easy */ ret = bs->curpos; /* string it at this position */ bs->curpos += ++i; /* increment new position */ bs->cursize -= i; /* eat that many bytes */ } *size = i; /* return that to user */ } else *size = 0; /* end of data, return empty */ return ret; } /* UNIX make pseudo-header * Accepts: MAIL stream * buffer to write pseudo-header * Returns: length of pseudo-header */ unsigned long unix_pseudo (MAILSTREAM *stream,char *hdr) { int i; char *s,*t,tmp[MAILTMPLEN]; time_t now = time(0); rfc822_fixed_date (tmp); sprintf (hdr,"From %s %.24s\r\nDate: %s\r\nFrom: %s <%s@%.80s>\r\nSubject: %s\r\nMessage-ID: <%lu@%.80s>\r\nX-IMAP: %010ld %010ld", pseudo_from,ctime (&now), tmp,pseudo_name,pseudo_from,mylocalhost (),pseudo_subject, (unsigned long) now,mylocalhost (),stream->uid_validity, stream->uid_last); for (t = hdr + strlen (hdr),i = 0; i < NUSERFLAGS; ++i) if (stream->user_flags[i]) sprintf (t += strlen (t)," %s",stream->user_flags[i]); strcpy (t += strlen (t),"\r\nStatus: RO\r\n\r\n"); for (s = pseudo_msg,t += strlen (t); *s; *t++ = *s++) if (*s == '\n') *t++ = '\r'; *t++ = '\r'; *t++ = '\n'; *t++ = '\r'; *t++ = '\n'; *t = '\0'; /* tie off pseudo header */ return t - hdr; /* return length of pseudo header */ } /* UNIX make status string * Accepts: MAIL stream * destination string to write * message cache entry * UID to write if non-zero (else use elt->private.uid) * non-zero flag to write UID (.LT. 0 to write UID base info too) * Returns: length of string */ unsigned long unix_xstatus (MAILSTREAM *stream,char *status,MESSAGECACHE *elt, unsigned long uid,long flag) { char *t,stack[64]; char *s = status; unsigned long n; unsigned long pad = 50; /* This used to use sprintf(), but thanks to certain cretinous C libraries with horribly slow implementations of sprintf() I had to change it to this mess. At least it should be fast. */ *s++ = 'S'; *s++ = 't'; *s++ = 'a'; *s++ = 't'; *s++ = 'u'; *s++ = 's'; *s++ = ':'; *s++ = ' '; if (elt->seen) *s++ = 'R'; /* only write O if have a UID */ if (flag && (!elt->recent || LOCAL->appending)) *s++ = 'O'; *s++ = '\r'; *s++ = '\n'; *s++ = 'X'; *s++ = '-'; *s++ = 'S'; *s++ = 't'; *s++ = 'a'; *s++ = 't'; *s++ = 'u'; *s++ = 's'; *s++ = ':'; *s++ = ' '; if (elt->deleted) *s++ = 'D'; if (elt->flagged) *s++ = 'F'; if (elt->answered) *s++ = 'A'; if (elt->draft) *s++ = 'T'; *s++ = '\r'; *s++ = '\n'; *s++ = 'X'; *s++ = '-'; *s++ = 'K'; *s++ = 'e'; *s++ = 'y'; *s++ = 'w'; *s++ = 'o'; *s++ = 'r'; *s++ = 'd'; *s++ = 's'; *s++ = ':'; if (n = elt->user_flags) do { *s++ = ' '; for (t = stream->user_flags[find_rightmost_bit (&n)]; *t; *s++ = *t++); } while (n); n = s - status; /* get size of stuff so far */ /* pad X-Keywords to make size constant */ if (n < pad) for (n = pad - n; n > 0; --n) *s++ = ' '; *s++ = '\r'; *s++ = '\n'; if (flag) { /* want to include UID? */ t = stack; /* push UID digits on the stack */ n = uid ? uid : elt->private.uid; do *t++ = (char) (n % 10) + '0'; while (n /= 10); *s++ = 'X'; *s++ = '-'; *s++ = 'U'; *s++ = 'I'; *s++ = 'D'; *s++ = ':'; *s++ = ' '; /* pop UID from stack */ while (t > stack) *s++ = *--t; *s++ = '\r'; *s++ = '\n'; } /* end of extended message status */ *s++ = '\r'; *s++ = '\n'; *s = '\0'; return s - status; /* return size of resulting string */ } /* Rewrite mailbox file * Accepts: MAIL stream, must be critical and locked * return pointer to number of expunged messages if want expunge * lock file name * expunge sequence, not deleted flag * Returns: T if success and mailbox unlocked, NIL if failure */ #define OVERFLOWBUFLEN 8192 /* initial overflow buffer length */ long unix_rewrite (MAILSTREAM *stream,unsigned long *nexp,char *lock, long flags) { MESSAGECACHE *elt; UNIXFILE f; char *s; struct utimbuf times; long ret,flag; unsigned long i,j; unsigned long recent = stream->recent; unsigned long size = LOCAL->pseudo ? unix_pseudo (stream,LOCAL->buf) : 0; if (nexp) *nexp = 0; /* initially nothing expunged */ /* calculate size of mailbox after rewrite */ for (i = 1,flag = LOCAL->pseudo ? 1 : -1; i <= stream->nmsgs; i++) { elt = mail_elt (stream,i); /* get cache */ if (!(nexp && elt->deleted && (flags ? elt->sequence : T))) { /* add RFC822 size of this message */ size += elt->private.special.text.size + elt->private.spare.data + unix_xstatus (stream,LOCAL->buf,elt,NIL,flag) + elt->private.msg.text.text.size + 2; flag = 1; /* only count X-IMAPbase once */ } } if (!size) { /* no messages and no pseudo, make one now */ size = unix_pseudo (stream,LOCAL->buf); LOCAL->pseudo = T; } /* extend the file as necessary */ if (ret = unix_extend (stream,size)) { /* Set up buffered I/O file structure * curpos current position being written through buffering * filepos current position being written physically to the disk * bufpos current position being written in the buffer * protect current maximum position that can be written to the disk * before buffering is forced * The code tries to buffer so that that disk is written in multiples of * OVERBLOWBUFLEN bytes. */ f.stream = stream; /* note mail stream */ f.curpos = f.filepos = 0; /* start of file */ f.protect = stream->nmsgs ? /* initial protection pointer */ mail_elt (stream,1)->private.special.offset : 8192; f.bufpos = f.buf = (char *) fs_get (f.buflen = OVERFLOWBUFLEN); if (LOCAL->pseudo) /* update pseudo-header */ unix_write (&f,LOCAL->buf,unix_pseudo (stream,LOCAL->buf)); /* loop through all messages */ for (i = 1,flag = LOCAL->pseudo ? 1 : -1; i <= stream->nmsgs;) { elt = mail_elt (stream,i);/* get cache */ /* expunge this message? */ if (nexp && elt->deleted && (flags ? elt->sequence : T)) { /* one less recent message */ if (elt->recent) --recent; mail_expunged(stream,i);/* notify upper levels */ ++*nexp; /* count up one more expunged message */ } else { /* preserve this message */ i++; /* advance to next message */ if ((flag < 0) || /* need to rewrite message? */ elt->private.dirty || (((unsigned long) f.curpos) != elt->private.special.offset) || (elt->private.msg.header.text.size != (elt->private.spare.data + unix_xstatus (stream,LOCAL->buf,elt,NIL,flag)))) { unsigned long newoffset = f.curpos; /* yes, seek to internal header */ lseek (LOCAL->fd,elt->private.special.offset,L_SET); read (LOCAL->fd,LOCAL->buf,elt->private.special.text.size); /* protection pointer moves to RFC822 header */ f.protect = elt->private.special.offset + elt->private.msg.header.offset; /* write internal header */ unix_write (&f,LOCAL->buf,elt->private.special.text.size); /* get RFC822 header */ s = unix_header (stream,elt->msgno,&j,NIL); /* in case this got decremented */ elt->private.msg.header.offset = elt->private.special.text.size; /* header size, sans trailing newline */ if ((j < 4) || (s[j - 4] == '\r')) j -= 2; if (j != elt->private.spare.data) fatal ("header size inconsistent"); /* protection pointer moves to RFC822 text */ f.protect = elt->private.special.offset + elt->private.msg.text.offset; unix_write (&f,s,j); /* write RFC822 header */ /* write status and UID */ unix_write (&f,LOCAL->buf, j = unix_xstatus (stream,LOCAL->buf,elt,NIL,flag)); flag = 1; /* only write X-IMAPbase once */ /* new file header size */ elt->private.msg.header.text.size = elt->private.spare.data + j; /* did text move? */ if (f.curpos != f.protect) { /* get message text */ s = unix_text_work (stream,elt,&j,FT_INTERNAL); /* can't happen it says here */ if (j > elt->private.msg.text.text.size) fatal ("text size inconsistent"); /* new text offset, status/UID may change it */ elt->private.msg.text.offset = f.curpos - newoffset; /* protection pointer moves to next message */ f.protect = (i <= stream->nmsgs) ? mail_elt (stream,i)->private.special.offset : (f.curpos + j + 2); unix_write (&f,s,j);/* write text */ /* write trailing newline */ unix_write (&f,"\r\n",2); } else { /* tie off header and status */ unix_write (&f,NIL,NIL); /* protection pointer moves to next message */ f.protect = (i <= stream->nmsgs) ? mail_elt (stream,i)->private.special.offset : size; /* locate end of message text */ j = f.filepos + elt->private.msg.text.text.size; /* trailing newline already there? */ if (f.protect == (off_t) (j + 2)) f.curpos = f.filepos = f.protect; else { /* trailing newline missing, write it */ f.curpos = f.filepos = j; unix_write (&f,"\r\n",2); } } /* new internal header offset */ elt->private.special.offset = newoffset; elt->private.dirty =NIL;/* message is now clean */ } else { /* no need to rewrite this message */ /* tie off previous message if needed */ unix_write (&f,NIL,NIL); /* protection pointer moves to next message */ f.protect = (i <= stream->nmsgs) ? mail_elt (stream,i)->private.special.offset : size; /* locate end of message text */ j = f.filepos + elt->private.special.text.size + elt->private.msg.header.text.size + elt->private.msg.text.text.size; /* trailing newline already there? */ if (f.protect == (off_t) (j + 2)) f.curpos = f.filepos = f.protect; else { /* trailing newline missing, write it */ f.curpos = f.filepos = j; unix_write (&f,"\r\n",2); } } } } unix_write (&f,NIL,NIL); /* tie off final message */ if (size != ((unsigned long) f.filepos)) fatal ("file size inconsistent"); fs_give ((void **) &f.buf); /* free buffer */ /* make sure tied off */ ftruncate (LOCAL->fd,LOCAL->filesize = size); fsync (LOCAL->fd); /* make sure the updates take */ if (size && (flag < 0)) fatal ("lost UID base information"); /* no longer dirty */ LOCAL->ddirty = LOCAL->dirty = NIL; /* notify upper level of new mailbox sizes */ mail_exists (stream,stream->nmsgs); mail_recent (stream,recent); /* set atime to now, mtime a second earlier */ times.modtime = (times.actime = time (0)) -1; /* set the times, note change */ if (!utime (stream->mailbox,×)) LOCAL->filetime = times.modtime; /* flush the lock file */ unix_unlock (LOCAL->fd,stream,lock); } return ret; /* return state from algorithm */ } /* Extend UNIX mailbox file * Accepts: MAIL stream * new desired size * Return: T if success, else NIL */ long unix_extend (MAILSTREAM *stream,unsigned long size) { unsigned long i = (size > ((unsigned long) LOCAL->filesize)) ? size - ((unsigned long) LOCAL->filesize) : 0; if (i) { /* does the mailbox need to grow? */ if (i > LOCAL->buflen) { /* make sure have enough space */ /* this user won the lottery all right */ fs_give ((void **) &LOCAL->buf); LOCAL->buf = (char *) fs_get ((LOCAL->buflen = i) + 1); } memset (LOCAL->buf,'\0',i); /* get a block of nulls */ while (T) { /* until write successful or punt */ lseek (LOCAL->fd,LOCAL->filesize,L_SET); if ((write (LOCAL->fd,LOCAL->buf,i) >= 0) && !fsync (LOCAL->fd)) break; else { long e = errno; /* note error before doing ftruncate */ ftruncate (LOCAL->fd,LOCAL->filesize); if (mm_diskerror (stream,e,NIL)) { fsync (LOCAL->fd); /* user chose to punt */ sprintf (LOCAL->buf,"Unable to extend mailbox: %s",strerror (e)); if (!stream->silent) mm_log (LOCAL->buf,ERROR); return NIL; } } } } return LONGT; } /* Write data to buffered file * Accepts: buffered file pointer * file data or NIL to indicate "flush buffer" * date size (ignored for "flush buffer") * Does not return until success */ void unix_write (UNIXFILE *f,char *buf,unsigned long size) { unsigned long i,j,k; if (buf) { /* doing buffered write? */ i = f->bufpos - f->buf; /* yes, get size of current buffer data */ /* yes, have space in current buffer chunk? */ if (j = i ? ((f->buflen - i) % OVERFLOWBUFLEN) : f->buflen) { /* yes, fill up buffer as much as we can */ memcpy (f->bufpos,buf,k = min (j,size)); f->bufpos += k; /* new buffer position */ f->curpos += k; /* new current position */ if (j -= k) return; /* all done if still have buffer free space */ buf += k; /* full, get new unwritten data pointer */ size -= k; /* new data size */ i += k; /* new buffer data size */ } /* This chunk of the buffer is full. See if can make some space by * writing to the disk, if there's enough unprotected space to do so. * Try to fill out any unaligned chunk, along with any subsequent full * chunks that will fit in unprotected space. */ /* any unprotected space we can write to? */ if (j = min (i,f->protect - f->filepos)) { /* yes, filepos not at chunk boundary? */ if ((k = f->filepos % OVERFLOWBUFLEN) && ((k = OVERFLOWBUFLEN - k) < j)) j -= k; /* yes, and can write out partial chunk */ else k = 0; /* no partial chunk to write */ /* if at least a chunk free, write that too */ if (j > OVERFLOWBUFLEN) k += j - (j % OVERFLOWBUFLEN); if (k) { /* write data if there is anything we can */ unix_phys_write (f,f->buf,k); /* slide buffer */ if (i -= k) memmove (f->buf,f->buf + k,i); f->bufpos = f->buf + i; /* new end of buffer */ } } /* Have flushed the buffer as best as possible. All done if no more * data to write. Otherwise, if the buffer is empty AND if the unwritten * data is larger than a chunk AND the unprotected space is also larger * than a chunk, then write as many chunks as we can directly from the * data. Buffer the rest, expanding the buffer as needed. */ if (size) { /* have more data that we need to buffer? */ /* can write any of it to disk instead? */ if ((f->bufpos == f->buf) && ((j = min (f->protect - f->filepos,size)) > OVERFLOWBUFLEN)) { /* write as much as we can right now */ unix_phys_write (f,buf,j -= (j % OVERFLOWBUFLEN)); buf += j; /* new data pointer */ size -= j; /* new data size */ f->curpos += j; /* advance current pointer */ } if (size) { /* still have data that we need to buffer? */ /* yes, need to expand the buffer? */ if ((i = ((f->bufpos + size) - f->buf)) > f->buflen) { /* note current position in buffer */ j = f->bufpos - f->buf; i += OVERFLOWBUFLEN; /* yes, grow another chunk */ fs_resize ((void **) &f->buf,f->buflen = i - (i % OVERFLOWBUFLEN)); /* in case buffer relocated */ f->bufpos = f->buf + j; } /* buffer remaining data */ memcpy (f->bufpos,buf,size); f->bufpos += size; /* new end of buffer */ f->curpos += size; /* advance current pointer */ } } } else { /* flush buffer to disk */ unix_phys_write (f,f->buf,i = f->bufpos - f->buf); f->bufpos = f->buf; /* reset buffer */ /* update positions */ f->curpos = f->protect = f->filepos; } } /* Physical disk write * Accepts: buffered file pointer * buffer address * buffer size * Does not return until success */ void unix_phys_write (UNIXFILE *f,char *buf,size_t size) { MAILSTREAM *stream = f->stream; /* write data at desired position */ while (size && ((lseek (LOCAL->fd,f->filepos,L_SET) < 0) || (write (LOCAL->fd,buf,size) < 0))) { int e; char tmp[MAILTMPLEN]; sprintf (tmp,"Unable to write to mailbox: %s",strerror (e = errno)); mm_log (tmp,ERROR); mm_diskerror (NIL,e,T); /* serious problem, must retry */ } f->filepos += size; /* update file position */ } alpine-2.10+dfsg/imap/src/osdep/nt/makefile.ntk0000600000175000017500000000662111512502123023103 0ustar paulproteuspaulproteus# ======================================================================== # Copyright 1988-2007 University of Washington # # Licensed under the Apache License, Version 2.0 (the "License"); # you may not use this file except in compliance with the License. # You may obtain a copy of the License at # # http://www.apache.org/licenses/LICENSE-2.0 # # # ======================================================================== # Program: Portable C client makefile -- NT version + Kerberos # # Author: Mark Crispin # Networks and Distributed Computing # Computing & Communications # University of Washington # Administration Building, AG-44 # Seattle, WA 98195 # Internet: MRC@CAC.Washington.EDU # # Date: 11 May 1989 # Last Edited: 23 May 2007 EXTRAAUTHENTICATORS = EXTRADRIVERS = EXTRACFLAGS = AUTHENTICATORS = ext gss md5 pla log DRIVERS = imap nntp pop3 mbx mtx tenex unix CREATEDRIVER = mbx APPENDDRIVER = unix OSCOMPAT = /DWIN32 /D_WIN32_WINNT=0x0400 /I\k5\include VSCOMPAT = /D_CRT_SECURE_NO_DEPRECATE /D_CRT_NONSTDC_NO_DEPRECATE CFLAGS = /MT /W3 /Ox /DCHUNKSIZE=65536 $(OSCOMPAT) $(VSCOMPAT) -nologo /I.. $(EXTRACFLAGS) CC = cl CCLIENTLIB = cclient.lib all: $(CCLIENTLIB) .c.obj: $(CC) -c $(CFLAGS) $*.c osdep.h: os_nt.h copy os_nt.h osdep.h drivers $(EXTRADRIVERS) $(DRIVERS) dummy setproto $(CREATEDRIVER) $(APPENDDRIVER) echo ssl_onceonlyinit (); >> linkage.c mkauths $(EXTRAAUTHENTICATORS) $(AUTHENTICATORS) echo mail_versioncheck (CCLIENTVERSION); >> linkage.c ip_nt.c: ip4_nt.c copy ip4_nt.c ip_nt.c mail.obj: mail.h misc.h osdep.h mail.c misc.obj: mail.h misc.h misc.c fdstring.obj: mail.h misc.h osdep.h fdstring.h fdstring.c flstring.obj: mail.h misc.h osdep.h flstring.h flstring.c netmsg.obj: mail.h misc.h netmsg.h osdep.h netmsg.c newsrc.obj: mail.h misc.h newsrc.h osdep.h newsrc.c rfc822.obj: mail.h rfc822.h misc.h rfc822.c smanager.obj: mail.h misc.h smanager.c utf8.obj: mail.h misc.h osdep.h utf8.h utf8aux.obj: mail.h misc.h osdep.h utf8.h imap4r1.obj: mail.h imap4r1.h misc.h osdep.h imap4r1.c nntp.obj: mail.h nntp.h smtp.h rfc822.h misc.h osdep.h nntp.c pop3.obj: mail.h rfc822.h misc.h osdep.h pop3.c smtp.obj: mail.h smtp.h rfc822.h misc.h osdep.h smtp.c os_ntk.obj: mail.h osdep.h env_nt.h fs.h ftl.h nl.h tcp.h tcp_nt.h yunchan.h \ os_ntk.c fs_nt.c ftl_nt.c nl_nt.c env_nt.c ssl_nt.c ssl_none.c \ ip_nt.c tcp_nt.c yunchan.c pmatch.c write.c \ mailfile.h auth_gss.c auth_md5.c auth_pla.c auth_log.c kerb_mit.c mbxnt.obj: mail.h misc.h osdep.h mbxnt.c mtxnt.obj: mail.h misc.h osdep.h mtxnt.c tenexnt.obj: mail.h misc.h osdep.h tenexnt.c unixnt.obj: mail.h unixnt.h pseudo.h misc.h osdep.h unixnt.c dummynt.obj: mail.h dummy.h misc.h osdep.h dummynt.c pseudo.obj: pseudo.h $(CCLIENTLIB): mail.obj misc.obj fdstring.obj flstring.obj netmsg.obj \ newsrc.obj rfc822.obj smanager.obj utf8.obj utf8aux.obj \ imap4r1.obj nntp.obj pop3.obj smtp.obj os_ntk.obj \ mbxnt.obj mtxnt.obj tenexnt.obj unixnt.obj dummynt.obj pseudo.obj if exist $(CCLIENTLIB) del $(CCLIENTLIB) LIB /NOLOGO /OUT:cclient.lib \ mail.obj misc.obj fdstring.obj flstring.obj netmsg.obj \ newsrc.obj rfc822.obj smanager.obj utf8.obj utf8aux.obj \ imap4r1.obj nntp.obj pop3.obj smtp.obj os_ntk.obj \ mbxnt.obj mtxnt.obj tenexnt.obj unixnt.obj dummynt.obj pseudo.obj clean: del *.lib *.obj linkage.* osdep.* ip_nt.c auths.c *.exe *.exp || rem # A monument to a hack of long ago and far away... love: @echo not war? alpine-2.10+dfsg/imap/src/osdep/nt/env_nt.c0000600000175000017500000005455011512502123022251 0ustar paulproteuspaulproteus/* ======================================================================== * Copyright 1988-2008 University of Washington * * Licensed under the Apache License, Version 2.0 (the "License"); * you may not use this file except in compliance with the License. * You may obtain a copy of the License at * * http://www.apache.org/licenses/LICENSE-2.0 * * * ======================================================================== */ /* * Program: NT environment routines * * Author: Mark Crispin * UW Technology * University of Washington * Seattle, WA 98195 * Internet: MRC@Washington.EDU * * Date: 1 August 1988 * Last Edited: 15 February 2008 */ static char *myUserName = NIL; /* user name */ static char *myLocalHost = NIL; /* local host name */ static char *myHomeDir = NIL; /* home directory name */ static char *myNewsrc = NIL; /* newsrc file name */ static char *sysInbox = NIL; /* system inbox name */ static long list_max_level = 5; /* maximum level of list recursion */ /* block environment init */ static short block_env_init = NIL; static short no822tztext = NIL; /* disable RFC [2]822 timezone text */ /* home namespace */ static NAMESPACE nshome = {"",'\\',NIL,NIL}; /* UNIX other user namespace */ static NAMESPACE nsother = {"#user.",'\\',NIL,NIL}; /* namespace list */ static NAMESPACE *nslist[3] = {&nshome,&nsother,NIL}; static long alarm_countdown = 0;/* alarm count down */ static void (*alarm_rang) (); /* alarm interrupt function */ static unsigned int rndm = 0; /* initial `random' number */ static int server_nli = 0; /* server and not logged in */ static int logtry = 3; /* number of login tries */ /* block notification */ static blocknotify_t mailblocknotify = mm_blocknotify; /* callback to get username */ static userprompt_t mailusername = NIL; static long is_nt = -1; /* T if NT, NIL if not NT, -1 unknown */ static HINSTANCE netapi = NIL; typedef NET_API_STATUS (CALLBACK *GETINFO) (LPCWSTR,LPCWSTR,DWORD,LPBYTE *); static GETINFO getinfo = NIL; #include "write.c" /* include safe writing routines */ #include "pmatch.c" /* include wildcard pattern matcher */ /* Get all authenticators */ #include "auths.c" /* Environment manipulate parameters * Accepts: function code * function-dependent value * Returns: function-dependent return value */ void *env_parameters (long function,void *value) { void *ret = NIL; switch ((int) function) { case GET_NAMESPACE: ret = (void *) nslist; break; case SET_USERPROMPT : mailusername = (userprompt_t) value; case GET_USERPROMPT : ret = (void *) mailusername; break; case SET_HOMEDIR: if (myHomeDir) fs_give ((void **) &myHomeDir); myHomeDir = cpystr ((char *) value); case GET_HOMEDIR: ret = (void *) myHomeDir; break; case SET_LOCALHOST: myLocalHost = cpystr ((char *) value); case GET_LOCALHOST: if (myLocalHost) fs_give ((void **) &myLocalHost); ret = (void *) myLocalHost; break; case SET_NEWSRC: if (myNewsrc) fs_give ((void **) &myNewsrc); myNewsrc = cpystr ((char *) value); case GET_NEWSRC: if (!myNewsrc) { /* set news file name if not defined */ char tmp[MAILTMPLEN]; sprintf (tmp,"%s\\NEWSRC",myhomedir ()); myNewsrc = cpystr (tmp); } ret = (void *) myNewsrc; break; case SET_SYSINBOX: if (sysInbox) fs_give ((void **) &sysInbox); sysInbox = cpystr ((char *) value); case GET_SYSINBOX: ret = (void *) sysInbox; break; case SET_LISTMAXLEVEL: list_max_level = (long) value; case GET_LISTMAXLEVEL: ret = (void *) list_max_level; break; case SET_DISABLE822TZTEXT: no822tztext = value ? T : NIL; case GET_DISABLE822TZTEXT: ret = (void *) (no822tztext ? VOIDT : NIL); break; case SET_BLOCKENVINIT: block_env_init = value ? T : NIL; case GET_BLOCKENVINIT: ret = (void *) (block_env_init ? VOIDT : NIL); break; case SET_BLOCKNOTIFY: mailblocknotify = (blocknotify_t) value; case GET_BLOCKNOTIFY: ret = (void *) mailblocknotify; break; } return ret; } /* Write current time * Accepts: destination string * optional format of day-of-week prefix * format of date and time * flag whether to append symbolic timezone */ static void do_date (char *date,char *prefix,char *fmt,int suffix) { time_t tn = time (0); struct tm *t = gmtime (&tn); int zone = t->tm_hour * 60 + t->tm_min; int julian = t->tm_yday; t = localtime (&tn); /* get local time now */ /* minus UTC minutes since midnight */ zone = t->tm_hour * 60 + t->tm_min - zone; /* julian can be one of: * 36x local time is December 31, UTC is January 1, offset -24 hours * 1 local time is 1 day ahead of UTC, offset +24 hours * 0 local time is same day as UTC, no offset * -1 local time is 1 day behind UTC, offset -24 hours * -36x local time is January 1, UTC is December 31, offset +24 hours */ if (julian = t->tm_yday -julian) zone += ((julian < 0) == (abs (julian) == 1)) ? -24*60 : 24*60; if (prefix) { /* want day of week? */ sprintf (date,prefix,days[t->tm_wday]); date += strlen (date); /* make next sprintf append */ } /* output the date */ sprintf (date,fmt,t->tm_mday,months[t->tm_mon],t->tm_year+1900, t->tm_hour,t->tm_min,t->tm_sec,zone/60,abs (zone) % 60); if (suffix) { /* append timezone suffix if desired */ char *tz; tzset (); /* get timezone from TZ environment stuff */ tz = tzname[daylight ? (((struct tm *) t)->tm_isdst > 0) : 0]; if (tz && tz[0]) { char *s; for (s = tz; *s; s++) if (*s & 0x80) return; sprintf (date + strlen (date)," (%.50s)",tz); } } } /* Write current time in RFC 822 format * Accepts: destination string */ void rfc822_date (char *date) { do_date (date,"%s, ","%d %s %d %02d:%02d:%02d %+03d%02d", no822tztext ? NIL : T); } /* Write current time in fixed-width RFC 822 format * Accepts: destination string */ void rfc822_fixed_date (char *date) { do_date (date,NIL,"%02d %s %4d %02d:%02d:%02d %+03d%02d",NIL); } /* Write current time in internal format * Accepts: destination string */ void internal_date (char *date) { do_date (date,NIL,"%02d-%s-%d %02d:%02d:%02d %+03d%02d",NIL); } /* Return random number */ long random (void) { if (!rndm) srand (rndm = (unsigned) time (0L)); return (long) rand (); } /* Set alarm timer * Accepts: new value * Returns: old alarm value */ long alarm (long seconds) { long ret = alarm_countdown; alarm_countdown = seconds; return ret; } /* The clock ticked */ void CALLBACK clock_ticked (UINT IDEvent,UINT uReserved,DWORD dwUser, DWORD dwReserved1,DWORD dwReserved2) { if (alarm_rang && !--alarm_countdown) (*alarm_rang) (); } /* Initialize server * Accepts: server name for syslog or NIL * /etc/services service name or NIL * alternate /etc/services service name or NIL * clock interrupt handler * kiss-of-death interrupt handler * hangup interrupt handler * termination interrupt handler */ void server_init (char *server,char *service,char *sslservice, void *clkint,void *kodint,void *hupint,void *trmint, void *staint) { if (!check_nt ()) { if (!auth_md5.server) fatal ("Can't run on Windows without MD5 database"); server_nli = T; /* Windows server not logged in */ } /* only do this if for init call */ if (server && service && sslservice) { long port; struct servent *sv; /* set server name in syslog */ openlog (server,LOG_PID,LOG_MAIL); fclose (stderr); /* possibly save a process ID */ /* Use SSL if SSL service, or if server starts with "s" and not service */ if (((port = tcp_serverport ()) >= 0)) { if ((sv = getservbyname (service,"tcp")) && (port == ntohs (sv->s_port))) syslog (LOG_DEBUG,"%s service init from %s",service,tcp_clientaddr ()); else if ((sv = getservbyname (sslservice,"tcp")) && (port == ntohs (sv->s_port))) { syslog (LOG_DEBUG,"%s SSL service init from %s",sslservice, tcp_clientaddr ()); ssl_server_init (server); } else { /* not service or SSL service port */ syslog (LOG_DEBUG,"port %ld service init from %s",port, tcp_clientaddr ()); if (*server == 's') ssl_server_init (server); } } /* make sure stdout does binary */ setmode (fileno (stdin),O_BINARY); setmode (fileno (stdout),O_BINARY); } alarm_rang = clkint; /* note the clock interrupt */ timeBeginPeriod (1000); /* set the timer interval */ timeSetEvent (1000,1000,clock_ticked,NIL,TIME_PERIODIC); } /* Wait for stdin input * Accepts: timeout in seconds * Returns: T if have input on stdin, else NIL */ long server_input_wait (long seconds) { fd_set rfd,efd; struct timeval tmo; FD_ZERO (&rfd); FD_ZERO (&efd); FD_SET (0,&rfd); FD_SET (0,&efd); tmo.tv_sec = seconds; tmo.tv_usec = 0; return select (1,&rfd,0,&efd,&tmo) ? LONGT : NIL; } /* Server log in * Accepts: user name string * password string * authenticating user name string * argument count * argument vector * Returns: T if password validated, NIL otherwise */ static int gotprivs = NIL; /* once-only flag to grab privileges */ long server_login (char *user,char *pass,char *authuser,int argc,char *argv[]) { HANDLE hdl; LUID tcbpriv; TOKEN_PRIVILEGES tkp; char *s; /* need to get privileges? */ if (!gotprivs++ && check_nt ()) { /* hack for inetlisn */ if (argc >= 2) myClientHost = argv[1]; /* get process token and TCB priv value */ if (!(OpenProcessToken (GetCurrentProcess (), TOKEN_ADJUST_PRIVILEGES | TOKEN_QUERY,&hdl) && LookupPrivilegeValue ((LPSTR) NIL,SE_TCB_NAME,&tcbpriv))) return NIL; tkp.PrivilegeCount = 1; /* want to enable this privilege */ tkp.Privileges[0].Luid = tcbpriv; tkp.Privileges[0].Attributes = SE_PRIVILEGE_ENABLED; /* enable it */ AdjustTokenPrivileges (hdl,NIL,&tkp,sizeof (TOKEN_PRIVILEGES), (PTOKEN_PRIVILEGES) NIL,(PDWORD) NIL); /* make sure it won */ if (GetLastError() != ERROR_SUCCESS) return NIL; } /* cretins still haven't given up */ if ((strlen (user) >= MAILTMPLEN) || (authuser && (strlen (authuser) >= MAILTMPLEN))) syslog (LOG_ALERT,"SYSTEM BREAK-IN ATTEMPT, host=%.80s",tcp_clienthost ()); else if (logtry > 0) { /* still have available logins? */ /* authentication user not supported */ if (authuser && *authuser && compare_cstring (authuser,user)) mm_log ("Authentication id must match authorization id",ERROR); if (check_nt ()) { /* NT: authserver_login() call not supported */ if (!pass) mm_log ("Unsupported authentication mechanism",ERROR); else if (( /* try to login and impersonate the guy */ #ifdef LOGIN32_LOGON_NETWORK LogonUser (user,".",pass,LOGON32_LOGON_NETWORK, LOGON32_PROVIDER_DEFAULT,&hdl) || #endif LogonUser (user,".",pass,LOGON32_LOGON_INTERACTIVE, LOGON32_PROVIDER_DEFAULT,&hdl) || LogonUser (user,".",pass,LOGON32_LOGON_BATCH, LOGON32_PROVIDER_DEFAULT,&hdl) || LogonUser (user,".",pass,LOGON32_LOGON_SERVICE, LOGON32_PROVIDER_DEFAULT,&hdl)) && ImpersonateLoggedOnUser (hdl)) return env_init (user,NIL); } else { /* Win9x: done if from authserver_login() */ if (!pass) server_nli = NIL; /* otherwise check MD5 database */ else if (s = auth_md5_pwd (user)) { /* change NLI state based on pwd match */ server_nli = strcmp (s,pass); memset (s,0,strlen (s));/* erase sensitive information */ fs_give ((void **) &s); /* flush erased password */ } /* success if no longer NLI */ if (!server_nli) return env_init (user,NIL); } } s = (logtry-- > 0) ? "Login failure" : "Excessive login attempts"; /* note the failure in the syslog */ syslog (LOG_INFO,"%s user=%.80s host=%.80s",s,user,tcp_clienthost ()); sleep (3); /* slow down possible cracker */ return NIL; } /* Authenticated server log in * Accepts: user name string * authentication user name string * argument count * argument vector * Returns: T if password validated, NIL otherwise */ long authserver_login (char *user,char *authuser,int argc,char *argv[]) { return server_login (user,NIL,authuser,argc,argv); } /* Log in as anonymous daemon * Accepts: argument count * argument vector * Returns: T if successful, NIL if error */ long anonymous_login (int argc,char *argv[]) { return server_login ("Guest",NIL,NIL,argc,argv); } /* Initialize environment * Accepts: user name * home directory, or NIL to use default * Returns: T, always */ long env_init (char *user,char *home) { /* don't init if blocked */ if (block_env_init) return LONGT; if (myUserName) fatal ("env_init called twice!"); myUserName = cpystr (user); /* remember user name */ if (!myHomeDir) /* only if home directory not set up yet */ myHomeDir = (home && *home) ? cpystr (home) : win_homedir (user); return T; } /* Check if NT * Returns: T if NT, NIL if Win9x */ int check_nt (void) { if (is_nt < 0) { /* not yet set up? */ OSVERSIONINFO ver; ver.dwOSVersionInfoSize = sizeof (OSVERSIONINFO); GetVersionEx (&ver); is_nt = (ver.dwPlatformId == VER_PLATFORM_WIN32_NT) ? T : NIL; } return is_nt; } /* Return Windows home directory * Accepts: user name * Returns: home directory */ char *win_homedir (char *user) { char *s,*t,tmp[MAILTMPLEN]; PUSER_INFO_1 ui; /* Win9x default */ if (!check_nt ()) sprintf (tmp,"%s\\My Documents",defaultDrive ()); /* get from user info on NT */ else if ((netapi || (netapi = LoadLibrary ("netapi32.dll"))) && (getinfo || (getinfo = (GETINFO) GetProcAddress (netapi,"NetUserGetInfo"))) && MultiByteToWideChar (CP_ACP,0,user,strlen (user) + 1, (WCHAR *) tmp,MAILTMPLEN) && !(*getinfo) (NIL,(LPWSTR) &tmp,1,(LPBYTE *) &ui) && WideCharToMultiByte (CP_ACP,0,ui->usri1_home_dir,-1, tmp,MAILTMPLEN,NIL,NIL) && tmp[0]) { /* make sure doesn't end with delimiter */ if ((*(s = tmp + strlen (tmp) - 1) == '\\') || (*s == '/')) *s = '\0'; } /* no home dir, found Win2K user profile? */ else if ((s = getenv ("USERPROFILE")) && (t = strrchr (s,'\\'))) { strncpy (tmp,s,t-s); /* copy up to user name */ sprintf (tmp+(t-s),"\\%.100s\\My Documents",user); } /* last resort NT default */ else sprintf (tmp,"%s\\users\\default",defaultDrive ()); return cpystr (tmp); } /* Return default drive * Returns: default drive */ static char *defaultDrive (void) { char *s = getenv ("SystemDrive"); return (s && *s) ? s : "C:"; } /* Return my user name * Accepts: pointer to optional flags * Returns: my user name */ char *myusername_full (unsigned long *flags) { UCHAR usr[MAILTMPLEN]; DWORD len = MAILTMPLEN; char *user,*path,*d,*p,pth[MAILTMPLEN]; char *ret = "SYSTEM"; /* get user name if don't have it yet */ if (!myUserName && !server_nli && /* use callback, else logon name */ ((mailusername && (user = (char *) (*mailusername) ())) || (GetUserName (usr,&len) && _stricmp (user = (char *) usr,"SYSTEM")))) { if (block_env_init) { /* don't env_init if blocked */ if (flags) *flags = MU_LOGGEDIN; return user; } /* try HOMEPATH, then HOME */ if (p = getenv ("HOMEPATH")) sprintf (path = pth,"%s%s", (d = getenv ("HOMEDRIVE")) ? d : defaultDrive (),p); else if (!(path = getenv ("HOME"))) sprintf (path = pth,"%s\\My Documents",defaultDrive ()); /* make sure doesn't end with delimiter */ if ((*(p = path + strlen (path) -1) == '\\') || (*p == '/')) *p = '\0'; env_init (user,path); /* initialize environment */ } if (myUserName) { /* logged in? */ if (flags) /* Guest is an anonymous user */ *flags = _stricmp (myUserName,"Guest") ? MU_LOGGEDIN : MU_ANONYMOUS; ret = myUserName; /* return user name */ } else if (flags) *flags = MU_NOTLOGGEDIN; return ret; } /* Return my local host name * Returns: my local host name */ char *mylocalhost (void) { if (!myLocalHost) { char tmp[MAILTMPLEN]; if (!wsa_initted++) { /* init Windows Sockets */ WSADATA wsock; if (WSAStartup (WINSOCK_VERSION,&wsock)) { wsa_initted = 0; return "random-pc"; /* try again later? */ } } myLocalHost = cpystr ((gethostname (tmp,MAILTMPLEN-1) == SOCKET_ERROR) ? "random-pc" : tcp_canonical (tmp)); } return myLocalHost; } /* Return my home directory name * Returns: my home directory name */ char *myhomedir () { if (!myHomeDir) myusername ();/* initialize if first time */ return myHomeDir ? myHomeDir : ""; } /* Return system standard INBOX * Accepts: buffer string */ char *sysinbox () { char tmp[MAILTMPLEN]; if (!sysInbox) { /* initialize if first time */ if (check_nt ()) sprintf (tmp,MAILFILE,myUserName); else sprintf (tmp,"%s\\INBOX",myhomedir ()); sysInbox = cpystr (tmp); /* system inbox is from mail spool */ } return sysInbox; } /* Return mailbox directory name * Accepts: destination buffer * directory prefix * name in directory * Returns: file name or NIL if error */ char *mailboxdir (char *dst,char *dir,char *name) { char tmp[MAILTMPLEN]; if (dir || name) { /* if either argument provided */ if (dir) { if (strlen (dir) > NETMAXMBX) return NIL; strcpy (tmp,dir); /* write directory prefix */ } else tmp[0] = '\0'; /* otherwise null string */ if (name) { if (strlen (name) > NETMAXMBX) return NIL; strcat (tmp,name); /* write name in directory */ } /* validate name, return its name */ if (!mailboxfile (dst,tmp)) return NIL; } else strcpy (dst,myhomedir());/* no arguments, wants home directory */ return dst; /* return the name */ } /* Return mailbox file name * Accepts: destination buffer * mailbox name * Returns: file name or empty string for driver-selected INBOX or NIL if error */ char *mailboxfile (char *dst,char *name) { char homedev[3]; char *dir = myhomedir (); if (dir[0] && isalpha (dir[0]) && (dir[1] == ':')) { homedev[0] = dir[0]; /* copy home device */ homedev[1] = dir[1]; homedev[2] = '\0'; } else homedev[0] = '\0'; /* ??no home device?? */ *dst = '\0'; /* default to empty string */ /* check for INBOX */ if (!compare_cstring (name,"INBOX")); /* reject names with / */ else if (strchr (name,'/')) dst = NIL; else switch (*name) { case '#': /* namespace names */ if (((name[1] == 'u') || (name[1] == 'U')) && ((name[2] == 's') || (name[2] == 'S')) && ((name[3] == 'e') || (name[3] == 'E')) && ((name[4] == 'r') || (name[4] == 'R')) && (name[5] == '.')) { /* copy user name to destination buffer */ for (dir = dst,name += 6; *name && (*name != '\\'); *dir++ = *name++); *dir++ = '\0'; /* tie off user name */ /* look up homedir for user name */ if (dir = win_homedir (dst)) { /* build resulting name */ sprintf (dst,"%s\\%s",dir,name); fs_give ((void **) &dir); } else dst = NIL; } else dst = NIL; /* unknown namespace name */ break; case '\\': /* absolute path on default drive? */ sprintf (dst,"%s%s",homedev,name); break; default: /* any other name */ if (name[1] == ':') { /* some other drive? */ if (name[2] == '\\') strcpy (dst,name); else sprintf (dst,"%c:\\%s",name[0],name+2); } /* build home-directory relative name */ else sprintf (dst,"%s\\%s",dir,name); } return dst; /* return it */ } /* Lock file name * Accepts: return buffer for file name * file name * locking to be placed on file if non-NIL * Returns: file descriptor of lock or -1 if error */ int lockname (char *lock,char *fname,int op) { int ld; char c,*s; /* Win2K and Win98 have TEMP under windir */ if (!((s = lockdir (lock,getenv ("windir"),"TEMP")) || /* NT4, NT3.x and Win95 use one of these */ (s = lockdir (lock,getenv ("TEMP"),NIL)) || (s = lockdir (lock,getenv ("TMP"),NIL)) || (s = lockdir (lock,getenv ("TMPDIR"),NIL)) || /* try one of these */ (s = lockdir (lock,defaultDrive (),"WINNT\\TEMP")) || (s = lockdir (lock,defaultDrive (),"WINDOWS\\TEMP")) || /* C:\TEMP is last resort */ (s = lockdir (lock,defaultDrive (),"TEMP")))) { mm_log ("Unable to find temporary directory",ERROR); return -1; } /* generate file name */ while (c = *fname++) switch (c) { case '/': case '\\': case ':': *s++ = '!'; /* convert bad chars to ! */ break; default: *s++ = c; break; } *s++ = c; /* tie off name */ /* get the lock */ if (((ld = open (lock,O_BINARY|O_RDWR|O_CREAT,S_IREAD|S_IWRITE)) >= 0) && op) flock (ld,op); /* apply locking function */ return ld; /* return locking file descriptor */ } /* Build lock directory, check to see if it exists * Accepts: return buffer for lock directory * first part of possible name * optional second part * Returns: pointer to end of buffer if buffer has a good name, else NIL */ char *lockdir (char *lock,char *first,char *last) { struct stat sbuf; char c,*s; if (first && *first) { /* first part must be non-NIL */ /* copy first part */ for (s = lock; c = *first++; *s++ = (c == '/') ? '\\' : c); if (last && *last) { /* copy last part if specified */ /* write trailing \ in case not in first */ if (s[-1] != '\\') *s++ = '\\'; while (c = *last++) *s++ = (c == '/') ? '\\' : c; } if (s[-1] == '\\') --s; /* delete trailing \ if any */ *s = s[1] = '\0'; /* tie off name at this point */ if (!stat (lock,&sbuf)) { /* does the name exist? */ *s++ = '\\'; /* yes, reinstall trailing \ */ return s; /* return the name */ } } return NIL; /* failed */ } /* Unlock file descriptor * Accepts: file descriptor * lock file name from lockfd() */ void unlockfd (int fd,char *lock) { flock (fd,LOCK_UN); /* unlock it */ close (fd); /* close it */ } /* Determine default prototype stream to user * Accepts: type (NIL for create, T for append) * Returns: default prototype stream */ MAILSTREAM *default_proto (long type) { extern MAILSTREAM CREATEPROTO,APPENDPROTO; return type ? &APPENDPROTO : &CREATEPROTO; } /* Default block notify routine * Accepts: reason for calling * data * Returns: data */ void *mm_blocknotify (int reason,void *data) { void *ret = data; switch (reason) { case BLOCK_SENSITIVE: /* entering sensitive code */ ret = (void *) alarm (0); break; case BLOCK_NONSENSITIVE: /* exiting sensitive code */ if ((unsigned int) data) alarm ((unsigned int) data); break; default: /* ignore all other reasons */ break; } return ret; } alpine-2.10+dfsg/imap/src/osdep/nt/ip4_nt.c0000600000175000017500000001220411512502123022143 0ustar paulproteuspaulproteus/* ======================================================================== * Copyright 1988-2006 University of Washington * * Licensed under the Apache License, Version 2.0 (the "License"); * you may not use this file except in compliance with the License. * You may obtain a copy of the License at * * http://www.apache.org/licenses/LICENSE-2.0 * * * ======================================================================== */ /* * Program: UNIX IPv4 routines * * Author: Mark Crispin * Networks and Distributed Computing * Computing & Communications * University of Washington * Administration Building, AG-44 * Seattle, WA 98195 * Internet: MRC@CAC.Washington.EDU * * Date: 18 December 2003 * Last Edited: 30 August 2006 */ #define SADRLEN sizeof (struct sockaddr) #define SADR4(sadr) ((struct sockaddr_in *) sadr) #define SADR4LEN sizeof (struct sockaddr_in) #define SADR4ADR(sadr) SADR4 (sadr)->sin_addr #define ADR4LEN sizeof (struct in_addr) #define SADR4PORT(sadr) SADR4 (sadr)->sin_port /* IP abstraction layer */ char *ip_sockaddrtostring (struct sockaddr *sadr); long ip_sockaddrtoport (struct sockaddr *sadr); void *ip_stringtoaddr (char *text,size_t *len,int *family); struct sockaddr *ip_newsockaddr (size_t *len); struct sockaddr *ip_sockaddr (int family,void *adr,size_t adrlen, unsigned short port,size_t *len); char *ip_sockaddrtoname (struct sockaddr *sadr); void *ip_nametoaddr (char *name,size_t *len,int *family,char **canonical, void **next); /* Return IP address string from socket address * Accepts: socket address * Returns: IP address as name string */ char *ip_sockaddrtostring (struct sockaddr *sadr) { return (sadr->sa_family == PF_INET) ? inet_ntoa (SADR4ADR (sadr)) : "NON-IPv4"; } /* Return port from socket address * Accepts: socket address * Returns: port number or -1 if can't determine it */ long ip_sockaddrtoport (struct sockaddr *sadr) { return (sadr->sa_family == PF_INET) ? ntohs (SADR4PORT (sadr)) : -1; } /* Return IP address from string * Accepts: name string * pointer to returned length * pointer to returned address family * Returns: address if valid, length and family updated, or NIL */ void *ip_stringtoaddr (char *text,size_t *len,int *family) { unsigned long adr; struct in_addr *ret; /* get address */ if ((adr = inet_addr (text)) == -1) ret = NIL; else { /* make in_addr */ ret = (struct in_addr *) fs_get (*len = ADR4LEN); *family = AF_INET; /* IPv4 */ ret->s_addr = adr; /* set address */ } return (void *) ret; } /* Create a maximum-size socket address * Accepts: pointer to return maximum socket address length * Returns: new, empty socket address of maximum size */ struct sockaddr *ip_newsockaddr (size_t *len) { return (struct sockaddr *) memset (fs_get (SADRLEN),0,*len = SADRLEN); } /* Stuff a socket address * Accepts: address family * IPv4 address * length of address (always 4 in IPv4) * port number * pointer to return socket address length * Returns: socket address or NIL if error */ struct sockaddr *ip_sockaddr (int family,void *adr,size_t adrlen, unsigned short port,size_t *len) { struct sockaddr *sadr = ip_newsockaddr (len); switch (family) { /* build socket address based upon family */ case AF_INET: /* IPv4 */ sadr->sa_family = PF_INET; /* copy host address */ memcpy (&SADR4ADR (sadr),adr,adrlen); /* copy port number in network format */ SADR4PORT (sadr) = htons (port); *len = SADR4LEN; break; default: /* non-IP?? */ sadr->sa_family = PF_UNSPEC; break; } return sadr; } /* Return name from socket address * Accepts: socket address * Returns: canonical name for that address or NIL if none */ char *ip_sockaddrtoname (struct sockaddr *sadr) { struct hostent *he; return ((sadr->sa_family == PF_INET) && (he = gethostbyaddr ((char *) &SADR4ADR (sadr),ADR4LEN,AF_INET))) ? (char *) he->h_name : NIL; } /* Return address from name * Accepts: name or NIL to return next address * pointer to previous/returned length * pointer to previous/returned address family * pointer to previous/returned canonical name * pointer to previous/return state for next-address calls * Returns: address with length/family/canonical updated if needed, or NIL */ void *ip_nametoaddr (char *name,size_t *len,int *family,char **canonical, void **next) { char **adl,tmp[MAILTMPLEN]; struct hostent *he; if (name) { /* first lookup? */ /* yes, do case-independent lookup */ if ((strlen (name) < MAILTMPLEN) && (he = gethostbyname (lcase (strcpy (tmp,name))))) { adl = he->h_addr_list; if (len) *len = he->h_length; if (family) *family = he->h_addrtype; if (canonical) *canonical = (char *) he->h_name; if (next) *next = (void *) adl; } else { /* error */ adl = NIL; if (len) *len = 0; if (family) *family = 0; if (canonical) *canonical = NIL; if (next) *next = NIL; } } /* return next in series */ else if (next && (adl = (char **) *next)) *next = ++adl; else adl = NIL; /* failure */ return adl ? (void *) *adl : NIL; } alpine-2.10+dfsg/imap/src/osdep/nt/env_nt.h0000600000175000017500000000363111512502123022250 0ustar paulproteuspaulproteus/* ======================================================================== * Copyright 1988-2006 University of Washington * * Licensed under the Apache License, Version 2.0 (the "License"); * you may not use this file except in compliance with the License. * You may obtain a copy of the License at * * http://www.apache.org/licenses/LICENSE-2.0 * * * ======================================================================== */ /* * Program: NT environment routines * * Author: Mark Crispin * Networks and Distributed Computing * Computing & Communications * University of Washington * Administration Building, AG-44 * Seattle, WA 98195 * Internet: MRC@CAC.Washington.EDU * * Date: 1 August 1988 * Last Edited: 30 August 2006 */ #define SUBSCRIPTIONFILE(t) sprintf (t,"%s\\MAILBOX.LST",myhomedir ()) #define SUBSCRIPTIONTEMP(t) sprintf (t,"%s\\MAILBOX.TMP",myhomedir ()) /* Note: the \CRAM-MD5.PWD file only works on DOS-based Windows (Win9x/Me) * and not on NT-based Windows (WinNT/2K/XP). If installed on NT-based * Windows, servers will advertise CRAM-MD5 authentication but it will * never succeed. */ #define MD5ENABLE "\\cram-md5.pwd" #define L_SET SEEK_SET /* Function prototypes */ #include "env.h" void rfc822_fixed_date (char *date); long env_init (char *user,char *home); int check_nt (void); char *win_homedir (char *user); static char *defaultDrive (void); char *myusername_full (unsigned long *flags); #define MU_LOGGEDIN 0 #define MU_NOTLOGGEDIN 1 #define MU_ANONYMOUS 2 #define myusername() \ myusername_full (NIL) char *sysinbox (); char *mailboxdir (char *dst,char *dir,char *name); int lockname (char *lock,char *fname,int op); char *lockdir (char *lock,char *first,char *last); void unlockfd (int fd,char *lock); long safe_write (int fd,char *buf,long nbytes); void *mm_blocknotify (int reason,void *data); long random (); #if _MSC_VER < 700 #define getpid random #endif alpine-2.10+dfsg/imap/src/osdep/nt/kerb_mit.c0000600000175000017500000000337011512502123022546 0ustar paulproteuspaulproteus/* ======================================================================== * Copyright 1988-2006 University of Washington * * Licensed under the Apache License, Version 2.0 (the "License"); * you may not use this file except in compliance with the License. * You may obtain a copy of the License at * * http://www.apache.org/licenses/LICENSE-2.0 * * * ======================================================================== */ /* * Program: MIT Kerberos routines * * Author: Mark Crispin * Networks and Distributed Computing * Computing & Communications * University of Washington * Administration Building, AG-44 * Seattle, WA 98195 * Internet: MRC@CAC.Washington.EDU * * Date: 4 March 2003 * Last Edited: 30 August 2006 */ #define PROTOTYPE(x) x #include #include long kerberos_server_valid (void); long kerberos_try_kinit (OM_uint32 error); char *kerberos_login (char *user,char *authuser,int argc,char *argv[]); /* Kerberos server valid check * Returns: T if have keytab, NIL otherwise */ long kerberos_server_valid () { return NIL; } /* Kerberos check for missing or expired credentials * Returns: T if should suggest running kinit, NIL otherwise */ long kerberos_try_kinit (OM_uint32 error) { switch (error) { case KRB5KRB_AP_ERR_TKT_EXPIRED: case KRB5_FCC_NOFILE: /* MIT */ case KRB5_CC_NOTFOUND: /* Heimdal */ return LONGT; } return NIL; } /* Kerberos server log in * Accepts: authorization ID as user name * authentication ID as Kerberos principal * argument count * argument vector * Returns: logged in user name if logged in, NIL otherwise */ char *kerberos_login (char *user,char *authuser,int argc,char *argv[]) { return NIL; } alpine-2.10+dfsg/imap/src/osdep/nt/drivraux.bat0000700000175000017500000000212611512502123023141 0ustar paulproteuspaulproteus@ECHO OFF REM ======================================================================== REM Copyright 1988-2006 University of Washington REM REM Licensed under the Apache License, Version 2.0 (the "License"); REM you may not use this file except in compliance with the License. REM You may obtain a copy of the License at REM REM http://www.apache.org/licenses/LICENSE-2.0 REM REM REM ======================================================================== REM Program: Driver Linkage Generator auxillary for NT/Win9x REM REM Author: Mark Crispin REM Networks and Distributed Computing REM Computing & Communications REM University of Washington REM Administration Building, AG-44 REM Seattle, WA 98195 REM Internet: MRC@CAC.Washington.EDU REM REM Date: 11 October 1989 REM Last Edited:30 August 2006 ECHO extern DRIVER %1driver; >> LINKAGE.H REM Note the introduction of the caret to quote the ampersand in NT if "%OS%" == "Windows_NT" ECHO mail_link (^&%1driver); /* link in the %1 driver */ >> LINKAGE.C if "%OS%" == "" ECHO mail_link (&%1driver); /* link in the %1 driver */ >> LINKAGE.C alpine-2.10+dfsg/imap/src/osdep/nt/mkauths.bat0000700000175000017500000000172411512502123022754 0ustar paulproteuspaulproteus@ECHO OFF REM ======================================================================== REM Copyright 1988-2006 University of Washington REM REM Licensed under the Apache License, Version 2.0 (the "License"); REM you may not use this file except in compliance with the License. REM You may obtain a copy of the License at REM REM http://www.apache.org/licenses/LICENSE-2.0 REM REM REM ======================================================================== REM Program: Authenticator Linkage Generator for DOS and Windows REM REM Author: Mark Crispin REM Networks and Distributed Computing REM Computing & Communications REM University of Washington REM Administration Building, AG-44 REM Seattle, WA 98195 REM Internet: MRC@CAC.Washington.EDU REM REM Date: 6 December 1995 REM Last Edited:30 August 2006 REM Erase old authenticators list IF EXIST AUTHS.C DEL AUTHS.C REM Now define the new list FOR %%D IN (%1 %2 %3 %4 %5 %6 %7 %8 %9) DO CALL MKAUTAUX %%D EXIT 0 alpine-2.10+dfsg/imap/src/osdep/nt/yunchan.h0000600000175000017500000000524011512502123022422 0ustar paulproteuspaulproteus/* ======================================================================== * Copyright 1988-2006 University of Washington * * Licensed under the Apache License, Version 2.0 (the "License"); * you may not use this file except in compliance with the License. * You may obtain a copy of the License at * * http://www.apache.org/licenses/LICENSE-2.0 * * * ======================================================================== */ /* * Program: Unix compatibility routines * * Author: Mark Crispin * Networks and Distributed Computing * Computing & Communications * University of Washington * Administration Building, AG-44 * Seattle, WA 98195 * Internet: MRC@CAC.Washington.EDU * * Date: 14 September 1996 * Last Edited: 30 August 2006 */ /* DEDICATION * * This file is dedicated to my dog, Unix, also known as Yun-chan and * Unix J. Terwilliker Jehosophat Aloysius Monstrosity Animal Beast. Unix * passed away at the age of 11 1/2 on September 14, 1996, 12:18 PM PDT, after * a two-month bout with cirrhosis of the liver. * * He was a dear friend, and I miss him terribly. * * Lift a leg, Yunie. Luv ya forever!!!! */ /* For flock() emulation */ #define LOCK_SH 1 #define LOCK_EX 2 #define LOCK_NB 4 #define LOCK_UN 8 /* syslog() emulation */ #define LOG_MAIL (2<<3) /* mail system */ #define LOG_DAEMON (3<<3) /* system daemons */ #define LOG_AUTH (4<<3) /* security/authorization messages */ #define LOG_EMERG 0 /* system is unusable */ #define LOG_ALERT 1 /* action must be taken immediately */ #define LOG_CRIT 2 /* critical conditions */ #define LOG_ERR 3 /* error conditions */ #define LOG_WARNING 4 /* warning conditions */ #define LOG_NOTICE 5 /* normal but signification condition */ #define LOG_INFO 6 /* informational */ #define LOG_DEBUG 7 /* debug-level messages */ #define LOG_PID 0x01 /* log the pid with each message */ #define LOG_CONS 0x02 /* log on the console if errors in sending */ #define LOG_ODELAY 0x04 /* delay open until syslog() is called */ #define LOG_NDELAY 0x08 /* don't delay open */ #define LOG_NOWAIT 0x10 /* if forking to log on console, don't wait() */ #define tmpfile create_tempfile #define fclose close_file #define fsync _commit #define ftruncate chsize #define gethostid clock #define sleep(x) Sleep (1000 * x) long alarm (long seconds); int flock (int fd,int op); void openlog (const char *ident,int logopt,int facility); void syslog (int priority,const char *message,...); unsigned long unix_crlfcpy (char **dst,unsigned long *dstl,char *src, unsigned long srcl); unsigned long unix_crlflen (STRING *s); FILE *create_tempfile (void); int close_file (FILE *stream); char *getpass (const char *prompt); alpine-2.10+dfsg/imap/src/osdep/nt/pseudo.c0000600000175000017500000000236611512502123022255 0ustar paulproteuspaulproteus/* ======================================================================== * Copyright 1988-2006 University of Washington * * Licensed under the Apache License, Version 2.0 (the "License"); * you may not use this file except in compliance with the License. * You may obtain a copy of the License at * * http://www.apache.org/licenses/LICENSE-2.0 * * * ======================================================================== */ /* * Program: Pseudo Header Strings * * Author: Mark Crispin * Networks and Distributed Computing * Computing & Communications * University of Washington * Administration Building, AG-44 * Seattle, WA 98195 * Internet: MRC@CAC.Washington.EDU * * Date: 26 September 1996 * Last Edited: 30 August 2006 */ /* Local sites may wish to alter this text */ char *pseudo_from = "MAILER-DAEMON"; char *pseudo_name = "Mail System Internal Data"; char *pseudo_subject = "DON'T DELETE THIS MESSAGE -- FOLDER INTERNAL DATA"; char *pseudo_msg = "This text is part of the internal format of your mail folder, and is not\na real message. It is created automatically by the mail system software.\nIf deleted, important folder data will be lost, and it will be re-created\nwith the data reset to initial values." ; alpine-2.10+dfsg/imap/src/osdep/nt/drivers.bat0000700000175000017500000000170311512502123022753 0ustar paulproteuspaulproteus@ECHO OFF REM ======================================================================== REM Copyright 1988-2006 University of Washington REM REM Licensed under the Apache License, Version 2.0 (the "License"); REM you may not use this file except in compliance with the License. REM You may obtain a copy of the License at REM REM http://www.apache.org/licenses/LICENSE-2.0 REM REM REM ======================================================================== REM Program: Driver Linkage Generator for DOS/NT REM REM Author: Mark Crispin REM Networks and Distributed Computing REM Computing & Communications REM University of Washington REM Administration Building, AG-44 REM Seattle, WA 98195 REM Internet: MRC@CAC.Washington.EDU REM REM Date: 11 October 1989 REM Last Edited:30 August 2006 REM Erase old driver linkage IF EXIST LINKAGE.* DEL LINKAGE.* REM Now define the new list FOR %%D IN (%1 %2 %3 %4 %5 %6 %7 %8 %9) DO CALL DRIVRAUX %%D EXIT 0 alpine-2.10+dfsg/imap/src/osdep/nt/yunchan.c0000600000175000017500000002064611512502123022424 0ustar paulproteuspaulproteus/* ======================================================================== * Copyright 1988-2006 University of Washington * * Licensed under the Apache License, Version 2.0 (the "License"); * you may not use this file except in compliance with the License. * You may obtain a copy of the License at * * http://www.apache.org/licenses/LICENSE-2.0 * * * ======================================================================== */ /* * Program: Unix compatibility routines * * Author: Mark Crispin * Networks and Distributed Computing * Computing & Communications * University of Washington * Administration Building, AG-44 * Seattle, WA 98195 * Internet: MRC@CAC.Washington.EDU * * Date: 14 September 1996 * Last Edited: 30 August 2006 */ /* DEDICATION * * This file is dedicated to my dog, Unix, also known as Yun-chan and * Unix J. Terwilliker Jehosophat Aloysius Monstrosity Animal Beast. Unix * passed away at the age of 11 1/2 on September 14, 1996, 12:18 PM PDT, after * a two-month bout with cirrhosis of the liver. * * He was a dear friend, and I miss him terribly. * * Lift a leg, Yunie. Luv ya forever!!!! */ /* Emulator for BSD flock() call * Accepts: file descriptor * operation bitmask * Returns: 0 if successful, -1 if failure */ /* Our friends in Redmond have decided that you can not write to any segment * which has a shared lock. This screws up the shared-write mailbox drivers * (mbx, mtx, and tenex). As a workaround, we'll only lock the first byte of * the file, meaning that you can't write that byte shared. * This behavior seems to be new as of NT 4.0. */ int flock (int fd,int op) { HANDLE hdl = (HANDLE) _get_osfhandle (fd); DWORD flags = (op & LOCK_NB) ? LOCKFILE_FAIL_IMMEDIATELY : 0; OVERLAPPED offset = {NIL,NIL,0,0,NIL}; int ret = -1; blocknotify_t bn = (blocknotify_t) ((op & LOCK_NB) ? NIL : mail_parameters (NIL,GET_BLOCKNOTIFY,NIL)); if (hdl < 0) errno = EBADF; /* error in file descriptor */ else switch (op & ~LOCK_NB) { /* translate to LockFileEx() op */ case LOCK_EX: /* exclusive */ flags |= LOCKFILE_EXCLUSIVE_LOCK; case LOCK_SH: /* shared */ if (!check_nt ()) return 0; /* always succeeds if not NT */ if (bn) (*bn) (BLOCK_FILELOCK,NIL); /* bug for bug compatible with Unix */ UnlockFileEx (hdl,NIL,1,0,&offset); /* lock the file as requested */ if (LockFileEx (hdl,flags,NIL,1,0,&offset)) ret = 0; if (bn) (*bn) (BLOCK_NONE,NIL); /* if failed */ if (ret) errno = (op & LOCK_NB) ? EAGAIN : EBADF; break; case LOCK_UN: /* unlock */ if (check_nt ()) UnlockFileEx (hdl,NIL,1,0,&offset); ret = 0; /* always succeeds */ default: /* default */ errno = EINVAL; /* bad call */ break; } return ret; } /* Local storage */ static char *loghdr; /* log file header string */ static HANDLE loghdl = NIL; /* handle of event source */ /* Emulator for BSD syslog() routine * Accepts: priority * message * parameters */ void syslog (int priority,const char *message,...) { va_list args; LPTSTR strs[2]; char tmp[MAILTMPLEN]; /* callers must be careful not to pop this */ unsigned short etype; if (!check_nt ()) return; /* no-op on non-NT system */ /* default event source */ if (!loghdl) openlog ("c-client",LOG_PID,LOG_MAIL); switch (priority) { /* translate UNIX type into NT type */ case LOG_ALERT: etype = EVENTLOG_ERROR_TYPE; break; case LOG_INFO: etype = EVENTLOG_INFORMATION_TYPE; break; default: etype = EVENTLOG_WARNING_TYPE; } va_start (args,message); /* initialize vararg mechanism */ vsprintf (tmp,message,args); /* build message */ strs[0] = loghdr; /* write header */ strs[1] = tmp; /* then the message */ /* report the event */ ReportEvent (loghdl,etype,(unsigned short) priority,2000,NIL,2,0,strs,NIL); va_end (args); } /* Emulator for BSD openlog() routine * Accepts: identity * options * facility */ void openlog (const char *ident,int logopt,int facility) { char tmp[MAILTMPLEN]; if (!check_nt ()) return; /* no-op on non-NT system */ if (loghdl) fatal ("Duplicate openlog()!"); loghdl = RegisterEventSource (NIL,ident); sprintf (tmp,(logopt & LOG_PID) ? "%s[%d]" : "%s",ident,getpid ()); loghdr = cpystr (tmp); /* save header for later */ } /* Copy Unix string with CRLF newlines * Accepts: destination string * pointer to size of destination string buffer * source string * length of source string * Returns: length of copied string */ unsigned long unix_crlfcpy (char **dst,unsigned long *dstl,char *src, unsigned long srcl) { unsigned long i,j; char *d = src; /* count number of LF's in source string(s) */ for (i = srcl,j = 0; j < srcl; j++) if (*d++ == '\012') i++; /* flush destination buffer if too small */ if (*dst && (i > *dstl)) fs_give ((void **) dst); if (!*dst) { /* make a new buffer if needed */ *dst = (char *) fs_get ((*dstl = i) + 1); if (dstl) *dstl = i; /* return new buffer length to main program */ } d = *dst; /* destination string */ /* copy strings, inserting CR's before LF's */ while (srcl--) switch (*src) { case '\015': /* unlikely carriage return */ *d++ = *src++; /* copy it and any succeeding linefeed */ if (srcl && *src == '\012') { *d++ = *src++; srcl--; } break; case '\012': /* line feed? */ *d++ ='\015'; /* yes, prepend a CR, drop into default case */ default: /* ordinary chararacter */ *d++ = *src++; /* just copy character */ break; } *d = '\0'; /* tie off destination */ return d - *dst; /* return length */ } /* Length of Unix string after unix_crlfcpy applied * Accepts: source string * Returns: length of string */ unsigned long unix_crlflen (STRING *s) { unsigned long pos = GETPOS (s); unsigned long i = SIZE (s); unsigned long j = i; while (j--) switch (SNX (s)) {/* search for newlines */ case '\015': /* unlikely carriage return */ if (j && (CHR (s) == '\012')) { SNX (s); /* eat the line feed */ j--; } break; case '\012': /* line feed? */ i++; default: /* ordinary chararacter */ break; } SETPOS (s,pos); /* restore old position */ return i; } /* Undoubtably, I'm going to regret these two routines in the future. I * regret them now. Their purpose is to work around two problems in the * VC++ 6.0 C library: * (1) tmpfile() creates the file in the current directory instead of a * temporary directory * (2) tmpfile() and fclose() think that on NT systems, it works to unlink * the file while it's still open, so there's no need for the _tmpfname * hook at fclose(). Unfortunately, that doesn't work in Win2K. * I would be delighted to have a better alternative. */ #undef fclose /* use the real fclose() in close_file() */ /* Substitute for Microsoft's tmpfile() that uses the real temporary directory * Returns: FILE structure if success, NIL if failure */ FILE *create_tempfile (void) { FILE *ret = NIL; char *s = _tempnam (getenv ("TEMP"),"msg"); if (s) { /* if got temporary name... */ /* open file, and stash name on _tmpfname */ if (ret = fopen (s,"w+b")) ret->_tmpfname = s; else fs_give ((void **) &s);/* flush temporary string */ } return ret; } /* Substitute for Microsoft's fclose() that always flushes _tmpfname * Returns: FILE structure if success, NIL if failure */ int close_file (FILE *stream) { int ret; char *s = stream->_tmpfname; stream->_tmpfname = NIL; /* just in case fclose() tries to delete it */ ret = fclose (stream); /* close the file */ if (s) { /* was there a _tmpfname? */ unlink (s); /* yup, delete it */ fs_give ((void **) &s); /* and flush the name */ } return ret; } /* Get password from console * Accepts: prompt * Returns: password */ #define PWDLEN 128 /* used by Linux */ char *getpass (const char *prompt) { static char pwd[PWDLEN]; int ch,i,done; fputs (prompt,stderr); /* output prompt */ for (i = done = 0; !done; ) switch (ch = _getch()) { case 0x03: /* CTRL/C stops program */ _exit (1); case '\b': /* BACKSPACE erase previous character */ if (i) pwd[--i] = '\0'; break; case '\n': case '\r': /* CR or LF terminates string */ done = 1; break; default: /* any other character is a pwd char */ if (i < (PWDLEN - 1)) pwd[i++] = ch; break; } pwd[i] = '\0'; /* tie off string with null */ putchar ('\n'); /* echo newline */ return pwd; } alpine-2.10+dfsg/imap/src/osdep/nt/unixnt.h0000600000175000017500000001506711512502123022312 0ustar paulproteuspaulproteus/* ======================================================================== * Copyright 1988-2006 University of Washington * * Licensed under the Apache License, Version 2.0 (the "License"); * you may not use this file except in compliance with the License. * You may obtain a copy of the License at * * http://www.apache.org/licenses/LICENSE-2.0 * * * ======================================================================== */ /* * Program: UNIX mail routines * * Author: Mark Crispin * Networks and Distributed Computing * Computing & Communications * University of Washington * Administration Building, AG-44 * Seattle, WA 98195 * Internet: MRC@CAC.Washington.EDU * * Date: 20 December 1989 * Last Edited: 30 August 2006 */ /* DEDICATION * * This file is dedicated to my dog, Unix, also known as Yun-chan and * Unix J. Terwilliker Jehosophat Aloysius Monstrosity Animal Beast. Unix * passed away at the age of 11 1/2 on September 14, 1996, 12:18 PM PDT, after * a two-month bout with cirrhosis of the liver. * * He was a dear friend, and I miss him terribly. * * Lift a leg, Yunie. Luv ya forever!!!! */ /* Validate line * Accepts: pointer to candidate string to validate as a From header * return pointer to end of date/time field * return pointer to offset from t of time (hours of ``mmm dd hh:mm'') * return pointer to offset from t of time zone (if non-zero) * Returns: t,ti,zn set if valid From string, else ti is NIL */ #define VALID(s,x,ti,zn) { \ ti = 0; \ if ((*s == 'F') && (s[1] == 'r') && (s[2] == 'o') && (s[3] == 'm') && \ (s[4] == ' ')) { \ for (x = s + 5; *x && *x != '\012'; x++); \ if (*x) { \ if (x[-1] == '\015') --x; \ if (x - s >= 41) { \ for (zn = -1; x[zn] != ' '; zn--); \ if ((x[zn-1] == 'm') && (x[zn-2] == 'o') && (x[zn-3] == 'r') && \ (x[zn-4] == 'f') && (x[zn-5] == ' ') && (x[zn-6] == 'e') && \ (x[zn-7] == 't') && (x[zn-8] == 'o') && (x[zn-9] == 'm') && \ (x[zn-10] == 'e') && (x[zn-11] == 'r') && (x[zn-12] == ' '))\ x += zn - 12; \ } \ if (x - s >= 27) { \ if (x[-5] == ' ') { \ if (x[-8] == ':') zn = 0,ti = -5; \ else if (x[-9] == ' ') ti = zn = -9; \ else if ((x[-11] == ' ') && ((x[-10]=='+') || (x[-10]=='-'))) \ ti = zn = -11; \ } \ else if (x[-4] == ' ') { \ if (x[-9] == ' ') zn = -4,ti = -9; \ } \ else if (x[-6] == ' ') { \ if ((x[-11] == ' ') && ((x[-5] == '+') || (x[-5] == '-'))) \ zn = -6,ti = -11; \ } \ if (ti && !((x[ti - 3] == ':') && \ (x[ti -= ((x[ti - 6] == ':') ? 9 : 6)] == ' ') && \ (x[ti - 3] == ' ') && (x[ti - 7] == ' ') && \ (x[ti - 11] == ' '))) ti = 0; \ } \ } \ } \ } /* You are not expected to understand this macro, but read the next page if * you are not faint of heart. * * Known formats to the VALID macro are: * From user Wed Dec 2 05:53 1992 * BSD From user Wed Dec 2 05:53:22 1992 * SysV From user Wed Dec 2 05:53 PST 1992 * rn From user Wed Dec 2 05:53:22 PST 1992 * From user Wed Dec 2 05:53 -0700 1992 * emacs From user Wed Dec 2 05:53:22 -0700 1992 * From user Wed Dec 2 05:53 1992 PST * From user Wed Dec 2 05:53:22 1992 PST * From user Wed Dec 2 05:53 1992 -0700 * Solaris From user Wed Dec 2 05:53:22 1992 -0700 * * Plus all of the above with `` remote from xxx'' after it. Thank you very * much, smail and Solaris, for making my life considerably more complicated. */ /* * What? You want to understand the VALID macro anyway? Alright, since you * insist. Actually, it isn't really all that difficult, provided that you * take it step by step. * * Line 1 Initializes the return ti value to failure (0); * Lines 2-3 Validates that the 1st-5th characters are ``From ''. * Lines 4-6 Validates that there is an end of line and points x at it. * Lines 7-14 First checks to see if the line is at least 41 characters long. * If so, it scans backwards to find the rightmost space. From * that point, it scans backwards to see if the string matches * `` remote from''. If so, it sets x to point to the space at * the start of the string. * Line 15 Makes sure that there are at least 27 characters in the line. * Lines 16-21 Checks if the date/time ends with the year (there is a space * five characters back). If there is a colon three characters * further back, there is no timezone field, so zn is set to 0 * and ti is set in front of the year. Otherwise, there must * either to be a space four characters back for a three-letter * timezone, or a space six characters back followed by a + or - * for a numeric timezone; in either case, zn and ti become the * offset of the space immediately before it. * Lines 22-24 Are the failure case for line 14. If there is a space four * characters back, it is a three-letter timezone; there must be a * space for the year nine characters back. zn is the zone * offset; ti is the offset of the space. * Lines 25-28 Are the failure case for line 20. If there is a space six * characters back, it is a numeric timezone; there must be a * space eleven characters back and a + or - five characters back. * zn is the zone offset; ti is the offset of the space. * Line 29-32 If ti is valid, make sure that the string before ti is of the * form www mmm dd hh:mm or www mmm dd hh:mm:ss, otherwise * invalidate ti. There must be a colon three characters back * and a space six or nine characters back (depending upon * whether or not the character six characters back is a colon). * There must be a space three characters further back (in front * of the day), one seven characters back (in front of the month), * and one eleven characters back (in front of the day of week). * ti is set to be the offset of the space before the time. * * Why a macro? It gets invoked a *lot* in a tight loop. On some of the * newer pipelined machines it is faster being open-coded than it would be if * subroutines are called. * * Why does it scan backwards from the end of the line, instead of doing the * much easier forward scan? There is no deterministic way to parse the * ``user'' field, because it may contain unquoted spaces! Yes, I tested it to * see if unquoted spaces were possible. They are, and I've encountered enough * evil mail to be totally unwilling to trust that ``it will never happen''. */ /* Build parameters */ #define KODRETRY 15 /* kiss-of-death retry in seconds */ #define LOCKTIMEOUT 5 /* lock timeout in minutes */ alpine-2.10+dfsg/imap/src/osdep/nt/tcp_nt.h0000600000175000017500000000267111512502123022251 0ustar paulproteuspaulproteus/* ======================================================================== * Copyright 1988-2006 University of Washington * * Licensed under the Apache License, Version 2.0 (the "License"); * you may not use this file except in compliance with the License. * You may obtain a copy of the License at * * http://www.apache.org/licenses/LICENSE-2.0 * * * ======================================================================== */ /* * Program: Winsock TCP/IP routines * * Author: Mark Crispin * Networks and Distributed Computing * Computing & Communications * University of Washington * Administration Building, AG-44 * Seattle, WA 98195 * Internet: MRC@CAC.Washington.EDU * * Date: 11 April 1989 * Last Edited: 30 August 2006 */ /* TCP input buffer -- must be large enough to prevent overflow */ #define BUFLEN 16384 /* 32768 causes stdin read() to barf */ #include #include #undef ERROR /* quell conflicting definition diagnostic */ /* TCP I/O stream (must be before osdep.h is included) */ #define TCPSTREAM struct tcp_stream TCPSTREAM { char *host; /* host name */ char *remotehost; /* remote host name */ unsigned long port; /* port number */ char *localhost; /* local host name */ SOCKET tcpsi; /* tcp socket */ SOCKET tcpso; /* tcp socket */ long ictr; /* input counter */ char *iptr; /* input pointer */ char ibuf[BUFLEN]; /* input buffer */ }; alpine-2.10+dfsg/imap/src/osdep/nt/setproto.bat0000700000175000017500000000163111512502123023154 0ustar paulproteuspaulproteus@ECHO OFF REM ======================================================================== REM Copyright 1988-2006 University of Washington REM REM Licensed under the Apache License, Version 2.0 (the "License"); REM you may not use this file except in compliance with the License. REM You may obtain a copy of the License at REM REM http://www.apache.org/licenses/LICENSE-2.0 REM REM REM ======================================================================== REM Program: Set default prototype for DOS/NT REM REM Author: Mark Crispin REM Networks and Distributed Computing REM Computing & Communications REM University of Washington REM Administration Building, AG-44 REM Seattle, WA 98195 REM Internet: MRC@CAC.Washington.EDU REM REM Date: 9 October 1995 REM Last Edited: 30 August 2006 REM Set the default drivers ECHO #define CREATEPROTO %1proto >> LINKAGE.H ECHO #define APPENDPROTO %2proto >> LINKAGE.H alpine-2.10+dfsg/imap/src/osdep/nt/os_old.c0000600000175000017500000000240011512502123022222 0ustar paulproteuspaulproteus/* ======================================================================== * Copyright 1988-2006 University of Washington * * Licensed under the Apache License, Version 2.0 (the "License"); * you may not use this file except in compliance with the License. * You may obtain a copy of the License at * * http://www.apache.org/licenses/LICENSE-2.0 * * * ======================================================================== */ /* * Program: Operating-system dependent routines -- NT version * * Author: Mark Crispin * Networks and Distributed Computing * Computing & Communications * University of Washington * Administration Building, AG-44 * Seattle, WA 98195 * Internet: MRC@CAC.Washington.EDU * * Date: 11 April 1989 * Last Edited: 21 December 2007 */ #include "tcp_nt.h" /* must be before osdep includes tcp.h */ #undef ERROR /* quell conflicting def warning */ #include "mail.h" #include "osdep.h" #include #include #include #include #include #include #include "misc.h" #include "mailfile.h" #include "fs_nt.c" #include "ftl_nt.c" #include "nl_nt.c" #include "yunchan.c" #include "tcp_nt.c" /* must be before env_nt.c */ #include "env_nt.c" #include "ssl_old.c" alpine-2.10+dfsg/imap/src/osdep/nt/makefile.w2k0000600000175000017500000000657511512502123023022 0ustar paulproteuspaulproteus# ======================================================================== # Copyright 1988-2007 University of Washington # # Licensed under the Apache License, Version 2.0 (the "License"); # you may not use this file except in compliance with the License. # You may obtain a copy of the License at # # http://www.apache.org/licenses/LICENSE-2.0 # # # ======================================================================== # Program: Portable C client makefile -- Windows 2000/XP version # # Author: Mark Crispin # Networks and Distributed Computing # Computing & Communications # University of Washington # Administration Building, AG-44 # Seattle, WA 98195 # Internet: MRC@CAC.Washington.EDU # # Date: 11 May 1989 # Last Edited: 23 May 2007 IP=6 EXTRAAUTHENTICATORS = EXTRADRIVERS = EXTRACFLAGS = AUTHENTICATORS = ext gss md5 pla log DRIVERS = imap nntp pop3 mbx mtx tenex unix CREATEDRIVER = mbx APPENDDRIVER = unix OSCOMPAT = /DWIN32 VSCOMPAT = /D_CRT_SECURE_NO_DEPRECATE /D_CRT_NONSTDC_NO_DEPRECATE CFLAGS = /MT /W3 /Ox /DCHUNKSIZE=65536 $(OSCOMPAT) $(VSCOMPAT) -nologo /I.. $(EXTRACFLAGS) CC = cl CCLIENTLIB = cclient.lib all: $(CCLIENTLIB) .c.obj: $(CC) -c $(CFLAGS) $*.c osdep.h: os_nt.h copy os_nt.h osdep.h drivers $(EXTRADRIVERS) $(DRIVERS) dummy setproto $(CREATEDRIVER) $(APPENDDRIVER) echo ssl_onceonlyinit (); >> linkage.c mkauths $(EXTRAAUTHENTICATORS) $(AUTHENTICATORS) echo mail_versioncheck (CCLIENTVERSION); >> linkage.c ip_nt.c: ip$(IP)_nt.c copy ip$(IP)_nt.c ip_nt.c mail.obj: mail.h misc.h osdep.h mail.c misc.obj: mail.h misc.h misc.c fdstring.obj: mail.h misc.h osdep.h fdstring.h fdstring.c flstring.obj: mail.h misc.h osdep.h flstring.h flstring.c netmsg.obj: mail.h misc.h netmsg.h osdep.h netmsg.c newsrc.obj: mail.h misc.h newsrc.h osdep.h newsrc.c rfc822.obj: mail.h rfc822.h misc.h rfc822.c smanager.obj: mail.h misc.h smanager.c utf8.obj: mail.h misc.h osdep.h utf8.h utf8aux.obj: mail.h misc.h osdep.h utf8.h imap4r1.obj: mail.h imap4r1.h misc.h osdep.h imap4r1.c nntp.obj: mail.h nntp.h smtp.h rfc822.h misc.h osdep.h nntp.c pop3.obj: mail.h rfc822.h misc.h osdep.h pop3.c smtp.obj: mail.h smtp.h rfc822.h misc.h osdep.h smtp.c os_w2k.obj: mail.h osdep.h env_nt.h fs.h ftl.h nl.h tcp.h tcp_nt.h yunchan.h \ os_w2k.c fs_nt.c ftl_nt.c nl_nt.c env_nt.c ssl_w2k.c ssl_none.c \ ip_nt.c tcp_nt.c yunchan.c pmatch.c write.c \ mailfile.h auth_gss.c auth_md5.c auth_pla.c auth_log.c kerb_w2k.c mbxnt.obj: mail.h misc.h osdep.h mbxnt.c mtxnt.obj: mail.h misc.h osdep.h mtxnt.c tenexnt.obj: mail.h misc.h osdep.h tenexnt.c unixnt.obj: mail.h unixnt.h pseudo.h misc.h osdep.h unixnt.c dummynt.obj: mail.h dummy.h misc.h osdep.h dummynt.c pseudo.obj: pseudo.h $(CCLIENTLIB): mail.obj misc.obj fdstring.obj flstring.obj netmsg.obj \ newsrc.obj rfc822.obj smanager.obj utf8.obj utf8aux.obj \ imap4r1.obj nntp.obj pop3.obj smtp.obj os_w2k.obj \ mbxnt.obj mtxnt.obj tenexnt.obj unixnt.obj dummynt.obj pseudo.obj if exist $(CCLIENTLIB) del $(CCLIENTLIB) LIB /NOLOGO /OUT:cclient.lib \ mail.obj misc.obj fdstring.obj flstring.obj netmsg.obj \ newsrc.obj rfc822.obj smanager.obj utf8.obj utf8aux.obj \ imap4r1.obj nntp.obj pop3.obj smtp.obj os_w2k.obj \ mbxnt.obj mtxnt.obj tenexnt.obj unixnt.obj dummynt.obj pseudo.obj clean: del *.lib *.obj linkage.* osdep.* ip_nt.c auths.c *.exe *.exp || rem # A monument to a hack of long ago and far away... love: @echo not war? alpine-2.10+dfsg/imap/src/osdep/nt/pseudo.h0000600000175000017500000000150611512502123022255 0ustar paulproteuspaulproteus/* ======================================================================== * Copyright 1988-2006 University of Washington * * Licensed under the Apache License, Version 2.0 (the "License"); * you may not use this file except in compliance with the License. * You may obtain a copy of the License at * * http://www.apache.org/licenses/LICENSE-2.0 * * * ======================================================================== */ /* * Program: Pseudo Header Strings * * Author: Mark Crispin * Networks and Distributed Computing * Computing & Communications * University of Washington * Administration Building, AG-44 * Seattle, WA 98195 * Internet: MRC@CAC.Washington.EDU * * Date: 26 September 1996 * Last Edited: 30 August 2006 */ extern char *pseudo_from,*pseudo_name,*pseudo_subject,*pseudo_msg; alpine-2.10+dfsg/imap/src/osdep/nt/dummynt.c0000600000175000017500000005265411512502123022460 0ustar paulproteuspaulproteus/* ======================================================================== * Copyright 1988-2007 University of Washington * * Licensed under the Apache License, Version 2.0 (the "License"); * you may not use this file except in compliance with the License. * You may obtain a copy of the License at * * http://www.apache.org/licenses/LICENSE-2.0 * * * ======================================================================== */ /* * Program: Dummy routines for NT * * Author: Mark Crispin * Networks and Distributed Computing * Computing & Communications * University of Washington * Administration Building, AG-44 * Seattle, WA 98195 * Internet: MRC@CAC.Washington.EDU * * Date: 24 May 1993 * Last Edited: 1 June 2007 */ #include #include #include #include #include #include "mail.h" #include "osdep.h" #include #include #include "dummy.h" #include "misc.h" /* Function prototypes */ DRIVER *dummy_valid (char *name); void *dummy_parameters (long function,void *value); void dummy_list_work (MAILSTREAM *stream,char *dir,char *pat,char *contents, long level); long dummy_listed (MAILSTREAM *stream,char delimiter,char *name, long attributes,char *contents); long dummy_subscribe (MAILSTREAM *stream,char *mailbox); MAILSTREAM *dummy_open (MAILSTREAM *stream); void dummy_close (MAILSTREAM *stream,long options); long dummy_ping (MAILSTREAM *stream); void dummy_check (MAILSTREAM *stream); long dummy_expunge (MAILSTREAM *stream,char *sequence,long options); long dummy_copy (MAILSTREAM *stream,char *sequence,char *mailbox,long options); long dummy_append (MAILSTREAM *stream,char *mailbox,append_t af,void *data); /* Dummy routines */ /* Driver dispatch used by MAIL */ DRIVER dummydriver = { "dummy", /* driver name */ DR_LOCAL|DR_MAIL, /* driver flags */ (DRIVER *) NIL, /* next driver */ dummy_valid, /* mailbox is valid for us */ dummy_parameters, /* manipulate parameters */ dummy_scan, /* scan mailboxes */ dummy_list, /* list mailboxes */ dummy_lsub, /* list subscribed mailboxes */ dummy_subscribe, /* subscribe to mailbox */ NIL, /* unsubscribe from mailbox */ dummy_create, /* create mailbox */ dummy_delete, /* delete mailbox */ dummy_rename, /* rename mailbox */ mail_status_default, /* status of mailbox */ dummy_open, /* open mailbox */ dummy_close, /* close mailbox */ NIL, /* fetch message "fast" attributes */ NIL, /* fetch message flags */ NIL, /* fetch overview */ NIL, /* fetch message structure */ NIL, /* fetch header */ NIL, /* fetch text */ NIL, /* fetch message data */ NIL, /* unique identifier */ NIL, /* message number from UID */ NIL, /* modify flags */ NIL, /* per-message modify flags */ NIL, /* search for message based on criteria */ NIL, /* sort messages */ NIL, /* thread messages */ dummy_ping, /* ping mailbox to see if still alive */ dummy_check, /* check for new messages */ dummy_expunge, /* expunge deleted messages */ dummy_copy, /* copy messages to another mailbox */ dummy_append, /* append string message to mailbox */ NIL /* garbage collect stream */ }; /* prototype stream */ MAILSTREAM dummyproto = {&dummydriver}; /* Dummy validate mailbox * Accepts: mailbox name * Returns: our driver if name is valid, NIL otherwise */ DRIVER *dummy_valid (char *name) { char *s,*t,tmp[MAILTMPLEN]; struct stat sbuf; /* must be valid local mailbox */ if (name && *name && (*name != '{') && (s = mailboxfile (tmp,name))) { /* indeterminate INBOX */ if (!*s) return &dummydriver; /* remove trailing \ */ if ((t = strrchr (s,'\\')) && !t[1]) *t = '\0'; if (!stat (s,&sbuf)) switch (sbuf.st_mode & S_IFMT) { case S_IFREG: /* file */ case S_IFDIR: /* future use */ return &dummydriver; } } return NIL; } /* Dummy manipulate driver parameters * Accepts: function code * function-dependent value * Returns: function-dependent return value */ void *dummy_parameters (long function,void *value) { return NIL; } /* Dummy scan mailboxes * Accepts: mail stream * reference * pattern to search * string to scan */ void dummy_scan (MAILSTREAM *stream,char *ref,char *pat,char *contents) { char *s,test[MAILTMPLEN],file[MAILTMPLEN]; long i = 0; if (!pat || !*pat) { /* empty pattern? */ if (dummy_canonicalize (test,ref,"*")) { /* tie off name at root */ if (s = strchr (test,'\\')) *++s = '\0'; else test[0] = '\0'; dummy_listed (stream,'\\',test,LATT_NOSELECT,NIL); } } /* get canonical form of name */ else if (dummy_canonicalize (test,ref,pat)) { /* found any wildcards? */ if (s = strpbrk (test,"%*")) { /* yes, copy name up to that point */ strncpy (file,test,(size_t) (i = s - test)); file[i] = '\0'; /* tie off */ } else strcpy (file,test); /* use just that name then */ /* find directory name */ if (s = strrchr (file,'\\')) { *++s = '\0'; /* found, tie off at that point */ s = file; } /* silly case */ else if (file[0] == '#') s = file; /* do the work */ dummy_list_work (stream,s,test,contents,0); if (pmatch ("INBOX",test)) /* always an INBOX */ dummy_listed (stream,NIL,"INBOX",LATT_NOINFERIORS,contents); } } /* Dummy list mailboxes * Accepts: mail stream * reference * pattern to search */ void dummy_list (MAILSTREAM *stream,char *ref,char *pat) { dummy_scan (stream,ref,pat,NIL); } /* Dummy list subscribed mailboxes * Accepts: mail stream * reference * pattern to search */ void dummy_lsub (MAILSTREAM *stream,char *ref,char *pat) { void *sdb = NIL; char *s,*t,test[MAILTMPLEN]; int showuppers = pat[strlen (pat) - 1] == '%'; /* get canonical form of name */ if (dummy_canonicalize (test,ref,pat) && (s = sm_read (&sdb))) do if (*s != '{') { if (pmatch_full (s,test,'\\')) { if (pmatch (s,"INBOX")) mm_lsub (stream,NIL,s,LATT_NOINFERIORS); else mm_lsub (stream,'\\',s,NIL); } else while (showuppers && (t = strrchr (s,'\\'))) { *t = '\0'; /* tie off the name */ if (pmatch_full (s,test,'\\')) mm_lsub (stream,'\\',s,LATT_NOSELECT); } } while (s = sm_read (&sdb)); /* until no more subscriptions */ } /* Dummy subscribe to mailbox * Accepts: mail stream * mailbox to add to subscription list * Returns: T on success, NIL on failure */ long dummy_subscribe (MAILSTREAM *stream,char *mailbox) { char *s,tmp[MAILTMPLEN]; struct stat sbuf; /* must be valid local mailbox */ if ((s = mailboxfile (tmp,mailbox)) && *s && !stat (s,&sbuf) && ((sbuf.st_mode & S_IFMT) == S_IFREG)) return sm_subscribe (mailbox); sprintf (tmp,"Can't subscribe %.80s: not a mailbox",mailbox); mm_log (tmp,ERROR); return NIL; } /* Dummy list mailboxes worker routine * Accepts: mail stream * directory name to search * search pattern * string to scan * search level */ void dummy_list_work (MAILSTREAM *stream,char *dir,char *pat,char *contents, long level) { struct _finddata_t f; struct stat sbuf; long fhandle; char tmp[MAILTMPLEN]; size_t len = 0; /* punt if bogus name */ if (!mailboxdir (tmp,dir,NIL)) return; /* make directory wildcard */ strcat (tmp,(tmp[strlen (tmp) -1] == '\\') ? "*.*" : "\\*.*"); /* do nothing if can't open directory */ if ((fhandle = _findfirst (tmp,&f)) >= 0) { /* list it if at top-level */ if (!level && dir && pmatch_full (dir,pat,'\\')) dummy_listed (stream,'\\',dir,LATT_NOSELECT,contents); /* scan directory */ if (!dir || dir[(len = strlen (dir)) - 1] == '\\') do if (((f.name[0] != '.') || (f.name[1] && ((f.name[1] != '.') || f.name[2]))) && ((len + strlen (f.name)) <= NETMAXMBX)) { /* see if name is useful */ if (dir) sprintf (tmp,"%s%s",dir,f.name); else strcpy (tmp,f.name); /* make sure useful and can get info */ if ((pmatch_full (tmp,pat,'\\') || pmatch_full (strcat (tmp,"\\"),pat,'\\') || dmatch (tmp,pat,'\\')) && mailboxdir (tmp,dir,f.name) && tmp[0] && !stat (tmp,&sbuf)) { /* now make name we'd return */ if (dir) sprintf (tmp,"%s%s",dir,f.name); else strcpy (tmp,f.name); /* only interested in file type */ switch (sbuf.st_mode & S_IFMT) { case S_IFDIR: /* directory? */ if (pmatch_full (tmp,pat,'\\')) { if (!dummy_listed (stream,'\\',tmp,LATT_NOSELECT,contents))break; strcat (tmp,"\\");/* set up for dmatch call */ } /* try again with trailing \ */ else if (pmatch_full (strcat (tmp,"\\"),pat,'\\') && !dummy_listed (stream,'\\',tmp,LATT_NOSELECT,contents)) break; if (dmatch (tmp,pat,'\\') && (level < (long) mail_parameters (NIL,GET_LISTMAXLEVEL,NIL))) dummy_list_work (stream,tmp,pat,contents,level+1); break; case S_IFREG: /* ordinary name */ if (pmatch_full (tmp,pat,'\\') && !pmatch ("INBOX",tmp)) dummy_listed (stream,'\\',tmp,LATT_NOINFERIORS,contents); break; } } } while (!_findnext (fhandle,&f)); _findclose(fhandle); } } /* Mailbox found * Accepts: hierarchy delimiter * mailbox name * attributes * contents to search before calling mm_list() * Returns: T, always */ #define BUFSIZE 4*MAILTMPLEN long dummy_listed (MAILSTREAM *stream,char delimiter,char *name, long attributes,char *contents) { struct stat sbuf; struct _finddata_t f; int fd,nochild; long fhandle,csiz,ssiz,bsiz; char *s,*buf,tmp[MAILTMPLEN]; /* if not \NoInferiors */ if (!(attributes & LATT_NOINFERIORS) && mailboxdir (tmp,name,NIL) && strcat (tmp,(tmp[strlen (tmp) -1] == '\\') ? "*.*" : "\\*.*") && ((fhandle = _findfirst (tmp,&f)) >= 0)) { nochild = T; do if ((f.name[0] != '.') || (f.name[1] && ((f.name[1] != '.') || f.name[2]))) nochild = NIL; while (nochild && !_findnext (fhandle,&f)); attributes |= nochild ? LATT_HASNOCHILDREN : LATT_HASCHILDREN; _findclose (fhandle); /* all done, flush directory */ } if (contents) { /* want to search contents? */ /* forget it if can't select or open */ if ((attributes & LATT_NOSELECT) || !(csiz = strlen (contents)) || !(s = dummy_file (tmp,name)) || stat (s,&sbuf) || (csiz > sbuf.st_size) || ((fd = open (tmp,O_RDONLY,NIL)) < 0)) return T; /* get buffer including slop */ buf = (char *) fs_get (BUFSIZE + (ssiz = 4 * ((csiz / 4) + 1)) + 1); memset (buf,'\0',ssiz); /* no slop area the first time */ while (sbuf.st_size) { /* until end of file */ read (fd,buf+ssiz,bsiz = min (sbuf.st_size,BUFSIZE)); if (search ((unsigned char *) buf,bsiz+ssiz, (unsigned char *) contents,csiz)) break; memcpy (buf,buf+BUFSIZE,ssiz); sbuf.st_size -= bsiz; /* note that we read that much */ } fs_give ((void **) &buf); /* flush buffer */ close (fd); /* finished with file */ if (!sbuf.st_size) return T;/* not found */ } /* notify main program */ mm_list (stream,delimiter,name,attributes); return T; } /* Dummy create mailbox * Accepts: mail stream * mailbox name to create * Returns: T on success, NIL on failure */ long dummy_create (MAILSTREAM *stream,char *mailbox) { char tmp[MAILTMPLEN]; if (compare_cstring (mailbox,"INBOX") && dummy_file (tmp,mailbox)) return dummy_create_path (stream,tmp,NIL); sprintf (tmp,"Can't create %.80s: invalid name",mailbox); mm_log (tmp,ERROR); return NIL; } /* Dummy create path * Accepts: mail stream * path name to create * directory mode * Returns: T on success, NIL on failure */ long dummy_create_path (MAILSTREAM *stream,char *path,long dirmode) { struct stat sbuf; char c,*s,tmp[MAILTMPLEN]; int fd; long ret = NIL; char *t = strrchr (path,'\\'); char *pt = (path[1] == ':') ? path + 2 : path; int wantdir = t && !t[1]; if (wantdir) *t = '\0'; /* flush trailing delimiter for directory */ /* found superior to this name? */ if ((s = strrchr (pt,'\\')) && (s != pt)) { strncpy (tmp,path,(size_t) (s - path)); tmp[s - path] = '\0'; /* make directory name for stat */ c = *++s; /* tie off in case need to recurse */ *s = '\0'; /* name doesn't exist, create it */ if ((stat (tmp,&sbuf) || ((sbuf.st_mode & S_IFMT) != S_IFDIR)) && !dummy_create_path (stream,path,dirmode)) return NIL; *s = c; /* restore full name */ } if (wantdir) { /* want to create directory? */ ret = !mkdir (path); *t = '\\'; /* restore directory delimiter */ } /* create file */ else if ((fd = open (path,O_WRONLY|O_CREAT|O_EXCL,S_IREAD|S_IWRITE)) >= 0) ret = !close (fd); /* close file */ if (!ret) { /* error? */ sprintf (tmp,"Can't create mailbox node %.80s: %.80s",path, strerror (errno)); mm_log (tmp,ERROR); } return ret; /* return status */ } /* Dummy delete mailbox * Accepts: mail stream * mailbox name to delete * Returns: T on success, NIL on failure */ long dummy_delete (MAILSTREAM *stream,char *mailbox) { struct stat sbuf; char *s,tmp[MAILTMPLEN]; if (!(s = dummy_file (tmp,mailbox))) { sprintf (tmp,"Can't delete - invalid name: %.80s",s); mm_log (tmp,ERROR); } /* no trailing \ */ if ((s = strrchr (tmp,'\\')) && !s[1]) *s = '\0'; if (stat (tmp,&sbuf) || ((sbuf.st_mode & S_IFMT) == S_IFDIR) ? rmdir (tmp) : unlink (tmp)) { sprintf (tmp,"Can't delete mailbox %.80s: %.80s",mailbox,strerror (errno)); mm_log (tmp,ERROR); return NIL; } return T; /* return success */ } /* Mail rename mailbox * Accepts: mail stream * old mailbox name * new mailbox name * Returns: T on success, NIL on failure */ long dummy_rename (MAILSTREAM *stream,char *old,char *newname) { struct stat sbuf; char c,*s,tmp[MAILTMPLEN],mbx[MAILTMPLEN],oldname[MAILTMPLEN]; long ret = NIL; /* no trailing \ allowed */ if (!dummy_file (oldname,old) || !(s = dummy_file (mbx,newname)) || stat (oldname,&sbuf) || ((s = strrchr (s,'\\')) && !s[1] && ((sbuf.st_mode & S_IFMT) != S_IFDIR))) { sprintf (mbx,"Can't rename %.80s to %.80s: invalid name",old,newname); mm_log (mbx,ERROR); return NIL; } if (s) { /* found a directory delimiter? */ if (!s[1]) *s = '\0'; /* ignore trailing delimiter */ /* found superior to destination name? */ else if ((s != mbx) && ((mbx[1] != ':') || (s != mbx + 2))) { c = s[1]; /* remember character after delimiter */ *s = s[1] = '\0'; /* tie off name at delimiter */ /* name doesn't exist, create it */ if (stat (mbx,&sbuf) || ((sbuf.st_mode & S_IFMT) != S_IFDIR)) { *s = '\\'; /* restore delimiter */ if (!dummy_create (stream,mbx)) return NIL; } else *s = '\\'; /* restore delimiter */ s[1] = c; /* restore character after delimiter */ } } /* rename of non-ex INBOX creates dest */ if (!compare_cstring (old,"INBOX") && stat (oldname,&sbuf)) return dummy_create (NIL,mbx); if (rename (oldname,mbx)) { sprintf (tmp,"Can't rename mailbox %.80s to %.80s: %.80s",old,newname, strerror (errno)); mm_log (tmp,ERROR); return NIL; } return LONGT; /* return success */ } /* Dummy open * Accepts: stream to open * Returns: stream on success, NIL on failure */ MAILSTREAM *dummy_open (MAILSTREAM *stream) { int fd; char err[MAILTMPLEN],tmp[MAILTMPLEN]; struct stat sbuf; /* OP_PROTOTYPE call */ if (!stream) return &dummyproto; err[0] = '\0'; /* no error message yet */ /* can we open the file? */ if (!dummy_file (tmp,stream->mailbox)) sprintf (err,"Can't open this name: %.80s",stream->mailbox); else if ((fd = open (tmp,O_RDONLY,NIL)) < 0) { /* no, error unless INBOX */ if (compare_cstring (stream->mailbox,"INBOX")) sprintf (err,"%.80s: %.80s",strerror (errno),stream->mailbox); } else { /* file had better be empty then */ fstat (fd,&sbuf); /* sniff at its size */ close (fd); if (sbuf.st_size) /* bogus format if non-empty */ sprintf (err,"%.80s (file %.80s) is not in valid mailbox format", stream->mailbox,tmp); } if (err[0]) { /* if an error happened */ mm_log (err,stream->silent ? WARN : ERROR); return NIL; } else if (!stream->silent) { /* only if silence not requested */ mail_exists (stream,0); /* say there are 0 messages */ mail_recent (stream,0); /* and certainly no recent ones! */ stream->uid_validity = (unsigned long) time (0); } stream->inbox = T; /* note that it's an INBOX */ return stream; /* return success */ } /* Dummy close * Accepts: MAIL stream * options */ void dummy_close (MAILSTREAM *stream,long options) { /* return silently */ } /* Dummy ping mailbox * Accepts: MAIL stream * Returns: T if stream alive, else NIL */ long dummy_ping (MAILSTREAM *stream) { MAILSTREAM *test; /* time to do another test? */ if (time (0) >= ((time_t) (stream->gensym + 30))) { /* has mailbox format changed? */ if ((test = mail_open (NIL,stream->mailbox,OP_PROTOTYPE)) && (test->dtb != stream->dtb) && (test = mail_open (NIL,stream->mailbox,NIL))) { /* preserve some resources */ test->original_mailbox = stream->original_mailbox; stream->original_mailbox = NIL; test->sparep = stream->sparep; stream->sparep = NIL; test->sequence = stream->sequence; mail_close ((MAILSTREAM *) /* flush resources used by dummy stream */ memcpy (fs_get (sizeof (MAILSTREAM)),stream, sizeof (MAILSTREAM))); /* swap the streams */ memcpy (stream,test,sizeof (MAILSTREAM)); fs_give ((void **) &test);/* flush test now that copied */ /* make sure application knows */ mail_exists (stream,stream->recent = stream->nmsgs); } /* still hasn't changed */ else stream->gensym = (unsigned long) time (0); } return T; } /* Dummy check mailbox * Accepts: MAIL stream * No-op for readonly files, since read/writer can expunge it from under us! */ void dummy_check (MAILSTREAM *stream) { dummy_ping (stream); /* invoke ping */ } /* Dummy expunge mailbox * Accepts: MAIL stream * sequence to expunge if non-NIL * expunge options * Returns: T, always */ long dummy_expunge (MAILSTREAM *stream,char *sequence,long options) { return LONGT; } /* Dummy copy message(s) * Accepts: MAIL stream * sequence * destination mailbox * options * Returns: T if copy successful, else NIL */ long dummy_copy (MAILSTREAM *stream,char *sequence,char *mailbox,long options) { if ((options & CP_UID) ? mail_uid_sequence (stream,sequence) : mail_sequence (stream,sequence)) fatal ("Impossible dummy_copy"); return NIL; } /* Dummy append message string * Accepts: mail stream * destination mailbox * append callback function * data for callback * Returns: T on success, NIL on failure */ long dummy_append (MAILSTREAM *stream,char *mailbox,append_t af,void *data) { struct stat sbuf; int fd = -1; int e; char tmp[MAILTMPLEN]; MAILSTREAM *ts = default_proto (T); if (compare_cstring (mailbox,"INBOX") && dummy_file (tmp,mailbox) && ((fd = open (tmp,O_RDONLY,NIL)) < 0)) { if ((e = errno) == ENOENT) /* failed, was it no such file? */ mm_notify (stream,"[TRYCREATE] Must create mailbox before append", (long) NIL); sprintf (tmp,"%.80s: %.80s",strerror (e),mailbox); mm_log (tmp,ERROR); /* pass up error */ return NIL; /* always fails */ } if (fd >= 0) { /* found file? */ fstat (fd,&sbuf); /* get its size */ close (fd); /* toss out the fd */ if (sbuf.st_size) ts = NIL; /* non-empty file? */ } if (ts) return (*ts->dtb->append) (stream,mailbox,af,data); sprintf (tmp,"Indeterminate mailbox format: %.80s",mailbox); mm_log (tmp,ERROR); return NIL; } /* Dummy mail generate file string * Accepts: temporary buffer to write into * mailbox name string * Returns: local file string or NIL if failure */ char *dummy_file (char *dst,char *name) { char *s = mailboxfile (dst,name); /* return our standard inbox */ return (s && !*s) ? strcpy (dst,sysinbox ()) : s; } /* Dummy canonicalize name * Accepts: buffer to write name * reference * pattern * Returns: T if success, NIL if failure */ long dummy_canonicalize (char *tmp,char *ref,char *pat) { unsigned long i; char *s,dev[4]; /* initially no device */ dev[0] = dev[1] = dev[2] = dev[3] = '\0'; if (ref) switch (*ref) { /* preliminary reference check */ case '{': /* remote names not allowed */ return NIL; /* disallowed */ case '\0': /* empty reference string */ break; default: /* all other names */ if (ref[1] == ':') { /* start with device name? */ dev[0] = *ref++; dev[1] = *ref++; } break; } if (pat[1] == ':') { /* device name in pattern? */ dev[0] = *pat++; dev[1] = *pat++; ref = NIL; /* ignore reference */ } switch (*pat) { case '#': /* namespace names */ if (mailboxfile (tmp,pat)) strcpy (tmp,pat); else return NIL; /* unknown namespace */ break; case '{': /* remote names not allowed */ return NIL; case '\\': /* rooted name */ ref = NIL; /* ignore reference */ break; } /* make sure device names are rooted */ if (dev[0] && (*(ref ? ref : pat) != '\\')) dev[2] = '\\'; /* build name */ sprintf (tmp,"%s%s%s",dev,ref ? ref : "",pat); ucase (tmp); /* force upper case */ /* count wildcards */ for (i = 0, s = tmp; *s; *s++) if ((*s == '*') || (*s == '%')) ++i; if (i > MAXWILDCARDS) { /* ridiculous wildcarding? */ MM_LOG ("Excessive wildcards in LIST/LSUB",ERROR); return NIL; } return T; } alpine-2.10+dfsg/imap/src/osdep/nt/os_nt.c0000600000175000017500000000237511512502123022100 0ustar paulproteuspaulproteus/* ======================================================================== * Copyright 1988-2006 University of Washington * * Licensed under the Apache License, Version 2.0 (the "License"); * you may not use this file except in compliance with the License. * You may obtain a copy of the License at * * http://www.apache.org/licenses/LICENSE-2.0 * * * ======================================================================== */ /* * Program: Operating-system dependent routines -- NT version * * Author: Mark Crispin * Networks and Distributed Computing * Computing & Communications * University of Washington * Administration Building, AG-44 * Seattle, WA 98195 * Internet: MRC@CAC.Washington.EDU * * Date: 11 April 1989 * Last Edited: 30 August 2006 */ #include "tcp_nt.h" /* must be before osdep includes tcp.h */ #undef ERROR /* quell conflicting def warning */ #include "mail.h" #include "osdep.h" #include #include #include #include #include #include #include "misc.h" #include "mailfile.h" #include "fs_nt.c" #include "ftl_nt.c" #include "nl_nt.c" #include "yunchan.c" #include "tcp_nt.c" /* must be before env_nt.c */ #include "env_nt.c" #include "ssl_nt.c" alpine-2.10+dfsg/imap/src/osdep/nt/nl_nt.c0000600000175000017500000000331711512502123022065 0ustar paulproteuspaulproteus/* ======================================================================== * Copyright 1988-2006 University of Washington * * Licensed under the Apache License, Version 2.0 (the "License"); * you may not use this file except in compliance with the License. * You may obtain a copy of the License at * * http://www.apache.org/licenses/LICENSE-2.0 * * * ======================================================================== */ /* * Program: Windows/TOPS-20 newline routines * * Author: Mark Crispin * Networks and Distributed Computing * Computing & Communications * University of Washington * Administration Building, AG-44 * Seattle, WA 98195 * Internet: MRC@CAC.Washington.EDU * * Date: 1 August 1988 * Last Edited: 30 August 2006 */ /* Copy string with CRLF newlines * Accepts: destination string * pointer to size of destination string buffer * source string * length of source string * Returns: length of copied string */ unsigned long strcrlfcpy (unsigned char **dst,unsigned long *dstl, unsigned char *src,unsigned long srcl) { /* flush destination buffer if too small */ if (*dst && (srcl > *dstl)) fs_give ((void **) dst); if (!*dst) { /* make a new buffer if needed */ *dst = (char *) fs_get ((size_t) (*dstl = srcl) + 1); if (dstl) *dstl = srcl; /* return new buffer length to main program */ } /* copy strings */ if (srcl) memcpy (*dst,src,(size_t) srcl); *(*dst + srcl) = '\0'; /* tie off destination */ return srcl; /* return length */ } /* Length of string after strcrlfcpy applied * Accepts: source string * Returns: length of string */ unsigned long strcrlflen (STRING *s) { return SIZE (s); /* no-brainer on DOS! */ } alpine-2.10+dfsg/imap/src/osdep/nt/ip6_nt.c0000600000175000017500000002105011512502123022144 0ustar paulproteuspaulproteus/* ======================================================================== * Copyright 1988-2006 University of Washington * * Licensed under the Apache License, Version 2.0 (the "License"); * you may not use this file except in compliance with the License. * You may obtain a copy of the License at * * http://www.apache.org/licenses/LICENSE-2.0 * * * ======================================================================== */ /* * Program: UNIX IPv6 routines * * Author: Mark Crispin * Networks and Distributed Computing * Computing & Communications * University of Washington * Administration Building, AG-44 * Seattle, WA 98195 * Internet: MRC@CAC.Washington.EDU * * Date: 18 December 2003 * Last Edited: 30 August 2006 */ /* * There is some amazingly bad design in IPv6 sockets. * * Supposedly, the new getnameinfo() and getaddrinfo() functions create an * abstraction that is not dependent upon IPv4 or IPv6. However, the * definition of getnameinfo() requires that the caller pass the length of * the sockaddr instead of deriving it from sa_family. The man page says * that there's an sa_len member in the sockaddr, but actually there isn't. * This means that any caller to getnameinfo() and getaddrinfo() has to know * the size for the protocol family used by that sockaddr. * * The new sockaddr_in6 is bigger than the generic sockaddr (which is what * connect(), accept(), bind(), getpeername(), getsockname(), etc. expect). * Rather than increase the size of sockaddr, there's a new sockaddr_storage * which is only usable for allocating space. */ #define SADRLEN sizeof (struct sockaddr_storage) #define SADR4(sadr) ((struct sockaddr_in *) sadr) #define SADR4LEN sizeof (struct sockaddr_in) #define SADR4ADR(sadr) SADR4 (sadr)->sin_addr #define ADR4LEN sizeof (struct in_addr) #define SADR4PORT(sadr) SADR4 (sadr)->sin_port #define SADR6(sadr) ((struct sockaddr_in6 *) sadr) #define SADR6LEN sizeof (struct sockaddr_in6) #define SADR6ADR(sadr) SADR6 (sadr)->sin6_addr #define ADR6LEN sizeof (struct in6_addr) #define SADR6PORT(sadr) SADR6 (sadr)->sin6_port /* IP abstraction layer */ char *ip_sockaddrtostring (struct sockaddr *sadr); long ip_sockaddrtoport (struct sockaddr *sadr); void *ip_stringtoaddr (char *text,size_t *len,int *family); struct sockaddr *ip_newsockaddr (size_t *len); struct sockaddr *ip_sockaddr (int family,void *adr,size_t adrlen, unsigned short port,size_t *len); char *ip_sockaddrtoname (struct sockaddr *sadr); void *ip_nametoaddr (char *name,size_t *len,int *family,char **canonical, void **next); /* Return IP address string from socket address * Accepts: socket address * Returns: IP address as name string */ char *ip_sockaddrtostring (struct sockaddr *sadr) { static char tmp[NI_MAXHOST]; switch (sadr->sa_family) { case PF_INET: /* IPv4 */ if (!getnameinfo (sadr,SADR4LEN,tmp,NI_MAXHOST,NIL,NIL,NI_NUMERICHOST)) return tmp; break; case PF_INET6: /* IPv6 */ if (!getnameinfo (sadr,SADR6LEN,tmp,NI_MAXHOST,NIL,NIL,NI_NUMERICHOST)) return tmp; break; } return "NON-IP"; } /* Return port from socket address * Accepts: socket address * Returns: port number or -1 if can't determine it */ long ip_sockaddrtoport (struct sockaddr *sadr) { switch (sadr->sa_family) { case PF_INET: return ntohs (SADR4PORT (sadr)); case PF_INET6: return ntohs (SADR6PORT (sadr)); } return -1; } /* Return IP address from string * Accepts: name string * pointer to returned length * pointer to returned address family * Returns: address if valid, length and family updated, or NIL */ void *ip_stringtoaddr (char *text,size_t *len,int *family) { char tmp[MAILTMPLEN]; static struct addrinfo *hints; struct addrinfo *ai; void *adr = NIL; if (!hints) { /* hints set up yet? */ hints = (struct addrinfo *) /* one-time setup */ memset (fs_get (sizeof (struct addrinfo)),0,sizeof (struct addrinfo)); hints->ai_family = AF_UNSPEC;/* allow any address family */ hints->ai_socktype = SOCK_STREAM; /* numeric name only */ hints->ai_flags = AI_NUMERICHOST; } /* case-independent lookup */ if (text && (strlen (text) < MAILTMPLEN) && (!getaddrinfo (lcase (strcpy (tmp,text)),NIL,hints,&ai))) { switch (*family = ai->ai_family) { case AF_INET: /* IPv4 */ adr = fs_get (*len = ADR4LEN); memcpy (adr,(void *) &SADR4ADR (ai->ai_addr),*len); break; case AF_INET6: /* IPv6 */ adr = fs_get (*len = ADR6LEN); memcpy (adr,(void *) &SADR6ADR (ai->ai_addr),*len); break; } freeaddrinfo (ai); /* free addrinfo */ } return adr; } /* Create a maximum-size socket address * Accepts: pointer to return maximum socket address length * Returns: new, empty socket address of maximum size */ struct sockaddr *ip_newsockaddr (size_t *len) { return (struct sockaddr *) memset (fs_get (SADRLEN),0,*len = SADRLEN); } /* Stuff a socket address * Accepts: address family * IPv4 address * length of address * port number * pointer to return socket address length * Returns: socket address */ struct sockaddr *ip_sockaddr (int family,void *adr,size_t adrlen, unsigned short port,size_t *len) { struct sockaddr *sadr = ip_newsockaddr (len); switch (family) { /* build socket address based upon family */ case AF_INET: /* IPv4 */ sadr->sa_family = PF_INET; /* copy host address */ memcpy (&SADR4ADR (sadr),adr,adrlen); /* copy port number in network format */ SADR4PORT (sadr) = htons (port); *len = SADR4LEN; break; case AF_INET6: /* IPv6 */ sadr->sa_family = PF_INET6; /* copy host address */ memcpy (&SADR6ADR (sadr),adr,adrlen); /* copy port number in network format */ SADR6PORT (sadr) = htons (port); *len = SADR6LEN; break; default: /* non-IP?? */ sadr->sa_family = PF_UNSPEC; break; } return sadr; } /* Return name from socket address * Accepts: socket address * Returns: canonical name for that address or NIL if none */ char *ip_sockaddrtoname (struct sockaddr *sadr) { static char tmp[NI_MAXHOST]; switch (sadr->sa_family) { case PF_INET: /* IPv4 */ if (!getnameinfo (sadr,SADR4LEN,tmp,NI_MAXHOST,NIL,NIL,NI_NAMEREQD)) return tmp; break; case PF_INET6: /* IPv6 */ if (!getnameinfo (sadr,SADR6LEN,tmp,NI_MAXHOST,NIL,NIL,NI_NAMEREQD)) return tmp; break; } return NIL; } /* Return address from name * Accepts: name or NIL to return next address * pointer to previous/returned length * pointer to previous/returned address family * pointer to previous/returned canonical name * pointer to previous/return state for next-address calls * Returns: address with length/family/canonical updated if needed, or NIL */ void *ip_nametoaddr (char *name,size_t *len,int *family,char **canonical, void **next) { struct addrinfo *cur = NIL; static struct addrinfo *hints; static struct addrinfo *ai = NIL; static char lcname[MAILTMPLEN]; if (!hints) { /* hints set up yet? */ hints = (struct addrinfo *) /* one-time setup */ memset (fs_get (sizeof (struct addrinfo)),0,sizeof (struct addrinfo)); /* allow any address family */ hints->ai_family = AF_UNSPEC; hints->ai_socktype = SOCK_STREAM; /* need canonical name */ hints->ai_flags = AI_CANONNAME; } if (name) { /* name supplied? */ if (ai) { freeaddrinfo (ai); /* free old addrinfo */ ai = NIL; } /* case-independent lookup */ if ((strlen (name) < MAILTMPLEN) && (!getaddrinfo (lcase (strcpy (lcname,name)),NIL,hints,&ai))) { cur = ai; /* current block */ if (canonical) /* set canonical name */ *canonical = cur->ai_canonname ? cur->ai_canonname : lcname; /* remember as next block */ if (next) *next = (void *) ai; } else { /* error */ cur = NIL; if (len) *len = 0; if (family) *family = 0; if (canonical) *canonical = NIL; if (next) *next = NIL; } } /* return next in series */ else if (next && (cur = ((struct addrinfo *) *next)->ai_next)) { *next = cur; /* set as last address */ /* set canonical in case changed */ if (canonical && cur->ai_canonname) *canonical = cur->ai_canonname; } if (cur) { /* got data? */ if (family) *family = cur->ai_family; switch (cur->ai_family) { case AF_INET: if (len) *len = ADR4LEN; return (void *) &SADR4ADR (cur->ai_addr); case AF_INET6: if (len) *len = ADR6LEN; return (void *) &SADR6ADR (cur->ai_addr); } } if (len) *len = 0; /* error return */ return NIL; } alpine-2.10+dfsg/imap/src/osdep/nt/tcp_nt.c0000600000175000017500000006724312074110156022257 0ustar paulproteuspaulproteus/* ======================================================================== * Copyright 1988-2007 University of Washington * * Licensed under the Apache License, Version 2.0 (the "License"); * you may not use this file except in compliance with the License. * You may obtain a copy of the License at * * http://www.apache.org/licenses/LICENSE-2.0 * * * ======================================================================== */ /* * Program: Winsock TCP/IP routines * * Author: Mark Crispin from Mike Seibel's Winsock code * Networks and Distributed Computing * Computing & Communications * University of Washington * Administration Building, AG-44 * Seattle, WA 98195 * Internet: MRC@CAC.Washington.EDU * * Date: 11 April 1989 * Last Edited: 13 January 2007 */ #include "ip_nt.c" #define TCPMAXSEND 32768 /* Private functions */ int tcp_socket_open (int family,void *adr,size_t adrlen,unsigned short port, char *tmp,char *hst); static char *tcp_getline_work (TCPSTREAM *stream,unsigned long *size, long *contd); long tcp_abort (TCPSTREAM *stream); long tcp_close_socket (SOCKET *sock); char *tcp_name (struct sockaddr *sadr,long flag); char *tcp_name_valid (char *s); /* Private data */ int wsa_initted = 0; /* init ? */ static int wsa_sock_open = 0; /* keep track of open sockets */ static tcptimeout_t tmoh = NIL; /* TCP timeout handler routine */ static long ttmo_open = 0; /* TCP timeouts, in seconds */ static long ttmo_read = 0; static long ttmo_write = 0; static long allowreversedns = T;/* allow reverse DNS lookup */ static long tcpdebug = NIL; /* extra TCP debugging telemetry */ static char *myClientAddr = NIL;/* client host address */ static char *myClientHost = NIL;/* client host name */ static long myClientPort = -1; /* client port */ static char *myServerAddr = NIL;/* server host address */ static char *myServerHost = NIL;/* server host name */ static long myServerPort = -1; /* server port */ extern long maxposint; /* get this from write.c */ /* TCP/IP manipulate parameters * Accepts: function code * function-dependent value * Returns: function-dependent return value */ void *tcp_parameters (long function,void *value) { void *ret = NIL; switch ((int) function) { case SET_TIMEOUT: tmoh = (tcptimeout_t) value; case GET_TIMEOUT: ret = (void *) tmoh; break; case SET_OPENTIMEOUT: ttmo_open = (long) value ? (long) value : (long) WSA_INFINITE; case GET_OPENTIMEOUT: ret = (void *) ttmo_open; break; case SET_READTIMEOUT: ttmo_read = (long) value; case GET_READTIMEOUT: ret = (void *) ttmo_read; break; case SET_WRITETIMEOUT: ttmo_write = (long) value; case GET_WRITETIMEOUT: ret = (void *) ttmo_write; break; case SET_ALLOWREVERSEDNS: allowreversedns = (long) value; case GET_ALLOWREVERSEDNS: ret = (void *) allowreversedns; break; case SET_TCPDEBUG: tcpdebug = (long) value; case GET_TCPDEBUG: ret = (void *) tcpdebug; break; } return ret; } /* TCP/IP open * Accepts: host name * contact service name * contact port number and optional silent flag * Returns: TCP/IP stream if success else NIL */ TCPSTREAM *tcp_open (char *host,char *service,unsigned long port) { TCPSTREAM *stream = NIL; int i,family; SOCKET sock = INVALID_SOCKET; int silent = (port & NET_SILENT) ? T : NIL; char *s,*hostname,tmp[MAILTMPLEN]; void *adr,*next; size_t adrlen; struct servent *sv = NIL; blocknotify_t bn = (blocknotify_t) mail_parameters (NIL,GET_BLOCKNOTIFY,NIL); if (!wsa_initted++) { /* init Windows Sockets */ WSADATA wsock; if (i = (int) WSAStartup (WINSOCK_VERSION,&wsock)) { wsa_initted = 0; /* in case we try again */ sprintf (tmp,"Unable to start Windows Sockets (%d)",i); mm_log (tmp,ERROR); return NIL; } } port &= 0xffff; /* erase flags */ /* lookup service */ if (service && (sv = getservbyname (service,"tcp"))) port = ntohs (sv->s_port); /* The domain literal form is used (rather than simply the dotted decimal as with other Windows programs) because it has to be a valid "host name" in mailsystem terminology. */ /* look like domain literal? */ if (host[0] == '[' && host[(strlen (host))-1] == ']') { strcpy (tmp,host+1); /* yes, copy number part */ tmp[strlen (tmp)-1] = '\0'; if (adr = ip_stringtoaddr (tmp,&adrlen,&family)) { (*bn) (BLOCK_TCPOPEN,NIL); sock = tcp_socket_open (family,adr,adrlen,(unsigned short) port,tmp, hostname = host); (*bn) (BLOCK_NONE,NIL); fs_give ((void **) &adr); } else sprintf (tmp,"Bad format domain-literal: %.80s",host); } else { /* lookup host name */ if (tcpdebug) { sprintf (tmp,"DNS resolution %.80s",host); mm_log (tmp,TCPDEBUG); } (*bn) (BLOCK_DNSLOOKUP,NIL);/* look up name */ if (!(s = ip_nametoaddr (host,&adrlen,&family,&hostname,&next))) sprintf (tmp,"Host not found (#%d): %s",WSAGetLastError (),host); (*bn) (BLOCK_NONE,NIL); if (s) { /* DNS resolution won? */ if (tcpdebug) mm_log ("DNS resolution done",TCPDEBUG); wsa_sock_open++; /* prevent tcp_close_socket() from freeing in loop */ do { (*bn) (BLOCK_TCPOPEN,NIL); if (((sock = tcp_socket_open (family,s,adrlen,(unsigned short) port, tmp,hostname)) == INVALID_SOCKET) && (s = ip_nametoaddr (NIL,&adrlen,&family,&hostname,&next)) && !silent) mm_log (tmp,WARN); (*bn) (BLOCK_NONE,NIL); } while ((sock == INVALID_SOCKET) && s); wsa_sock_open--; /* undo protection */ } } if (sock == INVALID_SOCKET) { /* do possible cleanup action */ if (!silent) mm_log (tmp,ERROR); tcp_close_socket (&sock); } else { /* got a socket, create TCP/IP stream */ stream = (TCPSTREAM *) memset (fs_get (sizeof (TCPSTREAM)),0, sizeof (TCPSTREAM)); stream->port = port; /* port number */ /* init socket */ stream->tcpsi = stream->tcpso = sock; stream->ictr = 0; /* init input counter */ /* copy official host name */ stream->host = cpystr (hostname); if (tcpdebug) mm_log ("Stream open and ready for read",TCPDEBUG); } return stream; /* return success */ } /* Open a TCP socket * Accepts: protocol family * address to connect to * address length * port * scratch buffer * host name * Returns: socket if success, else SOCKET_ERROR with error string in scratch */ int tcp_socket_open (int family,void *adr,size_t adrlen,unsigned short port, char *tmp,char *hst) { int sock,err; char *s,errmsg[100]; size_t len; DWORD eo; WSAEVENT event; WSANETWORKEVENTS events; unsigned long cmd = 0; struct protoent *pt = getprotobyname ("tcp"); struct sockaddr *sadr = ip_sockaddr (family,adr,adrlen,port,&len); sprintf (tmp,"Trying IP address [%s]",ip_sockaddrtostring (sadr)); mm_log (tmp,NIL); /* get a TCP stream */ if ((sock = socket (sadr->sa_family,SOCK_STREAM,pt ? pt->p_proto : 0)) == INVALID_SOCKET) sprintf (tmp,"Unable to create TCP socket (%d)",WSAGetLastError ()); else { /* On Windows, FD_SETSIZE is the number of descriptors which can be * held in an fd_set, as opposed to the maximum descriptor value on UNIX. * Similarly, an fd_set in Windows is a vector of descriptor values, as * opposed to a bitmask of set fds on UNIX. Thus, an fd_set can hold up * to FD_SETSIZE values which can be larger than FD_SETSIZE, and the test * that is used on UNIX is unnecessary here. */ wsa_sock_open++; /* count this socket as open */ /* set socket nonblocking */ if (ttmo_open) WSAEventSelect (sock,event = WSACreateEvent (),FD_CONNECT); else event = 0; /* no event */ /* open connection */ err = (connect (sock,sadr,len) == SOCKET_ERROR) ? WSAGetLastError () : NIL; /* if timer in effect, wait for event */ if (event) while (err == WSAEWOULDBLOCK) switch (eo = WSAWaitForMultipleEvents (1,&event,T,ttmo_open*1000,NIL)) { case WSA_WAIT_EVENT_0: /* got an event? */ err = (WSAEnumNetworkEvents (sock,event,&events) == SOCKET_ERROR) ? WSAGetLastError () : events.iErrorCode[FD_CONNECT_BIT]; break; case WSA_WAIT_IO_COMPLETION: break; /* fAlertable is NIL so shouldn't happen */ default: /* all other conditions */ err = eo; /* error from WSAWaitForMultipleEvents() */ break; } switch (err) { /* analyze result from connect and wait */ case 0: /* got a connection */ s = NIL; if (event) { /* unset blocking mode */ WSAEventSelect (sock,event,NIL); if (ioctlsocket (sock,FIONBIO,&cmd) == SOCKET_ERROR) sprintf (s = errmsg,"Can't set blocking mode (%d)", WSAGetLastError ()); } break; case WSAECONNREFUSED: s = "Refused"; break; case WSAENOBUFS: s = "Insufficient system resources"; break; case WSA_WAIT_TIMEOUT: case WSAETIMEDOUT: s = "Timed out"; break; case WSAEHOSTUNREACH: s = "Host unreachable"; break; default: /* horrible error 69 */ sprintf (s = errmsg,"Unknown error (%d)",err); break; } /* flush event */ if (event) WSACloseEvent (event); if (s) { /* got an error? */ sprintf (tmp,"Can't connect to %.80s,%ld: %.80s",hst,port,s); tcp_close_socket (&sock); /* flush socket */ sock = INVALID_SOCKET; } } fs_give ((void **) &sadr); /* and socket address */ return sock; /* return the socket */ } /* TCP/IP authenticated open * Accepts: NETMBX specifier * service name * returned user name buffer * Returns: TCP/IP stream if success else NIL */ TCPSTREAM *tcp_aopen (NETMBX *mb,char *service,char *usrbuf) { return NIL; /* always NIL on Windows */ } /* TCP receive line * Accepts: TCP stream * Returns: text line string or NIL if failure */ char *tcp_getline (TCPSTREAM *stream) { unsigned long n,contd; char *ret = tcp_getline_work (stream,&n,&contd); if (ret && contd) { /* got a line needing continuation? */ STRINGLIST *stl = mail_newstringlist (); STRINGLIST *stc = stl; do { /* collect additional lines */ stc->text.data = (unsigned char *) ret; stc->text.size = n; stc = stc->next = mail_newstringlist (); ret = tcp_getline_work (stream,&n,&contd); } while (ret && contd); if (ret) { /* stash final part of line on list */ stc->text.data = (unsigned char *) ret; stc->text.size = n; /* determine how large a buffer we need */ for (n = 0, stc = stl; stc; stc = stc->next) n += stc->text.size; ret = fs_get (n + 1); /* copy parts into buffer */ for (n = 0, stc = stl; stc; n += stc->text.size, stc = stc->next) memcpy (ret + n,stc->text.data,stc->text.size); ret[n] = '\0'; } mail_free_stringlist (&stl);/* either way, done with list */ } return ret; } /* TCP receive line or partial line * Accepts: TCP stream * pointer to return size * pointer to return continuation flag * Returns: text line string, size and continuation flag, or NIL if failure */ static char *tcp_getline_work (TCPSTREAM *stream,unsigned long *size, long *contd) { unsigned long n; char *s,*ret,c,d; *contd = NIL; /* assume no continuation */ /* make sure have data */ if (!tcp_getdata (stream)) return NIL; for (s = stream->iptr, n = 0, c = '\0'; stream->ictr--; n++, c = d) { d = *stream->iptr++; /* slurp another character */ if ((c == '\015') && (d == '\012')) { ret = (char *) fs_get (n--); memcpy (ret,s,*size = n); /* copy into a free storage string */ ret[n] = '\0'; /* tie off string with null */ return ret; } } /* copy partial string from buffer */ memcpy ((ret = (char *) fs_get (n)),s,*size = n); /* get more data from the net */ if (!tcp_getdata (stream)) fs_give ((void **) &ret); /* special case of newline broken by buffer */ else if ((c == '\015') && (*stream->iptr == '\012')) { stream->iptr++; /* eat the line feed */ stream->ictr--; ret[*size = --n] = '\0'; /* tie off string with null */ } else *contd = LONGT; /* continuation needed */ return ret; } /* TCP/IP receive buffer * Accepts: TCP/IP stream * size in bytes * buffer to read into * Returns: T if success, NIL otherwise */ long tcp_getbuffer (TCPSTREAM *stream,unsigned long size,char *s) { unsigned long n; /* make sure socket still alive */ if (stream->tcpsi == INVALID_SOCKET) return NIL; /* can transfer bytes from buffer? */ if (n = min (size,stream->ictr)) { memcpy (s,stream->iptr,n); /* yes, slurp as much as we can from it */ s += n; /* update pointer */ stream->iptr +=n; size -= n; /* update # of bytes to do */ stream->ictr -=n; } if (size) { int i; fd_set fds,efds; struct timeval tmo; time_t t = time (0); blocknotify_t bn=(blocknotify_t) mail_parameters (NIL,GET_BLOCKNOTIFY,NIL); (*bn) (BLOCK_TCPREAD,NIL); while (size > 0) { /* until request satisfied */ if (tcpdebug) mm_log ("Reading TCP buffer",TCPDEBUG); /* simple case if not a socket */ if (stream->tcpsi != stream->tcpso) while (((i = read (stream->tcpsi,s,(int) min (maxposint,size))) < 0) && (errno == EINTR)); else { /* socket case */ time_t tl = time (0); time_t now = tl; time_t ti = ttmo_read ? now + ttmo_read : 0; tmo.tv_usec = 0; FD_ZERO (&fds); /* initialize selection vector */ FD_ZERO (&efds); /* handle errors too */ /* set bit in selection vectors */ FD_SET (stream->tcpsi,&fds); FD_SET (stream->tcpsi,&efds); errno = NIL; /* initially no error */ do { /* block under timeout */ tmo.tv_sec = (long) (ti ? ti - now : 0); i = select (stream->tcpsi+1,&fds,NIL,&efds,ti ? &tmo : NIL); now = time (0); /* fake timeout if interrupt & time expired */ if ((i < 0) && ((errno = WSAGetLastError ()) == WSAEINTR) && ti && (ti <= now)) i = 0; } while ((i < 0) && (errno == WSAEINTR)); /* success from select, read what we can */ if (i > 0) while (((i = recv (stream->tcpsi,s, (int) min (maxposint,size),0)) == SOCKET_ERROR) && ((errno = WSAGetLastError ()) == WSAEINTR)); else if (!i) { /* timeout, ignore if told to resume */ if (tmoh && (*tmoh) ((long) (now - t),(long) (now - tl), stream->host)) continue; /* otherwise punt */ if (tcpdebug) mm_log ("TCP buffer read timeout",TCPDEBUG); return tcp_abort (stream); } } if (i <= 0) { /* error seen? */ if (tcpdebug) { char tmp[MAILTMPLEN]; if (i) sprintf (s = tmp,"TCP buffer read I/O error %d",errno); else s = "TCP buffer read end of file"; mm_log (s,TCPDEBUG); } return tcp_abort (stream); } s += i; /* point at new place to write */ size -= i; /* reduce byte count */ if (tcpdebug) mm_log ("Successfully read TCP buffer",TCPDEBUG); } (*bn) (BLOCK_NONE,NIL); } *s = '\0'; /* tie off string */ return LONGT; } /* TCP/IP receive data * Accepts: TCP/IP stream * Returns: T if success, NIL otherwise */ long tcp_getdata (TCPSTREAM *stream) { int i; fd_set fds,efds; struct timeval tmo; time_t t = time (0); blocknotify_t bn = (blocknotify_t) mail_parameters (NIL,GET_BLOCKNOTIFY,NIL); if (stream->tcpsi == INVALID_SOCKET) return NIL; (*bn) (BLOCK_TCPREAD,NIL); while (stream->ictr < 1) { /* if nothing in the buffer */ if (tcpdebug) mm_log ("Reading TCP data",TCPDEBUG); /* simple case if not a socket */ if (stream->tcpsi != stream->tcpso) while (((i = read (stream->tcpsi,stream->ibuf,BUFLEN)) < 0) && (errno == EINTR)); else { time_t tl = time (0); time_t now = tl; time_t ti = ttmo_read ? now + ttmo_read : 0; tmo.tv_usec = 0; FD_ZERO (&fds); /* initialize selection vector */ FD_ZERO (&efds); /* handle errors too */ /* set bit in selection vectors */ FD_SET (stream->tcpsi,&fds); FD_SET (stream->tcpsi,&efds); errno = NIL; /* initially no error */ do { /* block under timeout */ tmo.tv_sec = (long) (ti ? ti - now : 0); i = select (stream->tcpsi+1,&fds,NIL,&efds,ti ? &tmo : NIL); now = time (0); /* fake timeout if interrupt & time expired */ if ((i < 0) && ((errno = WSAGetLastError ()) == WSAEINTR) && ti && (ti <= now)) i = 0; } while ((i < 0) && (errno == WSAEINTR)); /* success from select, read what we can */ if (i > 0) while (((i = recv (stream->tcpsi,stream->ibuf,BUFLEN,0)) == SOCKET_ERROR) && ((errno = WSAGetLastError ()) == WSAEINTR)); else if (!i) { /* timeout, ignore if told to resume */ if (tmoh && (*tmoh) ((long) (now - t),(long) (now - tl), stream->host)) continue; /* otherwise punt */ if (tcpdebug) mm_log ("TCP data read timeout",TCPDEBUG); return tcp_abort (stream); } } if (i <= 0) { /* error seen? */ if (tcpdebug) { char *s,tmp[MAILTMPLEN]; if (i) sprintf (s = tmp,"TCP data read I/O error %d",errno); else s = "TCP data read end of file"; mm_log (tmp,TCPDEBUG); } return tcp_abort (stream); } stream->iptr = stream->ibuf;/* point at TCP buffer */ stream->ictr = i; /* set new byte count */ if (tcpdebug) mm_log ("Successfully read TCP data",TCPDEBUG); } (*bn) (BLOCK_NONE,NIL); return T; } /* TCP/IP send string as record * Accepts: TCP/IP stream * string pointer * Returns: T if success else NIL */ long tcp_soutr (TCPSTREAM *stream,char *string) { return tcp_sout (stream,string,(unsigned long) strlen (string)); } /* TCP/IP send string * Accepts: TCP/IP stream * string pointer * byte count * Returns: T if success else NIL */ long tcp_sout (TCPSTREAM *stream,char *string,unsigned long size) { int i; struct timeval tmo; fd_set fds,efds; time_t t = time (0); blocknotify_t bn = (blocknotify_t) mail_parameters (NIL,GET_BLOCKNOTIFY,NIL); tmo.tv_sec = ttmo_write; tmo.tv_usec = 0; FD_ZERO (&fds); /* initialize selection vector */ if (stream->tcpso == INVALID_SOCKET) return NIL; (*bn) (BLOCK_TCPWRITE,NIL); while (size > 0) { /* until request satisfied */ if (tcpdebug) mm_log ("Writing to TCP",TCPDEBUG); /* simple case if not a socket */ if (stream->tcpsi != stream->tcpso) while (((i = write (stream->tcpso,string,min (size,TCPMAXSEND))) < 0) && (errno == EINTR)); else { time_t tl = time (0); /* start of request */ time_t now = tl; time_t ti = ttmo_write ? now + ttmo_write : 0; tmo.tv_usec = 0; FD_ZERO (&fds); /* initialize selection vector */ FD_ZERO (&efds); /* handle errors too */ /* set bit in selection vectors */ FD_SET (stream->tcpso,&fds); FD_SET(stream->tcpso,&efds); errno = NIL; /* block and write */ do { /* block under timeout */ tmo.tv_sec = (long) (ti ? ti - now : 0); i = select (stream->tcpso+1,NIL,&fds,&efds,ti ? &tmo : NIL); now = time (0); /* fake timeout if interrupt & time expired */ if ((i < 0) && ((errno = WSAGetLastError ()) == WSAEINTR) && ti && (ti <= now)) i = 0; } while ((i < 0) && (errno == WSAEINTR)); /* OK to send data? */ if (i > 0) while (((i = send (stream->tcpso,string, (int) min (size,TCPMAXSEND),0)) == SOCKET_ERROR) && ((errno = WSAGetLastError ()) == WSAEINTR)); else if (!i) { /* timeout, ignore if told to resume */ if (tmoh && (*tmoh) ((long) (now - t),(long) (now - tl), stream->host)) continue; /* otherwise punt */ if (tcpdebug) mm_log ("TCP write timeout",TCPDEBUG); return tcp_abort (stream); } } if (i <= 0) { /* error seen? */ if (tcpdebug) { char tmp[MAILTMPLEN]; sprintf (tmp,"TCP write I/O error %d",errno); mm_log (tmp,TCPDEBUG); } return tcp_abort (stream); } string += i; /* how much we sent */ size -= i; /* count this size */ if (tcpdebug) mm_log ("successfully wrote to TCP",TCPDEBUG); } (*bn) (BLOCK_NONE,NIL); return T; /* all done */ } /* TCP/IP close * Accepts: TCP/IP stream */ void tcp_close (TCPSTREAM *stream) { tcp_abort (stream); /* nuke the sockets */ /* flush host names */ if (stream->host) fs_give ((void **) &stream->host); if (stream->remotehost) fs_give ((void **) &stream->remotehost); if (stream->localhost) fs_give ((void **) &stream->localhost); fs_give ((void **) &stream); /* flush the stream */ } /* TCP/IP abort sockets * Accepts: TCP/IP stream * Returns: NIL, always */ long tcp_abort (TCPSTREAM *stream) { if (stream->tcpsi != stream->tcpso) tcp_close_socket (&stream->tcpso); else stream->tcpso = INVALID_SOCKET; return tcp_close_socket (&stream->tcpsi); } /* TCP/IP abort stream * Accepts: WinSock socket * Returns: NIL, always */ long tcp_close_socket (SOCKET *sock) { blocknotify_t bn = (blocknotify_t) mail_parameters (NIL,GET_BLOCKNOTIFY,NIL); /* something to close? */ if (sock && (*sock != INVALID_SOCKET)) { (*bn) (BLOCK_TCPCLOSE,NIL); closesocket (*sock); /* WinSock socket close */ *sock = INVALID_SOCKET; (*bn) (BLOCK_NONE,NIL); wsa_sock_open--; /* drop this socket */ } /* no more open streams? */ if (wsa_initted && !wsa_sock_open) { mm_log ("Winsock cleanup",NIL); wsa_initted = 0; /* no more sockets, so... */ WSACleanup (); /* free up resources until needed */ } return NIL; } /* TCP/IP get host name * Accepts: TCP/IP stream * Returns: host name for this stream */ char *tcp_host (TCPSTREAM *stream) { return stream->host; /* use tcp_remotehost() if want guarantees */ } /* TCP/IP get remote host name * Accepts: TCP/IP stream * Returns: host name for this stream */ char *tcp_remotehost (TCPSTREAM *stream) { if (!stream->remotehost) { size_t sadrlen; struct sockaddr *sadr = ip_newsockaddr (&sadrlen); stream->remotehost = /* get socket's peer name */ ((getpeername (stream->tcpsi,sadr,&sadrlen) == SOCKET_ERROR) || (sadrlen <= 0)) ? cpystr (stream->host) : tcp_name (sadr,NIL); fs_give ((void **) &sadr); } return stream->remotehost; } /* TCP/IP return port for this stream * Accepts: TCP/IP stream * Returns: port number for this stream */ unsigned long tcp_port (TCPSTREAM *stream) { return stream->port; /* return port number */ } /* TCP/IP get local host name * Accepts: TCP/IP stream * Returns: local host name */ char *tcp_localhost (TCPSTREAM *stream) { if (!stream->localhost) { size_t sadrlen; struct sockaddr *sadr = ip_newsockaddr (&sadrlen); stream->localhost = /* get socket's name */ ((stream->port & 0xffff000) || ((getsockname (stream->tcpsi,sadr,&sadrlen) == SOCKET_ERROR) || (sadrlen <= 0))) ? cpystr (mylocalhost ()) : tcp_name (sadr,NIL); fs_give ((void **) &sadr); } return stream->localhost; /* return local host name */ } /* TCP/IP get client host address (server calls only) * Returns: client host address */ char *tcp_clientaddr () { if (!myClientAddr) { size_t sadrlen; struct sockaddr *sadr = ip_newsockaddr (&sadrlen); if ((getpeername (0,sadr,(void *) &sadrlen) == SOCKET_ERROR) || (sadrlen <= 0)) myClientAddr = cpystr ("UNKNOWN"); else { /* get stdin's peer name */ myClientAddr = cpystr (ip_sockaddrtostring (sadr)); if (myClientPort < 0) myClientPort = ip_sockaddrtoport (sadr); } fs_give ((void **) &sadr); } return myClientAddr; } /* TCP/IP get client host name (server calls only) * Returns: client host name */ char *tcp_clienthost () { if (!myClientHost) { size_t sadrlen; struct sockaddr *sadr = ip_newsockaddr (&sadrlen); if ((getpeername (0,sadr,(void *) &sadrlen) == SOCKET_ERROR) || (sadrlen <= 0)) myClientHost = cpystr ("UNKNOWN"); else { /* get stdin's peer name */ myClientHost = tcp_name (sadr,T); if (!myClientAddr) myClientAddr = cpystr (ip_sockaddrtostring (sadr)); if (myClientPort < 0) myClientPort = ip_sockaddrtoport (sadr); } fs_give ((void **) &sadr); } return myClientHost; } /* TCP/IP get client port number (server calls only) * Returns: client port number */ long tcp_clientport () { if (!myClientHost && !myClientAddr) tcp_clientaddr (); return myClientPort; } /* TCP/IP get server host address (server calls only) * Returns: server host address */ char *tcp_serveraddr () { if (!myServerAddr) { size_t sadrlen; struct sockaddr *sadr = ip_newsockaddr (&sadrlen); if (!wsa_initted++) { /* init Windows Sockets */ WSADATA wsock; if (WSAStartup (WINSOCK_VERSION,&wsock)) { wsa_initted = 0; return "random-pc"; /* try again later? */ } } if ((getsockname (0,sadr,(void *) &sadrlen) == SOCKET_ERROR) || (sadrlen <= 0)) myServerAddr = cpystr ("UNKNOWN"); else { /* get stdin's name */ myServerAddr = cpystr (ip_sockaddrtostring (sadr)); if (myServerPort < 0) myServerPort = ip_sockaddrtoport (sadr); } fs_give ((void **) &sadr); } return myServerAddr; } /* TCP/IP get server host name (server calls only) * Returns: server host name */ char *tcp_serverhost () { if (!myServerHost) { /* once-only */ size_t sadrlen; struct sockaddr *sadr = ip_newsockaddr (&sadrlen); if (!wsa_initted++) { /* init Windows Sockets */ WSADATA wsock; if (WSAStartup (WINSOCK_VERSION,&wsock)) { wsa_initted = 0; return "random-pc"; /* try again later? */ } } /* get stdin's name */ if ((getsockname (0,sadr,(void *) &sadrlen) == SOCKET_ERROR) || (sadrlen <= 0)) myServerHost = cpystr (mylocalhost ()); else { /* get stdin's name */ myServerHost = tcp_name (sadr,NIL); if (!myServerAddr) myServerAddr = cpystr (ip_sockaddrtostring (sadr)); if (myServerPort < 0) myServerPort = ip_sockaddrtoport (sadr); } fs_give ((void **) &sadr); } return myServerHost; } /* TCP/IP get server port number (server calls only) * Returns: server port number */ long tcp_serverport () { if (!myServerHost && !myServerAddr) tcp_serveraddr (); return myServerPort; } /* TCP/IP return canonical form of host name * Accepts: host name * Returns: canonical form of host name */ char *tcp_canonical (char *name) { char *ret,host[MAILTMPLEN]; blocknotify_t bn = (blocknotify_t) mail_parameters (NIL,GET_BLOCKNOTIFY,NIL); /* look like domain literal? */ if (name[0] == '[' && name[strlen (name) - 1] == ']') return name; (*bn) (BLOCK_DNSLOOKUP,NIL); if (tcpdebug) { sprintf (host,"DNS canonicalization %.80s",name); mm_log (host,TCPDEBUG); } /* get canonical name */ if (!ip_nametoaddr (name,NIL,NIL,&ret,NIL)) ret = name; (*bn) (BLOCK_NONE,NIL); /* alarms OK now */ if (tcpdebug) mm_log ("DNS canonicalization done",TCPDEBUG); return ret; } /* TCP/IP return name from socket * Accepts: socket * verbose flag * Returns: cpystr name */ char *tcp_name (struct sockaddr *sadr,long flag) { char *ret,*t,adr[MAILTMPLEN],tmp[MAILTMPLEN]; sprintf (ret = adr,"[%.80s]",ip_sockaddrtostring (sadr)); if (allowreversedns) { blocknotify_t bn = (blocknotify_t)mail_parameters(NIL,GET_BLOCKNOTIFY,NIL); if (tcpdebug) { sprintf (tmp,"Reverse DNS resolution %s",adr); mm_log (tmp,TCPDEBUG); } (*bn) (BLOCK_DNSLOOKUP,NIL);/* quell alarms */ /* translate address to name */ if (t = tcp_name_valid (ip_sockaddrtoname (sadr))) { /* produce verbose form if needed */ if (flag) sprintf (ret = tmp,"%s %s",t,adr); else ret = t; } (*bn) (BLOCK_NONE,NIL); /* alarms OK now */ if (tcpdebug) mm_log ("Reverse DNS resolution done",TCPDEBUG); } return cpystr (ret); } /* Validate name * Accepts: domain name * Returns: T if valid, NIL otherwise */ char *tcp_name_valid (char *s) { int c; char *ret,*tail; /* must be non-empty and not too long */ if ((ret = (s && *s) ? s : NIL) && (tail = ret + NETMAXHOST)) { /* must be alnum, dot, or hyphen */ while ((c = *s++) && (s <= tail) && (((c >= 'A') && (c <= 'Z')) || ((c >= 'a') && (c <= 'z')) || ((c >= '0') && (c <= '9')) || (c == '-') || (c == '.'))); if (c) ret = NIL; } return ret; } alpine-2.10+dfsg/imap/src/osdep/nt/write.c0000600000175000017500000000336711512502123022112 0ustar paulproteuspaulproteus/* ======================================================================== * Copyright 1988-2006 University of Washington * * Licensed under the Apache License, Version 2.0 (the "License"); * you may not use this file except in compliance with the License. * You may obtain a copy of the License at * * http://www.apache.org/licenses/LICENSE-2.0 * * * ======================================================================== */ /* * Program: Write data, treating partial writes as an error * * Author: Mark Crispin * Networks and Distributed Computing * Computing & Communications * University of Washington * Administration Building, AG-44 * Seattle, WA 98195 * Internet: MRC@CAC.Washington.EDU * * Date: 26 May 1995 * Last Edited: 30 August 2006 */ /* The whole purpose of this unfortunate routine is to deal with DOS and * certain cretinous versions of UNIX which decided that the "bytes actually * written" return value from write() gave them license to use that for things * that are really errors, such as disk quota exceeded, maximum file size * exceeded, disk full, etc. * * BSD won't screw us this way on the local filesystem, but who knows what * some NFS-mounted filesystem will do. */ #undef write /* Write data to file * Accepts: file descriptor * I/O vector structure * number of vectors in structure * Returns: number of bytes written if successful, -1 if failure */ long maxposint = (long)((((unsigned long) 1) << ((sizeof(int) * 8) - 1)) - 1); long safe_write (int fd,char *buf,long nbytes) { long i,j; if (nbytes > 0) for (i = nbytes; i; i -= j,buf += j) { while (((j = write (fd,buf,(int) min (maxposint,i))) < 0) && (errno == EINTR)); if (j < 0) return j; } return nbytes; } alpine-2.10+dfsg/imap/src/osdep/nt/mbxnt.c0000600000175000017500000016000711512502123022103 0ustar paulproteuspaulproteus/* ======================================================================== * Copyright 1988-2007 University of Washington * * Licensed under the Apache License, Version 2.0 (the "License"); * you may not use this file except in compliance with the License. * You may obtain a copy of the License at * * http://www.apache.org/licenses/LICENSE-2.0 * * * ======================================================================== */ /* * Program: MBX mail routines * * Author: Mark Crispin * Networks and Distributed Computing * Computing & Communications * University of Washington * Administration Building, AG-44 * Seattle, WA 98195 * Internet: MRC@CAC.Washington.EDU * * Date: 3 October 1995 * Last Edited: 28 September 2007 */ /* FILE TIME SEMANTICS * * The atime is the last read time of the file. * The mtime is the last flags update time of the file. * The ctime is the last write time of the file. */ #include #include #include extern int errno; /* just in case */ #include "mail.h" #include "osdep.h" #include #include #include #include #include "misc.h" #include "dummy.h" #include "fdstring.h" /* Build parameters */ #define HDRSIZE 2048 /* MBX I/O stream local data */ typedef struct mbx_local { unsigned int flagcheck: 1; /* if ping should sweep for flags */ unsigned int expok: 1; /* if expunging OK in ping */ unsigned int expunged : 1; /* if one or more expunged messages */ int fd; /* file descriptor for I/O */ int ld; /* lock file descriptor */ int ffuserflag; /* first free user flag */ off_t filesize; /* file size parsed */ time_t filetime; /* last file time */ time_t lastsnarf; /* last snarf time */ unsigned char *buf; /* temporary buffer */ unsigned long buflen; /* current size of temporary buffer */ char lock[MAILTMPLEN]; /* buffer to write lock name */ } MBXLOCAL; /* Convenient access to local data */ #define LOCAL ((MBXLOCAL *) stream->local) /* Function prototypes */ DRIVER *mbx_valid (char *name); int mbx_isvalid (MAILSTREAM **stream,char *name,char *file,int *ld,char *lock, long flags); void *mbx_parameters (long function,void *value); void mbx_scan (MAILSTREAM *stream,char *ref,char *pat,char *contents); void mbx_list (MAILSTREAM *stream,char *ref,char *pat); void mbx_lsub (MAILSTREAM *stream,char *ref,char *pat); long mbx_create (MAILSTREAM *stream,char *mailbox); long mbx_delete (MAILSTREAM *stream,char *mailbox); long mbx_rename (MAILSTREAM *stream,char *old,char *newname); long mbx_status (MAILSTREAM *stream,char *mbx,long flags); MAILSTREAM *mbx_open (MAILSTREAM *stream); void mbx_close (MAILSTREAM *stream,long options); void mbx_abort (MAILSTREAM *stream); void mbx_flags (MAILSTREAM *stream,char *sequence,long flags); char *mbx_header (MAILSTREAM *stream,unsigned long msgno,unsigned long *length, long flags); long mbx_text (MAILSTREAM *stream,unsigned long msgno,STRING *bs,long flags); void mbx_flag (MAILSTREAM *stream,char *sequence,char *flag,long flags); void mbx_flagmsg (MAILSTREAM *stream,MESSAGECACHE *elt); long mbx_ping (MAILSTREAM *stream); void mbx_check (MAILSTREAM *stream); long mbx_expunge (MAILSTREAM *stream,char *sequence,long options); void mbx_snarf (MAILSTREAM *stream); long mbx_copy (MAILSTREAM *stream,char *sequence,char *mailbox,long options); long mbx_append (MAILSTREAM *stream,char *mailbox,append_t af,void *data); long mbx_parse (MAILSTREAM *stream); MESSAGECACHE *mbx_elt (MAILSTREAM *stream,unsigned long msgno,long expok); unsigned long mbx_read_flags (MAILSTREAM *stream,MESSAGECACHE *elt); void mbx_update_header (MAILSTREAM *stream); void mbx_update_status (MAILSTREAM *stream,unsigned long msgno,long flags); unsigned long mbx_hdrpos (MAILSTREAM *stream,unsigned long msgno, unsigned long *size,char **hdr); unsigned long mbx_rewrite (MAILSTREAM *stream,unsigned long *reclaimed, long flags); long mbx_flaglock (MAILSTREAM *stream); /* MBX mail routines */ /* Driver dispatch used by MAIL */ DRIVER mbxdriver = { "mbx", /* driver name */ DR_LOCAL|DR_MAIL|DR_CRLF|DR_LOCKING, /* driver flags */ (DRIVER *) NIL, /* next driver */ mbx_valid, /* mailbox is valid for us */ mbx_parameters, /* manipulate parameters */ mbx_scan, /* scan mailboxes */ mbx_list, /* list mailboxes */ mbx_lsub, /* list subscribed mailboxes */ NIL, /* subscribe to mailbox */ NIL, /* unsubscribe from mailbox */ mbx_create, /* create mailbox */ mbx_delete, /* delete mailbox */ mbx_rename, /* rename mailbox */ mail_status_default, /* status of mailbox */ mbx_open, /* open mailbox */ mbx_close, /* close mailbox */ mbx_flags, /* fetch message "fast" attributes */ mbx_flags, /* fetch message flags */ NIL, /* fetch overview */ NIL, /* fetch message envelopes */ mbx_header, /* fetch message header */ mbx_text, /* fetch message body */ NIL, /* fetch partial message text */ NIL, /* unique identifier */ NIL, /* message number */ mbx_flag, /* modify flags */ mbx_flagmsg, /* per-message modify flags */ NIL, /* search for message based on criteria */ NIL, /* sort messages */ NIL, /* thread messages */ mbx_ping, /* ping mailbox to see if still alive */ mbx_check, /* check for new messages */ mbx_expunge, /* expunge deleted messages */ mbx_copy, /* copy messages to another mailbox */ mbx_append, /* append string message to mailbox */ NIL /* garbage collect stream */ }; /* prototype stream */ MAILSTREAM mbxproto = {&mbxdriver}; /* MBX mail validate mailbox * Accepts: mailbox name * Returns: our driver if name is valid, NIL otherwise */ DRIVER *mbx_valid (char *name) { char tmp[MAILTMPLEN]; int fd = mbx_isvalid (NIL,name,tmp,NIL,NIL,NIL); if (fd < 0) return NIL; close (fd); /* don't need the fd now */ return &mbxdriver; } /* MBX mail test for valid mailbox * Accepts: returned stream with valid mailbox keywords * mailbox name * buffer to write file name * returned lock fd * returned lock name * RW flags or NIL for readonly * Returns: file descriptor if valid, NIL otherwise */ #define MBXISVALIDNOUID 0x1 /* RW, don't do UID action */ #define MBXISVALIDUID 0x2 /* RW, do UID action */ int mbx_isvalid (MAILSTREAM **stream,char *name,char *file,int *ld,char *lock, long flags) { int fd,upd; int ret = -1; unsigned long i; long j,k; off_t pos; char c,*s,*t,hdr[HDRSIZE]; struct stat sbuf; struct utimbuf times; int error = EINVAL; /* assume invalid argument */ if (ld) *ld = -1; /* initially no lock */ /* if file, get its status */ if ((s = dummy_file (file,name)) && !stat (s,&sbuf) && ((sbuf.st_mode & S_IFMT) == S_IFREG) && ((fd = open (file,(flags ? O_RDWR : O_RDONLY)|O_BINARY,NIL)) >= 0)) { error = -1; /* assume bogus format */ if (((((j = read (fd,hdr,HDRSIZE)) == HDRSIZE) && (hdr[0] == '*')) || /* locked, set byte 0 to "*", read rest */ ((j < 0) && (lseek (fd,1,L_SET) == 1) && (read (fd,hdr+1,HDRSIZE-1) == (HDRSIZE-1)) && (hdr[0] = '*'))) && (hdr[1] == 'm') && (hdr[2] == 'b') && (hdr[3] == 'x') && (hdr[4] == '*') && (hdr[5] == '\015') && (hdr[6] == '\012') && isxdigit (hdr[7]) && isxdigit (hdr[8]) && isxdigit (hdr[9]) && isxdigit (hdr[10]) && isxdigit (hdr[11]) && isxdigit (hdr[12]) && isxdigit (hdr[13]) && isxdigit (hdr[14]) && isxdigit (c = hdr[15]) && isxdigit (hdr[16]) && isxdigit (hdr[17]) && isxdigit (hdr[18]) && isxdigit (hdr[19]) && isxdigit (hdr[20]) && isxdigit (hdr[21]) && isxdigit (hdr[22]) && (hdr[23] == '\015') && (hdr[24] == '\012')) { ret = fd; /* mbx format */ if (stream) { /* lock if making a mini-stream */ if (flock (fd,LOCK_SH) || (flags && ((*ld = lockname (lock,file,LOCK_EX)) < 0))) ret = -1; /* reread data now that locked */ else if (lseek (fd,0,L_SET) || (read (fd,hdr+1,HDRSIZE-1) != (HDRSIZE-1))) ret = -1; else { *stream = (MAILSTREAM *) memset (fs_get (sizeof (MAILSTREAM)),0, sizeof (MAILSTREAM)); hdr[15] = '\0'; /* tie off UIDVALIDITY */ (*stream)->uid_validity = strtoul (hdr+7,NIL,16); hdr[15] = c; /* now get UIDLAST */ (*stream)->uid_last = strtoul (hdr+15,NIL,16); /* parse user flags */ for (i = 0, s = hdr + 25; (i < NUSERFLAGS) && (t = strchr (s,'\015')) && (t - s); i++, s = t + 2) { *t = '\0'; /* tie off flag */ if (strlen (s) <= MAXUSERFLAG) (*stream)->user_flags[i] = cpystr (s); } /* make sure have true UIDLAST */ if (flags & MBXISVALIDUID) { for (upd = NIL,pos = 2048, k = 0; pos < sbuf.st_size; pos += (j + k)) { /* read header for this message */ lseek (fd,pos,L_SET); if ((j = read (fd,hdr,64)) >= 0) { hdr[j] = '\0'; if ((s = strchr (hdr,'\015')) && (s[1] == '\012')) { *s = '\0'; k = s + 2 - hdr; if ((s = strchr (hdr,',')) && (j = strtol (s+1,&s,10)) && (*s == ';') && (s = strchr (s+1,'-'))) { /* get UID if there is any */ i = strtoul (++s,&t,16); if (!*t && (t == (s + 8)) && (i <= (*stream)->uid_last)) { if (!i) { lseek (fd,pos + s - hdr,L_SET); sprintf (hdr,"%08lx",++(*stream)->uid_last); write (fd,hdr,8); upd = T; } continue; } } } ret = -1; /* error, give up */ *stream = mail_close (*stream); pos = sbuf.st_size + 1; j = k = 0; } } if (upd) { /* need to update hdr with new UIDLAST? */ lseek (fd,15,L_SET); sprintf (hdr,"%08lx",(*stream)->uid_last); write (fd,hdr,8); } } } } } if (ret != fd) close (fd); /* close the file */ else lseek (fd,0,L_SET); /* else rewind to start */ /* \Marked status? */ if (sbuf.st_ctime > sbuf.st_atime) { /* preserve atime and mtime */ times.actime = sbuf.st_atime; times.modtime = sbuf.st_mtime; utime (file,×); /* set the times */ } } /* in case INBOX but not mbx format */ else if (((error = errno) == ENOENT) && !compare_cstring (name,"INBOX")) error = -1; if ((ret < 0) && ld && (*ld >= 0)) { unlockfd (*ld,lock); *ld = -1; } errno = error; /* return as last error */ return ret; /* return what we should */ } /* MBX manipulate driver parameters * Accepts: function code * function-dependent value * Returns: function-dependent return value */ void *mbx_parameters (long function,void *value) { void *ret = NIL; switch ((int) function) { case SET_ONETIMEEXPUNGEATPING: if (value) ((MBXLOCAL *) ((MAILSTREAM *) value)->local)->expok = T; case GET_ONETIMEEXPUNGEATPING: if (value) ret = (void *) (((MBXLOCAL *) ((MAILSTREAM *) value)->local)->expok ? VOIDT : NIL); break; } return ret; } /* MBX mail scan mailboxes * Accepts: mail stream * reference * pattern to search * string to scan */ void mbx_scan (MAILSTREAM *stream,char *ref,char *pat,char *contents) { if (stream) dummy_scan (NIL,ref,pat,contents); } /* MBX mail list mailboxes * Accepts: mail stream * reference * pattern to search */ void mbx_list (MAILSTREAM *stream,char *ref,char *pat) { if (stream) dummy_list (NIL,ref,pat); } /* MBX mail list subscribed mailboxes * Accepts: mail stream * reference * pattern to search */ void mbx_lsub (MAILSTREAM *stream,char *ref,char *pat) { if (stream) dummy_lsub (NIL,ref,pat); } /* MBX mail create mailbox * Accepts: MAIL stream * mailbox name to create * Returns: T on success, NIL on failure */ long mbx_create (MAILSTREAM *stream,char *mailbox) { char *s,mbx[MAILTMPLEN],tmp[HDRSIZE]; long ret = NIL; int i,fd; if (!(s = dummy_file (mbx,mailbox))) { sprintf (mbx,"Can't create %.80s: invalid name",mailbox); mm_log (mbx,ERROR); } /* create underlying file */ else if (dummy_create (stream,s)) { /* done if made directory */ if ((s = strrchr (s,'\\')) && !s[1]) return T; if ((fd = open (mbx,O_WRONLY|O_BINARY,NIL)) < 0) { sprintf (tmp,"Can't reopen mailbox node %.80s: %s",mbx,strerror (errno)); mm_log (tmp,ERROR); unlink (mbx); /* delete the file */ } else { memset (tmp,'\0',HDRSIZE);/* initialize header */ sprintf (s = tmp,"*mbx*\015\012%08lx00000000\015\012", (unsigned long) time (0)); for (i = 0; i < NUSERFLAGS; ++i) sprintf (s += strlen (s),"%s\015\012", (stream && stream->user_flags[i]) ? stream->user_flags[i] : ""); if (write (fd,tmp,HDRSIZE) != HDRSIZE) { sprintf (tmp,"Can't initialize mailbox node %.80s: %s", mbx,strerror (errno)); mm_log (tmp,ERROR); unlink (mbx); /* delete the file */ } else ret = T; /* success */ close (fd); /* close file */ } } return ret; } /* MBX mail delete mailbox * Accepts: MAIL stream * mailbox name to delete * Returns: T on success, NIL on failure */ long mbx_delete (MAILSTREAM *stream,char *mailbox) { return mbx_rename (stream,mailbox,NIL); } /* MBX mail rename mailbox * Accepts: MAIL stream * old mailbox name * new mailbox name (or NIL for delete) * Returns: T on success, NIL on failure */ long mbx_rename (MAILSTREAM *stream,char *old,char *newname) { long ret = LONGT; char c,*s,tmp[MAILTMPLEN],file[MAILTMPLEN],lock[MAILTMPLEN]; int fd,ld; struct stat sbuf; if (!dummy_file (file,old) || (newname && (!((s = mailboxfile (tmp,newname)) && *s) || ((s = strrchr (tmp,'\\')) && !s[1])))) { sprintf (tmp,newname ? "Can't rename mailbox %.80s to %.80s: invalid name" : "Can't delete mailbox %.80s: invalid name", old,newname); mm_log (tmp,ERROR); return NIL; } else if ((fd = open (file,O_RDWR|O_BINARY,NIL)) < 0) { sprintf (tmp,"Can't open mailbox %.80s: %s",old,strerror (errno)); mm_log (tmp,ERROR); return NIL; } /* get parse/append permission */ if ((ld = lockname (lock,file,LOCK_EX)) < 0) { mm_log ("Unable to lock rename mailbox",ERROR); return NIL; } /* lock out other users */ if (flock (fd,LOCK_EX|LOCK_NB)) { close (fd); /* couldn't lock, give up on it then */ sprintf (tmp,"Mailbox %.80s is in use by another process",old); mm_log (tmp,ERROR); unlockfd (ld,lock); /* release exclusive parse/append permission */ return NIL; } if (newname) { /* want rename? */ /* found superior to destination name? */ if ((s = strrchr (tmp,'\\')) && (s != tmp) && ((tmp[1] != ':') || (s != tmp + 2))) { c = s[1]; /* remember character after delimiter */ *s = s[1] = '\0'; /* tie off name at delimiter */ /* name doesn't exist, create it */ if (stat (tmp,&sbuf) || ((sbuf.st_mode & S_IFMT) != S_IFDIR)) { *s = '\\'; /* restore delimiter */ if (!dummy_create (stream,tmp)) ret = NIL; } else *s = '\\'; /* restore delimiter */ s[1] = c; /* restore character after delimiter */ } flock (fd,LOCK_UN); /* release lock on the file */ close (fd); /* pacify NTFS */ /* rename the file */ if (ret && rename (file,tmp)) { sprintf (tmp,"Can't rename mailbox %.80s to %.80s: %s",old,newname, strerror (errno)); mm_log (tmp,ERROR); ret = NIL; /* set failure */ } } else { flock (fd,LOCK_UN); /* release lock on the file */ close (fd); /* pacify NTFS */ if (unlink (file)) { sprintf (tmp,"Can't delete mailbox %.80s: %s",old,strerror (errno)); mm_log (tmp,ERROR); ret = NIL; /* set failure */ } } unlockfd (ld,lock); /* release exclusive parse/append permission */ /* recreate file if renamed INBOX */ if (ret && !compare_cstring (old,"INBOX")) mbx_create (NIL,"INBOX"); return ret; /* return success */ } /* MBX mail open * Accepts: stream to open * Returns: stream on success, NIL on failure */ MAILSTREAM *mbx_open (MAILSTREAM *stream) { int fd,ld; short silent; char tmp[MAILTMPLEN]; if (!stream) return &mbxproto;/* return prototype for OP_PROTOTYPE call */ if (stream->local) fatal ("mbx recycle stream"); /* canonicalize the mailbox name */ if (!dummy_file (tmp,stream->mailbox)) { sprintf (tmp,"Can't open - invalid name: %.80s",stream->mailbox); mm_log (tmp,ERROR); } if (stream->rdonly || (fd = open (tmp,O_RDWR|O_BINARY,NIL)) < 0) { if ((fd = open (tmp,O_RDONLY|O_BINARY,NIL)) < 0) { sprintf (tmp,"Can't open mailbox: %s",strerror (errno)); mm_log (tmp,ERROR); return NIL; } else if (!stream->rdonly) { /* got it, but readonly */ mm_log ("Can't get write access to mailbox, access is readonly",WARN); stream->rdonly = T; } } stream->local = memset (fs_get (sizeof (MBXLOCAL)),NIL,sizeof (MBXLOCAL)); LOCAL->fd = fd; /* bind the file */ LOCAL->ld = -1; /* no flaglock */ LOCAL->buf = (char *) fs_get (CHUNKSIZE); LOCAL->buflen = CHUNKSIZE - 1; /* note if an INBOX or not */ stream->inbox = !compare_cstring (stream->mailbox,"INBOX"); fs_give ((void **) &stream->mailbox); stream->mailbox = cpystr (tmp); /* get parse/append permission */ if ((ld = lockname (tmp,stream->mailbox,LOCK_EX)) < 0) { mm_log ("Unable to lock open mailbox",ERROR); return NIL; } flock (LOCAL->fd,LOCK_SH); /* lock the file */ unlockfd (ld,tmp); /* release shared parse permission */ LOCAL->filesize = HDRSIZE; /* initialize parsed file size */ LOCAL->filetime = 0; /* time not set up yet */ LOCAL->expok = LOCAL->flagcheck = NIL; stream->sequence++; /* bump sequence number */ /* parse mailbox */ stream->nmsgs = stream->recent = 0; silent = stream->silent; /* defer events */ stream->silent = T; if (mbx_ping (stream) && !stream->nmsgs) mm_log ("Mailbox is empty",(long) NIL); stream->silent = silent; /* now notify upper level */ mail_exists (stream,stream->nmsgs); mail_recent (stream,stream->recent); if (!LOCAL) return NIL; /* failure if stream died */ stream->perm_seen = stream->perm_deleted = stream->perm_flagged = stream->perm_answered = stream->perm_draft = stream->rdonly ? NIL : T; stream->perm_user_flags = stream->rdonly ? NIL : 0xffffffff; stream->kwd_create = (stream->user_flags[NUSERFLAGS-1] || stream->rdonly) ? NIL : T; /* can we create new user flags? */ return stream; /* return stream to caller */ } /* MBX mail close * Accepts: MAIL stream * close options */ void mbx_close (MAILSTREAM *stream,long options) { if (stream && LOCAL) { /* only if a file is open */ int silent = stream->silent; stream->silent = T; /* note this stream is dying */ /* do an expunge if requested */ if (options & CL_EXPUNGE) mbx_expunge (stream,NIL,NIL); else { /* otherwise do a checkpoint to purge */ LOCAL->expok = T; /* possible expunged messages */ mbx_ping (stream); } stream->silent = silent; /* restore previous status */ mbx_abort (stream); } } /* MBX mail abort stream * Accepts: MAIL stream */ void mbx_abort (MAILSTREAM *stream) { if (stream && LOCAL) { /* only if a file is open */ flock (LOCAL->fd,LOCK_UN); /* unlock local file */ close (LOCAL->fd); /* close the local file */ /* free local text buffer */ if (LOCAL->buf) fs_give ((void **) &LOCAL->buf); /* nuke the local data */ fs_give ((void **) &stream->local); stream->dtb = NIL; /* log out the DTB */ } } /* MBX mail fetch flags * Accepts: MAIL stream * sequence * option flags * Sniffs at file to see if some other process changed the flags */ void mbx_flags (MAILSTREAM *stream,char *sequence,long flags) { MESSAGECACHE *elt; unsigned long i; if (mbx_ping (stream) && /* ping mailbox, get new status for messages */ ((flags & FT_UID) ? mail_uid_sequence (stream,sequence) : mail_sequence (stream,sequence))) for (i = 1; i <= stream->nmsgs; i++) if ((elt = mail_elt (stream,i))->sequence && !elt->valid) mbx_elt (stream,i,NIL); } /* MBX mail fetch message header * Accepts: MAIL stream * message # to fetch * pointer to returned header text length * option flags * Returns: message header in RFC822 format */ char *mbx_header (MAILSTREAM *stream,unsigned long msgno,unsigned long *length, long flags) { unsigned long i; char *s; *length = 0; /* default to empty */ if (flags & FT_UID) return "";/* UID call "impossible" */ /* get header position, possibly header */ i = mbx_hdrpos (stream,msgno,length,&s); if (!s) { /* mbx_hdrpos() returned header? */ lseek (LOCAL->fd,i,L_SET); /* no, get to header position */ /* is buffer big enough? */ if (*length > LOCAL->buflen) { fs_give ((void **) &LOCAL->buf); LOCAL->buf = (char *) fs_get ((LOCAL->buflen = *length) + 1); } /* slurp the data */ read (LOCAL->fd,s = LOCAL->buf,*length); } s[*length] = '\0'; /* tie off string */ return s; } /* MBX mail fetch message text (body only) * Accepts: MAIL stream * message # to fetch * pointer to returned header text length * option flags * Returns: T on success, NIL on failure */ long mbx_text (MAILSTREAM *stream,unsigned long msgno,STRING *bs,long flags) { FDDATA d; unsigned long i,j; MESSAGECACHE *elt; /* UID call "impossible" */ if (flags & FT_UID) return NIL; /* get message status */ elt = mbx_elt (stream,msgno,NIL); /* if message not seen */ if (!(flags & FT_PEEK) && !elt->seen && mbx_flaglock (stream)) { elt->seen = T; /* mark message as seen */ /* recalculate status */ mbx_update_status (stream,msgno,NIL); mm_flags (stream,msgno); /* update flags */ mbx_flag (stream,NIL,NIL,NIL); } if (!LOCAL) return NIL; /* mbx_flaglock() could have aborted */ /* find header position */ i = mbx_hdrpos (stream,msgno,&j,NIL); d.fd = LOCAL->fd; /* set up file descriptor */ d.pos = i + j; d.chunk = LOCAL->buf; /* initial buffer chunk */ d.chunksize = CHUNKSIZE; INIT (bs,fd_string,&d,elt->rfc822_size - j); return LONGT; /* success */ } /* MBX mail modify flags * Accepts: MAIL stream * sequence * flag(s) * option flags * Unlocks flag lock */ void mbx_flag (MAILSTREAM *stream,char *sequence,char *flag,long flags) { struct utimbuf times; struct stat sbuf; /* make sure the update takes */ if (!stream->rdonly && LOCAL && (LOCAL->fd >= 0) && (LOCAL->ld >= 0)) { fsync (LOCAL->fd); fstat (LOCAL->fd,&sbuf); /* get current write time */ times.modtime = LOCAL->filetime = sbuf.st_mtime; /* update header */ if ((LOCAL->ffuserflag < NUSERFLAGS) && stream->user_flags[LOCAL->ffuserflag]) mbx_update_header (stream); times.actime = time (0); /* make sure read comes after all that */ utime (stream->mailbox,×); } if (LOCAL->ld >= 0) { /* unlock now */ unlockfd (LOCAL->ld,LOCAL->lock); LOCAL->ld = -1; } } /* MBX mail per-message modify flags * Accepts: MAIL stream * message cache element */ void mbx_flagmsg (MAILSTREAM *stream,MESSAGECACHE *elt) { if (mbx_flaglock (stream)) mbx_update_status (stream,elt->msgno,NIL); } /* MBX mail ping mailbox * Accepts: MAIL stream * Returns: T if stream still alive, NIL if not */ long mbx_ping (MAILSTREAM *stream) { unsigned long i,pos; long ret = NIL; int ld; char lock[MAILTMPLEN]; MESSAGECACHE *elt; struct stat sbuf; if (stream && LOCAL) { /* only if stream already open */ ret = LONGT; /* assume OK */ fstat (LOCAL->fd,&sbuf); /* get current file poop */ /* allow expunge if permitted at ping */ if (mail_parameters (NIL,GET_EXPUNGEATPING,NIL)) LOCAL->expok = T; /* if external modification */ if (LOCAL->filetime && (LOCAL->filetime < sbuf.st_mtime)) LOCAL->flagcheck = T; /* upgrade to flag checking */ /* new mail or flagcheck handling needed? */ if (((sbuf.st_size - LOCAL->filesize) || LOCAL->flagcheck || !stream->nmsgs) && ((ld = lockname (lock,stream->mailbox,LOCK_EX)) >= 0)) { if (!LOCAL->flagcheck) ret = mbx_parse (stream); /* sweep mailbox for changed message status */ else if (ret = mbx_parse (stream)) { unsigned long recent = 0; LOCAL->filetime = sbuf.st_mtime; for (i = 1; i <= stream->nmsgs; ) if (elt = mbx_elt (stream,i,LOCAL->expok)) { if (elt->recent) ++recent; ++i; } mail_recent (stream,recent); LOCAL->flagcheck = NIL; /* got all the updates */ } unlockfd (ld,lock); /* release shared parse/append permission */ } if (ret) { /* must still be alive */ if (!LOCAL->expunged) /* look for holes if none known yet */ for (i = 1, pos = HDRSIZE; !LOCAL->expunged && (i <= stream->nmsgs); i++, pos += elt->private.special.text.size + elt->rfc822_size) if ((elt = mail_elt (stream,i))->private.special.offset != pos) LOCAL->expunged = T;/* found a hole */ /* burp any holes */ if (LOCAL->expunged && !stream->rdonly) { if (mbx_rewrite (stream,&i,NIL)) fatal ("expunge on check"); if (i) { /* any space reclaimed? */ LOCAL->expunged = NIL;/* no more pending expunge */ sprintf (LOCAL->buf,"Reclaimed %lu bytes of expunged space",i); mm_log (LOCAL->buf,(long) NIL); } } LOCAL->expok = NIL; /* no more expok */ } } return ret; /* return result of the parse */ } /* MBX mail check mailbox (reparses status too) * Accepts: MAIL stream */ void mbx_check (MAILSTREAM *stream) { if (LOCAL) LOCAL->expok = T; /* mark that a check is desired */ if (mbx_ping (stream)) mm_log ("Check completed",(long) NIL); } /* MBX mail expunge mailbox * Accepts: MAIL stream * sequence to expunge if non-NIL * expunge options * Returns: T if success, NIL if failure */ long mbx_expunge (MAILSTREAM *stream,char *sequence,long options) { long ret; unsigned long nexp,reclaimed; if (ret = sequence ? ((options & EX_UID) ? mail_uid_sequence (stream,sequence) : mail_sequence (stream,sequence)) : LONGT) { if (!mbx_ping (stream)); /* do nothing if stream dead */ else if (stream->rdonly) /* won't do on readonly files! */ mm_log ("Expunge ignored on readonly mailbox",WARN); /* if expunged any messages */ else if (nexp = mbx_rewrite (stream,&reclaimed,sequence ? -1 : 1)) { sprintf (LOCAL->buf,"Expunged %lu messages",nexp); mm_log (LOCAL->buf,(long) NIL); } else if (reclaimed) { /* or if any prior expunged space reclaimed */ sprintf (LOCAL->buf,"Reclaimed %lu bytes of expunged space",reclaimed); mm_log (LOCAL->buf,(long) NIL); } else mm_log ("No messages deleted, so no update needed",(long) NIL); } return ret; } /* MBX mail copy message(s) * Accepts: MAIL stream * sequence * destination mailbox * copy options * Returns: T if success, NIL if failed */ long mbx_copy (MAILSTREAM *stream,char *sequence,char *mailbox,long options) { struct stat sbuf; struct utimbuf times; MESSAGECACHE *elt; unsigned long i,j,k,m; long ret = LONGT; int fd,ld; char *s,*t,file[MAILTMPLEN],lock[MAILTMPLEN]; mailproxycopy_t pc = (mailproxycopy_t) mail_parameters (stream,GET_MAILPROXYCOPY,NIL); copyuid_t cu = (copyuid_t) mail_parameters (NIL,GET_COPYUID,NIL); SEARCHSET *source = cu ? mail_newsearchset () : NIL; SEARCHSET *dest = cu ? mail_newsearchset () : NIL; MAILSTREAM *dstream = NIL; if (!((options & CP_UID) ? mail_uid_sequence (stream,sequence) : mail_sequence (stream,sequence))) return NIL; /* make sure valid mailbox */ if ((fd = mbx_isvalid (&dstream,mailbox,file,&ld,lock, cu ? MBXISVALIDUID : MBXISVALIDNOUID)) < 0) switch (errno) { case ENOENT: /* no such file? */ mm_notify (stream,"[TRYCREATE] Must create mailbox before copy",NIL); return NIL; case EACCES: /* file protected */ sprintf (LOCAL->buf,"Can't access destination: %.80s",mailbox); MM_LOG (LOCAL->buf,ERROR); return NIL; case EINVAL: if (pc) return (*pc) (stream,sequence,mailbox,options); sprintf (LOCAL->buf,"Invalid MBX-format mailbox name: %.80s",mailbox); mm_log (LOCAL->buf,ERROR); return NIL; default: if (pc) return (*pc) (stream,sequence,mailbox,options); sprintf (LOCAL->buf,"Not a MBX-format mailbox: %.80s",mailbox); mm_log (LOCAL->buf,ERROR); return NIL; } /* got file? */ if ((fd = open (dummy_file (file,mailbox),O_RDWR|O_CREAT|O_BINARY, S_IREAD|S_IWRITE)) < 0) { sprintf (LOCAL->buf,"Unable to open copy mailbox: %s",strerror (errno)); mm_log (LOCAL->buf,ERROR); return NIL; } mm_critical (stream); /* go critical */ fstat (fd,&sbuf); /* get current file size */ lseek (fd,sbuf.st_size,L_SET);/* move to end of file */ /* for each requested message */ for (i = 1; ret && (i <= stream->nmsgs); i++) if ((elt = mail_elt (stream,i))->sequence) { lseek (LOCAL->fd,elt->private.special.offset + elt->private.special.text.size,L_SET); mail_date(LOCAL->buf,elt);/* build target header */ /* get target keyword mask */ for (j = elt->user_flags, k = 0; j; ) if (s = stream->user_flags[find_rightmost_bit (&j)]) for (m = 0; (m < NUSERFLAGS) && (t = dstream->user_flags[m]); m++) if (!compare_cstring (s,t) && (k |= 1 << m)) break; sprintf (LOCAL->buf+strlen(LOCAL->buf),",%lu;%08lx%04x-%08lx\015\012", elt->rfc822_size,k,(unsigned) ((fSEEN * elt->seen) + (fDELETED * elt->deleted) + (fFLAGGED * elt->flagged) + (fANSWERED * elt->answered) + (fDRAFT * elt->draft)),cu ? ++dstream->uid_last : 0); /* write target header */ if (ret = (write (fd,LOCAL->buf,strlen (LOCAL->buf)) > 0)) { for (k = elt->rfc822_size; ret && (j = min (k,LOCAL->buflen)); k -= j){ read (LOCAL->fd,LOCAL->buf,j); ret = write (fd,LOCAL->buf,j) >= 0; } if (cu) { /* need to pass back new UID? */ mail_append_set (source,mail_uid (stream,i)); mail_append_set (dest,dstream->uid_last); } } } /* make sure all the updates take */ if (!(ret && (ret = !fsync (fd)))) { sprintf (LOCAL->buf,"Unable to write message: %s",strerror (errno)); mm_log (LOCAL->buf,ERROR); ftruncate (fd,sbuf.st_size); } if (cu && ret) { /* return sets if doing COPYUID */ (*cu) (stream,mailbox,dstream->uid_validity,source,dest); lseek (fd,15,L_SET); /* update UIDLAST */ sprintf (LOCAL->buf,"%08lx",dstream->uid_last); write (fd,LOCAL->buf,8); } else { /* flush any sets we may have built */ mail_free_searchset (&source); mail_free_searchset (&dest); } /* set atime to now-1 if successful copy */ if (ret) times.actime = time (0) - 1; /* else preserved \Marked status */ else times.actime = (sbuf.st_ctime > sbuf.st_atime) ? sbuf.st_atime : time (0); times.modtime = sbuf.st_mtime;/* preserve mtime */ utime (file,×); /* set the times */ close (fd); /* close the file */ mm_nocritical (stream); /* release critical */ unlockfd (ld,lock); /* release exclusive parse/append permission */ /* delete all requested messages */ if (ret && (options & CP_MOVE) && mbx_flaglock (stream)) { for (i = 1; i <= stream->nmsgs; i++) if (mail_elt (stream,i)->sequence) { /* mark message deleted */ mbx_elt (stream,i,NIL)->deleted = T; /* recalculate status */ mbx_update_status (stream,i,NIL); } /* update flags */ mbx_flag (stream,NIL,NIL,NIL); } if (dstream != stream) mail_close (dstream); return ret; } /* MBX mail append message from stringstruct * Accepts: MAIL stream * destination mailbox * append callback * data for callback * Returns: T if append successful, else NIL */ long mbx_append (MAILSTREAM *stream,char *mailbox,append_t af,void *data) { struct stat sbuf; int fd,ld; char *flags,*date,tmp[MAILTMPLEN],file[MAILTMPLEN],lock[MAILTMPLEN]; struct utimbuf times; FILE *df; MESSAGECACHE elt; long f; unsigned long i,uf; STRING *message; long ret = NIL; MAILSTREAM *dstream = NIL; appenduid_t au = (appenduid_t) mail_parameters (NIL,GET_APPENDUID,NIL); SEARCHSET *dst = au ? mail_newsearchset () : NIL; /* make sure valid mailbox */ /* make sure valid mailbox */ if ((fd = mbx_isvalid (&dstream,mailbox,file,&ld,lock, au ? MBXISVALIDUID : MBXISVALIDNOUID)) < 0) switch (errno) { case ENOENT: /* no such file? */ if (compare_cstring (mailbox,"INBOX")) { mm_notify (stream,"[TRYCREATE] Must create mailbox before append",NIL); return NIL; } /* can create INBOX here */ mbx_create (dstream = stream ? stream : &mbxproto,"INBOX"); if ((fd = mbx_isvalid (&dstream,mailbox,file,&ld,lock, au ? MBXISVALIDUID : MBXISVALIDNOUID)) < 0) break; case EACCES: /* file protected */ sprintf (tmp,"Can't access destination: %.80s",mailbox); MM_LOG (tmp,ERROR); return NIL; case EINVAL: sprintf (tmp,"Invalid MBX-format mailbox name: %.80s",mailbox); mm_log (tmp,ERROR); return NIL; default: sprintf (tmp,"Not a MBX-format mailbox: %.80s",mailbox); mm_log (tmp,ERROR); return NIL; } /* get first message */ if (!(*af) (dstream,data,&flags,&date,&message)) close (fd); else if (!(df = fdopen (fd,"r+b"))) { MM_LOG ("Unable to reopen append mailbox",ERROR); close (fd); } else { mm_critical (dstream); /* go critical */ fstat (fd,&sbuf); /* get current file size */ fseek (df,sbuf.st_size,SEEK_SET); errno = 0; for (ret = LONGT; ret && message; ) { if (!SIZE (message)) { /* guard against zero-length */ mm_log ("Append of zero-length message",ERROR); ret = NIL; break; } f = mail_parse_flags (dstream,flags,&uf); if (date) { /* parse date if given */ if (!mail_parse_date (&elt,date)) { sprintf (tmp,"Bad date in append: %.80s",date); mm_log (tmp,ERROR); ret = NIL; /* mark failure */ break; } mail_date (tmp,&elt); /* write preseved date */ } else internal_date (tmp); /* get current date in IMAP format */ /* write header */ if (fprintf (df,"%s,%lu;%08lx%04lx-%08lx\015\012",tmp,i = SIZE (message), uf,(unsigned long) f,au ? ++dstream->uid_last : 0) < 0) ret = NIL; else { /* write message */ size_t j; if (!message->cursize) SETPOS (message,GETPOS (message)); while (i && (j = fwrite (message->curpos,1,message->cursize,df))) { i -= j; SETPOS (message,GETPOS (message) + j); } /* get next message */ if (i || !(*af) (dstream,data,&flags,&date,&message)) ret = NIL; else if (au) mail_append_set (dst,dstream->uid_last); } } /* if error... */ if (!ret || (fflush (df) == EOF)) { /* revert file */ ftruncate (fd,sbuf.st_size); close (fd); /* make sure fclose() doesn't corrupt us */ if (errno) { sprintf (tmp,"Message append failed: %s",strerror (errno)); mm_log (tmp,ERROR); } ret = NIL; } if (au && ret) { /* return sets if doing APPENDUID */ (*au) (mailbox,dstream->uid_validity,dst); fseek (df,15,SEEK_SET); /* update UIDLAST */ fprintf (df,"%08lx",dstream->uid_last); } else mail_free_searchset (&dst); if (ret) times.actime = time (0) - 1; /* else preserve \Marked status */ else times.actime = (sbuf.st_ctime > sbuf.st_atime) ? sbuf.st_atime : time (0); /* preserve mtime */ times.modtime = sbuf.st_mtime; utime (file,×); /* set the times */ fclose (df); /* close the file */ mm_nocritical (dstream); /* release critical */ } unlockfd (ld,lock); /* release exclusive parse/append permission */ if (dstream != stream) mail_close (dstream); return ret; } /* Internal routines */ /* MBX mail parse mailbox * Accepts: MAIL stream * Returns: T if parse OK * NIL if failure, stream aborted */ long mbx_parse (MAILSTREAM *stream) { struct stat sbuf; MESSAGECACHE *elt = NIL; unsigned char c,*s,*t,*x; char tmp[MAILTMPLEN]; unsigned long i,j,k,m; off_t curpos = LOCAL->filesize; unsigned long nmsgs = stream->nmsgs; unsigned long recent = stream->recent; unsigned long lastuid = 0; short dirty = NIL; short added = NIL; short silent = stream->silent; short uidwarn = T; fstat (LOCAL->fd,&sbuf); /* get status */ if (sbuf.st_size < curpos) { /* sanity check */ sprintf (tmp,"Mailbox shrank from %lu to %lu!", (unsigned long) curpos,(unsigned long) sbuf.st_size); mm_log (tmp,ERROR); mbx_abort (stream); return NIL; } lseek (LOCAL->fd,0,L_SET); /* rewind file */ /* read internal header */ read (LOCAL->fd,LOCAL->buf,HDRSIZE); LOCAL->buf[HDRSIZE] = '\0'; /* tie off header */ c = LOCAL->buf[15]; /* save first character of last UID */ LOCAL->buf[15] = '\0'; /* parse UID validity */ stream->uid_validity = strtoul (LOCAL->buf + 7,NIL,16); LOCAL->buf[15] = c; /* restore first character of last UID */ /* parse last UID */ i = strtoul (LOCAL->buf + 15,NIL,16); stream->uid_last = stream->rdonly ? max (i,stream->uid_last) : i; /* parse user flags */ for (i = 0, s = LOCAL->buf + 25; (i < NUSERFLAGS) && (t = strchr (s,'\015')) && (t - s); i++, s = t + 2) { *t = '\0'; /* tie off flag */ if (!stream->user_flags[i] && (strlen (s) <= MAXUSERFLAG)) stream->user_flags[i] = cpystr (s); } LOCAL->ffuserflag = (int) i; /* first free user flag */ stream->silent = T; /* don't pass up mm_exists() events yet */ while (sbuf.st_size - curpos){/* while there is stuff to parse */ /* get to that position in the file */ lseek (LOCAL->fd,curpos,L_SET); if ((i = read (LOCAL->fd,LOCAL->buf,64)) <= 0) { sprintf (tmp,"Unable to read internal header at %lu, size = %lu: %s", (unsigned long) curpos,(unsigned long) sbuf.st_size, i ? strerror (errno) : "no data read"); mm_log (tmp,ERROR); mbx_abort (stream); return NIL; } LOCAL->buf[i] = '\0'; /* tie off buffer just in case */ if (!((s = strchr (LOCAL->buf,'\015')) && (s[1] == '\012'))) { sprintf (tmp,"Unable to find CRLF at %lu in %lu bytes, text: %.80s", (unsigned long) curpos,i,(char *) LOCAL->buf); mm_log (tmp,ERROR); mbx_abort (stream); return NIL; } *s = '\0'; /* tie off header line */ i = (s + 2) - LOCAL->buf; /* note start of text offset */ if (!((s = strchr (LOCAL->buf,',')) && (t = strchr (s+1,';')))) { sprintf (tmp,"Unable to parse internal header at %lu: %.80s", (unsigned long) curpos,(char *) LOCAL->buf); mm_log (tmp,ERROR); mbx_abort (stream); return NIL; } if (!(isxdigit (t[1]) && isxdigit (t[2]) && isxdigit (t[3]) && isxdigit (t[4]) && isxdigit (t[5]) && isxdigit (t[6]) && isxdigit (t[7]) && isxdigit (t[8]) && isxdigit (t[9]) && isxdigit (t[10]) && isxdigit (t[11]) && isxdigit (t[12]))) { sprintf (tmp,"Unable to parse message flags at %lu: %.80s", (unsigned long) curpos,(char *) LOCAL->buf); mm_log (tmp,ERROR); mbx_abort (stream); return NIL; } if ((t[13] != '-') || t[22] || !(isxdigit (t[14]) && isxdigit (t[15]) && isxdigit (t[16]) && isxdigit (t[17]) && isxdigit (t[18]) && isxdigit (t[19]) && isxdigit (t[20]) && isxdigit (t[21]))) { sprintf (tmp,"Unable to parse message UID at %lu: %.80s", (unsigned long) curpos,(char *) LOCAL->buf); mm_log (tmp,ERROR); mbx_abort (stream); return NIL; } *s++ = '\0'; *t++ = '\0'; /* break up fields */ /* get message size */ if (!(j = strtoul (s,(char **) &x,10)) && (!(x && *x))) { sprintf (tmp,"Unable to parse message size at %lu: %.80s,%.80s;%.80s", (unsigned long) curpos,(char *) LOCAL->buf,(char *) s, (char *) t); mm_log (tmp,ERROR); mbx_abort (stream); return NIL; } /* make sure didn't run off end of file */ if (((off_t) (curpos + i + j)) > sbuf.st_size) { sprintf (tmp,"Last message (at %lu) runs past end of file (%lu > %lu)", (unsigned long) curpos,(unsigned long) (curpos + i + j), (unsigned long) sbuf.st_size); mm_log (tmp,ERROR); mbx_abort (stream); return NIL; } /* parse UID */ if ((m = strtoul (t+13,NIL,16)) && ((m <= lastuid) || (m > stream->uid_last))) { if (uidwarn) { sprintf (tmp,"Invalid UID %08lx in message %lu, rebuilding UIDs", m,nmsgs+1); mm_log (tmp,WARN); uidwarn = NIL; /* restart UID validity */ stream->uid_validity = (unsigned long) time (0); } m = 0; /* lose this UID */ dirty = T; /* mark dirty, set new lastuid */ stream->uid_last = lastuid; } t[12] = '\0'; /* parse system flags */ if ((k = strtoul (t+8,NIL,16)) & fEXPUNGED) { if (m) lastuid = m; /* expunge message, update last UID seen */ else { /* no UID assigned? */ lastuid = ++stream->uid_last; dirty = T; } } else { /* not expunged, swell the cache */ added = T; /* note that a new message was added */ mail_exists (stream,++nmsgs); /* instantiate an elt for this message */ (elt = mail_elt (stream,nmsgs))->valid = T; /* parse the date */ if (!mail_parse_date (elt,LOCAL->buf)) { sprintf (tmp,"Unable to parse message date at %lu: %.80s", (unsigned long) curpos,(char *) LOCAL->buf); mm_log (tmp,ERROR); mbx_abort (stream); return NIL; } /* note file offset of header */ elt->private.special.offset = curpos; /* and internal header size */ elt->private.special.text.size = i; /* header size not known yet */ elt->private.msg.header.text.size = 0; elt->rfc822_size = j; /* note message size */ /* calculate system flags */ if (k & fSEEN) elt->seen = T; if (k & fDELETED) elt->deleted = T; if (k & fFLAGGED) elt->flagged = T; if (k & fANSWERED) elt->answered = T; if (k & fDRAFT) elt->draft = T; t[8] = '\0'; /* get user flags value */ elt->user_flags = strtoul (t,NIL,16); /* UID already assigned? */ if (!(elt->private.uid = m) || !(k & fOLD)) { elt->recent = T; /* no, mark as recent */ ++recent; /* count up a new recent message */ dirty = T; /* and must rewrite header */ /* assign new UID */ if (!elt->private.uid) elt->private.uid = ++stream->uid_last; mbx_update_status (stream,elt->msgno,NIL); } /* update last parsed UID */ lastuid = elt->private.uid; } curpos += i + j; /* update position */ } if (dirty && !stream->rdonly){/* update header */ mbx_update_header (stream); fsync (LOCAL->fd); /* make sure all the UID updates take */ } /* update parsed file size and time */ LOCAL->filesize = sbuf.st_size; fstat (LOCAL->fd,&sbuf); /* get status again to ensure time is right */ LOCAL->filetime = sbuf.st_mtime; if (added && !stream->rdonly){/* make sure atime updated */ struct utimbuf times; times.actime = time (0); times.modtime = LOCAL->filetime; utime (stream->mailbox,×); } stream->silent = silent; /* can pass up events now */ mail_exists (stream,nmsgs); /* notify upper level of new mailbox size */ mail_recent (stream,recent); /* and of change in recent messages */ return LONGT; /* return the winnage */ } /* MBX get cache element with status updating from file * Accepts: MAIL stream * message number * expunge OK flag * Returns: cache element */ MESSAGECACHE *mbx_elt (MAILSTREAM *stream,unsigned long msgno,long expok) { MESSAGECACHE *elt = mail_elt (stream,msgno); struct { /* old flags */ unsigned int seen : 1; unsigned int deleted : 1; unsigned int flagged : 1; unsigned int answered : 1; unsigned int draft : 1; unsigned long user_flags; } old; old.seen = elt->seen; old.deleted = elt->deleted; old.flagged = elt->flagged; old.answered = elt->answered; old.draft = elt->draft; old.user_flags = elt->user_flags; /* get new flags */ if (mbx_read_flags (stream,elt) && expok) { mail_expunged (stream,elt->msgno); return NIL; /* return this message was expunged */ } if ((old.seen != elt->seen) || (old.deleted != elt->deleted) || (old.flagged != elt->flagged) || (old.answered != elt->answered) || (old.draft != elt->draft) || (old.user_flags != elt->user_flags)) mm_flags (stream,msgno); /* let top level know */ return elt; } /* MBX read flags from file * Accepts: MAIL stream * cache element * Returns: non-NIL if message expunged */ unsigned long mbx_read_flags (MAILSTREAM *stream,MESSAGECACHE *elt) { unsigned long i; struct stat sbuf; fstat (LOCAL->fd,&sbuf); /* get status */ /* make sure file size is good */ if (sbuf.st_size < LOCAL->filesize) { sprintf (LOCAL->buf,"Mailbox shrank from %lu to %lu in flag read!", (unsigned long) LOCAL->filesize,(unsigned long) sbuf.st_size); fatal (LOCAL->buf); } /* set the seek pointer */ lseek (LOCAL->fd,(off_t) elt->private.special.offset + elt->private.special.text.size - 24,L_SET); /* read the new flags */ if (read (LOCAL->fd,LOCAL->buf,14) < 0) { sprintf (LOCAL->buf,"Unable to read new status: %s",strerror (errno)); fatal (LOCAL->buf); } if ((LOCAL->buf[0] != ';') || (LOCAL->buf[13] != '-')) { LOCAL->buf[14] = '\0'; /* tie off buffer for error message */ sprintf (LOCAL->buf+50,"Invalid flags for message %lu (%lu %lu): %s", elt->msgno,elt->private.special.offset, elt->private.special.text.size,(char *) LOCAL->buf); fatal (LOCAL->buf+50); } LOCAL->buf[13] = '\0'; /* tie off buffer */ /* calculate system flags */ i = strtoul (LOCAL->buf+9,NIL,16); elt->seen = i & fSEEN ? T : NIL; elt->deleted = i & fDELETED ? T : NIL; elt->flagged = i & fFLAGGED ? T : NIL; elt->answered = i & fANSWERED ? T : NIL; elt->draft = i & fDRAFT ? T : NIL; LOCAL->expunged |= i & fEXPUNGED ? T : NIL; LOCAL->buf[9] = '\0'; /* tie off flags */ /* get user flags value */ elt->user_flags = strtoul (LOCAL->buf+1,NIL,16); elt->valid = T; /* have valid flags now */ return i & fEXPUNGED; } /* MBX update header * Accepts: MAIL stream */ #define NTKLUDGEOFFSET 7 void mbx_update_header (MAILSTREAM *stream) { int i; char *s = LOCAL->buf; memset (s,'\0',HDRSIZE); /* initialize header */ sprintf (s,"*mbx*\015\012%08lx%08lx\015\012", stream->uid_validity,stream->uid_last); for (i = 0; (i < NUSERFLAGS) && stream->user_flags[i]; ++i) sprintf (s += strlen (s),"%s\015\012",stream->user_flags[i]); LOCAL->ffuserflag = i; /* first free user flag */ /* can we create more user flags? */ stream->kwd_create = (i < NUSERFLAGS) ? T : NIL; /* write reserved lines */ while (i++ < NUSERFLAGS) strcat (s,"\015\012"); while (T) { /* rewind file */ lseek (LOCAL->fd,NTKLUDGEOFFSET,L_SET); /* write new header */ if (write (LOCAL->fd,LOCAL->buf + NTKLUDGEOFFSET, HDRSIZE - NTKLUDGEOFFSET) > 0) break; mm_notify (stream,strerror (errno),WARN); mm_diskerror (stream,errno,T); } } /* MBX update status string * Accepts: MAIL stream * message number * flags */ void mbx_update_status (MAILSTREAM *stream,unsigned long msgno,long flags) { struct stat sbuf; MESSAGECACHE *elt = mail_elt (stream,msgno); /* readonly */ if (stream->rdonly || !elt->valid) mbx_read_flags (stream,elt); else { /* readwrite */ fstat (LOCAL->fd,&sbuf); /* get status */ /* make sure file size is good */ if (sbuf.st_size < LOCAL->filesize) { sprintf (LOCAL->buf,"Mailbox shrank from %lu to %lu in flag update!", (unsigned long) LOCAL->filesize,(unsigned long) sbuf.st_size); fatal (LOCAL->buf); } /* set the seek pointer */ lseek (LOCAL->fd,(off_t) elt->private.special.offset + elt->private.special.text.size - 24,L_SET); /* read the new flags */ if (read (LOCAL->fd,LOCAL->buf,14) < 0) { sprintf (LOCAL->buf,"Unable to read old status: %s",strerror (errno)); fatal (LOCAL->buf); } if ((LOCAL->buf[0] != ';') || (LOCAL->buf[13] != '-')) { LOCAL->buf[14] = '\0'; /* tie off buffer for error message */ sprintf (LOCAL->buf+50,"Invalid flags for message %lu (%lu %lu): %s", elt->msgno,elt->private.special.offset, elt->private.special.text.size,(char *) LOCAL->buf); fatal (LOCAL->buf+50); } /* print new flag string */ sprintf (LOCAL->buf,"%08lx%04x-%08lx",elt->user_flags,(unsigned) (((elt->deleted && flags) ? fEXPUNGED : (strtoul (LOCAL->buf+9,NIL,16)) & fEXPUNGED) + (fSEEN * elt->seen) + (fDELETED * elt->deleted) + (fFLAGGED * elt->flagged) + (fANSWERED * elt->answered) + (fDRAFT * elt->draft) + fOLD),elt->private.uid); while (T) { /* get to that place in the file */ lseek (LOCAL->fd,(off_t) elt->private.special.offset + elt->private.special.text.size - 23,L_SET); /* write new flags and UID */ if (write (LOCAL->fd,LOCAL->buf,21) > 0) break; mm_notify (stream,strerror (errno),WARN); mm_diskerror (stream,errno,T); } } } /* MBX locate header for a message * Accepts: MAIL stream * message number * pointer to returned header size * pointer to possible returned header * Returns: position of header in file */ #define HDRBUFLEN 16384 /* good enough for most headers */ #define SLOP 4 /* CR LF CR LF */ unsigned long mbx_hdrpos (MAILSTREAM *stream,unsigned long msgno, unsigned long *size,char **hdr) { unsigned long siz,done; long i; unsigned char *s,*t,*te; MESSAGECACHE *elt = mail_elt (stream,msgno); unsigned long ret = elt->private.special.offset + elt->private.special.text.size; if (hdr) *hdr = NIL; /* assume no header returned */ /* is header size known? */ if (*size = elt->private.msg.header.text.size) return ret; /* paranoia check */ if (LOCAL->buflen < (HDRBUFLEN + SLOP)) fatal ("LOCAL->buf smaller than HDRBUFLEN"); lseek (LOCAL->fd,ret,L_SET); /* get to header position */ /* read HDRBUFLEN chunks with 4 byte slop */ for (done = siz = 0, s = LOCAL->buf; (i = min ((long) (elt->rfc822_size - done),(long) HDRBUFLEN)) && (read (LOCAL->fd,s,i) == i); done += i, siz += (t - LOCAL->buf) - SLOP, s = LOCAL->buf + SLOP) { te = (t = s + i) - 12; /* calculate end of fast scan */ /* fast scan for CR */ for (s = LOCAL->buf; s < te;) if (((*s++ == '\015') || (*s++ == '\015') || (*s++ == '\015') || (*s++ == '\015') || (*s++ == '\015') || (*s++ == '\015') || (*s++ == '\015') || (*s++ == '\015') || (*s++ == '\015') || (*s++ == '\015') || (*s++ == '\015') || (*s++ == '\015')) && (*s == '\012') && (*++s == '\015') && (*++s == '\012')) { *size = elt->private.msg.header.text.size = siz + (++s - LOCAL->buf); if (hdr) *hdr = LOCAL->buf; return ret; } for (te = t - 3; (s < te);) /* final character-at-a-time scan */ if ((*s++ == '\015') && (*s == '\012') && (*++s == '\015') && (*++s == '\012')) { *size = elt->private.msg.header.text.size = siz + (++s - LOCAL->buf); if (hdr) *hdr = LOCAL->buf; return ret; } if (i <= SLOP) break; /* end of data */ /* slide over last 4 bytes */ memmove (LOCAL->buf,t - SLOP,SLOP); hdr = NIL; /* can't return header this way */ } /* not found: header consumes entire message */ elt->private.msg.header.text.size = *size = elt->rfc822_size; if (hdr) *hdr = LOCAL->buf; /* possibly return header too */ return ret; } /* MBX mail rewrite mailbox * Accepts: MAIL stream * pointer to return reclaimed size * flags (0 = no expunge, 1 = expunge deleted, -1 = expunge sequence) * Returns: number of expunged messages */ unsigned long mbx_rewrite (MAILSTREAM *stream,unsigned long *reclaimed, long flags) { struct utimbuf times; struct stat sbuf; off_t pos,ppos; int ld; unsigned long i,j,k,m,delta; unsigned long n = *reclaimed = 0; unsigned long recent = 0; char lock[MAILTMPLEN]; MESSAGECACHE *elt; /* get parse/append permission */ if ((ld = lockname (lock,stream->mailbox,LOCK_EX)) < 0) { mm_log ("Unable to lock expunge mailbox",ERROR); return 0; } fstat (LOCAL->fd,&sbuf); /* get current write time */ if (LOCAL->filetime && !LOCAL->flagcheck && (LOCAL->filetime < sbuf.st_mtime)) LOCAL->flagcheck = T; if (!mbx_parse (stream)) { /* make sure see any newly-arrived messages */ unlockfd (ld,lock); /* failed?? */ return 0; } if (LOCAL->flagcheck) { /* sweep flags if need flagcheck */ LOCAL->filetime = sbuf.st_mtime; for (i = 1; i <= stream->nmsgs; ++i) mbx_elt (stream,i,NIL); LOCAL->flagcheck = NIL; } /* get exclusive access */ if (!flock (LOCAL->fd,LOCK_EX|LOCK_NB)) { mm_critical (stream); /* go critical */ for (i = 1,delta = 0,pos = ppos = HDRSIZE; i <= stream->nmsgs; ) { /* note if message not at predicted location */ if (m = (elt = mbx_elt (stream,i,NIL))->private.special.offset - ppos) { ppos = elt->private.special.offset; *reclaimed += m; /* note reclaimed message space */ delta += m; /* and as expunge delta */ } /* number of bytes to smash or preserve */ ppos += (k = elt->private.special.text.size + elt->rfc822_size); /* if need to expunge this message*/ if (flags && elt->deleted && ((flags > 0) || elt->sequence)) { delta += k; /* number of bytes to delete */ mail_expunged(stream,i);/* notify upper levels */ n++; /* count up one more expunged message */ } else { /* preserved message */ i++; /* count this message */ if (elt->recent) ++recent; if (delta) { /* moved, note first byte to preserve */ j = elt->private.special.offset; do { /* read from source position */ m = min (k,LOCAL->buflen); lseek (LOCAL->fd,j,L_SET); read (LOCAL->fd,LOCAL->buf,m); pos = j - delta; /* write to destination position */ while (T) { lseek (LOCAL->fd,pos,L_SET); if (write (LOCAL->fd,LOCAL->buf,m) > 0) break; mm_notify (stream,strerror (errno),WARN); mm_diskerror (stream,errno,T); } pos += m; /* new position */ j += m; /* next chunk, perhaps */ } while (k -= m); /* until done */ /* note the new address of this text */ elt->private.special.offset -= delta; } /* preserved but no deleted messages yet */ else pos = elt->private.special.offset + k; } } /* deltaed file size match position? */ if (m = (LOCAL->filesize -= delta) - pos) { *reclaimed += m; /* probably an fEXPUNGED msg */ LOCAL->filesize = pos; /* set correct size */ } /* truncate file after last message */ ftruncate (LOCAL->fd,LOCAL->filesize); fsync (LOCAL->fd); /* force disk update */ mm_nocritical (stream); /* release critical */ flock (LOCAL->fd,LOCK_SH); /* allow sharers again */ } else { /* can't get exclusive */ flock (LOCAL->fd,LOCK_SH); /* recover previous shared mailbox lock */ /* do hide-expunge when shared */ if (flags) for (i = 1; i <= stream->nmsgs; ) { if (elt = mbx_elt (stream,i,T)) { /* make the message invisible */ if (elt->deleted && ((flags > 0) || elt->sequence)) { mbx_update_status (stream,elt->msgno,LONGT); /* notify upper levels */ mail_expunged (stream,i); n++; /* count up one more expunged message */ } else { i++; /* preserved message */ if (elt->recent) ++recent; } } else n++; /* count up one more expunged message */ } fsync (LOCAL->fd); /* force disk update */ } fstat (LOCAL->fd,&sbuf); /* get new write time */ times.modtime = LOCAL->filetime = sbuf.st_mtime; times.actime = time (0); /* reset atime to now */ utime (stream->mailbox,×); unlockfd (ld,lock); /* release exclusive parse/append permission */ /* notify upper level of new mailbox size */ mail_exists (stream,stream->nmsgs); mail_recent (stream,recent); return n; /* return number of expunged messages */ } /* MBX mail lock for flag updating * Accepts: stream * Returns: T if successful, NIL if failure */ long mbx_flaglock (MAILSTREAM *stream) { struct stat sbuf; unsigned long i; int ld; char lock[MAILTMPLEN]; /* no-op if readonly or already locked */ if (!stream->rdonly && LOCAL && (LOCAL->fd >= 0) && (LOCAL->ld < 0)) { /* lock now */ if ((ld = lockname (lock,stream->mailbox,LOCK_EX)) < 0) return NIL; if (!LOCAL->flagcheck) { /* don't do this if flagcheck already needed */ if (LOCAL->filetime) { /* know previous time? */ fstat (LOCAL->fd,&sbuf);/* get current write time */ if (LOCAL->filetime < sbuf.st_mtime) LOCAL->flagcheck = T; LOCAL->filetime = 0; /* don't do this test for any other messages */ } if (!mbx_parse (stream)) {/* parse mailbox */ unlockfd (ld,lock); /* shouldn't happen */ return NIL; } if (LOCAL->flagcheck) /* invalidate cache if flagcheck */ for (i = 1; i <= stream->nmsgs; ++i) mail_elt (stream,i)->valid = NIL; } LOCAL->ld = ld; /* copy to stream for subsequent calls */ memcpy (LOCAL->lock,lock,MAILTMPLEN); } return LONGT; } alpine-2.10+dfsg/imap/src/osdep/nt/ssl_nt.c0000600000175000017500000005637011512502123022264 0ustar paulproteuspaulproteus/* ======================================================================== * Copyright 1988-2008 University of Washington * * Licensed under the Apache License, Version 2.0 (the "License"); * you may not use this file except in compliance with the License. * You may obtain a copy of the License at * * http://www.apache.org/licenses/LICENSE-2.0 * * * ======================================================================== */ /* * Program: SSL authentication/encryption module for Windows 9x and NT * * Author: Mark Crispin * Networks and Distributed Computing * Computing & Communications * University of Washington * Administration Building, AG-44 * Seattle, WA 98195 * Internet: MRC@CAC.Washington.EDU * * Date: 22 September 1998 * Last Edited: 13 January 2008 */ #define SECURITY_WIN32 #include #include #define SSLBUFLEN 8192 /* SSL I/O stream */ typedef struct ssl_stream { TCPSTREAM *tcpstream; /* TCP stream */ CredHandle cred; /* SSL credentials */ CtxtHandle context; /* SSL context */ /* stream encryption sizes */ SecPkgContext_StreamSizes sizes; size_t bufsize; int ictr; /* input counter */ char *iptr; /* input pointer */ int iextractr; /* extra input counter */ char *iextraptr; /* extra input pointer */ char *ibuf; /* input buffer */ char *obuf; /* output buffer */ } SSLSTREAM; #include "sslio.h" /* Function prototypes */ static SSLSTREAM *ssl_start(TCPSTREAM *tstream,char *host,unsigned long flags); static char *ssl_analyze_status (SECURITY_STATUS err,char *buf); static char *ssl_getline_work (SSLSTREAM *stream,unsigned long *size, long *contd); static long ssl_abort (SSLSTREAM *stream); /* Secure Sockets Layer network driver dispatch */ static struct ssl_driver ssldriver = { ssl_open, /* open connection */ ssl_aopen, /* open preauthenticated connection */ ssl_getline, /* get a line */ ssl_getbuffer, /* get a buffer */ ssl_soutr, /* output pushed data */ ssl_sout, /* output string */ ssl_close, /* close connection */ ssl_host, /* return host name */ ssl_remotehost, /* return remote host name */ ssl_port, /* return port number */ ssl_localhost /* return local host name */ }; /* security function table */ static SecurityFunctionTable *sft = NIL; static unsigned long ssltsz = 0;/* SSL maximum token length */ /* Define crypt32.dll stuff here in case a pre-IE5 Win9x system */ typedef DWORD (CALLBACK *CNTS) (DWORD,PCERT_NAME_BLOB,DWORD,LPSTR,DWORD); typedef BOOL (CALLBACK *CGCC) (HCERTCHAINENGINE,PCCERT_CONTEXT,LPFILETIME, HCERTSTORE,PCERT_CHAIN_PARA,DWORD,LPVOID, PCCERT_CHAIN_CONTEXT *); typedef BOOL (CALLBACK *CVCCP) (LPCSTR,PCCERT_CHAIN_CONTEXT, PCERT_CHAIN_POLICY_PARA, PCERT_CHAIN_POLICY_STATUS); typedef VOID (CALLBACK *CFCC) (PCCERT_CHAIN_CONTEXT); typedef BOOL (CALLBACK *CFCCX) (PCCERT_CONTEXT); static CNTS certNameToStr = NIL; static CGCC certGetCertificateChain = NIL; static CVCCP certVerifyCertificateChainPolicy = NIL; static CFCC certFreeCertificateChain = NIL; static CFCCX certFreeCertificateContext = NIL; /* One-time SSL initialization */ static int sslonceonly = 0; void ssl_onceonlyinit (void) { if (!sslonceonly++) { /* only need to call it once */ HINSTANCE lib; FARPROC pi; ULONG np; SecPkgInfo *pp; int i; /* get security library */ if (((lib = LoadLibrary ("schannel.dll")) || (lib = LoadLibrary ("security.dll"))) && (pi = GetProcAddress (lib,SECURITY_ENTRYPOINT)) && (sft = (SecurityFunctionTable *) pi ()) && !(sft->EnumerateSecurityPackages (&np,&pp))) { /* look for an SSL package */ for (i = 0; (i < (int) np); i++) if (!strcmp (pp[i].Name,UNISP_NAME)) { /* note maximum token size and name */ ssltsz = pp[i].cbMaxToken; /* apply runtime linkage */ mail_parameters (NIL,SET_SSLDRIVER,(void *) &ssldriver); mail_parameters (NIL,SET_SSLSTART,(void *) ssl_start); if ((lib = LoadLibrary ("crypt32.dll")) && (certGetCertificateChain = (CGCC) GetProcAddress (lib,"CertGetCertificateChain")) && (certVerifyCertificateChainPolicy = (CVCCP) GetProcAddress (lib,"CertVerifyCertificateChainPolicy")) && (certFreeCertificateChain = (CFCC) GetProcAddress (lib,"CertFreeCertificateChain")) && (certFreeCertificateContext = (CFCCX) GetProcAddress (lib,"CertFreeCertificateContext"))) certNameToStr = (CNTS) GetProcAddress (lib,"CertNameToStrA"); return; /* all done */ } } } } /* SSL open * Accepts: host name * contact service name * contact port number * Returns: SSL stream if success else NIL */ SSLSTREAM *ssl_open (char *host,char *service,unsigned long port) { TCPSTREAM *stream = tcp_open (host,service,port); return stream ? ssl_start (stream,host,port) : NIL; } /* SSL authenticated open * Accepts: host name * service name * returned user name buffer * Returns: SSL stream if success else NIL */ SSLSTREAM *ssl_aopen (NETMBX *mb,char *service,char *usrbuf) { return NIL; /* don't use this mechanism with SSL */ } /* Start SSL/TLS negotiations * Accepts: open TCP stream of session * user's host name * flags * Returns: SSL stream if success else NIL */ static SSLSTREAM *ssl_start (TCPSTREAM *tstream,char *host,unsigned long flags) { SECURITY_STATUS e; ULONG a; TimeStamp t; SecBuffer ibuf[2],obuf[1]; SecBufferDesc ibufs,obufs; SCHANNEL_CRED tlscred; CERT_CONTEXT *cert = NIL; CERT_CHAIN_PARA chparam; CERT_CHAIN_CONTEXT *chain; SSL_EXTRA_CERT_CHAIN_POLICY_PARA policy; CERT_CHAIN_POLICY_PARA polparam; CERT_CHAIN_POLICY_STATUS status; char tmp[MAILTMPLEN],certname[256]; char *reason = NIL; ULONG req = ISC_REQ_REPLAY_DETECT | ISC_REQ_SEQUENCE_DETECT | ISC_REQ_CONFIDENTIALITY | ISC_REQ_USE_SESSION_KEY | ISC_REQ_ALLOCATE_MEMORY | ISC_REQ_STREAM | ISC_REQ_EXTENDED_ERROR | ISC_REQ_MANUAL_CRED_VALIDATION; LPSTR usage[] = { szOID_PKIX_KP_SERVER_AUTH, szOID_SERVER_GATED_CRYPTO, szOID_SGC_NETSCAPE }; PWSTR whost = NIL; char *buf = (char *) fs_get (ssltsz); unsigned long size = 0; sslcertificatequery_t scq = (sslcertificatequery_t) mail_parameters (NIL,GET_SSLCERTIFICATEQUERY,NIL); sslfailure_t sf = (sslfailure_t) mail_parameters (NIL,GET_SSLFAILURE,NIL); SSLSTREAM *stream = (SSLSTREAM *) memset (fs_get (sizeof (SSLSTREAM)),0, sizeof (SSLSTREAM)); stream->tcpstream = tstream; /* bind TCP stream */ /* initialize TLS credential */ memset (&tlscred,0,sizeof (SCHANNEL_CRED)); tlscred.dwVersion = SCHANNEL_CRED_VERSION; tlscred.grbitEnabledProtocols = SP_PROT_TLS1; /* acquire credentials */ if (sft->AcquireCredentialsHandle (NIL,UNISP_NAME,SECPKG_CRED_OUTBOUND,NIL,(flags & NET_TLSCLIENT) ? &tlscred : NIL,NIL,NIL,&stream->cred,&t) != SEC_E_OK) reason = "Acquire credentials handle failed"; else while (!reason) { /* negotiate security context */ /* initialize buffers */ ibuf[0].cbBuffer = size; ibuf[0].pvBuffer = buf; ibuf[1].cbBuffer = 0; ibuf[1].pvBuffer = NIL; obuf[0].cbBuffer = 0; obuf[0].pvBuffer = NIL; ibuf[0].BufferType = obuf[0].BufferType = SECBUFFER_TOKEN; ibuf[1].BufferType = SECBUFFER_EMPTY; /* initialize buffer descriptors */ ibufs.ulVersion = obufs.ulVersion = SECBUFFER_VERSION; ibufs.cBuffers = 2; obufs.cBuffers = 1; ibufs.pBuffers = ibuf; obufs.pBuffers = obuf; /* negotiate security */ e = sft->InitializeSecurityContext (&stream->cred,size ? &stream->context : NIL,host,req,0, SECURITY_NETWORK_DREP,size? &ibufs:NIL,0,&stream->context,&obufs,&a,&t); /* have an output buffer we need to send? */ if (obuf[0].pvBuffer && obuf[0].cbBuffer) { if (!tcp_sout (stream->tcpstream,obuf[0].pvBuffer,obuf[0].cbBuffer)) reason = "Unexpected TCP output disconnect"; /* free the buffer */ sft->FreeContextBuffer (obuf[0].pvBuffer); } if (!reason) switch (e) { /* negotiation state */ case SEC_I_INCOMPLETE_CREDENTIALS: break; /* server wants client auth */ case SEC_I_CONTINUE_NEEDED: if (size) { /* continue, read any data? */ /* yes, anything regurgiated back to us? */ if (ibuf[1].BufferType == SECBUFFER_EXTRA) { /* yes, set this as the new data */ memmove (buf,buf + size - ibuf[1].cbBuffer,ibuf[1].cbBuffer); size = ibuf[1].cbBuffer; break; } size = 0; /* otherwise, read more stuff from server */ } case SEC_E_INCOMPLETE_MESSAGE: /* need to read more data from server */ if (!tcp_getdata (stream->tcpstream)) reason = "Unexpected TCP input disconnect"; else { memcpy (buf+size,stream->tcpstream->iptr,stream->tcpstream->ictr); size += stream->tcpstream->ictr; /* empty it from TCP's buffers */ stream->tcpstream->iptr += stream->tcpstream->ictr; stream->tcpstream->ictr = 0; } break; case SEC_E_OK: /* success, any data to be regurgitated? */ if (ibuf[1].BufferType == SECBUFFER_EXTRA) { /* yes, set this as the new data */ memmove (stream->tcpstream->iptr = stream->tcpstream->ibuf, buf + size - ibuf[1].cbBuffer,ibuf[1].cbBuffer); stream->tcpstream->ictr = ibuf[1].cbBuffer; } if (certNameToStr && !(flags & NET_NOVALIDATECERT)) { /* need validation, make wchar of host */ if (!((size = MultiByteToWideChar (CP_ACP,0,host,-1,NIL,0)) && (whost = (PWSTR) fs_get (size*sizeof (WCHAR))) && MultiByteToWideChar (CP_ACP,0,host,-1,whost,size))) fatal ("Can't make wchar of host name!"); /* get certificate */ if ((sft->QueryContextAttributes (&stream->context,SECPKG_ATTR_REMOTE_CERT_CONTEXT,&cert) != SEC_E_OK) || !cert) { reason = "*Unable to get certificate"; strcpy (certname,""); } else { /* get certificate subject name */ (*certNameToStr) (X509_ASN_ENCODING | PKCS_7_ASN_ENCODING, &cert->pCertInfo->Subject,CERT_X500_NAME_STR, certname,255); /* build certificate chain */ memset (&chparam,0,sizeof (chparam)); chparam.cbSize = sizeof (chparam); chparam.RequestedUsage.dwType = USAGE_MATCH_TYPE_OR; chparam.RequestedUsage.Usage.rgpszUsageIdentifier = usage; chparam.RequestedUsage.Usage.cUsageIdentifier = sizeof (usage) / sizeof (LPSTR); if (!(*certGetCertificateChain) (NIL,cert,NIL,cert->hCertStore,&chparam,NIL,NIL,&chain)) reason = ssl_analyze_status (GetLastError (),tmp); else { /* validate certificate chain */ memset (&policy,0,sizeof (SSL_EXTRA_CERT_CHAIN_POLICY_PARA)); policy.cbStruct = sizeof (SSL_EXTRA_CERT_CHAIN_POLICY_PARA); policy.dwAuthType = AUTHTYPE_SERVER; policy.fdwChecks = NIL; policy.pwszServerName = whost; memset (&polparam,0,sizeof (polparam)); polparam.cbSize = sizeof (polparam); polparam.pvExtraPolicyPara = &policy; memset (&status,0,sizeof (status)); status.cbSize = sizeof (status); if (!(*certVerifyCertificateChainPolicy) (CERT_CHAIN_POLICY_SSL,chain,&polparam,&status)) reason = ssl_analyze_status (GetLastError (),tmp); else if (status.dwError) reason = ssl_analyze_status (status.dwError,tmp); (*certFreeCertificateChain) (chain); } (*certFreeCertificateContext) (cert); } if (whost) fs_give ((void **) &whost); if (reason) { /* got an error? */ /* application callback */ if (scq) reason = (*scq) ((*reason == '*') ? reason + 1 : reason, host,certname) ? NIL : ""; else if (*certname) { /* error message to return via mm_log() */ sprintf (buf,"*%.128s: %.255s", (*reason == '*') ? reason + 1 : reason,certname); reason = buf; } } } if (reason || (reason = ssl_analyze_status (sft->QueryContextAttributes (&stream->context,SECPKG_ATTR_STREAM_SIZES,&stream->sizes),buf))) break; /* error in certificate or getting sizes */ fs_give ((void **) &buf); /* flush temporary buffer */ /* make maximum-sized buffers */ stream->bufsize = stream->sizes.cbHeader + stream->sizes.cbMaximumMessage + stream->sizes.cbTrailer; if (stream->sizes.cbMaximumMessage < SSLBUFLEN) fatal ("cbMaximumMessage is less than SSLBUFLEN!"); else if (stream->sizes.cbMaximumMessage < 16384) { sprintf (tmp,"WINDOWS BUG: cbMaximumMessage = %ld, should be 16384", (long) stream->sizes.cbMaximumMessage); mm_log (tmp,NIL); } stream->ibuf = (char *) fs_get (stream->bufsize); stream->obuf = (char *) fs_get (stream->bufsize); return stream; default: reason = ssl_analyze_status (e,buf); } } ssl_close (stream); /* failed to do SSL */ stream = NIL; /* no stream returned */ switch (*reason) { /* analyze reason */ case '*': /* certificate failure */ ++reason; /* skip over certificate failure indication */ /* pass to error callback */ if (sf) (*sf) (host,reason,flags); else { /* no error callback, build error message */ sprintf (tmp,"Certificate failure for %.80s: %.512s",host,reason); mm_log (tmp,ERROR); } case '\0': /* user answered no to certificate callback */ if (flags & NET_TRYSSL) /* return dummy stream to stop tryssl */ stream = (SSLSTREAM *) memset (fs_get (sizeof (SSLSTREAM)),0, sizeof (SSLSTREAM)); break; default: /* non-certificate failure */ if (flags & NET_TRYSSL); /* no error output if tryssl */ /* pass to error callback */ else if (sf) (*sf) (host,reason,flags); else { /* no error callback, build error message */ sprintf (tmp,"TLS/SSL failure for %.80s: %.512s",host,reason); mm_log (tmp,ERROR); } break; } fs_give ((void **) &buf); /* flush temporary buffer */ return stream; } /* Generate error text from SSL error code * Accepts: SSL status * scratch buffer * Returns: text if error status, else NIL */ static char *ssl_analyze_status (SECURITY_STATUS err,char *buf) { switch (err) { case SEC_E_OK: /* no error */ case SEC_I_CONTINUE_NEEDED: case SEC_I_INCOMPLETE_CREDENTIALS: case SEC_E_INCOMPLETE_MESSAGE: return NIL; case SEC_E_NO_AUTHENTICATING_AUTHORITY: mm_log ("unexpected SEC_E_NO_AUTHENTICATING_AUTHORITY",NIL); return "*No authority could be contacted for authentication"; case SEC_E_WRONG_PRINCIPAL: mm_log ("unexpected SEC_E_WRONG_PRINCIPAL",NIL); case CERT_E_CN_NO_MATCH: return "*Server name does not match certificate"; case SEC_E_UNTRUSTED_ROOT: mm_log ("unexpected SEC_E_UNTRUSTED_ROOT",NIL); case CERT_E_UNTRUSTEDROOT: return "*Self-signed certificate or untrusted authority"; case SEC_E_CERT_EXPIRED: mm_log ("unexpected SEC_E_CERT_EXPIRED",NIL); case CERT_E_EXPIRED: return "*Certificate has expired"; case CERT_E_REVOKED: return "*Certificate revoked"; case SEC_E_INVALID_TOKEN: return "Invalid token, probably not an SSL server"; case SEC_E_UNSUPPORTED_FUNCTION: return "SSL not supported on this machine - upgrade your system software"; } sprintf (buf,"Unexpected SSPI or certificate error %lx - report this",err); return buf; } /* SSL receive line * Accepts: SSL stream * Returns: text line string or NIL if failure */ char *ssl_getline (SSLSTREAM *stream) { unsigned long n,contd; char *ret = ssl_getline_work (stream,&n,&contd); if (ret && contd) { /* got a line needing continuation? */ STRINGLIST *stl = mail_newstringlist (); STRINGLIST *stc = stl; do { /* collect additional lines */ stc->text.data = (unsigned char *) ret; stc->text.size = n; stc = stc->next = mail_newstringlist (); ret = ssl_getline_work (stream,&n,&contd); } while (ret && contd); if (ret) { /* stash final part of line on list */ stc->text.data = (unsigned char *) ret; stc->text.size = n; /* determine how large a buffer we need */ for (n = 0, stc = stl; stc; stc = stc->next) n += stc->text.size; ret = fs_get (n + 1); /* copy parts into buffer */ for (n = 0, stc = stl; stc; n += stc->text.size, stc = stc->next) memcpy (ret + n,stc->text.data,stc->text.size); ret[n] = '\0'; } mail_free_stringlist (&stl);/* either way, done with list */ } return ret; } /* SSL receive line or partial line * Accepts: SSL stream * pointer to return size * pointer to return continuation flag * Returns: text line string, size and continuation flag, or NIL if failure */ static char *ssl_getline_work (SSLSTREAM *stream,unsigned long *size, long *contd) { unsigned long n; char *s,*ret,c,d; *contd = NIL; /* assume no continuation */ /* make sure have data */ if (!ssl_getdata (stream)) return NIL; for (s = stream->iptr, n = 0, c = '\0'; stream->ictr--; n++, c = d) { d = *stream->iptr++; /* slurp another character */ if ((c == '\015') && (d == '\012')) { ret = (char *) fs_get (n--); memcpy (ret,s,*size = n); /* copy into a free storage string */ ret[n] = '\0'; /* tie off string with null */ return ret; } } /* copy partial string from buffer */ memcpy ((ret = (char *) fs_get (n)),s,*size = n); /* get more data from the net */ if (!ssl_getdata (stream)) fs_give ((void **) &ret); /* special case of newline broken by buffer */ else if ((c == '\015') && (*stream->iptr == '\012')) { stream->iptr++; /* eat the line feed */ stream->ictr--; ret[*size = --n] = '\0'; /* tie off string with null */ } else *contd = LONGT; /* continuation needed */ return ret; } /* SSL receive buffer * Accepts: SSL stream * size in bytes * buffer to read into * Returns: T if success, NIL otherwise */ long ssl_getbuffer (SSLSTREAM *stream,unsigned long size,char *buffer) { unsigned long n; while (size > 0) { /* until request satisfied */ if (!ssl_getdata (stream)) return NIL; n = min (size,stream->ictr);/* number of bytes to transfer */ /* do the copy */ memcpy (buffer,stream->iptr,n); buffer += n; /* update pointer */ stream->iptr += n; size -= n; /* update # of bytes to do */ stream->ictr -= n; } buffer[0] = '\0'; /* tie off string */ return T; } /* SSL receive data * Accepts: TCP/IP stream * Returns: T if success, NIL otherwise */ long ssl_getdata (SSLSTREAM *stream) { while (stream->ictr < 1) { /* decrypted buffer empty? */ SECURITY_STATUS status; SecBuffer buf[4]; SecBufferDesc msg; size_t i; size_t n = 0; /* initially no bytes to decrypt */ do { /* yes, make sure have data from TCP */ if (stream->iextractr) { /* have previous unread data? */ memcpy (stream->ibuf + n,stream->iextraptr,stream->iextractr); n += stream->iextractr; /* update number of bytes read */ stream->iextractr = 0; /* no more extra data */ } else { /* read from TCP */ if (!tcp_getdata (stream->tcpstream)) return ssl_abort (stream); /* maximum amount of data to copy */ if (!(i = min (stream->bufsize - n,stream->tcpstream->ictr))) fatal ("incomplete SecBuffer exceeds maximum buffer size"); /* do the copy */ memcpy (stream->ibuf + n,stream->tcpstream->iptr,i); stream->tcpstream->iptr += i; stream->tcpstream->ictr -= i; n += i; /* update number of bytes to decrypt */ } buf[0].cbBuffer = n; /* first SecBuffer gets data */ buf[0].pvBuffer = stream->ibuf; buf[0].BufferType = SECBUFFER_DATA; /* subsequent ones are for spares */ buf[1].BufferType = buf[2].BufferType = buf[3].BufferType = SECBUFFER_EMPTY; msg.ulVersion = SECBUFFER_VERSION; msg.cBuffers = 4; /* number of SecBuffers */ msg.pBuffers = buf; /* first SecBuffer */ } while ((status = ((DECRYPT_MESSAGE_FN) sft->Reserved4) (&stream->context,&msg,0,NIL)) == SEC_E_INCOMPLETE_MESSAGE); switch (status) { case SEC_E_OK: /* won */ case SEC_I_RENEGOTIATE: /* won but lost it after this buffer */ /* hunt for a buffer */ for (i = 0; (i < 4) && (buf[i].BufferType != SECBUFFER_DATA) ; i++); if (i < 4) { /* found a buffer? */ /* yes, set up pointer and counter */ stream->iptr = buf[i].pvBuffer; stream->ictr = buf[i].cbBuffer; /* any unprocessed data? */ while (++i < 4) if (buf[i].BufferType == SECBUFFER_EXTRA) { /* yes, note for next time around */ stream->iextraptr = buf[i].pvBuffer; stream->iextractr = buf[i].cbBuffer; } } break; default: /* anything else means we've lost */ return ssl_abort (stream); } } return LONGT; } /* SSL send string as record * Accepts: SSL stream * string pointer * Returns: T if success else NIL */ long ssl_soutr (SSLSTREAM *stream,char *string) { return ssl_sout (stream,string,(unsigned long) strlen (string)); } /* SSL send string * Accepts: SSL stream * string pointer * byte count * Returns: T if success else NIL */ long ssl_sout (SSLSTREAM *stream,char *string,unsigned long size) { SecBuffer buf[4]; SecBufferDesc msg; char *s; size_t n; if (!stream->tcpstream) return NIL; /* until request satisfied */ for (s = stream->ibuf,n = 0; size;) { /* header */ buf[0].BufferType = SECBUFFER_STREAM_HEADER; memset (buf[0].pvBuffer = stream->obuf,0, buf[0].cbBuffer = stream->sizes.cbHeader); /* message (up to maximum size) */ buf[1].BufferType = SECBUFFER_DATA; memcpy (buf[1].pvBuffer = stream->obuf + stream->sizes.cbHeader,string, buf[1].cbBuffer = min (size,SSLBUFLEN)); /* trailer */ buf[2].BufferType = SECBUFFER_STREAM_TRAILER; memset (buf[2].pvBuffer = ((char *) buf[1].pvBuffer) + buf[1].cbBuffer,0, buf[2].cbBuffer = stream->sizes.cbTrailer); /* spare */ buf[3].BufferType = SECBUFFER_EMPTY; msg.ulVersion = SECBUFFER_VERSION; msg.cBuffers = 4; /* number of SecBuffers */ msg.pBuffers = buf; /* first SecBuffer */ string += buf[1].cbBuffer; size -= buf[1].cbBuffer; /* this many bytes processed */ /* encrypt and send message */ if ((((ENCRYPT_MESSAGE_FN) sft->Reserved3) (&stream->context,0,&msg,NIL) != SEC_E_OK) || !tcp_sout (stream->tcpstream,stream->obuf, buf[0].cbBuffer + buf[1].cbBuffer + buf[2].cbBuffer)) return ssl_abort (stream);/* encryption or sending failed */ } return LONGT; } /* SSL close * Accepts: SSL stream */ void ssl_close (SSLSTREAM *stream) { ssl_abort (stream); /* nuke the stream */ fs_give ((void **) &stream); /* flush the stream */ } /* SSL abort stream * Accepts: SSL stream * Returns: NIL always */ static long ssl_abort (SSLSTREAM *stream) { if (stream->tcpstream) { /* close TCP stream */ sft->DeleteSecurityContext (&stream->context); sft->FreeCredentialHandle (&stream->cred); tcp_close (stream->tcpstream); stream->tcpstream = NIL; } if (stream->ibuf) fs_give ((void **) &stream->ibuf); if (stream->obuf) fs_give ((void **) &stream->obuf); return NIL; } /* SSL get host name * Accepts: SSL stream * Returns: host name for this stream */ char *ssl_host (SSLSTREAM *stream) { return tcp_host (stream->tcpstream); } /* SSL get remote host name * Accepts: SSL stream * Returns: host name for this stream */ char *ssl_remotehost (SSLSTREAM *stream) { return tcp_remotehost (stream->tcpstream); } /* SSL return port for this stream * Accepts: SSL stream * Returns: port number for this stream */ unsigned long ssl_port (SSLSTREAM *stream) { return tcp_port (stream->tcpstream); } /* SSL get local host name * Accepts: SSL stream * Returns: local host name */ char *ssl_localhost (SSLSTREAM *stream) { return tcp_localhost (stream->tcpstream); } #include "ssl_none.c" /* currently no server support */ alpine-2.10+dfsg/imap/src/osdep/nt/os_ntk.c0000600000175000017500000000252611512502123022251 0ustar paulproteuspaulproteus/* ======================================================================== * Copyright 1988-2006 University of Washington * * Licensed under the Apache License, Version 2.0 (the "License"); * you may not use this file except in compliance with the License. * You may obtain a copy of the License at * * http://www.apache.org/licenses/LICENSE-2.0 * * * ======================================================================== */ /* * Program: Operating-system dependent routines -- NT version + Kerberos * * Author: Mark Crispin * Networks and Distributed Computing * Computing & Communications * University of Washington * Administration Building, AG-44 * Seattle, WA 98195 * Internet: MRC@CAC.Washington.EDU * * Date: 11 April 1989 * Last Edited: 30 August 2006 */ #include "tcp_nt.h" /* must be before osdep includes tcp.h */ #undef ERROR /* quell conflicting def warning */ #include "mail.h" #include "osdep.h" #include #include #include #include #include #include #include "misc.h" #include "mailfile.h" #define GSS_C_NT_HOSTBASED_SERVICE gss_nt_service_name #include "fs_nt.c" #include "ftl_nt.c" #include "nl_nt.c" #include "yunchan.c" #include "kerb_mit.c" #include "tcp_nt.c" /* must be before env_nt.c */ #include "env_nt.c" #include "ssl_nt.c" alpine-2.10+dfsg/imap/src/osdep/nt/fdstring.c0000600000175000017500000000540711512502123022575 0ustar paulproteuspaulproteus/* ======================================================================== * Copyright 1988-2007 University of Washington * * Licensed under the Apache License, Version 2.0 (the "License"); * you may not use this file except in compliance with the License. * You may obtain a copy of the License at * * http://www.apache.org/licenses/LICENSE-2.0 * * * ======================================================================== */ /* * Program: File descriptor string routines * * Author: Mark Crispin * Networks and Distributed Computing * Computing & Communications * University of Washington * Administration Building, AG-44 * Seattle, WA 98195 * Internet: MRC@CAC.Washington.EDU * * Date: 15 April 1997 * Last Edited: 4 April 2007 */ #include "mail.h" #include "osdep.h" #include "misc.h" #include "fdstring.h" /* String driver for fd stringstructs */ static void fd_string_init (STRING *s,void *data,unsigned long size); static char fd_string_next (STRING *s); static void fd_string_setpos (STRING *s,unsigned long i); STRINGDRIVER fd_string = { fd_string_init, /* initialize string structure */ fd_string_next, /* get next byte in string structure */ fd_string_setpos /* set position in string structure */ }; /* Initialize string structure for fd stringstruct * Accepts: string structure * pointer to string * size of string */ static void fd_string_init (STRING *s,void *data,unsigned long size) { FDDATA *d = (FDDATA *) data; /* note fd */ s->data = (void *) (unsigned long) d->fd; s->data1 = d->pos; /* note file offset */ s->size = size; /* note size */ s->curpos = s->chunk = d->chunk; s->chunksize = (unsigned long) d->chunksize; s->offset = 0; /* initial position */ /* and size of data */ s->cursize = min (s->chunksize,size); /* move to that position in the file */ lseek (d->fd,d->pos,L_SET); read (d->fd,s->chunk,(size_t) s->cursize); } /* Get next character from fd stringstruct * Accepts: string structure * Returns: character, string structure chunk refreshed */ static char fd_string_next (STRING *s) { char c = *s->curpos++; /* get next byte */ SETPOS (s,GETPOS (s)); /* move to next chunk */ return c; /* return the byte */ } /* Set string pointer position for fd stringstruct * Accepts: string structure * new position */ static void fd_string_setpos (STRING *s,unsigned long i) { if (i > s->size) i = s->size; /* don't permit setting beyond EOF */ s->offset = i; /* set new offset */ s->curpos = s->chunk; /* reset position */ /* set size of data */ if (s->cursize = min (s->chunksize,SIZE (s))) { /* move to that position in the file */ lseek ((long) s->data,s->data1 + s->offset,L_SET); read ((long) s->data,s->curpos,(size_t) s->cursize); } } alpine-2.10+dfsg/imap/src/osdep/nt/kerb_w2k.c0000600000175000017500000005431611512502123022466 0ustar paulproteuspaulproteus/* ======================================================================== * Copyright 1988-2006 University of Washington * * Licensed under the Apache License, Version 2.0 (the "License"); * you may not use this file except in compliance with the License. * You may obtain a copy of the License at * * http://www.apache.org/licenses/LICENSE-2.0 * * * ======================================================================== */ /* * Program: GSSAPI Kerberos Shim 5 for Windows 2000/XP IMAP Toolkit * * Author: Mark Crispin * Networks and Distributed Computing * Computing & Communications * University of Washington * Administration Building, AG-44 * Seattle, WA 98195 * Internet: MRC@CAC.Washington.EDU * * Date: 6 March 2000 * Last Edited: 30 August 2006 */ /* The purpose of this module is to be a shim, so that the auth_gss.c module * (written for MIT Kerberos) will compile, link, and run with SSPI Kerberos * on Windows 2000 systems. * There is no attempt whatsoever to make this be a complete implementation * of GSSAPI. A number of shortcuts were taken that a real GSSAPI * implementation for SSPI can't do. * Nor is there any attempt to make the types identical with MIT Kerberos; * you can't link this library with object files compiled with the MIT * Kerberos .h files. */ /* GSSAPI generic definitions */ #define SECURITY_WIN32 #include /* GSSAPI types for which we use SSPI equivalent types */ typedef ULONG OM_uint32; typedef PCredHandle gss_cred_id_t; typedef ULONG gss_cred_usage_t; typedef PCtxtHandle gss_ctx_id_t; typedef SEC_CHAR * gss_name_t; typedef ULONG gss_qop_t; /* Major status codes */ #define GSS_S_COMPLETE SEC_E_OK #define GSS_S_BAD_MECH SEC_E_SECPKG_NOT_FOUND #define GSS_S_CONTINUE_NEEDED SEC_I_CONTINUE_NEEDED #define GSS_S_CREDENTIALS_EXPIRED SEC_E_CERT_EXPIRED #define GSS_S_FAILURE SEC_E_INTERNAL_ERROR #define GSS_S_NO_CRED SEC_E_NO_CREDENTIALS #define GSS_S_NO_CONTEXT SEC_E_INVALID_HANDLE /* Flag bits for context-level services */ #define GSS_C_DELEG_FLAG ISC_REQ_DELEGATE #define GSS_C_MUTUAL_FLAG ISC_REQ_MUTUAL_AUTH #define GSS_C_REPLAY_FLAG ISC_REQ_REPLAY_DETECT #define GSS_C_SEQUENCE_FLAG ISC_REQ_SEQUENCE_DETECT #define GSS_C_CONF_FLAG ISC_REQ_CONFIDENTIALITY #define GSS_C_INTEG_FLAG ISC_REQ_INTEGRITY /* Credential usage options */ #define GSS_C_BOTH SECPKG_CRED_BOTH #define GSS_C_INITIATE SECPKG_CRED_OUTBOUND #define GSS_C_ACCEPT SECPKG_CRED_INBOUND /* Major status codes defined by shim */ #define GSS_S_BAD_BINDINGS 100 #define GSS_S_BAD_NAME 101 #define GSS_S_BAD_NAMETYPE 102 #define GSS_S_BAD_STATUS 103 /* GSSAPI types as used in GSSAPI */ /* Buffer */ typedef struct gss_buffer_desc_struct { size_t length; void *value; } gss_buffer_desc,*gss_buffer_t; /* Object identifier */ typedef struct gss_OID_desc_struct { OM_uint32 length; void *elements; } gss_OID_desc,*gss_OID; typedef struct gss_OID_set_desc_struct { size_t count; gss_OID elements; } gss_OID_set_desc,*gss_OID_set; /* Unused, but needed in prototypes */ typedef void * gss_channel_bindings_t; /* Default constants */ #define GSS_C_EMPTY_BUFFER {0,NIL} #define GSS_C_NO_BUFFER ((gss_buffer_t) NIL) #define GSS_C_NO_OID ((gss_OID) NIL) #define GSS_C_NO_CONTEXT ((gss_ctx_id_t) NIL) #define GSS_C_NO_CREDENTIAL ((gss_cred_id_t) NIL) #define GSS_C_NO_CHANNEL_BINDINGS ((gss_channel_bindings_t) NIL) #define GSS_C_QOP_DEFAULT NIL /* Status code types for gss_display_status */ #define GSS_C_GSS_CODE 1 #define GSS_C_MECH_CODE 2 /* GSSAPI constants */ const gss_OID gss_nt_service_name; #define GSS_C_NT_HOSTBASED_SERVICE gss_nt_service_name const gss_OID gss_mech_krb5; const gss_OID_set gss_mech_set_krb5; /* GSSAPI prototypes */ OM_uint32 gss_accept_sec_context (OM_uint32 *minor_status, gss_ctx_id_t *context_handle, gss_cred_id_t acceptor_cred_handle, gss_buffer_t input_token_buffer, gss_channel_bindings_t input_chan_bindings, gss_name_t *src_name,gss_OID *mech_type, gss_buffer_t output_token, OM_uint32 *ret_flags,OM_uint32 *time_rec, gss_cred_id_t *delegated_cred_handle); OM_uint32 gss_acquire_cred (OM_uint32 *minor_status,gss_name_t desired_name, OM_uint32 time_req,gss_OID_set desired_mechs, gss_cred_usage_t cred_usage, gss_cred_id_t *output_cred_handle, gss_OID_set *actual_mechs,OM_uint32 *time_rec); OM_uint32 gss_delete_sec_context (OM_uint32 *minor_status, gss_ctx_id_t *context_handle, gss_buffer_t output_token); OM_uint32 gss_display_name (OM_uint32 *minor_status,gss_name_t input_name, gss_buffer_t output_name_buffer, gss_OID *output_name_type); OM_uint32 gss_display_status (OM_uint32 *minor_status,OM_uint32 status_value, int status_type,gss_OID mech_type, OM_uint32 *message_context, gss_buffer_t status_string); OM_uint32 gss_import_name (OM_uint32 *minor_status, gss_buffer_t input_name_buffer, gss_OID input_name_type,gss_name_t *output_name); OM_uint32 gss_init_sec_context (OM_uint32 *minor_status, gss_cred_id_t claimant_cred_handle, gss_ctx_id_t *context_handle, gss_name_t target_name,gss_OID mech_type, OM_uint32 req_flags,OM_uint32 time_req, gss_channel_bindings_t input_chan_bindings, gss_buffer_t input_token, gss_OID *actual_mech_type, gss_buffer_t output_token,OM_uint32 *ret_flags, OM_uint32 *time_rec); OM_uint32 gss_release_buffer (OM_uint32 *minor_status,gss_buffer_t buffer); OM_uint32 gss_release_cred (OM_uint32 *minor_status,gss_cred_id_t *cred_handle); OM_uint32 gss_release_name (OM_uint32 *minor_status,gss_name_t *input_name); OM_uint32 gss_wrap (OM_uint32 *minor_status,gss_ctx_id_t context_handle, int conf_req_flag,gss_qop_t qop_req, gss_buffer_t input_message_buffer,int *conf_state, gss_buffer_t output_message_buffer); OM_uint32 gss_unwrap (OM_uint32 *minor_status,gss_ctx_id_t context_handle, gss_buffer_t input_message_buffer, gss_buffer_t output_message_buffer,int *conf_state, gss_qop_t *qop_state); /* Kerberos definitions */ long kerberos_server_valid (void); long kerberos_try_kinit (OM_uint32 error); char *kerberos_login (char *user,char *authuser,int argc,char *argv[]); #define STRING WINSTRING /* conflict with mail.h */ #include /* GSSAPI build-in object identifiers */ static gss_OID_desc oids[] = { /* stupid C language makes this necessary */ {10,"\052\206\110\206\367\022\001\002\001\004"}, {9,"\052\206\110\206\367\022\001\002\002"} }; /* stupid C language ditto */ static gss_OID_set_desc oidsets[] = { {1,(gss_OID) oids+1} }; /* these are the real OIDs */ const gss_OID gss_nt_service_name = oids+0; const gss_OID gss_mech_krb5 = oids+1; const gss_OID_set gss_mech_set_krb5 = oidsets+0; /* Other globals */ /* substitute for GSS_C_NO_CREDENTIAL */ static gss_cred_id_t gss_default_cred = NIL; /* GSSAPI import name (convert to full service principal name) * Accepts: pointer to return minor status * buffer containining input name * type of input name * pointer to return output internal name * Returns: major status, always */ OM_uint32 gss_import_name (OM_uint32 *minor_status, gss_buffer_t input_name_buffer, gss_OID input_name_type,gss_name_t *output_name) { OM_uint32 major_status = GSS_S_COMPLETE; TimeStamp expiry; static CredHandle gss_cred; char *s,tmp[MAILTMPLEN]; *minor_status = 0; /* never any minor status */ if (!gss_default_cred) { /* default credentials set up yet? */ if (AcquireCredentialsHandle/* no, acquire them now */ (NIL,MICROSOFT_KERBEROS_NAME_A,SECPKG_CRED_OUTBOUND,NIL,NIL,NIL,NIL, &gss_cred,&expiry) != SEC_E_OK) return GSS_S_FAILURE; /* have default credentials now */ gss_default_cred = &gss_cred; } /* must be the gss_nt_service_name format */ if (input_name_type != gss_nt_service_name) major_status = GSS_S_BAD_NAMETYPE; /* name must be of sane length */ else if (input_name_buffer->length > (MAILTMPLEN/2)) major_status = GSS_S_BAD_NAME; else { /* copy name */ memcpy (tmp,input_name_buffer->value,input_name_buffer->length); tmp[input_name_buffer->length] = '\0'; if (s = strchr (tmp,'@')) { /* find service/host/delimiter */ *s = '/'; /* convert to full service principal name */ *output_name = cpystr (tmp); } else major_status = GSS_S_BAD_NAME; } return major_status; } /* GSSAPI Initialize security context * Accepts: pointer to return minor status * claimant credential handle * context (NIL means "none assigned yet") * desired principal * desired mechanisms * required context attributes * desired lifetime * input channel bindings * input token buffer * pointer to return mechanism type * buffer to return output token * pointer to return flags * pointer to return context lifetime * Returns: major status, always */ OM_uint32 gss_init_sec_context (OM_uint32 *minor_status, gss_cred_id_t claimant_cred_handle, gss_ctx_id_t *context_handle, gss_name_t target_name,gss_OID mech_type, OM_uint32 req_flags,OM_uint32 time_req, gss_channel_bindings_t input_chan_bindings, gss_buffer_t input_token, gss_OID *actual_mech_type, gss_buffer_t output_token,OM_uint32 *ret_flags, OM_uint32 *time_rec) { OM_uint32 i; OM_uint32 major_status; TimeStamp expiry; SecBuffer ibuf[1],obuf[1]; SecBufferDesc ibufs,obufs; *minor_status = 0; /* never any minor status */ /* error if non-default time requested */ if (time_req) return GSS_S_FAILURE; if (mech_type && memcmp (mech_type,gss_mech_krb5,sizeof (gss_OID))) return GSS_S_BAD_MECH; /* ditto if any channel bindings */ if (input_chan_bindings != GSS_C_NO_CHANNEL_BINDINGS) return GSS_S_BAD_BINDINGS; /* apply default credential if necessary */ if (claimant_cred_handle == GSS_C_NO_CREDENTIAL) claimant_cred_handle = gss_default_cred; /* create output buffer storage as needed */ req_flags |= ISC_REQ_ALLOCATE_MEMORY; /* make output buffer */ obuf[0].BufferType = SECBUFFER_TOKEN; obuf[0].cbBuffer = 0; obuf[0].pvBuffer = NIL; /* output buffer descriptor */ obufs.ulVersion = SECBUFFER_VERSION; obufs.cBuffers = 1; obufs.pBuffers = obuf; /* first time caller? */ if (*context_handle == GSS_C_NO_CONTEXT) { /* yes, set up output context handle */ PCtxtHandle ctx = (PCtxtHandle) fs_get (sizeof (CtxtHandle)); major_status = InitializeSecurityContext (claimant_cred_handle,NIL, target_name,req_flags,0, SECURITY_NETWORK_DREP,NIL,0,ctx, &obufs, ret_flags ? ret_flags : &i, &expiry); *context_handle = ctx; /* return updated context */ } else { /* no, make SSPI buffer from GSSAPI buffer */ ibuf[0].BufferType = obuf[0].BufferType = SECBUFFER_TOKEN; ibuf[0].cbBuffer = input_token->length; ibuf[0].pvBuffer = input_token->value; /* input buffer descriptor */ ibufs.ulVersion = SECBUFFER_VERSION; ibufs.cBuffers = 1; ibufs.pBuffers = ibuf; major_status = InitializeSecurityContext (claimant_cred_handle, *context_handle,target_name, req_flags,0, SECURITY_NETWORK_DREP,&ibufs,0, *context_handle,&obufs, ret_flags ? ret_flags : &i, &expiry); } /* return output */ output_token->value = obuf[0].pvBuffer; output_token->length = obuf[0].cbBuffer; /* in case client wanted lifetime returned */ if (time_rec) *time_rec = expiry.LowPart; return major_status; } /* GSSAPI display status text * Accepts: pointer to return minor status * status to display * status type * message context for continuation * buffer to write status string * Returns: major status, always */ OM_uint32 gss_display_status (OM_uint32 *minor_status,OM_uint32 status_value, int status_type,gss_OID mech_type, OM_uint32 *message_context, gss_buffer_t status_string) { char *s,tmp[MAILTMPLEN]; *minor_status = 0; /* never any minor status */ if (*message_context) return GSS_S_FAILURE; switch (status_type) { /* what type of status code? */ case GSS_C_GSS_CODE: /* major_status */ switch (status_value) { /* analyze status value */ case GSS_S_FAILURE: s = "Unspecified failure"; break; case GSS_S_CREDENTIALS_EXPIRED: s = "Credentials expired"; break; case GSS_S_BAD_BINDINGS: s = "Bad bindings"; break; case GSS_S_BAD_MECH: s = "Bad mechanism type"; break; case GSS_S_BAD_NAME: s = "Bad name"; break; case GSS_S_BAD_NAMETYPE: s = "Bad name type"; break; case GSS_S_BAD_STATUS: s = "Bad status"; break; case GSS_S_NO_CONTEXT: s = "Invalid context handle"; break; case GSS_S_NO_CRED: s = "Unable to authenticate to Kerberos service"; mail_parameters (NIL,DISABLE_AUTHENTICATOR,"GSSAPI"); break; case SEC_E_NO_AUTHENTICATING_AUTHORITY: s = "No authenticating authority"; break; case SEC_E_TARGET_UNKNOWN: s = "Destination server unknown to Kerberos service"; break; default: sprintf (s = tmp,"SSPI code %lx",status_value); } break; case GSS_C_MECH_CODE: /* minor status - drop into default */ default: return GSS_S_BAD_STATUS; /* bad status type */ } /* return status string */ status_string->length = strlen (status_string->value = cpystr (s)); return GSS_S_COMPLETE; } /* GSSAPI delete security context * Accepts: pointer to return minor status * context to delete * output context token * Returns: major status, always */ OM_uint32 gss_delete_sec_context (OM_uint32 *minor_status, gss_ctx_id_t *context_handle, gss_buffer_t output_token) { OM_uint32 major_status; *minor_status = 0; /* never any minor status */ /* output token not supported */ major_status = output_token ? GSS_S_FAILURE : DeleteSecurityContext (*context_handle); fs_give ((void **) context_handle); return major_status; } /* GSSAPI release buffer * Accepts: pointer to return minor status * buffer to release * Returns: GSS_S_COMPLETE, always */ OM_uint32 gss_release_buffer (OM_uint32 *minor_status,gss_buffer_t buffer) { *minor_status = 0; /* never any minor status */ fs_give (&buffer->value); return GSS_S_COMPLETE; } /* GSSAPI release name * Accepts: pointer to return minor status * pointer to name to release * Returns: GSS_S_COMPLETE, always */ OM_uint32 gss_release_name (OM_uint32 *minor_status,gss_name_t *input_name) { *minor_status = 0; /* never any minor status */ fs_give (input_name); return GSS_S_COMPLETE; } /* GSSAPI wrap data * Accepts: pointer to return minor status * context handle * requested confidentiality * requested quality of protection * input message buffer * pointer to return confidentiality state * output message buffer * Returns: major status, always */ OM_uint32 gss_wrap (OM_uint32 *minor_status,gss_ctx_id_t context_handle, int conf_req_flag,gss_qop_t qop_req, gss_buffer_t input_message_buffer,int *conf_state, gss_buffer_t output_message_buffer) { OM_uint32 major_status; SecBuffer buf[3]; SecBufferDesc bufs; SecPkgContext_Sizes sizes; *minor_status = NIL; /* never any minor status */ *conf_state = conf_req_flag; /* same as requested */ if ((major_status = /* get trailer and padding sizes */ QueryContextAttributes (context_handle,SECPKG_ATTR_SIZES,&sizes)) == SEC_E_OK) { /* create big enough output buffer */ output_message_buffer->value = fs_get (sizes.cbSecurityTrailer + input_message_buffer->length + sizes.cbBlockSize); /* MSDN claims that for EncryptMessage() in Kerberos, you need an * uninitialized SECBUFFER_STREAM_HEADER; a SECBUFFER_DATA that "contains * the message to be encrypted. The message is encrypted in place, * overwriting the original contents of its buffer"; an uninitialized * SECBUFFER_STREAM_TRAILER, and an uninitialized SECBUFFER_EMPTY. I've * never been able to get it to work that way. */ bufs.cBuffers = 3; /* set up buffer descriptor */ bufs.pBuffers = buf; bufs.ulVersion = SECBUFFER_VERSION; buf[0].BufferType = SECBUFFER_TOKEN; buf[0].pvBuffer = output_message_buffer->value; buf[0].cbBuffer = sizes.cbSecurityTrailer; /* I/O buffer */ buf[1].BufferType = SECBUFFER_DATA; buf[1].pvBuffer = ((char *) buf[0].pvBuffer) + buf[0].cbBuffer; buf[1].cbBuffer = input_message_buffer->length; memcpy (buf[1].pvBuffer,input_message_buffer->value,buf[1].cbBuffer); buf[2].BufferType = SECBUFFER_PADDING; buf[2].pvBuffer = ((char *) buf[1].pvBuffer) + buf[1].cbBuffer; buf[2].cbBuffer = sizes.cbBlockSize; if ((major_status = EncryptMessage (context_handle,qop_req,&bufs,0)) == GSS_S_COMPLETE) { /* slide data as necessary (how annoying!) */ unsigned long i = sizes.cbSecurityTrailer - buf[0].cbBuffer; if (i) buf[1].pvBuffer = memmove (((char *) buf[0].pvBuffer) + buf[0].cbBuffer, buf[1].pvBuffer,buf[1].cbBuffer); if (i += (input_message_buffer->length - buf[1].cbBuffer)) buf[1].pvBuffer = memmove (((char *)buf[1].pvBuffer) + buf[1].cbBuffer, buf[2].pvBuffer,buf[2].cbBuffer); output_message_buffer->length = buf[0].cbBuffer + buf[1].cbBuffer + buf[2].cbBuffer; } else fs_give (&output_message_buffer->value); } return major_status; /* return status */ } /* GSSAPI unwrap data * Accepts: pointer to return minor status * context handle * input message buffer * output message buffer * pointer to return confidentiality state * pointer to return quality of protection * Returns: major status, always */ OM_uint32 gss_unwrap (OM_uint32 *minor_status,gss_ctx_id_t context_handle, gss_buffer_t input_message_buffer, gss_buffer_t output_message_buffer,int *conf_state, gss_qop_t *qop_state) { OM_uint32 major_status; SecBuffer buf[2]; SecBufferDesc bufs; *minor_status = NIL; /* never any minor status */ *conf_state = NIL; /* or confidentiality state */ /* MSDN implies that all that is needed for DecryptMessage() in Kerberos * is a single SECBUFFER_DATA which "contains the encrypted message. The * encrypted message is decrypted in place, overwriting the original * contents of its buffer." I've never been able to get it to work without * using a SECBUFFER_STREAM for input and an uninitialized SECBUFFER_DATA * for output. * It *does* overwrite the input buffer, but not at the same point; e.g. * with an input pointer of 0xa140a8 and size of 53, the output ends up * at 0xa140d5 and size of 4. */ bufs.cBuffers = 2; /* set up buffer descriptor */ bufs.pBuffers = buf; bufs.ulVersion = SECBUFFER_VERSION; /* input buffer */ buf[0].BufferType = SECBUFFER_STREAM; buf[0].pvBuffer = input_message_buffer->value; buf[0].cbBuffer = input_message_buffer->length; /* output buffer */ buf[1].BufferType = SECBUFFER_DATA; buf[1].pvBuffer = NIL; buf[1].cbBuffer = 0; /* decrypt and copy to output buffer */ if ((major_status = DecryptMessage (context_handle,&bufs,0,qop_state)) == SEC_E_OK) memcpy (output_message_buffer->value = fs_get (buf[1].cbBuffer), buf[1].pvBuffer,output_message_buffer->length = buf[1].cbBuffer); return major_status; /* return status */ } /* From here on are server-only functions, currently unused */ /* GSSAPI acquire credentials * Accepts: pointer to return minor status * desired principal * desired lifetime * desired mechanisms * credentials usage * pointer to return credentials handle * pointer to return mechanisms * pointer to return lifetime * Returns: GSS_S_FAILURE, always */ OM_uint32 gss_acquire_cred (OM_uint32 *minor_status,gss_name_t desired_name, OM_uint32 time_req,gss_OID_set desired_mechs, gss_cred_usage_t cred_usage, gss_cred_id_t *output_cred_handle, gss_OID_set *actual_mechs,OM_uint32 *time_rec) { *minor_status = 0; /* never any minor status */ return GSS_S_FAILURE; /* server only */ } /* GSSAPI release credentials * Accepts: pointer to return minor status * credentials handle to free * Returns: GSS_S_COMPLETE, always */ OM_uint32 gss_release_cred (OM_uint32 *minor_status,gss_cred_id_t *cred_handle) { *minor_status = 0; /* never any minor status */ return GSS_S_FAILURE; /* server only */ } /* GSSAPI Accept security context * Accepts: pointer to return minor status * context * acceptor credentials * input token buffer * input channel bindings * pointer to return source name * pointer to return mechanism type * buffer to return output token * pointer to return flags * pointer to return context lifetime * pointer to return delegated credentials * Returns: GSS_S_FAILURE, always */ OM_uint32 gss_accept_sec_context (OM_uint32 *minor_status, gss_ctx_id_t *context_handle, gss_cred_id_t acceptor_cred_handle, gss_buffer_t input_token_buffer, gss_channel_bindings_t input_chan_bindings, gss_name_t *src_name,gss_OID *mech_type, gss_buffer_t output_token, OM_uint32 *ret_flags,OM_uint32 *time_rec, gss_cred_id_t *delegated_cred_handle) { *minor_status = 0; /* never any minor status */ return GSS_S_FAILURE; /* server only */ } /* GSSAPI return printable name * Accepts: pointer to return minor status * internal name * buffer to return output name * output name type * Returns: GSS_S_FAILURE, always */ OM_uint32 gss_display_name (OM_uint32 *minor_status,gss_name_t input_name, gss_buffer_t output_name_buffer, gss_OID *output_name_type) { *minor_status = 0; /* never any minor status */ return GSS_S_FAILURE; /* server only */ } /* Kerberos server valid check * Returns: T if have keytab, NIL otherwise */ long kerberos_server_valid () { return NIL; } /* Kerberos check for missing or expired credentials * Returns: T if should suggest running kinit, NIL otherwise */ long kerberos_try_kinit (OM_uint32 error) { return NIL; } /* Kerberos server log in * Accepts: authorization ID as user name * authentication ID as Kerberos principal * argument count * argument vector * Returns: logged in user name if logged in, NIL otherwise */ char *kerberos_login (char *user,char *authuser,int argc,char *argv[]) { return NIL; } alpine-2.10+dfsg/imap/src/osdep/nt/fs_nt.c0000600000175000017500000000260011512502123022056 0ustar paulproteuspaulproteus/* ======================================================================== * Copyright 1988-2006 University of Washington * * Licensed under the Apache License, Version 2.0 (the "License"); * you may not use this file except in compliance with the License. * You may obtain a copy of the License at * * http://www.apache.org/licenses/LICENSE-2.0 * * * ======================================================================== */ /* * Program: Free storage management routines * * Author: Mark Crispin * Networks and Distributed Computing * Computing & Communications * University of Washington * Administration Building, AG-44 * Seattle, WA 98195 * Internet: MRC@CAC.Washington.EDU * * Date: 1 August 1988 * Last Edited: 30 August 2006 */ /* Get a block of free storage * Accepts: size of desired block * Returns: free storage block */ void *fs_get (size_t size) { void *block = malloc (size ? size : (size_t) 1); if (!block) fatal ("Out of memory"); return (block); } /* Resize a block of free storage * Accepts: ** pointer to current block * new size */ void fs_resize (void **block,size_t size) { if (!(*block = realloc (*block,size ? size : (size_t) 1))) fatal ("Can't resize memory"); } /* Return a block of free storage * Accepts: ** pointer to free storage block */ void fs_give (void **block) { free (*block); *block = NIL; } alpine-2.10+dfsg/imap/src/osdep/nt/os_nt.h0000600000175000017500000000274211512502123022103 0ustar paulproteuspaulproteus/* ======================================================================== * Copyright 1988-2007 University of Washington * * Licensed under the Apache License, Version 2.0 (the "License"); * you may not use this file except in compliance with the License. * You may obtain a copy of the License at * * http://www.apache.org/licenses/LICENSE-2.0 * * * ======================================================================== */ /* * Program: Operating-system dependent routines -- NT version * * Author: Mark Crispin * Networks and Distributed Computing * Computing & Communications * University of Washington * Administration Building, AG-44 * Seattle, WA 98195 * Internet: MRC@CAC.Washington.EDU * * Date: 11 May 1989 * Last Edited: 27 April 2007 */ #include #include #include #include #include #include #include #include #undef ERROR /* quell conflicting defintion warning */ #include #include #undef ERROR #define ERROR (long) 2 /* must match mail.h */ #if _MSC_VER >= 1400 #define strtok_r strtok_s /* for some reason they called it this */ #else /* strtok() is actually MT-safe in MSVC. Why is it that Microsoft can do * their CRT right, but GNU, Sun, etc. can't? */ #define strtok_r(a,b,c) strtok(*(c) = a,b) #endif #include "env_nt.h" #include "fs.h" #include "ftl.h" #include "nl.h" #include "tcp.h" #include "yunchan.h" #undef noErr #undef MAC alpine-2.10+dfsg/imap/src/osdep/nt/ssl_w2k.c0000600000175000017500000005313211512502123022337 0ustar paulproteuspaulproteus/* ======================================================================== * Copyright 1988-2008 University of Washington * * Licensed under the Apache License, Version 2.0 (the "License"); * you may not use this file except in compliance with the License. * You may obtain a copy of the License at * * http://www.apache.org/licenses/LICENSE-2.0 * * * ======================================================================== */ /* * Program: SSL authentication/encryption module for Windows 2000 * * Author: Mark Crispin * Networks and Distributed Computing * Computing & Communications * University of Washington * Administration Building, AG-44 * Seattle, WA 98195 * Internet: MRC@CAC.Washington.EDU * * Date: 22 September 1998 * Last Edited: 13 January 2008 */ #define SECURITY_WIN32 #include #include #define SSLBUFLEN 8192 /* SSL I/O stream */ typedef struct ssl_stream { TCPSTREAM *tcpstream; /* TCP stream */ CredHandle cred; /* SSL credentials */ CtxtHandle context; /* SSL context */ /* stream encryption sizes */ SecPkgContext_StreamSizes sizes; size_t bufsize; int ictr; /* input counter */ char *iptr; /* input pointer */ int iextractr; /* extra input counter */ char *iextraptr; /* extra input pointer */ char *ibuf; /* input buffer */ char *obuf; /* output buffer */ } SSLSTREAM; #include "sslio.h" /* Function prototypes */ static SSLSTREAM *ssl_start(TCPSTREAM *tstream,char *host,unsigned long flags); static char *ssl_analyze_status (SECURITY_STATUS err,char *buf); static char *ssl_getline_work (SSLSTREAM *stream,unsigned long *size, long *contd); static long ssl_abort (SSLSTREAM *stream); /* Secure Sockets Layer network driver dispatch */ static struct ssl_driver ssldriver = { ssl_open, /* open connection */ ssl_aopen, /* open preauthenticated connection */ ssl_getline, /* get a line */ ssl_getbuffer, /* get a buffer */ ssl_soutr, /* output pushed data */ ssl_sout, /* output string */ ssl_close, /* close connection */ ssl_host, /* return host name */ ssl_remotehost, /* return remote host name */ ssl_port, /* return port number */ ssl_localhost /* return local host name */ }; static unsigned long ssltsz = 0;/* SSL maximum token length */ /* One-time SSL initialization */ static int sslonceonly = 0; void ssl_onceonlyinit (void) { if (!sslonceonly++) { /* only need to call it once */ ULONG np; SecPkgInfo *pp; int i; /* get security library */ if (!EnumerateSecurityPackages (&np,&pp)) { /* look for an SSL package */ for (i = 0; (i < (int) np); i++) if (!strcmp (pp[i].Name,UNISP_NAME)) { /* note maximum token size and name */ ssltsz = pp[i].cbMaxToken; /* apply runtime linkage */ mail_parameters (NIL,SET_SSLDRIVER,(void *) &ssldriver); mail_parameters (NIL,SET_SSLSTART,(void *) ssl_start); return; /* all done */ } } } } /* SSL open * Accepts: host name * contact service name * contact port number * Returns: SSL stream if success else NIL */ SSLSTREAM *ssl_open (char *host,char *service,unsigned long port) { TCPSTREAM *stream = tcp_open (host,service,port); return stream ? ssl_start (stream,host,port) : NIL; } /* SSL authenticated open * Accepts: host name * service name * returned user name buffer * Returns: SSL stream if success else NIL */ SSLSTREAM *ssl_aopen (NETMBX *mb,char *service,char *usrbuf) { return NIL; /* don't use this mechanism with SSL */ } /* Start SSL/TLS negotiations * Accepts: open TCP stream of session * user's host name * flags * Returns: SSL stream if success else NIL */ static SSLSTREAM *ssl_start (TCPSTREAM *tstream,char *host,unsigned long flags) { SECURITY_STATUS e; ULONG a; TimeStamp t; SecBuffer ibuf[2],obuf[1]; SecBufferDesc ibufs,obufs; SCHANNEL_CRED tlscred; CERT_CONTEXT *cert = NIL; CERT_CHAIN_PARA chparam; CERT_CHAIN_CONTEXT *chain; SSL_EXTRA_CERT_CHAIN_POLICY_PARA policy; CERT_CHAIN_POLICY_PARA polparam; CERT_CHAIN_POLICY_STATUS status; char tmp[MAILTMPLEN],certname[256]; char *reason = NIL; ULONG req = ISC_REQ_REPLAY_DETECT | ISC_REQ_SEQUENCE_DETECT | ISC_REQ_CONFIDENTIALITY | ISC_REQ_USE_SESSION_KEY | ISC_REQ_ALLOCATE_MEMORY | ISC_REQ_STREAM | ISC_REQ_EXTENDED_ERROR | ISC_REQ_MANUAL_CRED_VALIDATION; LPSTR usage[] = { szOID_PKIX_KP_SERVER_AUTH, szOID_SERVER_GATED_CRYPTO, szOID_SGC_NETSCAPE }; PWSTR whost = NIL; char *buf = (char *) fs_get (ssltsz); unsigned long size = 0; sslcertificatequery_t scq = (sslcertificatequery_t) mail_parameters (NIL,GET_SSLCERTIFICATEQUERY,NIL); sslfailure_t sf = (sslfailure_t) mail_parameters (NIL,GET_SSLFAILURE,NIL); SSLSTREAM *stream = (SSLSTREAM *) memset (fs_get (sizeof (SSLSTREAM)),0, sizeof (SSLSTREAM)); stream->tcpstream = tstream; /* bind TCP stream */ /* initialize TLS credential */ memset (&tlscred,0,sizeof (SCHANNEL_CRED)); tlscred.dwVersion = SCHANNEL_CRED_VERSION; tlscred.grbitEnabledProtocols = SP_PROT_TLS1; /* acquire credentials */ if (AcquireCredentialsHandle (NIL,UNISP_NAME,SECPKG_CRED_OUTBOUND,NIL,(flags & NET_TLSCLIENT) ? &tlscred : NIL,NIL,NIL,&stream->cred,&t) != SEC_E_OK) reason = "Acquire credentials handle failed"; else while (!reason) { /* negotiate security context */ /* initialize buffers */ ibuf[0].cbBuffer = size; ibuf[0].pvBuffer = buf; ibuf[1].cbBuffer = 0; ibuf[1].pvBuffer = NIL; obuf[0].cbBuffer = 0; obuf[0].pvBuffer = NIL; ibuf[0].BufferType = obuf[0].BufferType = SECBUFFER_TOKEN; ibuf[1].BufferType = SECBUFFER_EMPTY; /* initialize buffer descriptors */ ibufs.ulVersion = obufs.ulVersion = SECBUFFER_VERSION; ibufs.cBuffers = 2; obufs.cBuffers = 1; ibufs.pBuffers = ibuf; obufs.pBuffers = obuf; /* negotiate security */ e = InitializeSecurityContext (&stream->cred,size ? &stream->context : NIL,host,req,0, SECURITY_NETWORK_DREP,size? &ibufs:NIL,0,&stream->context,&obufs,&a,&t); /* have an output buffer we need to send? */ if (obuf[0].pvBuffer && obuf[0].cbBuffer) { if (!tcp_sout (stream->tcpstream,obuf[0].pvBuffer,obuf[0].cbBuffer)) reason = "Unexpected TCP output disconnect"; /* free the buffer */ FreeContextBuffer (obuf[0].pvBuffer); } if (!reason) switch (e) { /* negotiation state */ case SEC_I_INCOMPLETE_CREDENTIALS: break; /* server wants client auth */ case SEC_I_CONTINUE_NEEDED: if (size) { /* continue, read any data? */ /* yes, anything regurgiated back to us? */ if (ibuf[1].BufferType == SECBUFFER_EXTRA) { /* yes, set this as the new data */ memmove (buf,buf + size - ibuf[1].cbBuffer,ibuf[1].cbBuffer); size = ibuf[1].cbBuffer; break; } size = 0; /* otherwise, read more stuff from server */ } case SEC_E_INCOMPLETE_MESSAGE: /* need to read more data from server */ if (!tcp_getdata (stream->tcpstream)) reason = "Unexpected TCP input disconnect"; else { memcpy (buf+size,stream->tcpstream->iptr,stream->tcpstream->ictr); size += stream->tcpstream->ictr; /* empty it from TCP's buffers */ stream->tcpstream->iptr += stream->tcpstream->ictr; stream->tcpstream->ictr = 0; } break; case SEC_E_OK: /* success, any data to be regurgitated? */ if (ibuf[1].BufferType == SECBUFFER_EXTRA) { /* yes, set this as the new data */ memmove (stream->tcpstream->iptr = stream->tcpstream->ibuf, buf + size - ibuf[1].cbBuffer,ibuf[1].cbBuffer); stream->tcpstream->ictr = ibuf[1].cbBuffer; } if (!(flags & NET_NOVALIDATECERT)) { /* need validation, make wchar of host */ if (!((size = MultiByteToWideChar (CP_ACP,0,host,-1,NIL,0)) && (whost = (PWSTR) fs_get (size*sizeof (WCHAR))) && MultiByteToWideChar (CP_ACP,0,host,-1,whost,size))) fatal ("Can't make wchar of host name!"); /* get certificate */ if ((QueryContextAttributes (&stream->context,SECPKG_ATTR_REMOTE_CERT_CONTEXT,&cert) != SEC_E_OK) || !cert) { reason = "*Unable to get certificate"; strcpy (certname,""); } else { /* get certificate subject name */ CertNameToStr (X509_ASN_ENCODING | PKCS_7_ASN_ENCODING, &cert->pCertInfo->Subject,CERT_X500_NAME_STR, certname,255); /* build certificate chain */ memset (&chparam,0,sizeof (chparam)); chparam.cbSize = sizeof (chparam); chparam.RequestedUsage.dwType = USAGE_MATCH_TYPE_OR; chparam.RequestedUsage.Usage.rgpszUsageIdentifier = usage; chparam.RequestedUsage.Usage.cUsageIdentifier = sizeof (usage) / sizeof (LPSTR); if (!CertGetCertificateChain (NIL,cert,NIL,cert->hCertStore,&chparam,NIL,NIL,&chain)) reason = ssl_analyze_status (GetLastError (),tmp); else { /* validate certificate chain */ memset (&policy,0,sizeof (SSL_EXTRA_CERT_CHAIN_POLICY_PARA)); policy.cbStruct = sizeof (SSL_EXTRA_CERT_CHAIN_POLICY_PARA); policy.dwAuthType = AUTHTYPE_SERVER; policy.fdwChecks = NIL; policy.pwszServerName = whost; memset (&polparam,0,sizeof (polparam)); polparam.cbSize = sizeof (polparam); polparam.pvExtraPolicyPara = &policy; memset (&status,0,sizeof (status)); status.cbSize = sizeof (status); if (!CertVerifyCertificateChainPolicy (CERT_CHAIN_POLICY_SSL,chain,&polparam,&status)) reason = ssl_analyze_status (GetLastError (),tmp); else if (status.dwError) reason = ssl_analyze_status (status.dwError,tmp); CertFreeCertificateChain (chain); } CertFreeCertificateContext (cert); } if (whost) fs_give ((void **) &whost); if (reason) { /* got an error? */ /* application callback */ if (scq) reason = (*scq) ((*reason == '*') ? reason + 1 : reason, host,certname) ? NIL : ""; else if (*certname) { /* error message to return via mm_log() */ sprintf (buf,"*%.128s: %.255s", (*reason == '*') ? reason + 1 : reason,certname); reason = buf; } } } if (reason || (reason = ssl_analyze_status (QueryContextAttributes (&stream->context,SECPKG_ATTR_STREAM_SIZES,&stream->sizes),buf))) break; /* error in certificate or getting sizes */ fs_give ((void **) &buf); /* flush temporary buffer */ /* make maximum-sized buffers */ stream->bufsize = stream->sizes.cbHeader + stream->sizes.cbMaximumMessage + stream->sizes.cbTrailer; if (stream->sizes.cbMaximumMessage < SSLBUFLEN) fatal ("cbMaximumMessage is less than SSLBUFLEN!"); else if (stream->sizes.cbMaximumMessage < 16384) { sprintf (tmp,"WINDOWS BUG: cbMaximumMessage = %ld, should be 16384", (long) stream->sizes.cbMaximumMessage); mm_log (tmp,NIL); } stream->ibuf = (char *) fs_get (stream->bufsize); stream->obuf = (char *) fs_get (stream->bufsize); return stream; default: reason = ssl_analyze_status (e,buf); } } ssl_close (stream); /* failed to do SSL */ stream = NIL; /* no stream returned */ switch (*reason) { /* analyze reason */ case '*': /* certificate failure */ ++reason; /* skip over certificate failure indication */ /* pass to error callback */ if (sf) (*sf) (host,reason,flags); else { /* no error callback, build error message */ sprintf (tmp,"Certificate failure for %.80s: %.512s",host,reason); mm_log (tmp,ERROR); } case '\0': /* user answered no to certificate callback */ if (flags & NET_TRYSSL) /* return dummy stream to stop tryssl */ stream = (SSLSTREAM *) memset (fs_get (sizeof (SSLSTREAM)),0, sizeof (SSLSTREAM)); break; default: /* non-certificate failure */ if (flags & NET_TRYSSL); /* no error output if tryssl */ /* pass to error callback */ else if (sf) (*sf) (host,reason,flags); else { /* no error callback, build error message */ sprintf (tmp,"TLS/SSL failure for %.80s: %.512s",host,reason); mm_log (tmp,ERROR); } break; } fs_give ((void **) &buf); /* flush temporary buffer */ return stream; } /* Generate error text from SSL error code * Accepts: SSL status * scratch buffer * Returns: text if error status, else NIL */ static char *ssl_analyze_status (SECURITY_STATUS err,char *buf) { switch (err) { case SEC_E_OK: /* no error */ case SEC_I_CONTINUE_NEEDED: case SEC_I_INCOMPLETE_CREDENTIALS: case SEC_E_INCOMPLETE_MESSAGE: return NIL; case SEC_E_NO_AUTHENTICATING_AUTHORITY: mm_log ("unexpected SEC_E_NO_AUTHENTICATING_AUTHORITY",NIL); return "*No authority could be contacted for authentication"; case SEC_E_WRONG_PRINCIPAL: mm_log ("unexpected SEC_E_WRONG_PRINCIPAL",NIL); case CERT_E_CN_NO_MATCH: return "*Server name does not match certificate"; case SEC_E_UNTRUSTED_ROOT: mm_log ("unexpected SEC_E_UNTRUSTED_ROOT",NIL); case CERT_E_UNTRUSTEDROOT: return "*Self-signed certificate or untrusted authority"; case SEC_E_CERT_EXPIRED: mm_log ("unexpected SEC_E_CERT_EXPIRED",NIL); case CERT_E_EXPIRED: return "*Certificate has expired"; case CERT_E_REVOKED: return "*Certificate revoked"; case SEC_E_INVALID_TOKEN: return "Invalid token, probably not an SSL server"; case SEC_E_UNSUPPORTED_FUNCTION: return "SSL not supported on this machine - upgrade your system software"; } sprintf (buf,"Unexpected SSPI or certificate error %lx - report this",err); return buf; } /* SSL receive line * Accepts: SSL stream * Returns: text line string or NIL if failure */ char *ssl_getline (SSLSTREAM *stream) { unsigned long n,contd; char *ret = ssl_getline_work (stream,&n,&contd); if (ret && contd) { /* got a line needing continuation? */ STRINGLIST *stl = mail_newstringlist (); STRINGLIST *stc = stl; do { /* collect additional lines */ stc->text.data = (unsigned char *) ret; stc->text.size = n; stc = stc->next = mail_newstringlist (); ret = ssl_getline_work (stream,&n,&contd); } while (ret && contd); if (ret) { /* stash final part of line on list */ stc->text.data = (unsigned char *) ret; stc->text.size = n; /* determine how large a buffer we need */ for (n = 0, stc = stl; stc; stc = stc->next) n += stc->text.size; ret = fs_get (n + 1); /* copy parts into buffer */ for (n = 0, stc = stl; stc; n += stc->text.size, stc = stc->next) memcpy (ret + n,stc->text.data,stc->text.size); ret[n] = '\0'; } mail_free_stringlist (&stl);/* either way, done with list */ } return ret; } /* SSL receive line or partial line * Accepts: SSL stream * pointer to return size * pointer to return continuation flag * Returns: text line string, size and continuation flag, or NIL if failure */ static char *ssl_getline_work (SSLSTREAM *stream,unsigned long *size, long *contd) { unsigned long n; char *s,*ret,c,d; *contd = NIL; /* assume no continuation */ /* make sure have data */ if (!ssl_getdata (stream)) return NIL; for (s = stream->iptr, n = 0, c = '\0'; stream->ictr--; n++, c = d) { d = *stream->iptr++; /* slurp another character */ if ((c == '\015') && (d == '\012')) { ret = (char *) fs_get (n--); memcpy (ret,s,*size = n); /* copy into a free storage string */ ret[n] = '\0'; /* tie off string with null */ return ret; } } /* copy partial string from buffer */ memcpy ((ret = (char *) fs_get (n)),s,*size = n); /* get more data from the net */ if (!ssl_getdata (stream)) fs_give ((void **) &ret); /* special case of newline broken by buffer */ else if ((c == '\015') && (*stream->iptr == '\012')) { stream->iptr++; /* eat the line feed */ stream->ictr--; ret[*size = --n] = '\0'; /* tie off string with null */ } else *contd = LONGT; /* continuation needed */ return ret; } /* SSL receive buffer * Accepts: SSL stream * size in bytes * buffer to read into * Returns: T if success, NIL otherwise */ long ssl_getbuffer (SSLSTREAM *stream,unsigned long size,char *buffer) { unsigned long n; while (size > 0) { /* until request satisfied */ if (!ssl_getdata (stream)) return NIL; n = min (size,stream->ictr);/* number of bytes to transfer */ /* do the copy */ memcpy (buffer,stream->iptr,n); buffer += n; /* update pointer */ stream->iptr += n; size -= n; /* update # of bytes to do */ stream->ictr -= n; } buffer[0] = '\0'; /* tie off string */ return T; } /* SSL receive data * Accepts: TCP/IP stream * Returns: T if success, NIL otherwise */ long ssl_getdata (SSLSTREAM *stream) { while (stream->ictr < 1) { /* decrypted buffer empty? */ SECURITY_STATUS status; SecBuffer buf[4]; SecBufferDesc msg; size_t i; size_t n = 0; /* initially no bytes to decrypt */ do { /* yes, make sure have data from TCP */ if (stream->iextractr) { /* have previous unread data? */ memcpy (stream->ibuf + n,stream->iextraptr,stream->iextractr); n += stream->iextractr; /* update number of bytes read */ stream->iextractr = 0; /* no more extra data */ } else { /* read from TCP */ if (!tcp_getdata (stream->tcpstream)) return ssl_abort (stream); /* maximum amount of data to copy */ if (!(i = min (stream->bufsize - n,stream->tcpstream->ictr))) fatal ("incomplete SecBuffer exceeds maximum buffer size"); /* do the copy */ memcpy (stream->ibuf + n,stream->tcpstream->iptr,i); stream->tcpstream->iptr += i; stream->tcpstream->ictr -= i; n += i; /* update number of bytes to decrypt */ } buf[0].cbBuffer = n; /* first SecBuffer gets data */ buf[0].pvBuffer = stream->ibuf; buf[0].BufferType = SECBUFFER_DATA; /* subsequent ones are for spares */ buf[1].BufferType = buf[2].BufferType = buf[3].BufferType = SECBUFFER_EMPTY; msg.ulVersion = SECBUFFER_VERSION; msg.cBuffers = 4; /* number of SecBuffers */ msg.pBuffers = buf; /* first SecBuffer */ } while ((status = DecryptMessage (&stream->context,&msg,0,NIL)) == SEC_E_INCOMPLETE_MESSAGE); switch (status) { case SEC_E_OK: /* won */ case SEC_I_RENEGOTIATE: /* won but lost it after this buffer */ /* hunt for a buffer */ for (i = 0; (i < 4) && (buf[i].BufferType != SECBUFFER_DATA) ; i++); if (i < 4) { /* found a buffer? */ /* yes, set up pointer and counter */ stream->iptr = buf[i].pvBuffer; stream->ictr = buf[i].cbBuffer; /* any unprocessed data? */ while (++i < 4) if (buf[i].BufferType == SECBUFFER_EXTRA) { /* yes, note for next time around */ stream->iextraptr = buf[i].pvBuffer; stream->iextractr = buf[i].cbBuffer; } } break; default: /* anything else means we've lost */ return ssl_abort (stream); } } return LONGT; } /* SSL send string as record * Accepts: SSL stream * string pointer * Returns: T if success else NIL */ long ssl_soutr (SSLSTREAM *stream,char *string) { return ssl_sout (stream,string,(unsigned long) strlen (string)); } /* SSL send string * Accepts: SSL stream * string pointer * byte count * Returns: T if success else NIL */ long ssl_sout (SSLSTREAM *stream,char *string,unsigned long size) { SecBuffer buf[4]; SecBufferDesc msg; char *s; size_t n; if (!stream->tcpstream) return NIL; /* until request satisfied */ for (s = stream->ibuf,n = 0; size;) { /* header */ buf[0].BufferType = SECBUFFER_STREAM_HEADER; memset (buf[0].pvBuffer = stream->obuf,0, buf[0].cbBuffer = stream->sizes.cbHeader); /* message (up to maximum size) */ buf[1].BufferType = SECBUFFER_DATA; memcpy (buf[1].pvBuffer = stream->obuf + stream->sizes.cbHeader,string, buf[1].cbBuffer = min (size,SSLBUFLEN)); /* trailer */ buf[2].BufferType = SECBUFFER_STREAM_TRAILER; memset (buf[2].pvBuffer = ((char *) buf[1].pvBuffer) + buf[1].cbBuffer,0, buf[2].cbBuffer = stream->sizes.cbTrailer); /* spare */ buf[3].BufferType = SECBUFFER_EMPTY; msg.ulVersion = SECBUFFER_VERSION; msg.cBuffers = 4; /* number of SecBuffers */ msg.pBuffers = buf; /* first SecBuffer */ string += buf[1].cbBuffer; size -= buf[1].cbBuffer; /* this many bytes processed */ /* encrypt and send message */ if ((EncryptMessage (&stream->context,0,&msg,NIL) != SEC_E_OK) || !tcp_sout (stream->tcpstream,stream->obuf, buf[0].cbBuffer + buf[1].cbBuffer + buf[2].cbBuffer)) return ssl_abort (stream);/* encryption or sending failed */ } return LONGT; } /* SSL close * Accepts: SSL stream */ void ssl_close (SSLSTREAM *stream) { ssl_abort (stream); /* nuke the stream */ fs_give ((void **) &stream); /* flush the stream */ } /* SSL abort stream * Accepts: SSL stream * Returns: NIL always */ static long ssl_abort (SSLSTREAM *stream) { if (stream->tcpstream) { /* close TCP stream */ DeleteSecurityContext (&stream->context); FreeCredentialHandle (&stream->cred); tcp_close (stream->tcpstream); stream->tcpstream = NIL; } if (stream->ibuf) fs_give ((void **) &stream->ibuf); if (stream->obuf) fs_give ((void **) &stream->obuf); return NIL; } /* SSL get host name * Accepts: SSL stream * Returns: host name for this stream */ char *ssl_host (SSLSTREAM *stream) { return tcp_host (stream->tcpstream); } /* SSL get remote host name * Accepts: SSL stream * Returns: host name for this stream */ char *ssl_remotehost (SSLSTREAM *stream) { return tcp_remotehost (stream->tcpstream); } /* SSL return port for this stream * Accepts: SSL stream * Returns: port number for this stream */ unsigned long ssl_port (SSLSTREAM *stream) { return tcp_port (stream->tcpstream); } /* SSL get local host name * Accepts: SSL stream * Returns: local host name */ char *ssl_localhost (SSLSTREAM *stream) { return tcp_localhost (stream->tcpstream); } #include "ssl_none.c" /* currently no server support */ alpine-2.10+dfsg/imap/src/osdep/nt/pmatch.c0000600000175000017500000000545411512502123022233 0ustar paulproteuspaulproteus/* ======================================================================== * Copyright 1988-2006 University of Washington * * Licensed under the Apache License, Version 2.0 (the "License"); * you may not use this file except in compliance with the License. * You may obtain a copy of the License at * * http://www.apache.org/licenses/LICENSE-2.0 * * * ======================================================================== */ /* * Program: IMAP Wildcard Matching Routines (case-independent) * * Author: Mark Crispin * Networks and Distributed Computing * Computing & Communications * University of Washington * Administration Building, AG-44 * Seattle, WA 98195 * Internet: MRC@CAC.Washington.EDU * * Date: 15 June 2000 * Last Edited: 30 August 2006 */ /* Wildcard pattern match * Accepts: base string * pattern string * delimiter character * Returns: T if pattern matches base, else NIL */ long pmatch_full (unsigned char *s,unsigned char *pat,unsigned char delim) { switch (*pat) { case '%': /* non-recursive */ /* % at end, OK if no inferiors */ if (!pat[1]) return (delim && strchr (s,delim)) ? NIL : T; /* scan remainder of string until delimiter */ do if (pmatch_full (s,pat+1,delim)) return T; while ((*s != delim) && *s++); break; case '*': /* match 0 or more characters */ if (!pat[1]) return T; /* * at end, unconditional match */ /* scan remainder of string */ do if (pmatch_full (s,pat+1,delim)) return T; while (*s++); break; case '\0': /* end of pattern */ return *s ? NIL : T; /* success if also end of base */ default: /* match this character */ return compare_uchar (*pat,*s) ? NIL : pmatch_full (s+1,pat+1,delim); } return NIL; } /* Directory pattern match * Accepts: base string * pattern string * delimiter character * Returns: T if base is a matching directory of pattern, else NIL */ long dmatch (unsigned char *s,unsigned char *pat,unsigned char delim) { switch (*pat) { case '%': /* non-recursive */ if (!*s) return T; /* end of base means have a subset match */ if (!*++pat) return NIL; /* % at end, no inferiors permitted */ /* scan remainder of string until delimiter */ do if (dmatch (s,pat,delim)) return T; while ((*s != delim) && *s++); if (*s && !s[1]) return T; /* ends with delimiter, must be subset */ return dmatch (s,pat,delim);/* do new scan */ case '*': /* match 0 or more characters */ return T; /* unconditional match */ case '\0': /* end of pattern */ break; default: /* match this character */ if (*s) return compare_uchar (*pat,*s) ? NIL : dmatch (s+1,pat+1,delim); /* end of base, return if at delimiter */ else if (*pat == delim) return T; break; } return NIL; } alpine-2.10+dfsg/imap/src/osdep/nt/mailfile.h0000600000175000017500000000144611512502123022543 0ustar paulproteuspaulproteus/* ======================================================================== * Copyright 1988-2006 University of Washington * * Licensed under the Apache License, Version 2.0 (the "License"); * you may not use this file except in compliance with the License. * You may obtain a copy of the License at * * http://www.apache.org/licenses/LICENSE-2.0 * * * ======================================================================== */ /* * Program: Mail Spool file name * * Author: Mark Crispin * Networks and Distributed Computing * Computing & Communications * University of Washington * Administration Building, AG-44 * Seattle, WA 98195 * Internet: MRC@CAC.Washington.EDU * * Date: 8 February 1996 * Last Edited: 30 August 2006 */ #define MAILFILE "C:\\WINSMTP\\%s.MBX" alpine-2.10+dfsg/imap/src/osdep/nt/makefile.nt0000600000175000017500000000653211512502123022731 0ustar paulproteuspaulproteus# ======================================================================== # Copyright 1988-2007 University of Washington # # Licensed under the Apache License, Version 2.0 (the "License"); # you may not use this file except in compliance with the License. # You may obtain a copy of the License at # # http://www.apache.org/licenses/LICENSE-2.0 # # # ======================================================================== # Program: Portable C client makefile -- NT version # # Author: Mark Crispin # Networks and Distributed Computing # Computing & Communications # University of Washington # Administration Building, AG-44 # Seattle, WA 98195 # Internet: MRC@CAC.Washington.EDU # # Date: 11 May 1989 # Last Edited: 23 May 2007 EXTRAAUTHENTICATORS = EXTRADRIVERS = EXTRACFLAGS = AUTHENTICATORS = ext md5 pla log DRIVERS = imap nntp pop3 mbx mtx tenex unix CREATEDRIVER = mbx APPENDDRIVER = unix OSCOMPAT = /DWIN32 /D_WIN32_WINNT=0x0400 VSCOMPAT = /D_CRT_SECURE_NO_DEPRECATE /D_CRT_NONSTDC_NO_DEPRECATE CFLAGS = /MT /W3 /Ox /DCHUNKSIZE=65536 $(OSCOMPAT) $(VSCOMPAT) -nologo /I.. $(EXTRACFLAGS) CC = cl CCLIENTLIB = cclient.lib all: $(CCLIENTLIB) .c.obj: $(CC) -c $(CFLAGS) $*.c osdep.h: os_nt.h copy os_nt.h osdep.h drivers $(EXTRADRIVERS) $(DRIVERS) dummy setproto $(CREATEDRIVER) $(APPENDDRIVER) echo ssl_onceonlyinit (); >> linkage.c mkauths $(EXTRAAUTHENTICATORS) $(AUTHENTICATORS) echo mail_versioncheck (CCLIENTVERSION); >> linkage.c ip_nt.c: ip4_nt.c copy ip4_nt.c ip_nt.c mail.obj: mail.h misc.h osdep.h mail.c misc.obj: mail.h misc.h misc.c fdstring.obj: mail.h misc.h osdep.h fdstring.h fdstring.c flstring.obj: mail.h misc.h osdep.h flstring.h flstring.c netmsg.obj: mail.h misc.h netmsg.h osdep.h netmsg.c newsrc.obj: mail.h misc.h newsrc.h osdep.h newsrc.c rfc822.obj: mail.h rfc822.h misc.h rfc822.c smanager.obj: mail.h misc.h smanager.c utf8.obj: mail.h misc.h osdep.h utf8.h utf8aux.obj: mail.h misc.h osdep.h utf8.h imap4r1.obj: mail.h imap4r1.h misc.h osdep.h imap4r1.c nntp.obj: mail.h nntp.h smtp.h rfc822.h misc.h osdep.h nntp.c pop3.obj: mail.h rfc822.h misc.h osdep.h pop3.c smtp.obj: mail.h smtp.h rfc822.h misc.h osdep.h smtp.c os_nt.obj: mail.h osdep.h env_nt.h fs.h ftl.h nl.h tcp.h tcp_nt.h yunchan.h \ os_nt.c fs_nt.c ftl_nt.c nl_nt.c env_nt.c ssl_nt.c ssl_none.c \ ip_nt.c tcp_nt.c yunchan.c pmatch.c write.c \ mailfile.h auth_md5.c auth_pla.c auth_log.c mbxnt.obj: mail.h misc.h osdep.h mbxnt.c mtxnt.obj: mail.h misc.h osdep.h mtxnt.c tenexnt.obj: mail.h misc.h osdep.h tenexnt.c unixnt.obj: mail.h unixnt.h pseudo.h misc.h osdep.h unixnt.c dummynt.obj: mail.h dummy.h misc.h osdep.h dummynt.c pseudo.obj: pseudo.h $(CCLIENTLIB): mail.obj misc.obj fdstring.obj flstring.obj netmsg.obj \ newsrc.obj rfc822.obj smanager.obj utf8.obj utf8aux.obj \ imap4r1.obj nntp.obj pop3.obj smtp.obj os_nt.obj \ mbxnt.obj mtxnt.obj tenexnt.obj unixnt.obj dummynt.obj pseudo.obj if exist $(CCLIENTLIB) del $(CCLIENTLIB) LIB /NOLOGO /OUT:cclient.lib \ mail.obj misc.obj fdstring.obj flstring.obj netmsg.obj \ newsrc.obj rfc822.obj smanager.obj utf8.obj utf8aux.obj \ imap4r1.obj nntp.obj pop3.obj smtp.obj os_nt.obj \ mbxnt.obj mtxnt.obj tenexnt.obj unixnt.obj dummynt.obj pseudo.obj clean: del *.lib *.obj linkage.* osdep.* ip_nt.c auths.c *.exe *.exp || rem # A monument to a hack of long ago and far away... love: @echo not war? alpine-2.10+dfsg/imap/src/osdep/nt/mtxnt.c0000600000175000017500000011753411512502123022134 0ustar paulproteuspaulproteus/* ======================================================================== * Copyright 1988-2007 University of Washington * * Licensed under the Apache License, Version 2.0 (the "License"); * you may not use this file except in compliance with the License. * You may obtain a copy of the License at * * http://www.apache.org/licenses/LICENSE-2.0 * * * ======================================================================== */ /* * Program: MTX mail routines * * Author: Mark Crispin * Networks and Distributed Computing * Computing & Communications * University of Washington * Administration Building, AG-44 * Seattle, WA 98195 * Internet: MRC@CAC.Washington.EDU * * Date: 22 May 1990 * Last Edited: 15 June 2007 */ /* FILE TIME SEMANTICS * * The atime is the last read time of the file. * The mtime is the last flags update time of the file. * The ctime is the last write time of the file. */ #include #include #include extern int errno; /* just in case */ #include "mail.h" #include "osdep.h" #include #include #include #include #include "misc.h" #include "dummy.h" #include "fdstring.h" /* MTX I/O stream local data */ typedef struct mtx_local { unsigned int shouldcheck: 1; /* if ping should do a check instead */ unsigned int mustcheck: 1; /* if ping must do a check instead */ int fd; /* file descriptor for I/O */ off_t filesize; /* file size parsed */ time_t filetime; /* last file time */ time_t lastsnarf; /* last snarf time */ unsigned char *buf; /* temporary buffer */ unsigned long buflen; /* current size of temporary buffer */ } MTXLOCAL; /* Convenient access to local data */ #define LOCAL ((MTXLOCAL *) stream->local) /* Function prototypes */ DRIVER *mtx_valid (char *name); int mtx_isvalid (char *name,char *file); void *mtx_parameters (long function,void *value); void mtx_scan (MAILSTREAM *stream,char *ref,char *pat,char *contents); void mtx_list (MAILSTREAM *stream,char *ref,char *pat); void mtx_lsub (MAILSTREAM *stream,char *ref,char *pat); long mtx_create (MAILSTREAM *stream,char *mailbox); long mtx_delete (MAILSTREAM *stream,char *mailbox); long mtx_rename (MAILSTREAM *stream,char *old,char *newname); long mtx_status (MAILSTREAM *stream,char *mbx,long flags); MAILSTREAM *mtx_open (MAILSTREAM *stream); void mtx_close (MAILSTREAM *stream,long options); void mtx_flags (MAILSTREAM *stream,char *sequence,long flags); char *mtx_header (MAILSTREAM *stream,unsigned long msgno, unsigned long *length,long flags); long mtx_text (MAILSTREAM *stream,unsigned long msgno,STRING *bs,long flags); void mtx_flag (MAILSTREAM *stream,char *sequence,char *flag,long flags); void mtx_flagmsg (MAILSTREAM *stream,MESSAGECACHE *elt); long mtx_ping (MAILSTREAM *stream); void mtx_check (MAILSTREAM *stream); void mtx_snarf (MAILSTREAM *stream); long mtx_expunge (MAILSTREAM *stream,char *sequence,long options); long mtx_copy (MAILSTREAM *stream,char *sequence,char *mailbox,long options); long mtx_append (MAILSTREAM *stream,char *mailbox,append_t af,void *data); long mtx_parse (MAILSTREAM *stream); MESSAGECACHE *mtx_elt (MAILSTREAM *stream,unsigned long msgno); void mtx_read_flags (MAILSTREAM *stream,MESSAGECACHE *elt); void mtx_update_status (MAILSTREAM *stream,unsigned long msgno,long syncflag); unsigned long mtx_hdrpos (MAILSTREAM *stream,unsigned long msgno, unsigned long *size); /* MTX mail routines */ /* Driver dispatch used by MAIL */ DRIVER mtxdriver = { "mtx", /* driver name */ /* driver flags */ DR_LOCAL|DR_MAIL|DR_CRLF|DR_NOSTICKY, (DRIVER *) NIL, /* next driver */ mtx_valid, /* mailbox is valid for us */ mtx_parameters, /* manipulate parameters */ mtx_scan, /* scan mailboxes */ mtx_list, /* list mailboxes */ mtx_lsub, /* list subscribed mailboxes */ NIL, /* subscribe to mailbox */ NIL, /* unsubscribe from mailbox */ mtx_create, /* create mailbox */ mtx_delete, /* delete mailbox */ mtx_rename, /* rename mailbox */ mail_status_default, /* status of mailbox */ mtx_open, /* open mailbox */ mtx_close, /* close mailbox */ mtx_flags, /* fetch message "fast" attributes */ mtx_flags, /* fetch message flags */ NIL, /* fetch overview */ NIL, /* fetch message envelopes */ mtx_header, /* fetch message header */ mtx_text, /* fetch message body */ NIL, /* fetch partial message text */ NIL, /* unique identifier */ NIL, /* message number */ mtx_flag, /* modify flags */ mtx_flagmsg, /* per-message modify flags */ NIL, /* search for message based on criteria */ NIL, /* sort messages */ NIL, /* thread messages */ mtx_ping, /* ping mailbox to see if still alive */ mtx_check, /* check for new messages */ mtx_expunge, /* expunge deleted messages */ mtx_copy, /* copy messages to another mailbox */ mtx_append, /* append string message to mailbox */ NIL /* garbage collect stream */ }; /* prototype stream */ MAILSTREAM mtxproto = {&mtxdriver}; /* MTX mail validate mailbox * Accepts: mailbox name * Returns: our driver if name is valid, NIL otherwise */ DRIVER *mtx_valid (char *name) { char tmp[MAILTMPLEN]; return mtx_isvalid (name,tmp) ? &mtxdriver : NIL; } /* MTX mail test for valid mailbox * Accepts: mailbox name * buffer to return file name * Returns: T if valid, NIL otherwise */ int mtx_isvalid (char *name,char *file) { int fd; int ret = NIL; char *s,tmp[MAILTMPLEN]; struct stat sbuf; struct utimbuf times; errno = EINVAL; /* assume invalid argument */ /* if file, get its status */ if ((s = dummy_file (file,name)) && !stat (s,&sbuf) && ((sbuf.st_mode & S_IFMT) == S_IFREG)) { if (!sbuf.st_size)errno = 0;/* empty file */ else if ((fd = open (file,O_BINARY|O_RDONLY,NIL)) >= 0) { memset (tmp,'\0',MAILTMPLEN); if ((read (fd,tmp,64) >= 0) && (s = strchr (tmp,'\015')) && (s[1] == '\012')) { /* valid format? */ *s = '\0'; /* tie off header */ /* must begin with dd-mmm-yy" */ ret = (((tmp[2] == '-' && tmp[6] == '-') || (tmp[1] == '-' && tmp[5] == '-')) && (s = strchr (tmp+18,',')) && strchr (s+2,';')) ? T : NIL; } else errno = -1; /* bogus format */ close (fd); /* close the file */ /* \Marked status? */ if (sbuf.st_ctime > sbuf.st_atime) { /* preserve atime and mtime */ times.actime = sbuf.st_atime; times.modtime = sbuf.st_mtime; utime (file,×); /* set the times */ } } } /* in case INBOX but not mtx format */ else if ((errno == ENOENT) && !compare_cstring (name,"INBOX")) errno = -1; return ret; /* return what we should */ } /* MTX manipulate driver parameters * Accepts: function code * function-dependent value * Returns: function-dependent return value */ void *mtx_parameters (long function,void *value) { return NIL; } /* MTX mail scan mailboxes * Accepts: mail stream * reference * pattern to search * string to scan */ void mtx_scan (MAILSTREAM *stream,char *ref,char *pat,char *contents) { if (stream) dummy_scan (NIL,ref,pat,contents); } /* MTX mail list mailboxes * Accepts: mail stream * reference * pattern to search */ void mtx_list (MAILSTREAM *stream,char *ref,char *pat) { if (stream) dummy_list (NIL,ref,pat); } /* MTX mail list subscribed mailboxes * Accepts: mail stream * reference * pattern to search */ void mtx_lsub (MAILSTREAM *stream,char *ref,char *pat) { if (stream) dummy_lsub (NIL,ref,pat); } /* MTX mail create mailbox * Accepts: MAIL stream * mailbox name to create * Returns: T on success, NIL on failure */ long mtx_create (MAILSTREAM *stream,char *mailbox) { char *s,mbx[MAILTMPLEN]; if (s = dummy_file (mbx,mailbox)) return dummy_create (stream,s); sprintf (mbx,"Can't create %.80s: invalid name",mailbox); mm_log (mbx,ERROR); return NIL; } /* MTX mail delete mailbox * Accepts: MAIL stream * mailbox name to delete * Returns: T on success, NIL on failure */ long mtx_delete (MAILSTREAM *stream,char *mailbox) { return mtx_rename (stream,mailbox,NIL); } /* MTX mail rename mailbox * Accepts: MAIL stream * old mailbox name * new mailbox name (or NIL for delete) * Returns: T on success, NIL on failure */ long mtx_rename (MAILSTREAM *stream,char *old,char *newname) { long ret = LONGT; char c,*s,tmp[MAILTMPLEN],file[MAILTMPLEN],lock[MAILTMPLEN]; int fd,ld; struct stat sbuf; if (!dummy_file (file,old) || (newname && (!((s = mailboxfile (tmp,newname)) && *s) || ((s = strrchr (tmp,'\\')) && !s[1])))) { sprintf (tmp,newname ? "Can't rename mailbox %.80s to %.80s: invalid name" : "Can't delete mailbox %.80s: invalid name", old,newname); mm_log (tmp,ERROR); return NIL; } if ((fd = open (file,O_BINARY|O_RDWR,NIL)) < 0) { sprintf (tmp,"Can't open mailbox %.80s: %s",old,strerror (errno)); mm_log (tmp,ERROR); return NIL; } /* get exclusive parse/append permission */ if ((ld = lockname (lock,file,LOCK_EX)) < 0) { mm_log ("Unable to lock rename mailbox",ERROR); return NIL; } /* lock out other users */ if (flock (fd,LOCK_EX|LOCK_NB)) { close (fd); /* couldn't lock, give up on it then */ sprintf (tmp,"Mailbox %.80s is in use by another process",old); mm_log (tmp,ERROR); unlockfd (ld,lock); /* release exclusive parse/append permission */ return NIL; } if (newname) { /* want rename? */ /* found superior to destination name? */ if ((s = strrchr (tmp,'\\')) && (s != tmp) && ((tmp[1] != ':') || (s != tmp + 2))) { c = s[1]; /* remember character after delimiter */ *s = s[1] = '\0'; /* tie off name at delimiter */ /* name doesn't exist, create it */ if (stat (tmp,&sbuf) || ((sbuf.st_mode & S_IFMT) != S_IFDIR)) { *s = '\\'; /* restore delimiter */ if (!dummy_create (stream,tmp)) ret = NIL; } else *s = '\\'; /* restore delimiter */ s[1] = c; /* restore character after delimiter */ } flock (fd,LOCK_UN); /* release lock on the file */ close (fd); /* pacify NTFS */ /* rename the file */ if (ret && rename (file,tmp)) { sprintf (tmp,"Can't rename mailbox %.80s to %.80s: %s",old,newname, strerror (errno)); mm_log (tmp,ERROR); ret = NIL; /* set failure */ } } else { flock (fd,LOCK_UN); /* release lock on the file */ close (fd); /* pacify NTFS */ if (unlink (file)) { sprintf (tmp,"Can't delete mailbox %.80s: %.80s",old,strerror (errno)); mm_log (tmp,ERROR); ret = NIL; /* set failure */ } } unlockfd (ld,lock); /* release exclusive parse/append permission */ return ret; /* return success */ } /* MTX mail open * Accepts: stream to open * Returns: stream on success, NIL on failure */ MAILSTREAM *mtx_open (MAILSTREAM *stream) { int fd,ld; char tmp[MAILTMPLEN]; /* return prototype for OP_PROTOTYPE call */ if (!stream) return &mtxproto; if (stream->local) fatal ("mtx recycle stream"); /* canonicalize the mailbox name */ if (!dummy_file (tmp,stream->mailbox)) { sprintf (tmp,"Can't open - invalid name: %.80s",stream->mailbox); mm_log (tmp,ERROR); } if (stream->rdonly || (fd = open (tmp,O_BINARY|O_RDWR,NIL)) < 0) { if ((fd = open (tmp,O_BINARY|O_RDONLY,NIL)) < 0) { sprintf (tmp,"Can't open mailbox: %.80s",strerror (errno)); mm_log (tmp,ERROR); return NIL; } else if (!stream->rdonly) { /* got it, but readonly */ mm_log ("Can't get write access to mailbox, access is readonly",WARN); stream->rdonly = T; } } stream->local = fs_get (sizeof (MTXLOCAL)); LOCAL->fd = fd; /* bind the file */ LOCAL->buf = (char *) fs_get (CHUNKSIZE); LOCAL->buflen = CHUNKSIZE - 1; /* note if an INBOX or not */ stream->inbox = !compare_cstring (stream->mailbox,"INBOX"); fs_give ((void **) &stream->mailbox); stream->mailbox = cpystr (tmp); /* get shared parse permission */ if ((ld = lockname (tmp,stream->mailbox,LOCK_SH)) < 0) { mm_log ("Unable to lock open mailbox",ERROR); return NIL; } flock (LOCAL->fd,LOCK_SH); /* lock the file */ unlockfd (ld,tmp); /* release shared parse permission */ LOCAL->filesize = 0; /* initialize parsed file size */ LOCAL->filetime = 0; /* time not set up yet */ LOCAL->mustcheck = LOCAL->shouldcheck = NIL; stream->sequence++; /* bump sequence number */ stream->uid_validity = (unsigned long) time (0); /* parse mailbox */ stream->nmsgs = stream->recent = 0; if (mtx_ping (stream) && !stream->nmsgs) mm_log ("Mailbox is empty",(long) NIL); if (!LOCAL) return NIL; /* failure if stream died */ stream->perm_seen = stream->perm_deleted = stream->perm_flagged = stream->perm_answered = stream->perm_draft = stream->rdonly ? NIL : T; stream->perm_user_flags = stream->rdonly ? NIL : 0xffffffff; return stream; /* return stream to caller */ } /* MTX mail close * Accepts: MAIL stream * close options */ void mtx_close (MAILSTREAM *stream,long options) { if (stream && LOCAL) { /* only if a file is open */ int silent = stream->silent; stream->silent = T; /* note this stream is dying */ if (options & CL_EXPUNGE) mtx_expunge (stream,NIL,NIL); stream->silent = silent; /* restore previous status */ flock (LOCAL->fd,LOCK_UN); /* unlock local file */ close (LOCAL->fd); /* close the local file */ /* free local text buffer */ if (LOCAL->buf) fs_give ((void **) &LOCAL->buf); /* nuke the local data */ fs_give ((void **) &stream->local); stream->dtb = NIL; /* log out the DTB */ } } /* MTX mail fetch flags * Accepts: MAIL stream * sequence * option flags * Sniffs at file to see if some other process changed the flags */ void mtx_flags (MAILSTREAM *stream,char *sequence,long flags) { unsigned long i; if (mtx_ping (stream) && /* ping mailbox, get new status for messages */ ((flags & FT_UID) ? mail_uid_sequence (stream,sequence) : mail_sequence (stream,sequence))) for (i = 1; i <= stream->nmsgs; i++) if (mail_elt (stream,i)->sequence) mtx_elt (stream,i); } /* MTX mail fetch message header * Accepts: MAIL stream * message # to fetch * pointer to returned header text length * option flags * Returns: message header in RFC822 format */ char *mtx_header (MAILSTREAM *stream,unsigned long msgno,unsigned long *length, long flags) { *length = 0; /* default to empty */ if (flags & FT_UID) return "";/* UID call "impossible" */ /* get to header position */ lseek (LOCAL->fd,mtx_hdrpos (stream,msgno,length),L_SET); /* is buffer big enough? */ if (*length > LOCAL->buflen) { fs_give ((void **) &LOCAL->buf); LOCAL->buf = (char *) fs_get ((LOCAL->buflen = *length) + 1); } LOCAL->buf[*length] = '\0'; /* tie off string */ /* slurp the data */ read (LOCAL->fd,LOCAL->buf,*length); return LOCAL->buf; } /* MTX mail fetch message text (body only) * Accepts: MAIL stream * message # to fetch * pointer to returned header text length * option flags * Returns: T, always */ long mtx_text (MAILSTREAM *stream,unsigned long msgno,STRING *bs,long flags) { FDDATA d; unsigned long i,j; MESSAGECACHE *elt; /* UID call "impossible" */ if (flags & FT_UID) return NIL; elt = mtx_elt (stream,msgno); /* get message status */ /* if message not seen */ if (!(flags & FT_PEEK) && !elt->seen) { elt->seen = T; /* mark message as seen */ /* recalculate status */ mtx_update_status (stream,msgno,NIL); mm_flags (stream,msgno); } /* find header position */ i = mtx_hdrpos (stream,msgno,&j); d.fd = LOCAL->fd; /* set up file descriptor */ d.pos = i + j; d.chunk = LOCAL->buf; /* initial buffer chunk */ d.chunksize = CHUNKSIZE; INIT (bs,fd_string,&d,elt->rfc822_size - j); return T; /* success */ } /* MTX mail modify flags * Accepts: MAIL stream * sequence * flag(s) * option flags */ void mtx_flag (MAILSTREAM *stream,char *sequence,char *flag,long flags) { struct utimbuf times; struct stat sbuf; if (!stream->rdonly) { /* make sure the update takes */ fsync (LOCAL->fd); fstat (LOCAL->fd,&sbuf); /* get current write time */ times.modtime = LOCAL->filetime = sbuf.st_mtime; times.actime = time (0); /* make sure read comes after all that */ utime (stream->mailbox,×); } } /* MTX mail per-message modify flags * Accepts: MAIL stream * message cache element */ void mtx_flagmsg (MAILSTREAM *stream,MESSAGECACHE *elt) { struct stat sbuf; /* maybe need to do a checkpoint? */ if (LOCAL->filetime && !LOCAL->shouldcheck) { fstat (LOCAL->fd,&sbuf); /* get current write time */ if (LOCAL->filetime < sbuf.st_mtime) LOCAL->shouldcheck = T; LOCAL->filetime = 0; /* don't do this test for any other messages */ } /* recalculate status */ mtx_update_status (stream,elt->msgno,NIL); } /* MTX mail ping mailbox * Accepts: MAIL stream * Returns: T if stream still alive, NIL if not */ long mtx_ping (MAILSTREAM *stream) { unsigned long i = 1; long r = T; int ld; char lock[MAILTMPLEN]; struct stat sbuf; if (stream && LOCAL) { /* only if stream already open */ fstat (LOCAL->fd,&sbuf); /* get current file poop */ if (LOCAL->filetime && !(LOCAL->mustcheck || LOCAL->shouldcheck) && (LOCAL->filetime < sbuf.st_mtime)) LOCAL->shouldcheck = T; /* check for changed message status */ if (LOCAL->mustcheck || LOCAL->shouldcheck) { LOCAL->filetime = sbuf.st_mtime; if (LOCAL->shouldcheck) /* babble when we do this unilaterally */ mm_notify (stream,"[CHECK] Checking for flag updates",NIL); while (i <= stream->nmsgs) mtx_elt (stream,i++); LOCAL->mustcheck = LOCAL->shouldcheck = NIL; } /* get shared parse/append permission */ if ((sbuf.st_size != LOCAL->filesize) && ((ld = lockname (lock,stream->mailbox,LOCK_SH)) >= 0)) { /* parse resulting mailbox */ r = (mtx_parse (stream)) ? T : NIL; unlockfd (ld,lock); /* release shared parse/append permission */ } } return r; /* return result of the parse */ } /* MTX mail check mailbox (reparses status too) * Accepts: MAIL stream */ void mtx_check (MAILSTREAM *stream) { /* mark that a check is desired */ if (LOCAL) LOCAL->mustcheck = T; if (mtx_ping (stream)) mm_log ("Check completed",(long) NIL); } /* MTX mail expunge mailbox * sequence to expunge if non-NIL * expunge options * Returns: T, always */ long mtx_expunge (MAILSTREAM *stream,char *sequence,long options) { long ret; struct utimbuf times; struct stat sbuf; off_t pos = 0; int ld; unsigned long i = 1; unsigned long j,k,m,recent; unsigned long n = 0; unsigned long delta = 0; char lock[MAILTMPLEN]; MESSAGECACHE *elt; if (!(ret = (sequence ? ((options & EX_UID) ? mail_uid_sequence (stream,sequence) : mail_sequence (stream,sequence)) : LONGT) && mtx_ping (stream))); /* parse sequence if given, ping stream */ else if (stream->rdonly) mm_log ("Expunge ignored on readonly mailbox",WARN); else { if (LOCAL->filetime && !LOCAL->shouldcheck) { fstat (LOCAL->fd,&sbuf); /* get current write time */ if (LOCAL->filetime < sbuf.st_mtime) LOCAL->shouldcheck = T; } /* get exclusive parse/append permission */ if ((ld = lockname (lock,stream->mailbox,LOCK_EX)) < 0) mm_log ("Unable to lock expunge mailbox",ERROR); /* make sure see any newly-arrived messages */ else if (!mtx_parse (stream)); /* get exclusive access */ else if (flock (LOCAL->fd,LOCK_EX|LOCK_NB)) { flock (LOCAL->fd,LOCK_SH);/* recover previous lock */ mm_log ("Can't expunge because mailbox is in use by another process", ERROR); unlockfd (ld,lock); /* release exclusive parse/append permission */ } else { mm_critical (stream); /* go critical */ recent = stream->recent; /* get recent now that pinged and locked */ /* for each message */ while (i <= stream->nmsgs) { /* get cache element */ elt = mtx_elt (stream,i); /* number of bytes to smash or preserve */ k = elt->private.special.text.size + elt->rfc822_size; /* if need to expunge this message */ if (elt->deleted && (sequence ? elt->sequence : T)) { /* if recent, note one less recent message */ if (elt->recent) --recent; delta += k; /* number of bytes to delete */ /* notify upper levels */ mail_expunged (stream,i); n++; /* count up one more expunged message */ } else if (i++ && delta) {/* preserved message */ /* first byte to preserve */ j = elt->private.special.offset; do { /* read from source position */ m = min (k,LOCAL->buflen); lseek (LOCAL->fd,j,L_SET); read (LOCAL->fd,LOCAL->buf,m); pos = j - delta; /* write to destination position */ while (T) { lseek (LOCAL->fd,pos,L_SET); if (write (LOCAL->fd,LOCAL->buf,m) > 0) break; mm_notify (stream,strerror (errno),WARN); mm_diskerror (stream,errno,T); } pos += m; /* new position */ j += m; /* next chunk, perhaps */ } while (k -= m); /* until done */ /* note the new address of this text */ elt->private.special.offset -= delta; } /* preserved but no deleted messages */ else pos = elt->private.special.offset + k; } if (n) { /* truncate file after last message */ if (pos != (LOCAL->filesize -= delta)) { sprintf (LOCAL->buf, "Calculated size mismatch %lu != %lu, delta = %lu", (unsigned long) pos,(unsigned long) LOCAL->filesize,delta); mm_log (LOCAL->buf,WARN); LOCAL->filesize = pos;/* fix it then */ } ftruncate (LOCAL->fd,LOCAL->filesize); sprintf (LOCAL->buf,"Expunged %lu messages",n); /* output the news */ mm_log (LOCAL->buf,(long) NIL); } else mm_log ("No messages deleted, so no update needed",(long) NIL); fsync (LOCAL->fd); /* force disk update */ fstat (LOCAL->fd,&sbuf); /* get new write time */ times.modtime = LOCAL->filetime = sbuf.st_mtime; times.actime = time (0); /* reset atime to now */ utime (stream->mailbox,×); mm_nocritical (stream); /* release critical */ /* notify upper level of new mailbox size */ mail_exists (stream,stream->nmsgs); mail_recent (stream,recent); flock (LOCAL->fd,LOCK_SH);/* allow sharers again */ unlockfd (ld,lock); /* release exclusive parse/append permission */ } } return ret; } /* MTX mail copy message(s) * Accepts: MAIL stream * sequence * destination mailbox * copy options * Returns: T if success, NIL if failed */ long mtx_copy (MAILSTREAM *stream,char *sequence,char *mailbox,long options) { struct stat sbuf; struct utimbuf times; MESSAGECACHE *elt; unsigned long i,j,k; long ret = LONGT; int fd,ld; char file[MAILTMPLEN],lock[MAILTMPLEN]; mailproxycopy_t pc = (mailproxycopy_t) mail_parameters (stream,GET_MAILPROXYCOPY,NIL); /* make sure valid mailbox */ if (!mtx_isvalid (mailbox,file)) switch (errno) { case ENOENT: /* no such file? */ mm_notify (stream,"[TRYCREATE] Must create mailbox before copy",NIL); return NIL; case 0: /* merely empty file? */ break; case EACCES: /* file protected */ sprintf (LOCAL->buf,"Can't access destination: %.80s",mailbox); MM_LOG (LOCAL->buf,ERROR); return NIL; case EINVAL: if (pc) return (*pc) (stream,sequence,mailbox,options); sprintf (LOCAL->buf,"Invalid MTX-format mailbox name: %.80s",mailbox); mm_log (LOCAL->buf,ERROR); return NIL; default: if (pc) return (*pc) (stream,sequence,mailbox,options); sprintf (LOCAL->buf,"Not a MTX-format mailbox: %.80s",mailbox); mm_log (LOCAL->buf,ERROR); return NIL; } if (!((options & CP_UID) ? mail_uid_sequence (stream,sequence) : mail_sequence (stream,sequence))) return NIL; /* got file? */ if ((fd = open (file,O_BINARY|O_RDWR|O_CREAT,S_IREAD|S_IWRITE)) < 0) { sprintf (LOCAL->buf,"Unable to open copy mailbox: %.80s",strerror (errno)); mm_log (LOCAL->buf,ERROR); return NIL; } mm_critical (stream); /* go critical */ /* get exclusive parse/append permission */ if (flock (fd,LOCK_SH) || ((ld = lockname (lock,file,LOCK_EX)) < 0)) { mm_log ("Unable to lock copy mailbox",ERROR); mm_nocritical (stream); return NIL; } fstat (fd,&sbuf); /* get current file size */ lseek (fd,sbuf.st_size,L_SET);/* move to end of file */ /* for each requested message */ for (i = 1; ret && (i <= stream->nmsgs); i++) if ((elt = mail_elt (stream,i))->sequence) { lseek (LOCAL->fd,elt->private.special.offset,L_SET); /* number of bytes to copy */ k = elt->private.special.text.size + elt->rfc822_size; do { /* read from source position */ j = min (k,LOCAL->buflen); read (LOCAL->fd,LOCAL->buf,j); if (write (fd,LOCAL->buf,j) < 0) ret = NIL; } while (ret && (k -= j));/* until done */ } /* make sure all the updates take */ if (!(ret && (ret = !fsync (fd)))) { sprintf (LOCAL->buf,"Unable to write message: %s",strerror (errno)); mm_log (LOCAL->buf,ERROR); ftruncate (fd,sbuf.st_size); } /* set atime to now-1 if successful copy */ if (ret) times.actime = time (0) - 1; /* else preserved \Marked status */ else times.actime = (sbuf.st_ctime > sbuf.st_atime) ? sbuf.st_atime : time (0); times.modtime = sbuf.st_mtime;/* preserve mtime */ utime (file,×); /* set the times */ unlockfd (ld,lock); /* release exclusive parse/append permission */ close (fd); /* close the file */ mm_nocritical (stream); /* release critical */ /* delete all requested messages */ if (ret && (options & CP_MOVE)) { for (i = 1; i <= stream->nmsgs; i++) if ((elt = mtx_elt (stream,i))->sequence) { elt->deleted = T; /* mark message deleted */ /* recalculate status */ mtx_update_status (stream,i,NIL); } if (!stream->rdonly) { /* make sure the update takes */ fsync (LOCAL->fd); fstat (LOCAL->fd,&sbuf); /* get current write time */ times.modtime = LOCAL->filetime = sbuf.st_mtime; times.actime = time (0); /* make sure atime remains greater */ utime (stream->mailbox,×); } } if (ret && mail_parameters (NIL,GET_COPYUID,NIL)) mm_log ("Can not return meaningful COPYUID with this mailbox format",WARN); return ret; } /* MTX mail append message from stringstruct * Accepts: MAIL stream * destination mailbox * append callback * data for callback * Returns: T if append successful, else NIL */ long mtx_append (MAILSTREAM *stream,char *mailbox,append_t af,void *data) { struct stat sbuf; int fd,ld,c; char *flags,*date,tmp[MAILTMPLEN],file[MAILTMPLEN],lock[MAILTMPLEN]; struct utimbuf times; FILE *df; MESSAGECACHE elt; long f; unsigned long i,uf; STRING *message; long ret = LONGT; /* default stream to prototype */ if (!stream) stream = &mtxproto; /* make sure valid mailbox */ if (!mtx_isvalid (mailbox,file)) switch (errno) { case ENOENT: /* no such file? */ if (!compare_cstring (mailbox,"INBOX")) mtx_create (NIL,"INBOX"); else { mm_notify (stream,"[TRYCREATE] Must create mailbox before append",NIL); return NIL; } /* falls through */ case 0: /* merely empty file? */ break; case EACCES: /* file protected */ sprintf (tmp,"Can't access destination: %.80s",mailbox); MM_LOG (tmp,ERROR); return NIL; case EINVAL: sprintf (tmp,"Invalid MTX-format mailbox name: %.80s",mailbox); mm_log (tmp,ERROR); return NIL; default: sprintf (tmp,"Not a MTX-format mailbox: %.80s",mailbox); mm_log (tmp,ERROR); return NIL; } /* get first message */ if (!(*af) (stream,data,&flags,&date,&message)) return NIL; /* open destination mailbox */ if (((fd = open (file,O_BINARY|O_WRONLY|O_APPEND|O_CREAT,S_IREAD|S_IWRITE)) < 0) || !(df = fdopen (fd,"ab"))) { sprintf (tmp,"Can't open append mailbox: %s",strerror (errno)); mm_log (tmp,ERROR); return NIL; } /* get parse/append permission */ if (flock (fd,LOCK_SH) || ((ld = lockname (lock,file,LOCK_EX)) < 0)) { mm_log ("Unable to lock append mailbox",ERROR); close (fd); return NIL; } mm_critical (stream); /* go critical */ fstat (fd,&sbuf); /* get current file size */ errno = 0; do { /* parse flags */ if (!SIZE (message)) { /* guard against zero-length */ mm_log ("Append of zero-length message",ERROR); ret = NIL; break; } f = mail_parse_flags (stream,flags,&i); /* reverse bits (dontcha wish we had CIRC?) */ for (uf = 0; i; uf |= 1 << (29 - find_rightmost_bit (&i))); if (date) { /* parse date if given */ if (!mail_parse_date (&elt,date)) { sprintf (tmp,"Bad date in append: %.80s",date); mm_log (tmp,ERROR); ret = NIL; /* mark failure */ break; } mail_date (tmp,&elt); /* write preseved date */ } else internal_date (tmp); /* get current date in IMAP format */ /* write header */ if (fprintf (df,"%s,%lu;%010lo%02lo\015\012",tmp,i = SIZE (message),uf, (unsigned long) f) < 0) ret = NIL; else { /* write message */ if (i) do c = 0xff & SNX (message); while ((putc (c,df) != EOF) && --i); /* get next message */ if (i || !(*af) (stream,data,&flags,&date,&message)) ret = NIL; } } while (ret && message); /* if error... */ if (!ret || (fflush (df) == EOF)) { ftruncate (fd,sbuf.st_size);/* revert file */ close (fd); /* make sure fclose() doesn't corrupt us */ if (errno) { sprintf (tmp,"Message append failed: %s",strerror (errno)); mm_log (tmp,ERROR); } ret = NIL; } if (ret) times.actime = time (0) - 1; /* else preserved \Marked status */ else times.actime = (sbuf.st_ctime > sbuf.st_atime) ? sbuf.st_atime : time (0); times.modtime = sbuf.st_mtime;/* preserve mtime */ utime (file,×); /* set the times */ fclose (df); /* close the file */ unlockfd (ld,lock); /* release exclusive parse/append permission */ mm_nocritical (stream); /* release critical */ if (ret && mail_parameters (NIL,GET_APPENDUID,NIL)) mm_log ("Can not return meaningful APPENDUID with this mailbox format", WARN); return ret; } /* Internal routines */ /* MTX mail parse mailbox * Accepts: MAIL stream * Returns: T if parse OK * NIL if failure, stream aborted */ long mtx_parse (MAILSTREAM *stream) { struct stat sbuf; MESSAGECACHE *elt = NIL; unsigned char c,*s,*t,*x; char tmp[MAILTMPLEN]; unsigned long i,j; long curpos = LOCAL->filesize; long nmsgs = stream->nmsgs; long recent = stream->recent; short added = NIL; short silent = stream->silent; fstat (LOCAL->fd,&sbuf); /* get status */ if (sbuf.st_size < curpos) { /* sanity check */ sprintf (tmp,"Mailbox shrank from %ld to %ld!",curpos,sbuf.st_size); mm_log (tmp,ERROR); mtx_close (stream,NIL); return NIL; } stream->silent = T; /* don't pass up mm_exists() events yet */ while (sbuf.st_size - curpos){/* while there is stuff to parse */ /* get to that position in the file */ lseek (LOCAL->fd,curpos,L_SET); if ((i = read (LOCAL->fd,LOCAL->buf,64)) <= 0) { sprintf (tmp,"Unable to read internal header at %lu, size = %lu: %s", (unsigned long) curpos,(unsigned long) sbuf.st_size, i ? strerror (errno) : "no data read"); mm_log (tmp,ERROR); mtx_close (stream,NIL); return NIL; } LOCAL->buf[i] = '\0'; /* tie off buffer just in case */ if (!((s = strchr (LOCAL->buf,'\015')) && (s[1] == '\012'))) { sprintf (tmp,"Unable to find CRLF at %lu in %lu bytes, text: %s", (unsigned long) curpos,i,(char *) LOCAL->buf); mm_log (tmp,ERROR); mtx_close (stream,NIL); return NIL; } *s = '\0'; /* tie off header line */ i = (s + 2) - LOCAL->buf; /* note start of text offset */ if (!((s = strchr (LOCAL->buf,',')) && (t = strchr (s+1,';')))) { sprintf (tmp,"Unable to parse internal header at %lu: %s", (unsigned long) curpos,(char *) LOCAL->buf); mm_log (tmp,ERROR); mtx_close (stream,NIL); return NIL; } *s++ = '\0'; *t++ = '\0'; /* tie off fields */ added = T; /* note that a new message was added */ /* swell the cache */ mail_exists (stream,++nmsgs); /* instantiate an elt for this message */ (elt = mail_elt (stream,nmsgs))->valid = T; elt->private.uid = ++stream->uid_last; /* note file offset of header */ elt->private.special.offset = curpos; /* in case error */ elt->private.special.text.size = 0; /* header size not known yet */ elt->private.msg.header.text.size = 0; x = s; /* parse the header components */ if (mail_parse_date (elt,LOCAL->buf) && (elt->rfc822_size = strtoul (s,(char **) &s,10)) && (!(s && *s)) && isdigit (t[0]) && isdigit (t[1]) && isdigit (t[2]) && isdigit (t[3]) && isdigit (t[4]) && isdigit (t[5]) && isdigit (t[6]) && isdigit (t[7]) && isdigit (t[8]) && isdigit (t[9]) && isdigit (t[10]) && isdigit (t[11]) && !t[12]) elt->private.special.text.size = i; else { /* oops */ sprintf (tmp,"Unable to parse internal header elements at %ld: %s,%s;%s", curpos,(char *) LOCAL->buf,(char *) x,(char *) t); mm_log (tmp,ERROR); mtx_close (stream,NIL); return NIL; } /* make sure didn't run off end of file */ if ((curpos += (elt->rfc822_size + i)) > sbuf.st_size) { sprintf (tmp,"Last message (at %lu) runs past end of file (%lu > %lu)", elt->private.special.offset,(unsigned long) curpos, (unsigned long) sbuf.st_size); mm_log (tmp,ERROR); mtx_close (stream,NIL); return NIL; } c = t[10]; /* remember first system flags byte */ t[10] = '\0'; /* tie off flags */ j = strtoul (t,NIL,8); /* get user flags value */ t[10] = c; /* restore first system flags byte */ /* set up all valid user flags (reversed!) */ while (j) if (((i = 29 - find_rightmost_bit (&j)) < NUSERFLAGS) && stream->user_flags[i]) elt->user_flags |= 1 << i; /* calculate system flags */ if ((j = ((t[10]-'0') * 8) + t[11]-'0') & fSEEN) elt->seen = T; if (j & fDELETED) elt->deleted = T; if (j & fFLAGGED) elt->flagged = T; if (j & fANSWERED) elt->answered = T; if (j & fDRAFT) elt->draft = T; if (!(j & fOLD)) { /* newly arrived message? */ elt->recent = T; recent++; /* count up a new recent message */ /* mark it as old */ mtx_update_status (stream,nmsgs,NIL); } } fsync (LOCAL->fd); /* make sure all the fOLD flags take */ /* update parsed file size and time */ LOCAL->filesize = sbuf.st_size; fstat (LOCAL->fd,&sbuf); /* get status again to ensure time is right */ LOCAL->filetime = sbuf.st_mtime; if (added && !stream->rdonly){/* make sure atime updated */ struct utimbuf times; times.actime = time (0); times.modtime = LOCAL->filetime; utime (stream->mailbox,×); } stream->silent = silent; /* can pass up events now */ mail_exists (stream,nmsgs); /* notify upper level of new mailbox size */ mail_recent (stream,recent); /* and of change in recent messages */ return LONGT; /* return the winnage */ } /* MTX get cache element with status updating from file * Accepts: MAIL stream * message number * Returns: cache element */ MESSAGECACHE *mtx_elt (MAILSTREAM *stream,unsigned long msgno) { MESSAGECACHE *elt = mail_elt (stream,msgno); struct { /* old flags */ unsigned int seen : 1; unsigned int deleted : 1; unsigned int flagged : 1; unsigned int answered : 1; unsigned int draft : 1; unsigned long user_flags; } old; old.seen = elt->seen; old.deleted = elt->deleted; old.flagged = elt->flagged; old.answered = elt->answered; old.draft = elt->draft; old.user_flags = elt->user_flags; mtx_read_flags (stream,elt); if ((old.seen != elt->seen) || (old.deleted != elt->deleted) || (old.flagged != elt->flagged) || (old.answered != elt->answered) || (old.draft != elt->draft) || (old.user_flags != elt->user_flags)) mm_flags (stream,msgno); /* let top level know */ return elt; } /* MTX read flags from file * Accepts: MAIL stream * Returns: cache element */ void mtx_read_flags (MAILSTREAM *stream,MESSAGECACHE *elt) { unsigned long i,j; /* noop if readonly and have valid flags */ if (stream->rdonly && elt->valid) return; /* set the seek pointer */ lseek (LOCAL->fd,(off_t) elt->private.special.offset + elt->private.special.text.size - 14,L_SET); /* read the new flags */ if (read (LOCAL->fd,LOCAL->buf,12) < 0) { sprintf (LOCAL->buf,"Unable to read new status: %s",strerror (errno)); fatal (LOCAL->buf); } /* calculate system flags */ i = (((LOCAL->buf[10]-'0') * 8) + LOCAL->buf[11]-'0'); elt->seen = i & fSEEN ? T : NIL; elt->deleted = i & fDELETED ? T : NIL; elt->flagged = i & fFLAGGED ? T : NIL; elt->answered = i & fANSWERED ? T : NIL; elt->draft = i & fDRAFT ? T : NIL; LOCAL->buf[10] = '\0'; /* tie off flags */ j = strtoul(LOCAL->buf,NIL,8);/* get user flags value */ /* set up all valid user flags (reversed!) */ while (j) if (((i = 29 - find_rightmost_bit (&j)) < NUSERFLAGS) && stream->user_flags[i]) elt->user_flags |= 1 << i; elt->valid = T; /* have valid flags now */ } /* MTX update status string * Accepts: MAIL stream * message number * flag saying whether or not to sync */ void mtx_update_status (MAILSTREAM *stream,unsigned long msgno,long syncflag) { struct utimbuf times; struct stat sbuf; MESSAGECACHE *elt = mail_elt (stream,msgno); unsigned long j,k = 0; /* readonly */ if (stream->rdonly || !elt->valid) mtx_read_flags (stream,elt); else { /* readwrite */ j = elt->user_flags; /* get user flags */ /* reverse bits (dontcha wish we had CIRC?) */ while (j) k |= 1 << (29 - find_rightmost_bit (&j)); /* print new flag string */ sprintf (LOCAL->buf,"%010lo%02o",k,(unsigned) (fOLD + (fSEEN * elt->seen) + (fDELETED * elt->deleted) + (fFLAGGED * elt->flagged) + (fANSWERED * elt->answered) + (fDRAFT * elt->draft))); while (T) { /* get to that place in the file */ lseek (LOCAL->fd,(off_t) elt->private.special.offset + elt->private.special.text.size - 14,L_SET); /* write new flags */ if (write (LOCAL->fd,LOCAL->buf,12) > 0) break; mm_notify (stream,strerror (errno),WARN); mm_diskerror (stream,errno,T); } if (syncflag) { /* sync if requested */ fsync (LOCAL->fd); fstat (LOCAL->fd,&sbuf); /* get new write time */ times.modtime = LOCAL->filetime = sbuf.st_mtime; times.actime = time (0); /* make sure read is later */ utime (stream->mailbox,×); } } } /* MTX locate header for a message * Accepts: MAIL stream * message number * pointer to returned header size * Returns: position of header in file */ unsigned long mtx_hdrpos (MAILSTREAM *stream,unsigned long msgno, unsigned long *size) { unsigned long siz; long i = 0; int q = 0; char *s,tmp[MAILTMPLEN]; MESSAGECACHE *elt = mtx_elt (stream,msgno); unsigned long ret = elt->private.special.offset + elt->private.special.text.size; /* is header size known? */ if (!(*size = elt->private.msg.header.text.size)) { lseek (LOCAL->fd,ret,L_SET);/* get to header position */ /* search message for CRLF CRLF */ for (siz = 1,s = tmp; siz <= elt->rfc822_size; siz++) { /* read another buffer as necessary */ if ((--i <= 0) && /* buffer empty? */ (read (LOCAL->fd,s = tmp, i = min (elt->rfc822_size - siz,(long) MAILTMPLEN)) < 0)) return ret; /* I/O error? */ switch (q) { /* sniff at buffer */ case 0: /* first character */ q = (*s++ == '\015') ? 1 : 0; break; case 1: /* second character */ q = (*s++ == '\012') ? 2 : 0; break; case 2: /* third character */ q = (*s++ == '\015') ? 3 : 0; break; case 3: /* fourth character */ if (*s++ == '\012') { /* have the sequence? */ /* yes, note for later */ elt->private.msg.header.text.size = *size = siz; return ret; } q = 0; /* lost... */ break; } } /* header consumes entire message */ elt->private.msg.header.text.size = *size = elt->rfc822_size; } return ret; } alpine-2.10+dfsg/imap/src/osdep/nt/tenexnt.c0000600000175000017500000012575111512502123022447 0ustar paulproteuspaulproteus/* ======================================================================== * Copyright 1988-2007 University of Washington * * Licensed under the Apache License, Version 2.0 (the "License"); * you may not use this file except in compliance with the License. * You may obtain a copy of the License at * * http://www.apache.org/licenses/LICENSE-2.0 * * * ======================================================================== */ /* * Program: Tenex mail routines * * Author: Mark Crispin * Networks and Distributed Computing * Computing & Communications * University of Washington * Administration Building, AG-44 * Seattle, WA 98195 * Internet: MRC@CAC.Washington.EDU * * Date: 22 May 1990 * Last Edited: 18 June 2007 */ /* FILE TIME SEMANTICS * * The atime is the last read time of the file. * The mtime is the last flags update time of the file. * The ctime is the last write time of the file. * * TEXT SIZE SEMANTICS * * Most of the text sizes are in internal (LF-only) form, except for the * msg.text size. Beware. */ #include #include #include extern int errno; /* just in case */ #include "mail.h" #include "osdep.h" #include #include #include #include #include "misc.h" #include "dummy.h" /* TENEX I/O stream local data */ typedef struct tenex_local { unsigned int shouldcheck: 1; /* if ping should do a check instead */ unsigned int mustcheck: 1; /* if ping must do a check instead */ int fd; /* file descriptor for I/O */ off_t filesize; /* file size parsed */ time_t filetime; /* last file time */ time_t lastsnarf; /* local snarf time */ unsigned char *buf; /* temporary buffer */ unsigned long buflen; /* current size of temporary buffer */ unsigned long uid; /* current text uid */ SIZEDTEXT text; /* current text */ } TENEXLOCAL; /* Convenient access to local data */ #define LOCAL ((TENEXLOCAL *) stream->local) /* Function prototypes */ DRIVER *tenex_valid (char *name); int tenex_isvalid (char *name,char *file); void *tenex_parameters (long function,void *value); void tenex_scan (MAILSTREAM *stream,char *ref,char *pat,char *contents); void tenex_list (MAILSTREAM *stream,char *ref,char *pat); void tenex_lsub (MAILSTREAM *stream,char *ref,char *pat); long tenex_create (MAILSTREAM *stream,char *mailbox); long tenex_delete (MAILSTREAM *stream,char *mailbox); long tenex_rename (MAILSTREAM *stream,char *old,char *newname); long tenex_status (MAILSTREAM *stream,char *mbx,long flags); MAILSTREAM *tenex_open (MAILSTREAM *stream); void tenex_close (MAILSTREAM *stream,long options); void tenex_fast (MAILSTREAM *stream,char *sequence,long flags); void tenex_flags (MAILSTREAM *stream,char *sequence,long flags); char *tenex_header (MAILSTREAM *stream,unsigned long msgno, unsigned long *length,long flags); long tenex_text (MAILSTREAM *stream,unsigned long msgno,STRING *bs,long flags); void tenex_flag (MAILSTREAM *stream,char *sequence,char *flag,long flags); void tenex_flagmsg (MAILSTREAM *stream,MESSAGECACHE *elt); long tenex_ping (MAILSTREAM *stream); void tenex_check (MAILSTREAM *stream); void tenex_snarf (MAILSTREAM *stream); long tenex_expunge (MAILSTREAM *stream,char *sequence,long options); long tenex_copy (MAILSTREAM *stream,char *sequence,char *mailbox,long options); long tenex_append (MAILSTREAM *stream,char *mailbox,append_t af,void *data); unsigned long tenex_size (MAILSTREAM *stream,unsigned long m); long tenex_parse (MAILSTREAM *stream); MESSAGECACHE *tenex_elt (MAILSTREAM *stream,unsigned long msgno); void tenex_read_flags (MAILSTREAM *stream,MESSAGECACHE *elt); void tenex_update_status (MAILSTREAM *stream,unsigned long msgno, long syncflag); unsigned long tenex_hdrpos (MAILSTREAM *stream,unsigned long msgno, unsigned long *size); /* Tenex mail routines */ /* Driver dispatch used by MAIL */ DRIVER tenexdriver = { "tenex", /* driver name */ DR_LOCAL|DR_MAIL, /* driver flags */ (DRIVER *) NIL, /* next driver */ tenex_valid, /* mailbox is valid for us */ tenex_parameters, /* manipulate parameters */ tenex_scan, /* scan mailboxes */ tenex_list, /* list mailboxes */ tenex_lsub, /* list subscribed mailboxes */ NIL, /* subscribe to mailbox */ NIL, /* unsubscribe from mailbox */ tenex_create, /* create mailbox */ tenex_delete, /* delete mailbox */ tenex_rename, /* rename mailbox */ mail_status_default, /* status of mailbox */ tenex_open, /* open mailbox */ tenex_close, /* close mailbox */ tenex_flags, /* fetch message "fast" attributes */ tenex_flags, /* fetch message flags */ NIL, /* fetch overview */ NIL, /* fetch message envelopes */ tenex_header, /* fetch message header */ tenex_text, /* fetch message body */ NIL, /* fetch partial message text */ NIL, /* unique identifier */ NIL, /* message number */ tenex_flag, /* modify flags */ tenex_flagmsg, /* per-message modify flags */ NIL, /* search for message based on criteria */ NIL, /* sort messages */ NIL, /* thread messages */ tenex_ping, /* ping mailbox to see if still alive */ tenex_check, /* check for new messages */ tenex_expunge, /* expunge deleted messages */ tenex_copy, /* copy messages to another mailbox */ tenex_append, /* append string message to mailbox */ NIL /* garbage collect stream */ }; /* prototype stream */ MAILSTREAM tenexproto = {&tenexdriver}; /* Tenex mail validate mailbox * Accepts: mailbox name * Returns: our driver if name is valid, NIL otherwise */ DRIVER *tenex_valid (char *name) { char tmp[MAILTMPLEN]; return tenex_isvalid (name,tmp) ? &tenexdriver : NIL; } /* Tenex mail test for valid mailbox * Accepts: mailbox name * buffer to return file name * Returns: T if valid, NIL otherwise */ int tenex_isvalid (char *name,char *file) { int fd; int ret = NIL; char *s,tmp[MAILTMPLEN]; struct stat sbuf; struct utimbuf times; errno = EINVAL; /* assume invalid argument */ /* if file, get its status */ if ((s = dummy_file (file,name)) && !stat (s,&sbuf) && ((sbuf.st_mode & S_IFMT) == S_IFREG)) { if (!sbuf.st_size)errno = 0;/* empty file */ else if ((fd = open (file,O_BINARY|O_RDONLY,NIL)) >= 0) { memset (tmp,'\0',MAILTMPLEN); if ((read (fd,tmp,64) >= 0) && (s = strchr (tmp,'\012')) && (s[-1] != '\015')) { /* valid format? */ *s = '\0'; /* tie off header */ /* must begin with dd-mmm-yy" */ ret = (((tmp[2] == '-' && tmp[6] == '-') || (tmp[1] == '-' && tmp[5] == '-')) && (s = strchr (tmp+18,',')) && strchr (s+2,';')) ? T : NIL; } else errno = -1; /* bogus format */ close (fd); /* close the file */ /* \Marked status? */ if (sbuf.st_ctime > sbuf.st_atime) { /* preserve atime and mtime */ times.actime = sbuf.st_atime; times.modtime = sbuf.st_mtime; utime (file,×); /* set the times */ } } } /* in case INBOX but not tenex format */ else if ((errno == ENOENT) && !compare_cstring (name,"INBOX")) errno = -1; return ret; /* return what we should */ } /* Tenex manipulate driver parameters * Accepts: function code * function-dependent value * Returns: function-dependent return value */ void *tenex_parameters (long function,void *value) { return NIL; } /* Tenex mail scan mailboxes * Accepts: mail stream * reference * pattern to search * string to scan */ void tenex_scan (MAILSTREAM *stream,char *ref,char *pat,char *contents) { if (stream) dummy_scan (NIL,ref,pat,contents); } /* Tenex mail list mailboxes * Accepts: mail stream * reference * pattern to search */ void tenex_list (MAILSTREAM *stream,char *ref,char *pat) { if (stream) dummy_list (NIL,ref,pat); } /* Tenex mail list subscribed mailboxes * Accepts: mail stream * reference * pattern to search */ void tenex_lsub (MAILSTREAM *stream,char *ref,char *pat) { if (stream) dummy_lsub (NIL,ref,pat); } /* Tenex mail create mailbox * Accepts: MAIL stream * mailbox name to create * Returns: T on success, NIL on failure */ long tenex_create (MAILSTREAM *stream,char *mailbox) { char *s,mbx[MAILTMPLEN]; if (s = dummy_file (mbx,mailbox)) return dummy_create (stream,s); sprintf (mbx,"Can't create %.80s: invalid name",mailbox); mm_log (mbx,ERROR); return NIL; } /* Tenex mail delete mailbox * Accepts: MAIL stream * mailbox name to delete * Returns: T on success, NIL on failure */ long tenex_delete (MAILSTREAM *stream,char *mailbox) { return tenex_rename (stream,mailbox,NIL); } /* Tenex mail rename mailbox * Accepts: MAIL stream * old mailbox name * new mailbox name (or NIL for delete) * Returns: T on success, NIL on failure */ long tenex_rename (MAILSTREAM *stream,char *old,char *newname) { long ret = LONGT; char c,*s,tmp[MAILTMPLEN],file[MAILTMPLEN],lock[MAILTMPLEN]; int fd,ld; struct stat sbuf; if (!dummy_file (file,old) || (newname && (!((s = mailboxfile (tmp,newname)) && *s) || ((s = strrchr (tmp,'\\')) && !s[1])))) { sprintf (tmp,newname ? "Can't rename mailbox %.80s to %.80s: invalid name" : "Can't delete mailbox %.80s: invalid name", old,newname); mm_log (tmp,ERROR); return NIL; } else if ((fd = open (file,O_BINARY|O_RDWR,NIL)) < 0) { sprintf (tmp,"Can't open mailbox %.80s: %s",old,strerror (errno)); mm_log (tmp,ERROR); return NIL; } /* get exclusive parse/append permission */ if ((ld = lockname (lock,file,LOCK_EX)) < 0) { mm_log ("Unable to lock rename mailbox",ERROR); return NIL; } /* lock out other users */ if (flock (fd,LOCK_EX|LOCK_NB)) { close (fd); /* couldn't lock, give up on it then */ sprintf (tmp,"Mailbox %.80s is in use by another process",old); mm_log (tmp,ERROR); unlockfd (ld,lock); /* release exclusive parse/append permission */ return NIL; } if (newname) { /* want rename? */ /* found superior to destination name? */ if ((s = strrchr (tmp,'\\')) && (s != tmp) && ((tmp[1] != ':') || (s != tmp + 2))) { c = s[1]; /* remember character after delimiter */ *s = s[1] = '\0'; /* tie off name at delimiter */ /* name doesn't exist, create it */ if (stat (tmp,&sbuf) || ((sbuf.st_mode & S_IFMT) != S_IFDIR)) { *s = '\\'; /* restore delimiter */ if (!dummy_create (stream,tmp)) ret = NIL; } else *s = '\\'; /* restore delimiter */ s[1] = c; /* restore character after delimiter */ } flock (fd,LOCK_UN); /* release lock on the file */ close (fd); /* pacify NTFS */ /* rename the file */ if (ret && rename (file,tmp)) { sprintf (tmp,"Can't rename mailbox %.80s to %.80s: %s",old,newname, strerror (errno)); mm_log (tmp,ERROR); ret = NIL; /* set failure */ } } else { flock (fd,LOCK_UN); /* release lock on the file */ close (fd); /* pacify NTFS */ if (unlink (file)) { sprintf (tmp,"Can't delete mailbox %.80s: %.80s",old,strerror (errno)); mm_log (tmp,ERROR); ret = NIL; /* set failure */ } } unlockfd (ld,lock); /* release exclusive parse/append permission */ return ret; /* return success */ } /* Tenex mail open * Accepts: stream to open * Returns: stream on success, NIL on failure */ MAILSTREAM *tenex_open (MAILSTREAM *stream) { int fd,ld; char tmp[MAILTMPLEN]; /* return prototype for OP_PROTOTYPE call */ if (!stream) return &tenexproto; if (stream->local) fatal ("tenex recycle stream"); /* canonicalize the mailbox name */ if (!dummy_file (tmp,stream->mailbox)) { sprintf (tmp,"Can't open - invalid name: %.80s",stream->mailbox); mm_log (tmp,ERROR); } if (stream->rdonly || (fd = open (tmp,O_BINARY|O_RDWR,NIL)) < 0) { if ((fd = open (tmp,O_BINARY|O_RDONLY,NIL)) < 0) { sprintf (tmp,"Can't open mailbox: %.80s",strerror (errno)); mm_log (tmp,ERROR); return NIL; } else if (!stream->rdonly) { /* got it, but readonly */ mm_log ("Can't get write access to mailbox, access is readonly",WARN); stream->rdonly = T; } } stream->local = fs_get (sizeof (TENEXLOCAL)); LOCAL->fd = fd; /* bind the file */ LOCAL->buf = (char *) fs_get (CHUNKSIZE); LOCAL->buflen = CHUNKSIZE - 1; LOCAL->text.data = (unsigned char *) fs_get (CHUNKSIZE); LOCAL->text.size = CHUNKSIZE - 1; /* note if an INBOX or not */ stream->inbox = !compare_cstring (stream->mailbox,"INBOX"); fs_give ((void **) &stream->mailbox); stream->mailbox = cpystr (tmp); /* get shared parse permission */ if ((ld = lockname (tmp,stream->mailbox,LOCK_SH)) < 0) { mm_log ("Unable to lock open mailbox",ERROR); return NIL; } flock (LOCAL->fd,LOCK_SH); /* lock the file */ unlockfd (ld,tmp); /* release shared parse permission */ LOCAL->filesize = 0; /* initialize parsed file size */ LOCAL->filetime = 0; /* time not set up yet */ LOCAL->mustcheck = LOCAL->shouldcheck = NIL; stream->sequence++; /* bump sequence number */ stream->uid_validity = (unsigned long) time (0); /* parse mailbox */ stream->nmsgs = stream->recent = 0; if (tenex_ping (stream) && !stream->nmsgs) mm_log ("Mailbox is empty",(long) NIL); if (!LOCAL) return NIL; /* failure if stream died */ stream->perm_seen = stream->perm_deleted = stream->perm_flagged = stream->perm_answered = stream->perm_draft = stream->rdonly ? NIL : T; stream->perm_user_flags = stream->rdonly ? NIL : 0xffffffff; return stream; /* return stream to caller */ } /* Tenex mail close * Accepts: MAIL stream * close options */ void tenex_close (MAILSTREAM *stream,long options) { if (stream && LOCAL) { /* only if a file is open */ int silent = stream->silent; stream->silent = T; /* note this stream is dying */ if (options & CL_EXPUNGE) tenex_expunge (stream,NIL,NIL); stream->silent = silent; /* restore previous status */ flock (LOCAL->fd,LOCK_UN); /* unlock local file */ close (LOCAL->fd); /* close the local file */ /* free local text buffer */ if (LOCAL->buf) fs_give ((void **) &LOCAL->buf); if (LOCAL->text.data) fs_give ((void **) &LOCAL->text.data); /* nuke the local data */ fs_give ((void **) &stream->local); stream->dtb = NIL; /* log out the DTB */ } } /* Tenex mail fetch flags * Accepts: MAIL stream * sequence * option flags * Sniffs at file to get flags */ void tenex_flags (MAILSTREAM *stream,char *sequence,long flags) { STRING bs; MESSAGECACHE *elt; unsigned long i; if (stream && LOCAL && ((flags & FT_UID) ? mail_uid_sequence (stream,sequence) : mail_sequence (stream,sequence))) for (i = 1; i <= stream->nmsgs; i++) if ((elt = mail_elt (stream,i))->sequence) { if (!elt->rfc822_size) { /* have header size yet? */ lseek (LOCAL->fd,elt->private.special.offset + elt->private.special.text.size,L_SET); /* resize bigbuf if necessary */ if (LOCAL->buflen < elt->private.msg.full.text.size) { fs_give ((void **) &LOCAL->buf); LOCAL->buflen = elt->private.msg.full.text.size; LOCAL->buf = (char *) fs_get (LOCAL->buflen + 1); } /* tie off string */ LOCAL->buf[elt->private.msg.full.text.size] = '\0'; /* read in the message */ read (LOCAL->fd,LOCAL->buf,elt->private.msg.full.text.size); INIT (&bs,mail_string,(void *) LOCAL->buf, elt->private.msg.full.text.size); /* calculate its CRLF size */ elt->rfc822_size = unix_crlflen (&bs); } tenex_elt (stream,i); /* get current flags from file */ } } /* TENEX mail fetch message header * Accepts: MAIL stream * message # to fetch * pointer to returned header text length * option flags * Returns: message header in RFC822 format */ char *tenex_header (MAILSTREAM *stream,unsigned long msgno, unsigned long *length,long flags) { char *s; unsigned long i; *length = 0; /* default to empty */ if (flags & FT_UID) return "";/* UID call "impossible" */ /* get to header position */ lseek (LOCAL->fd,tenex_hdrpos (stream,msgno,&i),L_SET); if (flags & FT_INTERNAL) { if (i > LOCAL->buflen) { /* resize if not enough space */ fs_give ((void **) &LOCAL->buf); LOCAL->buf = (char *) fs_get (LOCAL->buflen = i + 1); } /* slurp the data */ read (LOCAL->fd,LOCAL->buf,*length = i); } else { s = (char *) fs_get (i + 1);/* get readin buffer */ s[i] = '\0'; /* tie off string */ read (LOCAL->fd,s,i); /* slurp the data */ /* make CRLF copy of string */ *length = unix_crlfcpy (&LOCAL->buf,&LOCAL->buflen,s,i); fs_give ((void **) &s); /* free readin buffer */ } return LOCAL->buf; } /* TENEX mail fetch message text (body only) * Accepts: MAIL stream * message # to fetch * pointer to returned stringstruct * option flags * Returns: T, always */ long tenex_text (MAILSTREAM *stream,unsigned long msgno,STRING *bs,long flags) { char *s; unsigned long i,j; MESSAGECACHE *elt; /* UID call "impossible" */ if (flags & FT_UID) return NIL; /* get message status */ elt = tenex_elt (stream,msgno); /* if message not seen */ if (!(flags & FT_PEEK) && !elt->seen) { elt->seen = T; /* mark message as seen */ /* recalculate status */ tenex_update_status (stream,msgno,T); mm_flags (stream,msgno); } if (flags & FT_INTERNAL) { /* if internal representation wanted */ /* find header position */ i = tenex_hdrpos (stream,msgno,&j); if (i > LOCAL->buflen) { /* resize if not enough space */ fs_give ((void **) &LOCAL->buf); LOCAL->buf = (char *) fs_get (LOCAL->buflen = i + 1); } /* go to text position */ lseek (LOCAL->fd,i + j,L_SET); /* slurp the data */ if (read (LOCAL->fd,LOCAL->buf,i) != (long) i) return NIL; /* set up stringstruct for internal */ INIT (bs,mail_string,LOCAL->buf,i); } else { /* normal form, previous text cached? */ if (elt->private.uid == LOCAL->uid) i = elt->private.msg.text.text.size; else { /* not cached, cache it now */ LOCAL->uid = elt->private.uid; /* find header position */ i = tenex_hdrpos (stream,msgno,&j); /* go to text position */ lseek (LOCAL->fd,i + j,L_SET); s = (char *) fs_get ((i = tenex_size (stream,msgno) - j) + 1); s[i] = '\0'; /* tie off string */ read (LOCAL->fd,s,i); /* slurp the data */ /* make CRLF copy of string */ i = elt->private.msg.text.text.size = strcrlfcpy (&LOCAL->text.data,&LOCAL->text.size,s,i); fs_give ((void **) &s); /* free readin buffer */ } /* set up stringstruct */ INIT (bs,mail_string,LOCAL->text.data,i); } return T; /* success */ } /* Tenex mail modify flags * Accepts: MAIL stream * sequence * flag(s) * option flags */ void tenex_flag (MAILSTREAM *stream,char *sequence,char *flag,long flags) { struct utimbuf times; struct stat sbuf; if (!stream->rdonly) { /* make sure the update takes */ fsync (LOCAL->fd); fstat (LOCAL->fd,&sbuf); /* get current write time */ times.modtime = LOCAL->filetime = sbuf.st_mtime; times.actime = time (0); /* make sure read comes after all that */ utime (stream->mailbox,×); } } /* Tenex mail per-message modify flags * Accepts: MAIL stream * message cache element */ void tenex_flagmsg (MAILSTREAM *stream,MESSAGECACHE *elt) { struct stat sbuf; /* maybe need to do a checkpoint? */ if (LOCAL->filetime && !LOCAL->shouldcheck) { fstat (LOCAL->fd,&sbuf); /* get current write time */ if (LOCAL->filetime < sbuf.st_mtime) LOCAL->shouldcheck = T; LOCAL->filetime = 0; /* don't do this test for any other messages */ } /* recalculate status */ tenex_update_status (stream,elt->msgno,NIL); } /* Tenex mail ping mailbox * Accepts: MAIL stream * Returns: T if stream still alive, NIL if not */ long tenex_ping (MAILSTREAM *stream) { unsigned long i = 1; long r = T; int ld; char lock[MAILTMPLEN]; struct stat sbuf; if (stream && LOCAL) { /* only if stream already open */ fstat (LOCAL->fd,&sbuf); /* get current file poop */ if (LOCAL->filetime && !(LOCAL->mustcheck || LOCAL->shouldcheck) && (LOCAL->filetime < sbuf.st_mtime)) LOCAL->shouldcheck = T; /* check for changed message status */ if (LOCAL->mustcheck || LOCAL->shouldcheck) { LOCAL->filetime = sbuf.st_mtime; if (LOCAL->shouldcheck) /* babble when we do this unilaterally */ mm_notify (stream,"[CHECK] Checking for flag updates",NIL); while (i <= stream->nmsgs) tenex_elt (stream,i++); LOCAL->mustcheck = LOCAL->shouldcheck = NIL; } /* get shared parse/append permission */ if ((sbuf.st_size != LOCAL->filesize) && ((ld = lockname (lock,stream->mailbox,LOCK_SH)) >= 0)) { /* parse resulting mailbox */ r = (tenex_parse (stream)) ? T : NIL; unlockfd (ld,lock); /* release shared parse/append permission */ } } return r; /* return result of the parse */ } /* Tenex mail check mailbox (reparses status too) * Accepts: MAIL stream */ void tenex_check (MAILSTREAM *stream) { /* mark that a check is desired */ if (LOCAL) LOCAL->mustcheck = T; if (tenex_ping (stream)) mm_log ("Check completed",(long) NIL); } /* Tenex mail expunge mailbox * sequence to expunge if non-NIL * expunge options * Returns: T, always */ long tenex_expunge (MAILSTREAM *stream,char *sequence,long options) { long ret; struct utimbuf times; struct stat sbuf; off_t pos = 0; int ld; unsigned long i = 1; unsigned long j,k,m,recent; unsigned long n = 0; unsigned long delta = 0; char lock[MAILTMPLEN]; MESSAGECACHE *elt; if (!(ret = (sequence ? ((options & EX_UID) ? mail_uid_sequence (stream,sequence) : mail_sequence (stream,sequence)) : LONGT) && tenex_ping (stream))); /* parse sequence if given, ping stream */ else if (stream->rdonly) mm_log ("Expunge ignored on readonly mailbox",WARN); else { if (LOCAL->filetime && !LOCAL->shouldcheck) { fstat (LOCAL->fd,&sbuf); /* get current write time */ if (LOCAL->filetime < sbuf.st_mtime) LOCAL->shouldcheck = T; } /* get exclusive access */ if ((ld = lockname (lock,stream->mailbox,LOCK_EX)) < 0) mm_log ("Unable to lock expunge mailbox",ERROR); /* make sure see any newly-arrived messages */ else if (!tenex_parse (stream)); /* get exclusive access */ else if (flock (LOCAL->fd,LOCK_EX|LOCK_NB)) { flock (LOCAL->fd,LOCK_SH);/* recover previous lock */ mm_log ("Can't expunge because mailbox is in use by another process", ERROR); unlockfd (ld,lock); /* release exclusive parse/append permission */ } else { mm_critical (stream); /* go critical */ recent = stream->recent; /* get recent now that pinged and locked */ /* for each message */ while (i <= stream->nmsgs) { /* get cache element */ elt = tenex_elt (stream,i); /* number of bytes to smash or preserve */ k = elt->private.special.text.size + tenex_size (stream,i); /* if need to expunge this message */ if (elt->deleted && (sequence ? elt->sequence : T)) { /* if recent, note one less recent message */ if (elt->recent) --recent; delta += k; /* number of bytes to delete */ /* notify upper levels */ mail_expunged (stream,i); n++; /* count up one more expunged message */ } else if (i++ && delta) {/* preserved message */ /* first byte to preserve */ j = elt->private.special.offset; do { /* read from source position */ m = min (k,LOCAL->buflen); lseek (LOCAL->fd,j,L_SET); read (LOCAL->fd,LOCAL->buf,m); pos = j - delta; /* write to destination position */ while (T) { lseek (LOCAL->fd,pos,L_SET); if (write (LOCAL->fd,LOCAL->buf,m) > 0) break; mm_notify (stream,strerror (errno),WARN); mm_diskerror (stream,errno,T); } pos += m; /* new position */ j += m; /* next chunk, perhaps */ } while (k -= m); /* until done */ /* note the new address of this text */ elt->private.special.offset -= delta; } /* preserved but no deleted messages */ else pos = elt->private.special.offset + k; } if (n) { /* truncate file after last message */ if (pos != (LOCAL->filesize -= delta)) { sprintf (LOCAL->buf, "Calculated size mismatch %lu != %lu, delta = %lu", (unsigned long) pos,(unsigned long) LOCAL->filesize,delta); mm_log (LOCAL->buf,WARN); LOCAL->filesize = pos;/* fix it then */ } ftruncate (LOCAL->fd,LOCAL->filesize); sprintf (LOCAL->buf,"Expunged %lu messages",n); /* output the news */ mm_log (LOCAL->buf,(long) NIL); } else mm_log ("No messages deleted, so no update needed",(long) NIL); fsync (LOCAL->fd); /* force disk update */ fstat (LOCAL->fd,&sbuf); /* get new write time */ times.modtime = LOCAL->filetime = sbuf.st_mtime; times.actime = time (0); /* reset atime to now */ utime (stream->mailbox,×); mm_nocritical (stream); /* release critical */ /* notify upper level of new mailbox size */ mail_exists (stream,stream->nmsgs); mail_recent (stream,recent); flock (LOCAL->fd,LOCK_SH);/* allow sharers again */ unlockfd (ld,lock); /* release exclusive parse/append permission */ } } return ret; } /* Tenex mail copy message(s) * Accepts: MAIL stream * sequence * destination mailbox * copy options * Returns: T if success, NIL if failed */ long tenex_copy (MAILSTREAM *stream,char *sequence,char *mailbox,long options) { struct stat sbuf; struct utimbuf times; MESSAGECACHE *elt; unsigned long i,j,k; long ret = LONGT; int fd,ld; char file[MAILTMPLEN],lock[MAILTMPLEN]; mailproxycopy_t pc = (mailproxycopy_t) mail_parameters (stream,GET_MAILPROXYCOPY,NIL); /* make sure valid mailbox */ if (!tenex_isvalid (mailbox,file)) switch (errno) { case ENOENT: /* no such file? */ mm_notify (stream,"[TRYCREATE] Must create mailbox before copy",NIL); return NIL; case 0: /* merely empty file? */ break; case EACCES: /* file protected */ sprintf (LOCAL->buf,"Can't access destination: %.80s",mailbox); MM_LOG (LOCAL->buf,ERROR); return NIL; case EINVAL: if (pc) return (*pc) (stream,sequence,mailbox,options); sprintf (LOCAL->buf,"Invalid Tenex-format mailbox name: %.80s",mailbox); mm_log (LOCAL->buf,ERROR); return NIL; default: if (pc) return (*pc) (stream,sequence,mailbox,options); sprintf (LOCAL->buf,"Not a Tenex-format mailbox: %.80s",mailbox); mm_log (LOCAL->buf,ERROR); return NIL; } if (!((options & CP_UID) ? mail_uid_sequence (stream,sequence) : mail_sequence (stream,sequence))) return NIL; /* got file? */ if ((fd = open (file,O_BINARY|O_RDWR|O_CREAT,S_IREAD|S_IWRITE)) < 0) { sprintf (LOCAL->buf,"Unable to open copy mailbox: %.80s",strerror (errno)); mm_log (LOCAL->buf,ERROR); return NIL; } mm_critical (stream); /* go critical */ /* get exclusive parse/append permission */ if (flock (fd,LOCK_SH) || ((ld = lockname (lock,file,LOCK_EX)) < 0)) { mm_log ("Unable to lock copy mailbox",ERROR); mm_nocritical (stream); return NIL; } fstat (fd,&sbuf); /* get current file size */ lseek (fd,sbuf.st_size,L_SET);/* move to end of file */ /* for each requested message */ for (i = 1; ret && (i <= stream->nmsgs); i++) if ((elt = mail_elt (stream,i))->sequence) { lseek (LOCAL->fd,elt->private.special.offset,L_SET); /* number of bytes to copy */ k = elt->private.special.text.size + tenex_size (stream,i); do { /* read from source position */ j = min (k,LOCAL->buflen); read (LOCAL->fd,LOCAL->buf,j); if (write (fd,LOCAL->buf,j) < 0) ret = NIL; } while (ret && (k -= j));/* until done */ } /* delete all requested messages */ if (ret && (options & CP_MOVE)) { sprintf (LOCAL->buf,"Unable to write message: %s",strerror (errno)); mm_log (LOCAL->buf,ERROR); ftruncate (fd,sbuf.st_size); } /* set atime to now-1 if successful copy */ if (ret) times.actime = time (0) - 1; /* else preserved \Marked status */ else times.actime = (sbuf.st_ctime > sbuf.st_atime) ? sbuf.st_atime : time (0); times.modtime = sbuf.st_mtime;/* preserve mtime */ utime (file,×); /* set the times */ unlockfd (ld,lock); /* release exclusive parse/append permission */ close (fd); /* close the file */ mm_nocritical (stream); /* release critical */ /* delete all requested messages */ if (ret && (options & CP_MOVE)) { for (i = 1; i <= stream->nmsgs; i++) if ((elt = tenex_elt (stream,i))->sequence) { elt->deleted = T; /* mark message deleted */ /* recalculate status */ tenex_update_status (stream,i,NIL); } if (!stream->rdonly) { /* make sure the update takes */ fsync (LOCAL->fd); fstat (LOCAL->fd,&sbuf); /* get current write time */ times.modtime = LOCAL->filetime = sbuf.st_mtime; times.actime = time (0); /* make sure atime remains greater */ utime (stream->mailbox,×); } } if (ret && mail_parameters (NIL,GET_COPYUID,NIL)) mm_log ("Can not return meaningful COPYUID with this mailbox format",WARN); return ret; } /* Tenex mail append message from stringstruct * Accepts: MAIL stream * destination mailbox * append callback * data for callback * Returns: T if append successful, else NIL */ long tenex_append (MAILSTREAM *stream,char *mailbox,append_t af,void *data) { struct stat sbuf; int fd,ld,c; char *flags,*date,tmp[MAILTMPLEN],file[MAILTMPLEN],lock[MAILTMPLEN]; struct utimbuf times; FILE *df; MESSAGECACHE elt; long f; unsigned long i,j,uf,size; STRING *message; long ret = LONGT; /* default stream to prototype */ if (!stream) stream = &tenexproto; /* make sure valid mailbox */ if (!tenex_isvalid (mailbox,file)) switch (errno) { case ENOENT: /* no such file? */ if (!compare_cstring (mailbox,"INBOX")) tenex_create (NIL,"INBOX"); else { mm_notify (stream,"[TRYCREATE] Must create mailbox before append",NIL); return NIL; } /* falls through */ case 0: /* merely empty file? */ break; case EACCES: /* file protected */ sprintf (tmp,"Can't access destination: %.80s",mailbox); MM_LOG (tmp,ERROR); return NIL; case EINVAL: sprintf (tmp,"Invalid TENEX-format mailbox name: %.80s",mailbox); mm_log (tmp,ERROR); return NIL; default: sprintf (tmp,"Not a TENEX-format mailbox: %.80s",mailbox); mm_log (tmp,ERROR); return NIL; } /* get first message */ if (!(*af) (stream,data,&flags,&date,&message)) return NIL; /* open destination mailbox */ if (((fd = open (file,O_BINARY|O_WRONLY|O_APPEND|O_CREAT,S_IREAD|S_IWRITE)) < 0) || !(df = fdopen (fd,"ab"))) { sprintf (tmp,"Can't open append mailbox: %s",strerror (errno)); mm_log (tmp,ERROR); return NIL; } /* get parse/append permission */ if (flock (fd,LOCK_SH) || ((ld = lockname (lock,file,LOCK_EX)) < 0)) { mm_log ("Unable to lock append mailbox",ERROR); close (fd); return NIL; } mm_critical (stream); /* go critical */ fstat (fd,&sbuf); /* get current file size */ errno = 0; do { /* parse flags */ if (!SIZE (message)) { /* guard against zero-length */ mm_log ("Append of zero-length message",ERROR); ret = NIL; break; } f = mail_parse_flags (stream,flags,&i); /* reverse bits (dontcha wish we had CIRC?) */ for (uf = 0; i; uf |= 1 << (29 - find_rightmost_bit (&i))); if (date) { /* parse date if given */ if (!mail_parse_date (&elt,date)) { sprintf (tmp,"Bad date in append: %.80s",date); mm_log (tmp,ERROR); ret = NIL; /* mark failure */ break; } mail_date (tmp,&elt); /* write preseved date */ } else internal_date (tmp); /* get current date in IMAP format */ i = GETPOS (message); /* remember current position */ for (j = SIZE (message), size = 0; j; --j) if (SNX (message) != '\015') ++size; SETPOS (message,i); /* restore position */ /* write header */ if (fprintf (df,"%s,%lu;%010lo%02lo\n",tmp,size,uf,(unsigned long) f) < 0) ret = NIL; else { /* write message */ while (size) if ((c = 0xff & SNX (message)) != '\015') { if (putc (c,df) != EOF) --size; else break; } /* get next message */ if (size || !(*af) (stream,data,&flags,&date,&message)) ret = NIL; } } while (ret && message); /* if error... */ if (!ret || (fflush (df) == EOF)) { ftruncate (fd,sbuf.st_size);/* revert file */ close (fd); /* make sure fclose() doesn't corrupt us */ if (errno) { sprintf (tmp,"Message append failed: %s",strerror (errno)); mm_log (tmp,ERROR); } ret = NIL; } if (ret) times.actime = time (0) - 1; /* else preserved \Marked status */ else times.actime = (sbuf.st_ctime > sbuf.st_atime) ? sbuf.st_atime : time (0); times.modtime = sbuf.st_mtime;/* preserve mtime */ utime (file,×); /* set the times */ fclose (df); /* close the file */ unlockfd (ld,lock); /* release exclusive parse/append permission */ mm_nocritical (stream); /* release critical */ if (ret && mail_parameters (NIL,GET_APPENDUID,NIL)) mm_log ("Can not return meaningful APPENDUID with this mailbox format", WARN); return ret; } /* Internal routines */ /* Tenex mail return internal message size in bytes * Accepts: MAIL stream * message # * Returns: internal size of message */ unsigned long tenex_size (MAILSTREAM *stream,unsigned long m) { MESSAGECACHE *elt = mail_elt (stream,m); return ((m < stream->nmsgs) ? mail_elt (stream,m+1)->private.special.offset : LOCAL->filesize) - (elt->private.special.offset + elt->private.special.text.size); } /* Tenex mail parse mailbox * Accepts: MAIL stream * Returns: T if parse OK * NIL if failure, stream aborted */ long tenex_parse (MAILSTREAM *stream) { struct stat sbuf; MESSAGECACHE *elt = NIL; unsigned char c,*s,*t,*x; char tmp[MAILTMPLEN]; unsigned long i,j; long curpos = LOCAL->filesize; long nmsgs = stream->nmsgs; long recent = stream->recent; short added = NIL; short silent = stream->silent; fstat (LOCAL->fd,&sbuf); /* get status */ if (sbuf.st_size < curpos) { /* sanity check */ sprintf (tmp,"Mailbox shrank from %ld to %ld!",curpos,sbuf.st_size); mm_log (tmp,ERROR); tenex_close (stream,NIL); return NIL; } stream->silent = T; /* don't pass up mm_exists() events yet */ while (sbuf.st_size - curpos){/* while there is stuff to parse */ /* get to that position in the file */ lseek (LOCAL->fd,curpos,L_SET); if ((i = read (LOCAL->fd,LOCAL->buf,64)) <= 0) { sprintf (tmp,"Unable to read internal header at %lu, size = %lu: %s", (unsigned long) curpos,(unsigned long) sbuf.st_size, i ? strerror (errno) : "no data read"); mm_log (tmp,ERROR); tenex_close (stream,NIL); return NIL; } LOCAL->buf[i] = '\0'; /* tie off buffer just in case */ if (!(s = strchr (LOCAL->buf,'\012'))) { sprintf (tmp,"Unable to find newline at %lu in %lu bytes, text: %s", (unsigned long) curpos,i,(char *) LOCAL->buf); mm_log (tmp,ERROR); tenex_close (stream,NIL); return NIL; } *s = '\0'; /* tie off header line */ i = (s + 1) - LOCAL->buf; /* note start of text offset */ if (!((s = strchr (LOCAL->buf,',')) && (t = strchr (s+1,';')))) { sprintf (tmp,"Unable to parse internal header at %lu: %s", (unsigned long) curpos,(char *) LOCAL->buf); mm_log (tmp,ERROR); tenex_close (stream,NIL); return NIL; } *s++ = '\0'; *t++ = '\0'; /* tie off fields */ added = T; /* note that a new message was added */ /* swell the cache */ mail_exists (stream,++nmsgs); /* instantiate an elt for this message */ (elt = mail_elt (stream,nmsgs))->valid = T; elt->private.uid = ++stream->uid_last; /* note file offset of header */ elt->private.special.offset = curpos; /* in case error */ elt->private.special.text.size = 0; /* header size not known yet */ elt->private.msg.header.text.size = 0; x = s; /* parse the header components */ if (mail_parse_date (elt,LOCAL->buf) && (elt->private.msg.full.text.size = strtoul (s,(char **) &s,10)) && (!(s && *s)) && isdigit (t[0]) && isdigit (t[1]) && isdigit (t[2]) && isdigit (t[3]) && isdigit (t[4]) && isdigit (t[5]) && isdigit (t[6]) && isdigit (t[7]) && isdigit (t[8]) && isdigit (t[9]) && isdigit (t[10]) && isdigit (t[11]) && !t[12]) elt->private.special.text.size = i; else { /* oops */ sprintf (tmp,"Unable to parse internal header elements at %ld: %s,%s;%s", curpos,(char *) LOCAL->buf,(char *) x,(char *) t); mm_log (tmp,ERROR); tenex_close (stream,NIL); return NIL; } /* make sure didn't run off end of file */ if ((curpos += (elt->private.msg.full.text.size + i)) > sbuf.st_size) { sprintf (tmp,"Last message (at %lu) runs past end of file (%lu > %lu)", elt->private.special.offset,(unsigned long) curpos, (unsigned long) sbuf.st_size); mm_log (tmp,ERROR); tenex_close (stream,NIL); return NIL; } c = t[10]; /* remember first system flags byte */ t[10] = '\0'; /* tie off flags */ j = strtoul (t,NIL,8); /* get user flags value */ t[10] = c; /* restore first system flags byte */ /* set up all valid user flags (reversed!) */ while (j) if (((i = 29 - find_rightmost_bit (&j)) < NUSERFLAGS) && stream->user_flags[i]) elt->user_flags |= 1 << i; /* calculate system flags */ if ((j = ((t[10]-'0') * 8) + t[11]-'0') & fSEEN) elt->seen = T; if (j & fDELETED) elt->deleted = T; if (j & fFLAGGED) elt->flagged = T; if (j & fANSWERED) elt->answered = T; if (j & fDRAFT) elt->draft = T; if (!(j & fOLD)) { /* newly arrived message? */ elt->recent = T; recent++; /* count up a new recent message */ /* mark it as old */ tenex_update_status (stream,nmsgs,NIL); } } fsync (LOCAL->fd); /* make sure all the fOLD flags take */ /* update parsed file size and time */ LOCAL->filesize = sbuf.st_size; fstat (LOCAL->fd,&sbuf); /* get status again to ensure time is right */ LOCAL->filetime = sbuf.st_mtime; if (added && !stream->rdonly){/* make sure atime updated */ struct utimbuf times; times.actime = time (0); times.modtime = LOCAL->filetime; utime (stream->mailbox,×); } stream->silent = silent; /* can pass up events now */ mail_exists (stream,nmsgs); /* notify upper level of new mailbox size */ mail_recent (stream,recent); /* and of change in recent messages */ return LONGT; /* return the winnage */ } /* Tenex get cache element with status updating from file * Accepts: MAIL stream * message number * Returns: cache element */ MESSAGECACHE *tenex_elt (MAILSTREAM *stream,unsigned long msgno) { MESSAGECACHE *elt = mail_elt (stream,msgno); struct { /* old flags */ unsigned int seen : 1; unsigned int deleted : 1; unsigned int flagged : 1; unsigned int answered : 1; unsigned int draft : 1; unsigned long user_flags; } old; old.seen = elt->seen; old.deleted = elt->deleted; old.flagged = elt->flagged; old.answered = elt->answered; old.draft = elt->draft; old.user_flags = elt->user_flags; tenex_read_flags (stream,elt); if ((old.seen != elt->seen) || (old.deleted != elt->deleted) || (old.flagged != elt->flagged) || (old.answered != elt->answered) || (old.draft != elt->draft) || (old.user_flags != elt->user_flags)) mm_flags (stream,msgno); /* let top level know */ return elt; } /* Tenex read flags from file * Accepts: MAIL stream * Returns: cache element */ void tenex_read_flags (MAILSTREAM *stream,MESSAGECACHE *elt) { unsigned long i,j; /* noop if readonly and have valid flags */ if (stream->rdonly && elt->valid) return; /* set the seek pointer */ lseek (LOCAL->fd,(off_t) elt->private.special.offset + elt->private.special.text.size - 13,L_SET); /* read the new flags */ if (read (LOCAL->fd,LOCAL->buf,12) < 0) { sprintf (LOCAL->buf,"Unable to read new status: %s",strerror (errno)); fatal (LOCAL->buf); } /* calculate system flags */ i = (((LOCAL->buf[10]-'0') * 8) + LOCAL->buf[11]-'0'); elt->seen = i & fSEEN ? T : NIL; elt->deleted = i & fDELETED ? T : NIL; elt->flagged = i & fFLAGGED ? T : NIL; elt->answered = i & fANSWERED ? T : NIL; elt->draft = i & fDRAFT ? T : NIL; LOCAL->buf[10] = '\0'; /* tie off flags */ j = strtoul(LOCAL->buf,NIL,8);/* get user flags value */ /* set up all valid user flags (reversed!) */ while (j) if (((i = 29 - find_rightmost_bit (&j)) < NUSERFLAGS) && stream->user_flags[i]) elt->user_flags |= 1 << i; elt->valid = T; /* have valid flags now */ } /* Tenex update status string * Accepts: MAIL stream * message number * flag saying whether or not to sync */ void tenex_update_status (MAILSTREAM *stream,unsigned long msgno,long syncflag) { struct utimbuf times; struct stat sbuf; MESSAGECACHE *elt = mail_elt (stream,msgno); unsigned long j,k = 0; /* readonly */ if (stream->rdonly || !elt->valid) tenex_read_flags (stream,elt); else { /* readwrite */ j = elt->user_flags; /* get user flags */ /* reverse bits (dontcha wish we had CIRC?) */ while (j) k |= 1 << (29 - find_rightmost_bit (&j)); /* print new flag string */ sprintf (LOCAL->buf,"%010lo%02o",k,(unsigned) (fOLD + (fSEEN * elt->seen) + (fDELETED * elt->deleted) + (fFLAGGED * elt->flagged) + (fANSWERED * elt->answered) + (fDRAFT * elt->draft))); while (T) { /* get to that place in the file */ lseek (LOCAL->fd,(off_t) elt->private.special.offset + elt->private.special.text.size - 13,L_SET); /* write new flags */ if (write (LOCAL->fd,LOCAL->buf,12) > 0) break; mm_notify (stream,strerror (errno),WARN); mm_diskerror (stream,errno,T); } if (syncflag) { /* sync if requested */ fsync (LOCAL->fd); fstat (LOCAL->fd,&sbuf); /* get new write time */ times.modtime = LOCAL->filetime = sbuf.st_mtime; times.actime = time (0); /* make sure read is later */ utime (stream->mailbox,×); } } } /* Tenex locate header for a message * Accepts: MAIL stream * message number * pointer to returned header size * Returns: position of header in file */ unsigned long tenex_hdrpos (MAILSTREAM *stream,unsigned long msgno, unsigned long *size) { unsigned long siz; long i = 0; char c = '\0'; char *s = NIL; MESSAGECACHE *elt = tenex_elt (stream,msgno); unsigned long ret = elt->private.special.offset + elt->private.special.text.size; unsigned long msiz = tenex_size (stream,msgno); /* is header size known? */ if (!(*size = elt->private.msg.header.text.size)) { lseek (LOCAL->fd,ret,L_SET);/* get to header position */ /* search message for LF LF */ for (siz = 0; siz < msiz; siz++) { if (--i <= 0) /* read another buffer as necessary */ read (LOCAL->fd,s = LOCAL->buf,i = min (msiz-siz,(long) MAILTMPLEN)); /* two newline sequence? */ if ((c == '\012') && (*s == '\012')) { /* yes, note for later */ elt->private.msg.header.text.size = (*size = siz + 1); return ret; /* return to caller */ } else c = *s++; /* next character */ } /* header consumes entire message */ elt->private.msg.header.text.size = *size = msiz; } return ret; } alpine-2.10+dfsg/imap/src/osdep/nt/ssl_none.c0000600000175000017500000000511011512502123022564 0ustar paulproteuspaulproteus/* ======================================================================== * Copyright 1988-2006 University of Washington * * Licensed under the Apache License, Version 2.0 (the "License"); * you may not use this file except in compliance with the License. * You may obtain a copy of the License at * * http://www.apache.org/licenses/LICENSE-2.0 * * * ======================================================================== */ /* * Program: Dummy (no SSL) authentication/encryption module * * Author: Mark Crispin * Networks and Distributed Computing * Computing & Communications * University of Washington * Administration Building, AG-44 * Seattle, WA 98195 * Internet: MRC@CAC.Washington.EDU * * Date: 7 February 2001 * Last Edited: 30 August 2006 */ /* Init server for SSL * Accepts: server name */ void ssl_server_init (char *server) { syslog (LOG_ERR,"This server does not support SSL"); exit (1); /* punt this program too */ } /* Start TLS * Accepts: /etc/services service name * Returns: cpystr'd error string if TLS failed, else NIL for success */ char *ssl_start_tls (char *server) { return cpystr ("This server does not support TLS"); } /* Get character * Returns: character or EOF */ int PBIN (void) { return getchar (); } /* Get string * Accepts: destination string pointer * number of bytes available * Returns: destination string pointer or NIL if EOF */ char *PSIN (char *s,int n) { return fgets (s,n,stdin); } /* Get record * Accepts: destination string pointer * number of bytes to read * Returns: T if success, NIL otherwise */ long PSINR (char *s,unsigned long n) { unsigned long i; while (n && ((i = fread (s,1,n,stdin)) || (errno == EINTR))) s += i,n -= i; return n ? NIL : LONGT; } /* Wait for input * Accepts: timeout in seconds * Returns: T if have input on stdin, else NIL */ long INWAIT (long seconds) { return server_input_wait (seconds); } /* Put character * Accepts: character * Returns: character written or EOF */ int PBOUT (int c) { return putchar (c); } /* Put string * Accepts: source string pointer * Returns: 0 or EOF if error */ int PSOUT (char *s) { return fputs (s,stdout); } /* Put record * Accepts: source sized text * Returns: 0 or EOF if error */ int PSOUTR (SIZEDTEXT *s) { unsigned char *t; unsigned long i,j; for (t = s->data,i = s->size; (i && ((j = fwrite (t,1,i,stdout)) || (errno == EINTR))); t += j,i -= j); return i ? EOF : NIL; } /* Flush output * Returns: 0 or EOF if error */ int PFLUSH (void) { return fflush (stdout); } alpine-2.10+dfsg/imap/src/mlock/0000700000175000017500000000000011512502151020154 5ustar paulproteuspaulproteusalpine-2.10+dfsg/imap/src/mlock/Makefile0000600000175000017500000000212111512502122021610 0ustar paulproteuspaulproteus# ======================================================================== # Copyright 1988-2006 University of Washington # # Licensed under the Apache License, Version 2.0 (the "License"); # you may not use this file except in compliance with the License. # You may obtain a copy of the License at # # http://www.apache.org/licenses/LICENSE-2.0 # # # ======================================================================== # Program: MLOCK Makefile # # Author: Mark Crispin # Networks and Distributed Computing # Computing & Communications # University of Washington # Administration Building, AG-44 # Seattle, WA 98195 # Internet: MRC@CAC.Washington.EDU # # Date: 8 February 1999 # Last Edited: 30 August 2006 C = ../c-client SHELL = /bin/sh # Get local definitions from c-client directory CC = `cat $C/CCTYPE` CFLAGS = `cat $C/CFLAGS` all: mlock mlock: mlock.o $(CC) $(CFLAGS) -o mlock mlock.o install: mlock chgrp mail mlock chmod 3711 mlock cp -p mlock /etc/mlock clean: rm -f *.o mlock || true # A monument to a hack of long ago and far away... love: @echo 'not war?' alpine-2.10+dfsg/imap/src/mlock/mlock.c0000600000175000017500000001345711512502122021437 0ustar paulproteuspaulproteus/* ======================================================================== * Copyright 1988-2008 University of Washington * * Licensed under the Apache License, Version 2.0 (the "License"); * you may not use this file except in compliance with the License. * You may obtain a copy of the License at * * http://www.apache.org/licenses/LICENSE-2.0 * * * ======================================================================== */ /* * Program: Standalone Mailbox Lock program * * Author: Mark Crispin * Networks and Distributed Computing * Computing & Communications * University of Washington * Administration Building, AG-44 * Seattle, WA 98195 * Internet: MRC@CAC.Washington.EDU * * Date: 8 February 1999 * Last Edited: 3 March 2008 */ #include #include #include #include #include #include #include #include #include #include #include #include #include #include #define LOCKTIMEOUT 5 /* lock timeout in minutes */ #define LOCKPROTECTION 0664 #ifndef MAXHOSTNAMELEN /* Solaris still sucks */ #define MAXHOSTNAMELEN 256 #endif /* Fatal error * Accepts: Message string * exit code * Returns: code */ int die (char *msg,int code) { syslog (LOG_NOTICE,"(%u) %s",code,msg); write (1,"?",1); /* indicate "impossible" failure */ return code; } int main (int argc,char *argv[]) { int ld,i; int tries = LOCKTIMEOUT * 60 - 1; char *s,*dir,*file,*lock,*hitch,tmp[1024]; size_t dlen,len; struct stat sb,fsb; struct group *grp = getgrnam ("mail"); /* get syslog */ openlog (argv[0],LOG_PID,LOG_MAIL); if (!grp || (grp->gr_gid != getegid ())) return die ("not setgid mail",EX_USAGE); if (argc != 3) return die ("invalid arguments",EX_USAGE); for (s = argv[1]; *s; s++) if (!isdigit (*s)) return die ("invalid fd",EX_USAGE); /* find directory */ if ((*argv[2] != '/') || !(file = strrchr (argv[2],'/')) || !file[1]) return die ("invalid path",EX_USAGE); /* calculate lengths of directory and file */ if (!(dlen = file - argv[2])) dlen = 1; len = strlen (++file); /* make buffers */ dir = (char *) malloc (dlen + 1); lock = (char *) malloc (len + 6); hitch = (char *) malloc (len + 6 + 40 + MAXHOSTNAMELEN); if (!dir || !lock || !hitch) return die ("malloc failure",errno); strncpy (dir,argv[2],dlen); /* connect to desired directory */ dir[dlen] = '\0'; printf ("dir=%s, file=%s\n",dir,file); chdir (dir); /* get device/inode of file descriptor */ if (fstat (atoi (argv[1]),&fsb)) return die ("fstat failure",errno); /* better be a regular file */ if ((fsb.st_mode & S_IFMT) != S_IFREG) return die ("fd not regular file",EX_USAGE); /* now get device/inode of file */ if (lstat (file,&sb)) return die ("lstat failure",errno); /* does it match? */ if ((sb.st_mode & S_IFMT) != S_IFREG) return die ("name not regular file",EX_USAGE); if ((sb.st_dev != fsb.st_dev) || (sb.st_ino != fsb.st_ino)) return die ("fd and name different",EX_USAGE); /* build lock filename */ sprintf (lock,"%s.lock",file); if (!lstat (lock,&sb) && ((sb.st_mode & S_IFMT) != S_IFREG)) return die ("existing lock not regular file",EX_NOPERM); do { /* until OK or out of tries */ if (!stat (lock,&sb) && (time (0) > (sb.st_ctime + LOCKTIMEOUT * 60))) unlink (lock); /* time out lock if enough time has passed */ /* SUN-OS had an NFS * As kludgy as an albatross; * And everywhere that it was installed, * It was a total loss. * -- MRC 9/25/91 */ /* build hitching post file name */ sprintf (hitch,"%s.%lu.%lu.",lock,(unsigned long) time (0), (unsigned long) getpid ()); len = strlen (hitch); /* append local host name */ gethostname (hitch + len,MAXHOSTNAMELEN); /* try to get hitching-post file */ if ((ld = open (hitch,O_WRONLY|O_CREAT|O_EXCL,LOCKPROTECTION)) >= 0) { /* make sure others can break the lock */ chmod (hitch,LOCKPROTECTION); /* get device/inode of hitch file */ if (fstat (ld,&fsb)) return die ("hitch fstat failure",errno); close (ld); /* close the hitching-post */ /* Note: link() may return an error even if it actually succeeded. So we * always check for success via the link count, and ignore the error if * the link count is right. */ /* tie hitching-post to lock */ i = link (hitch,lock) ? errno : 0; /* success if link count now 2 */ if (stat (hitch,&sb) || (sb.st_nlink != 2) || (fsb.st_dev != sb.st_dev) || (fsb.st_ino != sb.st_ino)) { ld = -1; /* failed to hitch */ if (i == EPERM) { /* was it because links not allowed? */ /* Probably a FAT filesystem on Linux. It can't be NFS, so try * creating the lock file directly. */ if ((ld = open (lock,O_WRONLY|O_CREAT|O_EXCL,LOCKPROTECTION)) >= 0) { /* get device/inode of lock file */ if (fstat (ld,&fsb)) return die ("lock fstat failure",errno); close (ld); /* close the file */ } /* give up immediately if protection failure */ else if (errno != EEXIST) tries = 0; } } unlink (hitch); /* flush hitching post */ } /* give up immediately if protection failure */ else if (errno == EACCES) tries = 0; if (ld < 0) { /* lock failed */ if (tries--) sleep (1); /* sleep 1 second and try again */ else { write (1,"-",1); /* hard failure */ return EX_CANTCREAT; } } } while (ld < 0); write (1,"+",1); /* indicate that all is well */ read (0,tmp,1); /* read continue signal from parent */ /* flush the lock file */ if (!stat (lock,&sb) && (fsb.st_dev == sb.st_dev) && (fsb.st_ino == sb.st_ino)) unlink (lock); else syslog (LOG_NOTICE,"lock file %s/%s changed dev/inode",dir,lock); return EX_OK; } alpine-2.10+dfsg/imap/src/imapd/0000700000175000017500000000000011512502152020142 5ustar paulproteuspaulproteusalpine-2.10+dfsg/imap/src/imapd/makefile.ntk0000600000175000017500000000315611512502123022442 0ustar paulproteuspaulproteus# ======================================================================== # Copyright 1988-2006 University of Washington # # Licensed under the Apache License, Version 2.0 (the "License"); # you may not use this file except in compliance with the License. # You may obtain a copy of the License at # # http://www.apache.org/licenses/LICENSE-2.0 # # # ======================================================================== # Program: IMAPD Makefile for Windows 9x and Windows NT + Kerberos # # Author: Mark Crispin # Networks and Distributed Computing # Computing & Communications # University of Washington # Administration Building, AG-44 # Seattle, WA 98195 # Internet: MRC@CAC.Washington.EDU # # Date: 5 November 1990 # Last Edited: 30 August 2006 ALERT=\\imapd.alert USERALERT=alert.txt SHUTDOWN=\\nologin ANO=\\anonymous.newsgroups NNTP=\\imapd.nntp C = ..\c-client CCLIENTLIB = $C\cclient.lib K5 = \k5\lib K5LIB = $(K5)\comerr32.lib $(K5)\gssapi32.lib $(K5)\krb5_32.lib LIBS = $(CCLIENTLIB) $(K5LIB) ws2_32.lib winmm.lib advapi32.lib OSCOMPAT = /DWIN32 /D_WIN32_WINNT=0x0400 VSCOMPAT = /D_CRT_SECURE_NO_DEPRECATE /D_CRT_NONSTDC_NO_DEPRECATE CFLAGS= -I$C /MT /W3 $(OSCOMPAT) $(VSCOMPAT) -nologo $(EXTRACFLAGS) -DALERTFILE=\"$(ALERT)\" -DNNTPFILE=\"$(NNTP)\" -DUSERALERTFILE=\"$(USERALERT)\" -DANOFILE=\"$(ANO)\" -DSHUTDOWNFILE=\"$(SHUTDOWN)\" imapd: $(CCLIENTLIB) imapd.obj LINK /NOLOGO imapd.obj $(LIBS) imapd.obj: $C\mail.h $C\misc.h $C\osdep.h $(CCLIENTLIB): @echo Make c-client first false clean: del *.obj *.exe *.lib *.exp || rem # A monument to a hack of long ago and far away... love: @echo not war? alpine-2.10+dfsg/imap/src/imapd/Makefile0000600000175000017500000000337411512502123021611 0ustar paulproteuspaulproteus# ======================================================================== # Copyright 1988-2006 University of Washington # # Licensed under the Apache License, Version 2.0 (the "License"); # you may not use this file except in compliance with the License. # You may obtain a copy of the License at # # http://www.apache.org/licenses/LICENSE-2.0 # # # ======================================================================== # Program: IMAPD Makefile # # Author: Mark Crispin # Networks and Distributed Computing # Computing & Communications # University of Washington # Administration Building, AG-44 # Seattle, WA 98195 # Internet: MRC@CAC.Washington.EDU # # Date: 5 November 1990 # Last Edited: 30 August 2006 ALERT=/etc/imapd.alert USERALERT=.imapalert SHUTDOWN=/etc/nologin ANO=/etc/anonymous.newsgroups NNTP=/etc/imapd.nntp SHELL= /bin/sh # Un-comment this to get somewhat better interoperability with Netscape. It # causes the "Manage Mail" menu item to open the given URL, e.g. to point to # an alternative IMAP client (e.g. Pine) or perhaps to a homebrew mail # account management page. #NSBD= -DNETSCAPE_BRAIN_DAMAGE=\"http://www.washington.edu/pine\" # Get local definitions from c-client directory C = ../c-client CCLIENTLIB = $C/c-client.a CC = `cat $C/CCTYPE` CFLAGS = -I$C `cat $C/CFLAGS` $(NSBD) $(ENBD) -DANOFILE=\"$(ANO)\" \ -DALERTFILE=\"$(ALERT)\" -DNNTPFILE=\"$(NNTP)\" \ -DUSERALERTFILE=\"$(USERALERT)\" -DSHUTDOWNFILE=\"$(SHUTDOWN)\" LDFLAGS = $(CCLIENTLIB) `cat $C/LDFLAGS` all: imapd imapd: $(CCLIENTLIB) imapd.o $(CC) $(CFLAGS) -o imapd imapd.o $(LDFLAGS) imapd.o: $C/mail.h $C/misc.h $C/osdep.h $(CCLIENTLIB): cd $C;make clean: rm -f *.o imapd || true # A monument to a hack of long ago and far away... love: @echo 'not war?' alpine-2.10+dfsg/imap/src/imapd/imapd.80000600000175000017500000000241511512502123021327 0ustar paulproteuspaulproteus.ig * ======================================================================== * Copyright 1988-2006 University of Washington * * Licensed under the Apache License, Version 2.0 (the "License"); * you may not use this file except in compliance with the License. * You may obtain a copy of the License at * * http://www.apache.org/licenses/LICENSE-2.0 * * * ======================================================================== .. .TH IMAPD 8 "August 30, 2006" .UC 5 .SH NAME IMAPd \- Internet Message Access Protocol server .SH SYNOPSIS .B /usr/etc/imapd .SH DESCRIPTION .I imapd is a server which supports the .B IMAP4rev1 remote mail access protocol as documented in RFC-3501. .I imapd is invoked by the internet server (see .IR inetd (8)), normally for requests to connect to the .B IMAP port as indicated by the .I /etc/services file (see .IR services (5)). Normally, this is port 143 for plaintext IMAP and 993 for SSL IMAP. .PP This daemons contains CRAM-MD5 support. See the md5.txt documentation file for additional information. .PP .I imapd can also be accessed via .IR rsh (1) by many Unix-based clients. To do this, the .I imapd binary must have a link to .I /etc/rimapd since this is where this software expects it to be located. .SH "SEE ALSO" rsh(1) ipopd(8) alpine-2.10+dfsg/imap/src/imapd/makefile.w2k0000600000175000017500000000300411512502123022341 0ustar paulproteuspaulproteus# ======================================================================== # Copyright 1988-2006 University of Washington # # Licensed under the Apache License, Version 2.0 (the "License"); # you may not use this file except in compliance with the License. # You may obtain a copy of the License at # # http://www.apache.org/licenses/LICENSE-2.0 # # # ======================================================================== # Program: IMAPD Makefile for Windows 2000/XP # # Author: Mark Crispin # Networks and Distributed Computing # Computing & Communications # University of Washington # Administration Building, AG-44 # Seattle, WA 98195 # Internet: MRC@CAC.Washington.EDU # # Date: 5 November 1990 # Last Edited: 30 August 2006 ALERT=\\imapd.alert USERALERT=alert.txt SHUTDOWN=\\nologin ANO=\\anonymous.newsgroups NNTP=\\imapd.nntp C = ..\c-client CCLIENTLIB = $C\cclient.lib LIBS = $(CCLIENTLIB) ws2_32.lib winmm.lib advapi32.lib secur32.lib crypt32.lib OSCOMPAT = /DWIN32 VSCOMPAT = /D_CRT_SECURE_NO_DEPRECATE /D_CRT_NONSTDC_NO_DEPRECATE CFLAGS= -I$C /MT /W3 $(OSCOMPAT) $(VSCOMPAT) -nologo $(EXTRACFLAGS) -DALERTFILE=\"$(ALERT)\" -DNNTPFILE=\"$(NNTP)\" -DUSERALERTFILE=\"$(USERALERT)\" -DANOFILE=\"$(ANO)\" -DSHUTDOWNFILE=\"$(SHUTDOWN)\" imapd: $(CCLIENTLIB) imapd.obj LINK /NOLOGO imapd.obj $(LIBS) imapd.obj: $C\mail.h $C\misc.h $C\osdep.h $(CCLIENTLIB): @echo Make c-client first false clean: del *.obj *.exe *.lib *.exp || rem # A monument to a hack of long ago and far away... love: @echo not war? alpine-2.10+dfsg/imap/src/imapd/imapd.c0000600000175000017500000043143311512502123021410 0ustar paulproteuspaulproteus/* ======================================================================== * Copyright 1988-2008 University of Washington * * Licensed under the Apache License, Version 2.0 (the "License"); * you may not use this file except in compliance with the License. * You may obtain a copy of the License at * * http://www.apache.org/licenses/LICENSE-2.0 * * * ======================================================================== */ /* * Program: IMAP4rev1 server * * Author: Mark Crispin * UW Technology * University of Washington * Seattle, WA 98195 * Internet: MRC@Washington.EDU * * Date: 5 November 1990 * Last Edited: 3 March 2008 */ /* Parameter files */ #include #include #include extern int errno; /* just in case */ #include #include #include #include "c-client.h" #include "newsrc.h" #include #define CRLF PSOUT ("\015\012") /* primary output terpri */ /* Timeouts and timers */ #define MINUTES *60 #define LOGINTIMEOUT 3 MINUTES /* not logged in autologout timer */ #define TIMEOUT 30 MINUTES /* RFC 3501 minimum autologout timer */ #define INPUTTIMEOUT 5 MINUTES /* timer for additional command input */ #define ALERTTIMER 1 MINUTES /* alert check timer */ #define SHUTDOWNTIMER 1 MINUTES /* shutdown dally timer */ #define IDLETIMER 1 MINUTES /* IDLE command poll timer */ #define CHECKTIMER 15 MINUTES /* IDLE command last checkpoint timer */ #define LITSTKLEN 20 /* length of literal stack */ #define MAXCLIENTLIT 10000 /* maximum non-APPEND client literal size * must be smaller than 4294967295 */ #define MAXAPPENDTXT 0x40000000 /* maximum APPEND literal size * must be smaller than 4294967295 */ #define CMDLEN 65536 /* size of command buffer */ /* Server states */ #define LOGIN 0 #define SELECT 1 #define OPEN 2 #define LOGOUT 3 /* Body text fetching */ typedef struct text_args { char *section; /* body section */ STRINGLIST *lines; /* header lines */ unsigned long first; /* first octet to fetch */ unsigned long last; /* number of octets to fetch */ long flags; /* fetch flags */ long binary; /* binary flags */ } TEXTARGS; #define FTB_BINARY 0x1 /* fetch as binary */ #define FTB_SIZE 0x2 /* fetch size only */ /* Append data */ typedef struct append_data { unsigned char *arg; /* append argument pointer */ char *flags; /* message flags */ char *date; /* message date */ char *msg; /* message text */ STRING *message; /* message stringstruct */ } APPENDDATA; /* Message pointer */ typedef struct msg_data { MAILSTREAM *stream; /* stream */ unsigned long msgno; /* message number */ char *flags; /* current flags */ char *date; /* current date */ STRING *message; /* stringstruct of message */ } MSGDATA; /* Function prototypes */ int main (int argc,char *argv[]); void ping_mailbox (unsigned long uid); time_t palert (char *file,time_t oldtime); void msg_string_init (STRING *s,void *data,unsigned long size); char msg_string_next (STRING *s); void msg_string_setpos (STRING *s,unsigned long i); void new_flags (MAILSTREAM *stream); void settimeout (unsigned int i); void clkint (void); void kodint (void); void hupint (void); void trmint (void); void staint (void); char *sout (char *s,char *t); char *nout (char *s,unsigned long n,unsigned long base); void slurp (char *s,int n,unsigned long timeout); void inliteral (char *s,unsigned long n); unsigned char *flush (void); void ioerror (FILE *f,char *reason); unsigned char *parse_astring (unsigned char **arg,unsigned long *i, unsigned char *del); unsigned char *snarf (unsigned char **arg); unsigned char *snarf_base64 (unsigned char **arg); unsigned char *snarf_list (unsigned char **arg); STRINGLIST *parse_stringlist (unsigned char **s,int *list); unsigned long uidmax (MAILSTREAM *stream); long parse_criteria (SEARCHPGM *pgm,unsigned char **arg,unsigned long maxmsg, unsigned long maxuid,unsigned long depth); long parse_criterion (SEARCHPGM *pgm,unsigned char **arg,unsigned long msgmsg, unsigned long maxuid,unsigned long depth); long crit_date (unsigned short *date,unsigned char **arg); long crit_date_work (unsigned short *date,unsigned char **arg); long crit_set (SEARCHSET **set,unsigned char **arg,unsigned long maxima); long crit_number (unsigned long *number,unsigned char **arg); long crit_string (STRINGLIST **string,unsigned char **arg); void fetch (char *t,unsigned long uid); typedef void (*fetchfn_t) (unsigned long i,void *args); void fetch_work (char *t,unsigned long uid,fetchfn_t f[],void *fa[]); void fetch_bodystructure (unsigned long i,void *args); void fetch_body (unsigned long i,void *args); void fetch_body_part_mime (unsigned long i,void *args); void fetch_body_part_contents (unsigned long i,void *args); void fetch_body_part_binary (unsigned long i,void *args); void fetch_body_part_header (unsigned long i,void *args); void fetch_body_part_text (unsigned long i,void *args); void remember (unsigned long uid,char *id,SIZEDTEXT *st); void fetch_envelope (unsigned long i,void *args); void fetch_encoding (unsigned long i,void *args); void changed_flags (unsigned long i,int f); void fetch_flags (unsigned long i,void *args); void put_flag (int *c,char *s); void fetch_internaldate (unsigned long i,void *args); void fetch_uid (unsigned long i,void *args); void fetch_rfc822 (unsigned long i,void *args); void fetch_rfc822_header (unsigned long i,void *args); void fetch_rfc822_size (unsigned long i,void *args); void fetch_rfc822_text (unsigned long i,void *args); void penv (ENVELOPE *env); void pbodystructure (BODY *body); void pbody (BODY *body); void pparam (PARAMETER *param); void paddr (ADDRESS *a); void pset (SEARCHSET **set); void pnum (unsigned long i); void pstring (char *s); void pnstring (char *s); void pastring (char *s); void psizedquoted (SIZEDTEXT *s); void psizedliteral (SIZEDTEXT *s,STRING *st); void psizedstring (SIZEDTEXT *s,STRING *st); void psizedastring (SIZEDTEXT *s); void pastringlist (STRINGLIST *s); void pnstringorlist (STRINGLIST *s); void pbodypartstring (unsigned long msgno,char *id,SIZEDTEXT *st,STRING *bs, TEXTARGS *ta); void ptext (SIZEDTEXT *s,STRING *st); void pthread (THREADNODE *thr); void pcapability (long flag); long nameok (char *ref,char *name); char *bboardname (char *cmd,char *name); long isnewsproxy (char *name); long newsproxypattern (char *ref,char *pat,char *pattern,long flag); char *imap_responder (void *challenge,unsigned long clen,unsigned long *rlen); long proxycopy (MAILSTREAM *stream,char *sequence,char *mailbox,long options); long proxy_append (MAILSTREAM *stream,void *data,char **flags,char **date, STRING **message); long append_msg (MAILSTREAM *stream,void *data,char **flags,char **date, STRING **message); void copyuid (MAILSTREAM *stream,char *mailbox,unsigned long uidvalidity, SEARCHSET *sourceset,SEARCHSET *destset); void appenduid (char *mailbox,unsigned long uidvalidity,SEARCHSET *set); char *referral (MAILSTREAM *stream,char *url,long code); void mm_list_work (char *what,int delimiter,char *name,long attributes); char *lasterror (void); /* Global storage */ char *version = "404"; /* edit number of this server */ char *logout = "Logout"; /* syslogreason for logout */ char *goodbye = NIL; /* bye reason */ time_t alerttime = 0; /* time of last alert */ time_t sysalerttime = 0; /* time of last system alert */ time_t useralerttime = 0; /* time of last user alert */ time_t lastcheck = 0; /* time of last checkpoint */ time_t shutdowntime = 0; /* time of last shutdown */ int state = LOGIN; /* server state */ int cancelled = NIL; /* authenticate cancelled */ int trycreate = 0; /* saw a trycreate */ int finding = NIL; /* doing old FIND command */ int anonymous = 0; /* non-zero if anonymous */ int critical = NIL; /* non-zero if in critical code */ int quell_events = NIL; /* non-zero if in FETCH response */ int existsquelled = NIL; /* non-zero if an EXISTS was quelled */ int proxylist = NIL; /* doing a proxy LIST */ MAILSTREAM *stream = NIL; /* mailbox stream */ DRIVER *curdriver = NIL; /* note current driver */ MAILSTREAM *tstream = NIL; /* temporary mailbox stream */ unsigned int nflags = 0; /* current number of keywords */ unsigned long nmsgs =0xffffffff;/* last reported # of messages and recent */ unsigned long recent = 0xffffffff; char *nntpproxy = NIL; /* NNTP proxy name */ unsigned char *user = NIL; /* user name */ unsigned char *pass = NIL; /* password */ unsigned char *initial = NIL; /* initial response */ unsigned char cmdbuf[CMDLEN]; /* command buffer */ char *status = "starting up"; /* server status */ char *tag; /* tag portion of command */ unsigned char *cmd; /* command portion of command */ unsigned char *arg; /* pointer to current argument of command */ char *lstwrn = NIL; /* last warning message from c-client */ char *lsterr = NIL; /* last error message from c-client */ char *lstref = NIL; /* last referral from c-client */ char *response = NIL; /* command response */ struct { unsigned long size; /* size of current LITERAL+ */ unsigned int ok : 1; /* LITERAL+ in effect */ } litplus; int litsp = 0; /* literal stack pointer */ char *litstk[LITSTKLEN]; /* stack to hold literals */ unsigned long uidvalidity = 0; /* last reported UID validity */ unsigned long lastuid = 0; /* last fetched uid */ char *lastid = NIL; /* last fetched body id for this message */ char *lastsel = NIL; /* last selected mailbox name */ SIZEDTEXT lastst = {NIL,0}; /* last sizedtext */ unsigned long cauidvalidity = 0;/* UIDVALIDITY for COPYUID/APPENDUID */ SEARCHSET *csset = NIL; /* COPYUID source set */ SEARCHSET *caset = NIL; /* COPYUID/APPENDUID destination set */ jmp_buf jmpenv; /* stack context for setjmp */ /* Response texts which appear in multiple places */ char *win = "%.80s OK "; char *rowin = "%.80s OK [READ-ONLY] %.80s completed\015\012"; char *rwwin = "%.80s OK [READ-WRITE] %.80s completed\015\012"; char *lose = "%.80s NO "; char *logwin = "%.80s OK ["; char *losetry = "%.80s NO [TRYCREATE] %.80s failed: %.900s\015\012"; char *loseunknowncte = "%.80s NO [UNKNOWN-CTE] %.80s failed: %.900s\015\012"; char *badcmd = "%.80s BAD Command unrecognized: %.80s\015\012"; char *misarg = "%.80s BAD Missing or invalid argument to %.80s\015\012"; char *badarg = "%.80s BAD Argument given to %.80s when none expected\015\012"; char *badseq = "%.80s BAD Bogus sequence in %.80s: %.80s\015\012"; char *badatt = "%.80s BAD Bogus attribute list in %.80s\015\012"; char *badbin = "%.80s BAD Syntax error in binary specifier\015\012"; /* Message string driver for message stringstructs */ STRINGDRIVER msg_string = { msg_string_init, /* initialize string structure */ msg_string_next, /* get next byte in string structure */ msg_string_setpos /* set position in string structure */ }; /* Main program */ int main (int argc,char *argv[]) { unsigned long i,uid; long f; unsigned char *s,*t,*u,*v,tmp[MAILTMPLEN]; struct stat sbuf; logouthook_t lgoh; int ret = 0; time_t autologouttime = 0; char *pgmname; /* if case we get borked immediately */ if (setjmp (jmpenv)) _exit (1); pgmname = (argc && argv[0]) ? (((s = strrchr (argv[0],'/')) || (s = strrchr (argv[0],'\\'))) ? (char *) s+1 : argv[0]) : "imapd"; /* set service name before linkage */ mail_parameters (NIL,SET_SERVICENAME,(void *) "imap"); #include "linkage.c" rfc822_date (tmp); /* get date/time at startup */ /* initialize server */ server_init (pgmname,"imap","imaps",clkint,kodint,hupint,trmint,staint); /* forbid automatic untagged expunge */ mail_parameters (NIL,SET_EXPUNGEATPING,NIL); /* arm proxy copy callback */ mail_parameters (NIL,SET_MAILPROXYCOPY,(void *) proxycopy); /* arm referral callback */ mail_parameters (NIL,SET_IMAPREFERRAL,(void *) referral); /* arm COPYUID callback */ mail_parameters (NIL,SET_COPYUID,(void *) copyuid); /* arm APPENDUID callback */ mail_parameters (NIL,SET_APPENDUID,(void *) appenduid); if (stat (SHUTDOWNFILE,&sbuf)) { char proxy[MAILTMPLEN]; FILE *nntp = fopen (NNTPFILE,"r"); if (nntp) { /* desire NNTP proxy? */ if (fgets (proxy,MAILTMPLEN,nntp)) { /* remove newline and set NNTP proxy */ if (s = strchr (proxy,'\n')) *s = '\0'; nntpproxy = cpystr (proxy); /* disable the news driver */ mail_parameters (NIL,DISABLE_DRIVER,"news"); } fclose (nntp); /* done reading proxy name */ } s = myusername_full (&i); /* get user name and flags */ switch (i) { case MU_NOTLOGGEDIN: PSOUT ("* OK ["); /* not logged in, ordinary startup */ pcapability (-1); break; case MU_ANONYMOUS: anonymous = T; /* anonymous user, fall into default */ s = "ANONYMOUS"; case MU_LOGGEDIN: PSOUT ("* PREAUTH ["); /* already logged in, pre-authorized */ pcapability (1); user = cpystr (s); /* copy user name */ pass = cpystr ("*"); /* set fake password */ state = SELECT; /* enter select state */ break; default: fatal ("Unknown state from myusername_full()"); } PSOUT ("] "); if (user) { /* preauthenticated as someone? */ PSOUT ("Pre-authenticated user "); PSOUT (user); PBOUT (' '); } } else { /* login disabled */ PSOUT ("* BYE Service not available "); state = LOGOUT; } PSOUT (tcp_serverhost ()); PSOUT (" IMAP4rev1 "); PSOUT (CCLIENTVERSION); PBOUT ('.'); PSOUT (version); PSOUT (" at "); PSOUT (tmp); CRLF; PFLUSH (); /* dump output buffer */ switch (state) { /* do this after the banner */ case LOGIN: autologouttime = time (0) + LOGINTIMEOUT; break; case SELECT: syslog (LOG_INFO,"Preauthenticated user=%.80s host=%.80s", user,tcp_clienthost ()); break; } if (setjmp (jmpenv)) { /* die if a signal handler say so */ /* in case we get borked now */ if (setjmp (jmpenv)) _exit (1); /* need to close stream gracefully? */ if (stream && !stream->lock && (stream->dtb->flags & DR_XPOINT)) stream = mail_close (stream); ret = 1; /* set exit status */ } else while (state != LOGOUT) {/* command processing loop */ slurp (cmdbuf,CMDLEN,TIMEOUT); /* no more last error or literal */ if (lstwrn) fs_give ((void **) &lstwrn); if (lsterr) fs_give ((void **) &lsterr); if (lstref) fs_give ((void **) &lstref); while (litsp) fs_give ((void **) &litstk[--litsp]); /* find end of line */ if (!strchr (cmdbuf,'\012')) { if (t = strchr (cmdbuf,' ')) *t = '\0'; if ((t - cmdbuf) > 100) t = NIL; flush (); /* flush excess */ if (state == LOGIN) /* error if NLI */ syslog (LOG_INFO,"Line too long before authentication host=%.80s", tcp_clienthost ()); sprintf (tmp,response,t ? (char *) cmdbuf : "*"); PSOUT (tmp); } else if (!(tag = strtok (cmdbuf," \015\012"))) { if (state == LOGIN) /* error if NLI */ syslog (LOG_INFO,"Null command before authentication host=%.80s", tcp_clienthost ()); PSOUT ("* BAD Null command\015\012"); } else if (strlen (tag) > 50) PSOUT ("* BAD Excessively long tag\015\012"); else if (!(s = strtok (NIL," \015\012"))) { if (state == LOGIN) /* error if NLI */ syslog (LOG_INFO,"Missing command before authentication host=%.80s", tcp_clienthost ()); PSOUT (tag); PSOUT (" BAD Missing command\015\012"); } else { /* parse command */ response = win; /* set default response */ finding = NIL; /* no longer FINDing */ ucase (s); /* canonicalize command case */ /* UID command? */ if (!strcmp (s,"UID") && strtok (NIL," \015\012")) { uid = T; /* a UID command */ s[3] = ' '; /* restore the space delimiter */ ucase (s); /* make sure command all uppercase */ } else uid = NIL; /* not a UID command */ /* flush previous saved command */ if (cmd) fs_give ((void **) &cmd); cmd = cpystr (s); /* save current command */ /* snarf argument, see if possible litplus */ if ((arg = strtok (NIL,"\015\012")) && ((i = strlen (arg)) > 3) && (arg[i - 1] == '}') && (arg[i - 2] == '+') && isdigit (arg[i - 3])) { /* back over possible count */ for (i -= 4; i && isdigit (arg[i]); i--); if (arg[i] == '{') { /* found a literal? */ litplus.ok = T; /* yes, note LITERAL+ in effect, set size */ litplus.size = strtoul (arg + i + 1,NIL,10); } } /* these commands always valid */ if (!strcmp (cmd,"NOOP")) { if (arg) response = badarg; else if (stream) /* allow untagged EXPUNGE */ mail_parameters (stream,SET_ONETIMEEXPUNGEATPING,(void *) stream); } else if (!strcmp (cmd,"LOGOUT")) { if (arg) response = badarg; else { /* time to say farewell */ server_init (NIL,NIL,NIL,SIG_IGN,SIG_IGN,SIG_IGN,SIG_IGN,SIG_IGN); if (lastsel) fs_give ((void **) &lastsel); if (state == OPEN) stream = mail_close (stream); state = LOGOUT; PSOUT ("* BYE "); PSOUT (mylocalhost ()); PSOUT (" IMAP4rev1 server terminating connection\015\012"); } } else if (!strcmp (cmd,"CAPABILITY")) { if (arg) response = badarg; else { PSOUT ("* "); pcapability (0); /* print capabilities */ CRLF; } if (stream) /* allow untagged EXPUNGE */ mail_parameters (stream,SET_ONETIMEEXPUNGEATPING,(void *) stream); } #ifdef NETSCAPE_BRAIN_DAMAGE else if (!strcmp (cmd,"NETSCAPE")) { PSOUT ("* OK [NETSCAPE]\015\012* VERSION 1.0 UNIX\015\012* ACCOUNT-URL \""); PSOUT (NETSCAPE_BRAIN_DAMAGE); PBOUT ('"'); CRLF; } #endif else switch (state) { /* dispatch depending upon state */ case LOGIN: /* waiting to get logged in */ /* new style authentication */ if (!strcmp (cmd,"AUTHENTICATE")) { if (user) fs_give ((void **) &user); if (pass) fs_give ((void **) &pass); initial = NIL; /* no initial argument */ cancelled = NIL; /* not cancelled */ /* mandatory first argument */ if (!(s = snarf (&arg))) response = misarg; else if (arg && !(initial = snarf_base64 (&arg))) response = misarg; /* optional second argument */ else if (arg) response = badarg; else if (!strcmp (ucase (s),"ANONYMOUS") && !stat (ANOFILE,&sbuf)) { if (!(s = imap_responder ("",0,NIL))) response ="%.80s BAD AUTHENTICATE ANONYMOUS cancelled\015\012"; else if (anonymous_login (argc,argv)) { anonymous = T; /* note we are anonymous */ user = cpystr ("ANONYMOUS"); pass = cpystr ("*"); state = SELECT; /* make select */ alerttime = 0; /* force alert */ response = logwin;/* return logged-in capabilities */ syslog (LOG_INFO,"Authenticated anonymous=%.80s host=%.80s",s, tcp_clienthost ()); fs_give ((void **) &s); } else response ="%.80s NO AUTHENTICATE ANONYMOUS failed\015\012"; } else if (user = cpystr (mail_auth (s,imap_responder,argc,argv))) { pass = cpystr ("*"); state = SELECT; /* make select */ alerttime = 0; /* force alert */ response = logwin; /* return logged-in capabilities */ syslog (LOG_INFO,"Authenticated user=%.80s host=%.80s mech=%.80s", user,tcp_clienthost (),s); } else { AUTHENTICATOR *auth = mail_lookup_auth (1); char *msg = (char *) fs_get (strlen (cmd) + strlen (s) + 2); sprintf (msg,"%s %s",cmd,s); fs_give ((void **) &cmd); cmd = msg; for (i = !mail_parameters (NIL,GET_DISABLEPLAINTEXT,NIL); auth && compare_cstring (s,auth->name); auth = auth->next); /* Failed authentication when hidden looks like invalid command. * This is intentional but confused me when I was debugging. */ if (auth && auth->server && !(auth->flags & AU_DISABLE) && !(auth->flags & AU_HIDE) && (i || (auth->flags & AU_SECURE))) { response = lose; if (cancelled) { if (lsterr) fs_give ((void **) &lsterr); lsterr = cpystr ("cancelled by user"); } if (!lsterr) /* catch-all */ lsterr = cpystr ("Invalid authentication credentials"); syslog (LOG_INFO,"AUTHENTICATE %.80s failure host=%.80s",s, tcp_clienthost ()); } else { response = badcmd; syslog (LOG_INFO,"AUTHENTICATE %.80s invalid host=%.80s",s, tcp_clienthost ()); } } } /* plaintext login with password */ else if (!strcmp (cmd,"LOGIN")) { if (user) fs_give ((void **) &user); if (pass) fs_give ((void **) &pass); /* two arguments */ if (!((user = cpystr (snarf (&arg))) && (pass = cpystr (snarf (&arg))))) response = misarg; else if (arg) response = badarg; /* see if we allow anonymous */ else if (!compare_cstring (user,"ANONYMOUS") && !stat (ANOFILE,&sbuf) && anonymous_login (argc,argv)) { anonymous = T; /* note we are anonymous */ ucase (user); /* make all uppercase for consistency */ state = SELECT; /* make select */ alerttime = 0; /* force alert */ response = logwin; /* return logged-in capabilities */ syslog (LOG_INFO,"Login anonymous=%.80s host=%.80s",pass, tcp_clienthost ()); } else { /* delimit user from possible admin */ if (s = strchr (user,'*')) *s++ ='\0'; /* see if username and password are OK */ if (server_login (user,pass,s,argc,argv)) { state = SELECT; /* make select */ alerttime = 0; /* force alert */ response = logwin;/* return logged-in capabilities */ syslog (LOG_INFO,"Login user=%.80s host=%.80s",user, tcp_clienthost ()); } else { response = lose; if (!lsterr) lsterr = cpystr ("Invalid login credentials"); } } } /* start TLS security */ else if (!strcmp (cmd,"STARTTLS")) { if (arg) response = badarg; else if (lsterr = ssl_start_tls (pgmname)) response = lose; } else response = badcmd; break; case OPEN: /* valid only when mailbox open */ /* fetch mailbox attributes */ if (!strcmp (cmd,"FETCH") || !strcmp (cmd,"UID FETCH")) { if (!(arg && (s = strtok (arg," ")) && (t = strtok(NIL,"\015\012")))) response = misarg; else if (uid ? mail_uid_sequence (stream,s) : mail_sequence (stream,s)) fetch (t,uid); else response = badseq; } /* store mailbox attributes */ else if (!strcmp (cmd,"STORE") || !strcmp (cmd,"UID STORE")) { /* must have three arguments */ if (!(arg && (s = strtok (arg," ")) && (v = strtok (NIL," ")) && (t = strtok (NIL,"\015\012")))) response = misarg; else if (!(uid ? mail_uid_sequence (stream,s) : mail_sequence (stream,s))) response = badseq; else { f = ST_SET | (uid ? ST_UID : NIL)|((v[5]&&v[6]) ? ST_SILENT : NIL); if (!strcmp (ucase (v),"FLAGS") || !strcmp (v,"FLAGS.SILENT")) { strcpy (tmp,"\\Answered \\Flagged \\Deleted \\Draft \\Seen"); for (i = 0, u = tmp; (i < NUSERFLAGS) && (v = stream->user_flags[i]); i++) if (strlen (v) < ((size_t) (MAILTMPLEN - ((u += strlen (u)) + 2 - tmp)))) { *u++ = ' '; /* write next flag */ strcpy (u,v); } mail_flag (stream,s,tmp,f & ~ST_SET); } else if (!strcmp (v,"-FLAGS") || !strcmp (v,"-FLAGS.SILENT")) f &= ~ST_SET; /* clear flags */ else if (strcmp (v,"+FLAGS") && strcmp (v,"+FLAGS.SILENT")) { response = badatt; break; } /* find last keyword */ for (i = 0; (i < NUSERFLAGS) && stream->user_flags[i]; i++); mail_flag (stream,s,t,f); /* any new keywords appeared? */ if (i < NUSERFLAGS && stream->user_flags[i]) new_flags (stream); /* return flags if silence not wanted */ if (uid ? mail_uid_sequence (stream,s) : mail_sequence (stream,s)) for (i = 1; i <= nmsgs; i++) if (mail_elt(stream,i)->sequence) mail_elt (stream,i)->spare2 = (f & ST_SILENT) ? NIL : T; } } /* check for new mail */ else if (!strcmp (cmd,"CHECK")) { /* no arguments */ if (arg) response = badarg; else if (!anonymous) { mail_check (stream); /* remember last check time */ lastcheck = time (0); } } /* expunge deleted messages */ else if (!(anonymous || (strcmp (cmd,"EXPUNGE") && strcmp (cmd,"UID EXPUNGE")))) { if (uid && !arg) response = misarg; else if (!uid && arg) response = badarg; else { /* expunge deleted or specified UIDs */ mail_expunge_full (stream,arg,arg ? EX_UID : NIL); /* remember last checkpoint */ lastcheck = time (0); } } /* close mailbox */ else if (!strcmp (cmd,"CLOSE") || !strcmp (cmd,"UNSELECT")) { /* no arguments */ if (arg) response = badarg; else { /* no last uid */ uidvalidity = lastuid = 0; if (lastsel) fs_give ((void **) &lastsel); if (lastid) fs_give ((void **) &lastid); if (lastst.data) fs_give ((void **) &lastst.data); stream = mail_close_full (stream,((*cmd == 'C') && !anonymous) ? CL_EXPUNGE : NIL); state = SELECT; /* no longer opened */ lastcheck = 0; /* no last checkpoint */ } } else if (!anonymous && /* copy message(s) */ (!strcmp (cmd,"COPY") || !strcmp (cmd,"UID COPY"))) { trycreate = NIL; /* no trycreate status */ if (!(arg && (s = strtok (arg," ")) && (arg = strtok(NIL,"\015\012")) && (t = snarf (&arg)))) response = misarg; else if (arg) response = badarg; else if (!nmsgs) { response = lose; if (!lsterr) lsterr = cpystr ("Mailbox is empty"); } else if (!(uid ? mail_uid_sequence (stream,s) : mail_sequence (stream,s))) response = badseq; /* try copy */ else if (!mail_copy_full (stream,s,t,uid ? CP_UID : NIL)) { response = trycreate ? losetry : lose; if (!lsterr) lsterr = cpystr ("No such destination mailbox"); } } /* sort mailbox */ else if (!strcmp (cmd,"SORT") || !strcmp (cmd,"UID SORT")) { /* must have four arguments */ if (!(arg && (*arg == '(') && (t = strchr (s = arg + 1,')')) && (t[1] == ' ') && (*(arg = t + 2)))) response = misarg; else { /* read criteria */ SEARCHPGM *spg = NIL; char *cs = NIL; SORTPGM *pgm = NIL,*pg = NIL; unsigned long *slst,*sl; *t = NIL; /* tie off criteria list */ if (!(s = strtok (ucase (s)," "))) response = badatt; else { do { /* parse sort attributes */ if (pg) pg = pg->next = mail_newsortpgm (); else pgm = pg = mail_newsortpgm (); if (!strcmp (s,"REVERSE")) { pg->reverse = T; if (!(s = strtok (NIL," "))) { s = ""; /* end of attributes */ break; } } if (!strcmp (s,"DATE")) pg->function = SORTDATE; else if (!strcmp (s,"ARRIVAL")) pg->function = SORTARRIVAL; else if (!strcmp (s,"FROM")) pg->function = SORTFROM; else if (!strcmp (s,"SUBJECT")) pg->function = SORTSUBJECT; else if (!strcmp (s,"TO")) pg->function = SORTTO; else if (!strcmp (s,"CC")) pg->function = SORTCC; else if (!strcmp (s,"SIZE")) pg->function = SORTSIZE; else break; } while (s = strtok (NIL," ")); /* bad SORT attribute */ if (s) response = badatt; /* get charset and search criteria */ else if (!((t = snarf (&arg)) && (cs = cpystr (t)) && arg && *arg)) response = misarg; /* parse search criteria */ else if (!parse_criteria (spg = mail_newsearchpgm (),&arg,nmsgs, uidmax (stream),0)) response = badatt; else if (arg && *arg) response = badarg; else if (slst = mail_sort (stream,cs,spg,pgm,uid ? SE_UID:NIL)) { PSOUT ("* SORT"); for (sl = slst; *sl; sl++) { PBOUT (' '); pnum (*sl); } CRLF; fs_give ((void **) &slst); } } if (pgm) mail_free_sortpgm (&pgm); if (spg) mail_free_searchpgm (&spg); if (cs) fs_give ((void **) &cs); } } /* thread mailbox */ else if (!strcmp (cmd,"THREAD") || !strcmp (cmd,"UID THREAD")) { THREADNODE *thr; SEARCHPGM *spg = NIL; char *cs = NIL; /* must have four arguments */ if (!(arg && (s = strtok (arg," ")) && (cs = strtok (NIL," ")) && (cs = cpystr (cs)) && (arg = strtok (NIL,"\015\012")))) response = misarg; else if (!parse_criteria (spg = mail_newsearchpgm (),&arg,nmsgs, uidmax (stream),0)) response = badatt; else if (arg && *arg) response = badarg; else { if (thr = mail_thread (stream,s,cs,spg,uid ? SE_UID : NIL)) { PSOUT ("* THREAD "); pthread (thr); mail_free_threadnode (&thr); } else PSOUT ("* THREAD"); CRLF; } if (spg) mail_free_searchpgm (&spg); if (cs) fs_give ((void **) &cs); } /* search mailbox */ else if (!strcmp (cmd,"SEARCH") || !strcmp (cmd,"UID SEARCH")) { int retval = NIL; char *charset = NIL; SEARCHPGM *pgm; response = misarg; /* assume failure */ if (!arg) break; /* one or more arguments required */ if (((arg[0] == 'R') || (arg[0] == 'r')) && ((arg[1] == 'E') || (arg[1] == 'e')) && ((arg[2] == 'T') || (arg[2] == 't')) && ((arg[3] == 'U') || (arg[3] == 'u')) && ((arg[4] == 'R') || (arg[4] == 'r')) && ((arg[5] == 'N') || (arg[5] == 'n')) && (arg[6] == ' ') && (arg[7] == '(')) { retval = 0x4000; /* return is specified */ for (arg += 8; *arg && (*arg != ')'); ) { if (((arg[0] == 'M') || (arg[0] == 'm')) && ((arg[1] == 'I') || (arg[1] == 'i')) && ((arg[2] == 'N') || (arg[2] == 'n')) && ((arg[3] == ' ') || (arg[3] == ')'))) { retval |= 0x1; arg += 3; } else if (((arg[0] == 'M') || (arg[0] == 'm')) && ((arg[1] == 'A') || (arg[1] == 'a')) && ((arg[2] == 'X') || (arg[2] == 'x')) && ((arg[3] == ' ') || (arg[3] == ')'))) { retval |= 0x2; arg += 3; } else if (((arg[0] == 'A') || (arg[0] == 'a')) && ((arg[1] == 'L') || (arg[1] == 'l')) && ((arg[2] == 'L') || (arg[2] == 'l')) && ((arg[3] == ' ') || (arg[3] == ')'))) { retval |= 0x4; arg += 3; } else if (((arg[0] == 'C') || (arg[0] == 'c')) && ((arg[1] == 'O') || (arg[1] == 'o')) && ((arg[2] == 'U') || (arg[2] == 'u')) && ((arg[3] == 'N') || (arg[3] == 'n')) && ((arg[4] == 'T') || (arg[4] == 't')) && ((arg[5] == ' ') || (arg[5] == ')'))) { retval |= 0x10; arg += 5; } else break; /* unknown return value */ /* more return values to come */ if ((*arg == ' ') && (arg[1] != ')')) ++arg; } /* RETURN list must be properly terminated */ if ((*arg++ != ')') || (*arg++ != ' ')) break; /* default return value is ALL */ if (!(retval &= 0x3fff)) retval = 0x4; } /* character set specified? */ if (((arg[0] == 'C') || (arg[0] == 'c')) && ((arg[1] == 'H') || (arg[1] == 'h')) && ((arg[2] == 'A') || (arg[2] == 'a')) && ((arg[3] == 'R') || (arg[3] == 'r')) && ((arg[4] == 'S') || (arg[4] == 's')) && ((arg[5] == 'E') || (arg[5] == 'e')) && ((arg[6] == 'T') || (arg[6] == 't')) && (arg[7] == ' ')) { arg += 8; /* yes, skip over CHARSET token */ if (s = snarf (&arg)) charset = cpystr (s); else break; /* missing character set */ } /* must have arguments here */ if (!(arg && *arg)) break; if (parse_criteria (pgm = mail_newsearchpgm (),&arg,nmsgs, uidmax (stream),0) && !*arg) { response = win; /* looks good, try the search */ mail_search_full (stream,charset,pgm,SE_FREE); /* output search results if success */ if (response == win) { if (retval) { /* ESEARCH desired */ PSOUT ("* ESEARCH (TAG "); pstring (tag); PBOUT (')'); if (uid) PSOUT (" UID"); /* wants MIN */ if (retval & 0x1) { for (i = 1; (i <= nmsgs) && !mail_elt (stream,i)->searched; ++i); if (i <= nmsgs) { PSOUT (" MIN "); pnum (uid ? mail_uid (stream,i) : i); } } /* wants MAX */ if (retval & 0x2) { for (i = nmsgs; i && !mail_elt (stream,i)->searched; --i); if (i) { PSOUT (" MAX "); pnum (uid ? mail_uid (stream,i) : i); } } /* wants ALL */ if (retval & 0x4) { unsigned long j; /* find first match */ for (i = 1; (i <= nmsgs) && !mail_elt (stream,i)->searched; ++i); if (i <= nmsgs) { PSOUT (" ALL "); pnum (uid ? mail_uid (stream,i) : i); j = i; /* last message output */ } while (++i <= nmsgs) { if (mail_elt (stream,i)->searched) { while ((++i <= nmsgs) && mail_elt (stream,i)->searched); /* previous message is end of range */ if (j != --i) { PBOUT (':'); pnum (uid ? mail_uid (stream,i) : i); } } /* search for next match */ while ((++i <= nmsgs) && !mail_elt (stream,i)->searched); if (i <= nmsgs) { PBOUT (','); pnum (uid ? mail_uid (stream,i) : i); j = i; /* last message output */ } } } /* wants COUNT */ if (retval & 0x10) { unsigned long j; for (i = 1, j = 0; i <= nmsgs; ++i) if (mail_elt (stream,i)->searched) ++j; PSOUT (" COUNT "); pnum (j); } } else { /* standard search */ PSOUT ("* SEARCH"); for (i = 1; i <= nmsgs; ++i) if (mail_elt (stream,i)->searched) { PBOUT (' '); pnum (uid ? mail_uid (stream,i) : i); } } CRLF; } } else mail_free_searchpgm (&pgm); if (charset) fs_give ((void **) &charset); } else /* fall into select case */ case SELECT: /* valid whenever logged in */ /* select new mailbox */ if (!(strcmp (cmd,"SELECT") && strcmp (cmd,"EXAMINE") && strcmp (cmd,"BBOARD"))) { /* single argument */ if (!(s = snarf (&arg))) response = misarg; else if (arg) response = badarg; else if (nameok (NIL,s = bboardname (cmd,s))) { DRIVER *factory = mail_valid (NIL,s,NIL); f = (anonymous ? OP_ANONYMOUS + OP_READONLY : NIL) | ((*cmd == 'S') ? NIL : OP_READONLY); curdriver = NIL; /* no drivers known */ /* no last uid */ uidvalidity = lastuid = 0; if (lastid) fs_give ((void **) &lastid); if (lastst.data) fs_give ((void **) &lastst.data); nflags = 0; /* force update */ nmsgs = recent = 0xffffffff; if (factory && !strcmp (factory->name,"phile") && (stream = mail_open (stream,s,f | OP_SILENT)) && (response == win)) { BODY *b; /* see if proxy open */ if ((mail_elt (stream,1)->rfc822_size < 400) && mail_fetchstructure (stream,1,&b) && (b->type == TYPETEXT) && (t = mail_fetch_text (stream,1,NIL,&i,NIL)) && (i < MAILTMPLEN) && (t[0] == '{')) { /* copy and tie off */ strncpy (tmp,t,i)[i] = '\0'; /* nuke any trailing newline */ if (t = strpbrk (tmp,"\r\n")) *t = '\0'; /* try to open proxy */ if ((tstream = mail_open (NIL,tmp,f | OP_SILENT)) && (response == win) && tstream->nmsgs) { s = tmp; /* got it, close the link */ mail_close (stream); stream = tstream; tstream = NIL; } } /* now give the exists event */ stream->silent = NIL; mm_exists (stream,stream->nmsgs); } else if (!factory && isnewsproxy (s)) { sprintf (tmp,"{%.300s/nntp}%.300s",nntpproxy,(char *) s+6); stream = mail_open (stream,tmp,f); } /* open stream normally then */ else stream = mail_open (stream,s,f); if (stream && (response == win)) { state = OPEN; /* note state open */ if (lastsel) fs_give ((void **) &lastsel); /* canonicalize INBOX */ if (!compare_cstring (s,"#MHINBOX")) lastsel = cpystr ("#MHINBOX"); else lastsel = cpystr (compare_cstring (s,"INBOX") ? (char *) s : "INBOX"); /* note readonly/readwrite */ response = stream->rdonly ? rowin : rwwin; if (anonymous) syslog (LOG_INFO,"Anonymous select of %.80s host=%.80s", stream->mailbox,tcp_clienthost ()); lastcheck = 0; /* no last check */ } else { /* failed, nuke old selection */ if (stream) stream = mail_close (stream); state = SELECT; /* no mailbox open now */ if (lastsel) fs_give ((void **) &lastsel); response = lose; /* open failed */ } } } /* APPEND message to mailbox */ else if (!(anonymous || strcmp (cmd,"APPEND"))) { /* parse mailbox name */ if ((s = snarf (&arg)) && arg) { STRING st; /* message stringstruct */ APPENDDATA ad; ad.arg = arg; /* command arguments */ /* no message yet */ ad.flags = ad.date = ad.msg = NIL; ad.message = &st; /* pointer to stringstruct to use */ trycreate = NIL; /* no trycreate status */ if (!mail_append_multiple (NIL,s,append_msg,(void *) &ad)) { if (response == win) response = trycreate ? losetry : lose; /* this can happen with #driver. hack */ if (!lsterr) lsterr = cpystr ("No such destination mailbox"); } /* clean up any message text left behind */ if (ad.flags) fs_give ((void **) &ad.flags); if (ad.date) fs_give ((void **) &ad.date); if (ad.msg) fs_give ((void **) &ad.msg); } else response = misarg; if (stream) /* allow untagged EXPUNGE */ mail_parameters (stream,SET_ONETIMEEXPUNGEATPING,(void *) stream); } /* list mailboxes */ else if (!strcmp (cmd,"LIST") || !strcmp (cmd,"RLIST")) { /* get reference and mailbox argument */ if (!((s = snarf (&arg)) && (t = snarf_list (&arg)))) response = misarg; else if (arg) response = badarg; /* make sure anonymous can't do bad things */ else if (nameok (s,t)) { if (newsproxypattern (s,t,tmp,LONGT)) { proxylist = T; mail_list (NIL,"",tmp); proxylist = NIL; } else mail_list (NIL,s,t); } if (stream) /* allow untagged EXPUNGE */ mail_parameters (stream,SET_ONETIMEEXPUNGEATPING,(void *) stream); } /* scan mailboxes */ else if (!strcmp (cmd,"SCAN")) { /* get arguments */ if (!((s = snarf (&arg)) && (t = snarf_list (&arg)) && (u = snarf (&arg)))) response = misarg; else if (arg) response = badarg; /* make sure anonymous can't do bad things */ else if (nameok (s,t)) { if (newsproxypattern (s,t,tmp,NIL)) mm_log ("SCAN not permitted for news",ERROR); else mail_scan (NIL,s,t,u); } if (stream) /* allow untagged EXPUNGE */ mail_parameters (stream,SET_ONETIMEEXPUNGEATPING,(void *) stream); } /* list subscribed mailboxes */ else if (!strcmp (cmd,"LSUB") || !strcmp (cmd,"RLSUB")) { /* get reference and mailbox argument */ if (!((s = snarf (&arg)) && (t = snarf_list (&arg)))) response = misarg; else if (arg) response = badarg; /* make sure anonymous can't do bad things */ else if (nameok (s,t)) { if (newsproxypattern (s,t,tmp,NIL)) newsrc_lsub (NIL,tmp); else mail_lsub (NIL,s,t); } if (stream) /* allow untagged EXPUNGE */ mail_parameters (stream,SET_ONETIMEEXPUNGEATPING,(void *) stream); } /* find mailboxes */ else if (!strcmp (cmd,"FIND")) { /* get subcommand and true argument */ if (!(arg && (s = strtok (arg," \015\012")) && (s == cmd + 5) && (cmd[4] = ' ') && ucase (s) && (arg = strtok (NIL,"\015\012")) && (s = snarf_list (&arg)))) response = misarg; /* missing required argument */ else if (arg) response = badarg; /* punt on single-char wildcards */ else if (strpbrk (s,"%?")) response = "%.80s NO IMAP2 ? and %% wildcards not supported: %.80s\015\012"; else if (nameok (NIL,s)) { finding = T; /* note that we are FINDing */ /* dispatch based on type */ if (!strcmp (cmd,"FIND MAILBOXES") && !anonymous) mail_lsub (NIL,NIL,s); else if (!strcmp (cmd,"FIND ALL.MAILBOXES")) { /* convert * to % for compatible behavior */ for (t = s; *t; t++) if (*t == '*') *t = '%'; mail_list (NIL,NIL,s); } else response = badcmd; } if (stream) /* allow untagged EXPUNGE */ mail_parameters (stream,SET_ONETIMEEXPUNGEATPING,(void *) stream); } /* status of mailbox */ else if (!strcmp (cmd,"STATUS")) { if (!((s = snarf (&arg)) && arg && (*arg++ == '(') && (t = strchr (arg,')')) && (t - arg) && !t[1])) response = misarg; else { f = NIL; /* initially no flags */ *t = '\0'; /* tie off flag string */ /* read flags */ t = strtok (ucase (arg)," "); do { /* parse each one; unknown generate warning */ if (!strcmp (t,"MESSAGES")) f |= SA_MESSAGES; else if (!strcmp (t,"RECENT")) f |= SA_RECENT; else if (!strcmp (t,"UNSEEN")) f |= SA_UNSEEN; else if (!strcmp (t,"UIDNEXT")) f |= SA_UIDNEXT; else if (!strcmp (t,"UIDVALIDITY")) f |= SA_UIDVALIDITY; else { PSOUT ("* NO Unknown status flag "); PSOUT (t); CRLF; } } while (t = strtok (NIL," ")); ping_mailbox (uid); /* in case the fool did STATUS on open mbx */ PFLUSH (); /* make sure stdout is dumped in case slave */ if (!compare_cstring (s,"INBOX")) s = "INBOX"; else if (!compare_cstring (s,"#MHINBOX")) s = "#MHINBOX"; if (state == LOGOUT) response = lose; /* get mailbox status */ else if (lastsel && (!strcmp (s,lastsel) || (stream && !strcmp (s,stream->mailbox)))) { unsigned long unseen; /* snarl at cretins which do this */ PSOUT ("* NO CLIENT BUG DETECTED: STATUS on selected mailbox: "); PSOUT (s); CRLF; tmp[0] = ' '; tmp[1] = '\0'; if (f & SA_MESSAGES) sprintf (tmp + strlen (tmp)," MESSAGES %lu",stream->nmsgs); if (f & SA_RECENT) sprintf (tmp + strlen (tmp)," RECENT %lu",stream->recent); if (f & SA_UNSEEN) { for (i = 1,unseen = 0; i <= stream->nmsgs; i++) if (!mail_elt (stream,i)->seen) unseen++; sprintf (tmp + strlen (tmp)," UNSEEN %lu",unseen); } if (f & SA_UIDNEXT) sprintf (tmp + strlen (tmp)," UIDNEXT %lu",stream->uid_last+1); if (f & SA_UIDVALIDITY) sprintf (tmp + strlen(tmp)," UIDVALIDITY %lu", stream->uid_validity); tmp[1] = '('; strcat (tmp,")\015\012"); PSOUT ("* STATUS "); pastring (s); PSOUT (tmp); } else if (isnewsproxy (s)) { sprintf (tmp,"{%.300s/nntp}%.300s",nntpproxy,(char *) s+6); if (!mail_status (NIL,tmp,f)) response = lose; } else if (!mail_status (NIL,s,f)) response = lose; } if (stream) /* allow untagged EXPUNGE */ mail_parameters (stream,SET_ONETIMEEXPUNGEATPING,(void *) stream); } /* subscribe to mailbox */ else if (!(anonymous || strcmp (cmd,"SUBSCRIBE"))) { /* get or MAILBOX */ if (!(s = snarf (&arg))) response = misarg; else if (arg) { /* IMAP2bis form */ if (compare_cstring (s,"MAILBOX")) response = badarg; else if (!(s = snarf (&arg))) response = misarg; else if (arg) response = badarg; else mail_subscribe (NIL,s); } else if (isnewsproxy (s)) newsrc_update (NIL,s+6,':'); else mail_subscribe (NIL,s); if (stream) /* allow untagged EXPUNGE */ mail_parameters (stream,SET_ONETIMEEXPUNGEATPING,(void *) stream); } /* unsubscribe to mailbox */ else if (!(anonymous || strcmp (cmd,"UNSUBSCRIBE"))) { /* get or MAILBOX */ if (!(s = snarf (&arg))) response = misarg; else if (arg) { /* IMAP2bis form */ if (compare_cstring (s,"MAILBOX")) response = badarg; else if (!(s = snarf (&arg))) response = misarg; else if (arg) response = badarg; else if (isnewsproxy (s)) newsrc_update (NIL,s+6,'!'); else mail_unsubscribe (NIL,s); } else mail_unsubscribe (NIL,s); if (stream) /* allow untagged EXPUNGE */ mail_parameters (stream,SET_ONETIMEEXPUNGEATPING,(void *) stream); } else if (!strcmp (cmd,"NAMESPACE")) { if (arg) response = badarg; else { NAMESPACE **ns = (NAMESPACE **) mail_parameters(NIL,GET_NAMESPACE, NIL); NAMESPACE *n; PARAMETER *p; PSOUT ("* NAMESPACE"); if (ns) for (i = 0; i < 3; i++) { if (n = ns[i]) { PSOUT (" ("); do { PBOUT ('('); pstring (n->name); switch (n->delimiter) { case '\\': /* quoted delimiter */ case '"': PSOUT (" \"\\\\\""); break; case '\0': /* no delimiter */ PSOUT (" NIL"); break; default: /* unquoted delimiter */ PSOUT (" \""); PBOUT (n->delimiter); PBOUT ('"'); break; } /* NAMESPACE extensions are hairy */ if (p = n->param) do { PBOUT (' '); pstring (p->attribute); PSOUT (" ("); do pstring (p->value); while (p->next && !p->next->attribute && (p = p->next)); PBOUT (')'); } while (p = p->next); PBOUT (')'); } while (n = n->next); PBOUT (')'); } else PSOUT (" NIL"); } else PSOUT (" NIL NIL NIL"); CRLF; } if (stream) /* allow untagged EXPUNGE */ mail_parameters (stream,SET_ONETIMEEXPUNGEATPING,(void *) stream); } /* create mailbox */ else if (!(anonymous || strcmp (cmd,"CREATE"))) { if (!(s = snarf (&arg))) response = misarg; else if (arg) response = badarg; else mail_create (NIL,s); if (stream) /* allow untagged EXPUNGE */ mail_parameters (stream,SET_ONETIMEEXPUNGEATPING,(void *) stream); } /* delete mailbox */ else if (!(anonymous || strcmp (cmd,"DELETE"))) { if (!(s = snarf (&arg))) response = misarg; else if (arg) response = badarg; else { /* make sure not selected */ if (lastsel && (!strcmp (s,lastsel) || (stream && !strcmp (s,stream->mailbox)))) mm_log ("Can not DELETE the selected mailbox",ERROR); else mail_delete (NIL,s); } if (stream) /* allow untagged EXPUNGE */ mail_parameters (stream,SET_ONETIMEEXPUNGEATPING,(void *) stream); } /* rename mailbox */ else if (!(anonymous || strcmp (cmd,"RENAME"))) { if (!((s = snarf (&arg)) && (t = snarf (&arg)))) response = misarg; else if (arg) response = badarg; else { /* make sure not selected */ if (!compare_cstring (s,"INBOX")) s = "INBOX"; else if (!compare_cstring (s,"#MHINBOX")) s = "#MHINBOX"; if (lastsel && (!strcmp (s,lastsel) || (stream && !strcmp (s,stream->mailbox)))) mm_log ("Can not RENAME the selected mailbox",ERROR); else mail_rename (NIL,s,t); } if (stream) /* allow untagged EXPUNGE */ mail_parameters (stream,SET_ONETIMEEXPUNGEATPING,(void *) stream); } /* idle mode */ else if (!strcmp (cmd,"IDLE")) { /* no arguments */ if (arg) response = badarg; else { /* tell client ready for argument */ unsigned long donefake = 0; PSOUT ("+ Waiting for DONE\015\012"); PFLUSH (); /* dump output buffer */ /* inactivity countdown */ i = ((TIMEOUT) / (IDLETIMER)) + 1; do { /* main idle loop */ if (!donefake) { /* don't ping mailbox if faking */ mail_parameters (stream,SET_ONETIMEEXPUNGEATPING, (void *) stream); ping_mailbox (uid); /* maybe do a checkpoint if not anonymous */ if (!anonymous && stream && (time (0) > lastcheck + CHECKTIMER)) { mail_check (stream); /* cancel likely altwin from mail_check() */ if (lsterr) fs_give ((void **) &lsterr); if (lstwrn) fs_give ((void **) &lstwrn); /* remember last checkpoint */ lastcheck = time (0); } } if (lstwrn) { /* have a warning? */ PSOUT ("* NO "); PSOUT (lstwrn); CRLF; fs_give ((void **) &lstwrn); } if (!(i % 2)) { /* prevent NAT timeouts */ sprintf (tmp,"* OK Timeout in %lu minutes\015\012", (i * IDLETIMER) / 60); PSOUT (tmp); } /* two minutes before the end... */ if ((state == OPEN) && (i <= 2)) { sprintf (tmp,"* %lu EXISTS\015\012* %lu RECENT\015\012", donefake = nmsgs + 1,recent + 1); PSOUT (tmp); /* prod client to wake up */ } PFLUSH (); /* dump output buffer */ } while ((state != LOGOUT) && !INWAIT (IDLETIMER) && --i); /* time to exit idle loop */ if (state != LOGOUT) { if (i) { /* still have time left? */ /* yes, read expected DONE */ slurp (tmp,MAILTMPLEN,INPUTTIMEOUT); if (((tmp[0] != 'D') && (tmp[0] != 'd')) || ((tmp[1] != 'O') && (tmp[1] != 'o')) || ((tmp[2] != 'N') && (tmp[2] != 'n')) || ((tmp[3] != 'E') && (tmp[3] != 'e')) || (((tmp[4] != '\015') || (tmp[5] != '\012')) && (tmp[4] != '\012'))) response = "%.80s BAD Bogus IDLE continuation\015\012"; if (donefake) { /* if faking at the end */ /* send EXPUNGE (should be just 1) */ while (donefake > nmsgs) { sprintf (tmp,"* %lu EXPUNGE\015\012",donefake--); PSOUT (tmp); } sprintf (tmp,"* %lu EXISTS\015\012* %lu RECENT\015\012", nmsgs,recent); PSOUT (tmp); } } else clkint (); /* otherwise do autologout action */ } } } else response = badcmd; break; default: response = "%.80s BAD Unknown state for %.80s command\015\012"; break; } while (litplus.ok) { /* any unread LITERAL+? */ litplus.ok = NIL; /* yes, cancel it now */ clearerr (stdin); /* clear stdin errors */ status = "discarding unread literal"; /* read literal and discard it */ while (i = (litplus.size > MAILTMPLEN) ? MAILTMPLEN : litplus.size) { if (state == LOGOUT) litplus.size = 0; else { settimeout (INPUTTIMEOUT); if (PSINR (tmp,i)) litplus.size -= i; else { ioerror (stdin,status); litplus.size = 0; /* in case it continues */ } } } settimeout (0); /* stop timeout */ /* get new command tail */ slurp (tmp,MAILTMPLEN,INPUTTIMEOUT); /* locate end of line */ if (t = strchr (tmp,'\012')) { /* back over CR */ if ((t > tmp) && (t[-1] == '\015')) --t; *t = NIL; /* tie off CRLF */ /* possible LITERAL+? */ if (((i = strlen (tmp)) > 3) && (tmp[i - 1] == '}') && (tmp[i - 2] == '+') && isdigit (tmp[i - 3])) { /* back over possible count */ for (i -= 4; i && isdigit (tmp[i]); i--); if (tmp[i] == '{') { /* found a literal? */ litplus.ok = T; /* yes, note LITERAL+ in effect, set size */ litplus.size = strtoul (tmp + i + 1,NIL,10); } } } else flush (); /* overlong line after LITERAL+, punt */ } ping_mailbox (uid); /* update mailbox status before response */ if (lstwrn && lsterr) { /* output most recent warning */ PSOUT ("* NO "); PSOUT (lstwrn); CRLF; fs_give ((void **) &lstwrn); } if (response == logwin) { /* authentication win message */ sprintf (tmp,response,lstref ? "*" : tag); PSOUT (tmp); /* start response */ pcapability (1); /* print logged-in capabilities */ PSOUT ("] User "); PSOUT (user); PSOUT (" authenticated\015\012"); if (lstref) { sprintf (tmp,response,tag); PSOUT (tmp); /* start response */ PSOUT ("[REFERRAL "); PSOUT (lstref); PSOUT ("] "); PSOUT (lasterror ()); CRLF; } } else if ((response == win) || (response == lose)) { sprintf (tmp,response,tag); PSOUT (tmp); if (cauidvalidity) { /* COPYUID/APPENDUID response? */ sprintf (tmp,"[%.80sUID %lu ",(char *) ((s = strchr (cmd,' ')) ? s+1 : cmd),cauidvalidity); PSOUT (tmp); cauidvalidity = 0; /* cancel response for future */ if (csset) { pset (&csset); PBOUT (' '); } pset (&caset); PSOUT ("] "); } else if (lstref) { /* have a referral? */ PSOUT ("[REFERRAL "); PSOUT (lstref); PSOUT ("] "); } if (lsterr || lstwrn) PSOUT (lasterror ()); else { PSOUT (cmd); PSOUT ((response == win) ? " completed" : "failed"); } CRLF; } else { /* normal response */ if ((response == rowin) || (response == rwwin)) { if (lstwrn) { /* output most recent warning */ PSOUT ("* NO "); PSOUT (lstwrn); CRLF; fs_give ((void **) &lstwrn); } } sprintf (tmp,response,tag,cmd,lasterror ()); PSOUT (tmp); /* output response */ } } PFLUSH (); /* make sure output blatted */ if (autologouttime) { /* have an autologout in effect? */ /* cancel if no longer waiting for login */ if (state != LOGIN) autologouttime = 0; /* took too long to login */ else if (autologouttime < time (0)) { logout = goodbye = "Autologout"; stream = NIL; state = LOGOUT; /* sayonara */ } } } if (goodbye && !quell_events){/* have a goodbye message? */ PSOUT ("* BYE "); /* utter it */ PSOUT (goodbye); CRLF; PFLUSH (); /* make sure blatted */ } syslog (LOG_INFO,"%s user=%.80s host=%.80s",logout, user ? (char *) user : "???",tcp_clienthost ()); /* do logout hook if needed */ if (lgoh = (logouthook_t) mail_parameters (NIL,GET_LOGOUTHOOK,NIL)) (*lgoh) (mail_parameters (NIL,GET_LOGOUTDATA,NIL)); _exit (ret); /* all done */ return ret; /* stupid compilers */ } /* Ping mailbox during each cycle. Also check alerts * Accepts: last command was UID flag */ void ping_mailbox (unsigned long uid) { unsigned long i; char tmp[MAILTMPLEN]; if (state == OPEN) { if (!mail_ping (stream)) { /* make sure stream still alive */ PSOUT ("* BYE "); PSOUT (mylocalhost ()); PSOUT (" Fatal mailbox error: "); PSOUT (lasterror ()); CRLF; stream = NIL; /* don't try to clean up stream */ state = LOGOUT; /* go away */ syslog (LOG_INFO, "Fatal mailbox error user=%.80s host=%.80s mbx=%.80s: %.80s", user ? (char *) user : "???",tcp_clienthost (), (stream && stream->mailbox) ? stream->mailbox : "???", lasterror ()); return; } /* change in number of messages? */ if (existsquelled || (nmsgs != stream->nmsgs)) { PSOUT ("* "); pnum (nmsgs = stream->nmsgs); PSOUT (" EXISTS\015\012"); } /* change in recent messages? */ if (existsquelled || (recent != stream->recent)) { PSOUT ("* "); pnum (recent = stream->recent); PSOUT (" RECENT\015\012"); } existsquelled = NIL; /* don't do this until asked again */ if (stream->uid_validity && (stream->uid_validity != uidvalidity)) { PSOUT ("* OK [UIDVALIDITY "); pnum (stream->uid_validity); PSOUT ("] UID validity status\015\012* OK [UIDNEXT "); pnum (stream->uid_last + 1); PSOUT ("] Predicted next UID\015\012"); if (stream->uid_nosticky) { PSOUT ("* NO [UIDNOTSTICKY] Non-permanent unique identifiers: "); PSOUT (stream->mailbox); CRLF; } uidvalidity = stream->uid_validity; } /* don't bother if driver changed */ if (curdriver == stream->dtb) { /* first report any new flags */ if ((nflags < NUSERFLAGS) && stream->user_flags[nflags]) new_flags (stream); for (i = 1; i <= nmsgs; i++) if (mail_elt (stream,i)->spare2) { PSOUT ("* "); pnum (i); PSOUT (" FETCH ("); fetch_flags (i,NIL); /* output changed flags */ if (uid) { /* need to include UIDs in response? */ PBOUT (' '); fetch_uid (i,NIL); } PSOUT (")\015\012"); } } else { /* driver changed */ new_flags (stream); /* send mailbox flags */ if (curdriver) { /* note readonly/write if possible change */ PSOUT ("* OK [READ-"); PSOUT (stream->rdonly ? "ONLY" : "WRITE"); PSOUT ("] Mailbox status\015\012"); } curdriver = stream->dtb; if (nmsgs) { /* get flags for all messages */ sprintf (tmp,"1:%lu",nmsgs); mail_fetch_flags (stream,tmp,NIL); /* don't do this if newsrc already did */ if (!(curdriver->flags & DR_NEWS)) { /* find first unseen message */ for (i = 1; i <= nmsgs && mail_elt (stream,i)->seen; i++); if (i <= nmsgs) { PSOUT ("* OK [UNSEEN "); pnum (i); PSOUT ("] first unseen message in "); PSOUT (stream->mailbox); CRLF; } } } } } if (shutdowntime && (time (0) > shutdowntime + SHUTDOWNTIMER)) { PSOUT ("* BYE Server shutting down\015\012"); state = LOGOUT; } /* don't do these stat()s every cycle */ else if (time (0) > alerttime + ALERTTIMER) { struct stat sbuf; /* have a shutdown file? */ if (!stat (SHUTDOWNFILE,&sbuf)) { PSOUT ("* OK [ALERT] Server shutting down shortly\015\012"); shutdowntime = time (0); } alerttime = time (0); /* output any new alerts */ sysalerttime = palert (ALERTFILE,sysalerttime); if (state != LOGIN) /* do user alert if logged in */ useralerttime = palert (mailboxfile (tmp,USERALERTFILE),useralerttime); } } /* Print an alert file * Accepts: path of alert file * time of last printed alert file * Returns: updated time of last printed alert file */ time_t palert (char *file,time_t oldtime) { FILE *alf; struct stat sbuf; int c,lc = '\012'; /* have a new alert file? */ if (stat (file,&sbuf) || (sbuf.st_mtime <= oldtime) || !(alf = fopen (file,"r"))) return oldtime; /* yes, display it */ while ((c = getc (alf)) != EOF) { if (lc == '\012') PSOUT ("* OK [ALERT] "); switch (c) { /* output character */ case '\012': /* newline means do CRLF */ CRLF; case '\015': /* flush CRs */ case '\0': /* flush nulls */ break; default: PBOUT (c); /* output all other characters */ break; } lc = c; /* note previous character */ } fclose (alf); if (lc != '\012') CRLF; /* final terminating CRLF */ return sbuf.st_mtime; /* return updated last alert time */ } /* Initialize file string structure for file stringstruct * Accepts: string structure * pointer to message data structure * size of string */ void msg_string_init (STRING *s,void *data,unsigned long size) { MSGDATA *md = (MSGDATA *) data; s->data = data; /* note stream/msgno and header length */ #if 0 s->size = size; /* message size */ s->curpos = s->chunk = /* load header */ mail_fetchheader_full (md->stream,md->msgno,NIL,&s->data1, FT_PREFETCHTEXT | FT_PEEK); #else /* This kludge is necessary because of broken mail stores */ mail_fetchtext_full (md->stream,md->msgno,&s->size,FT_PEEK); s->curpos = s->chunk = /* load header */ mail_fetchheader_full (md->stream,md->msgno,NIL,&s->data1,FT_PEEK); s->size += s->data1; /* header + body size */ #endif s->cursize = s->chunksize = s->data1; s->offset = 0; /* offset is start of message */ } /* Get next character from file stringstruct * Accepts: string structure * Returns: character, string structure chunk refreshed */ char msg_string_next (STRING *s) { char c = *s->curpos++; /* get next byte */ SETPOS (s,GETPOS (s)); /* move to next chunk */ return c; /* return the byte */ } /* Set string pointer position for file stringstruct * Accepts: string structure * new position */ void msg_string_setpos (STRING *s,unsigned long i) { MSGDATA *md = (MSGDATA *) s->data; if (i < s->data1) { /* want header? */ s->chunk = mail_fetchheader_full (md->stream,md->msgno,NIL,NIL,FT_PEEK); s->chunksize = s->data1; /* header length */ s->offset = 0; /* offset is start of message */ } else if (i < s->size) { /* want body */ s->chunk = mail_fetchtext_full (md->stream,md->msgno,NIL,FT_PEEK); s->chunksize = s->size - s->data1; s->offset = s->data1; /* offset is end of header */ } else { /* off end of message */ s->chunk = NIL; /* make sure that we crack on this then */ s->chunksize = 1; /* make sure SNX cracks the right way... */ s->offset = i; } /* initial position and size */ s->curpos = s->chunk + (i -= s->offset); s->cursize = s->chunksize - i; } /* Send flags for stream * Accepts: MAIL stream * scratch buffer */ void new_flags (MAILSTREAM *stream) { int i,c; PSOUT ("* FLAGS ("); for (i = 0; i < NUSERFLAGS; i++) if (stream->user_flags[i]) { PSOUT (stream->user_flags[i]); PBOUT (' '); nflags = i + 1; } PSOUT ("\\Answered \\Flagged \\Deleted \\Draft \\Seen)\015\012* OK [PERMANENTFLAGS ("); for (i = c = 0; i < NUSERFLAGS; i++) if ((stream->perm_user_flags & (1 << i)) && stream->user_flags[i]) put_flag (&c,stream->user_flags[i]); if (stream->kwd_create) put_flag (&c,"\\*"); if (stream->perm_answered) put_flag (&c,"\\Answered"); if (stream->perm_flagged) put_flag (&c,"\\Flagged"); if (stream->perm_deleted) put_flag (&c,"\\Deleted"); if (stream->perm_draft) put_flag (&c,"\\Draft"); if (stream->perm_seen) put_flag (&c,"\\Seen"); PSOUT (")] Permanent flags\015\012"); } /* Set timeout * Accepts: desired interval */ void settimeout (unsigned int i) { /* limit if not logged in */ if (i) alarm ((state == LOGIN) ? LOGINTIMEOUT : i); else alarm (0); } /* Clock interrupt * Returns only if critical code in progress */ void clkint (void) { settimeout (0); /* disable all interrupts */ server_init (NIL,NIL,NIL,SIG_IGN,SIG_IGN,SIG_IGN,SIG_IGN,SIG_IGN); logout = "Autologout"; goodbye = "Autologout (idle for too long)"; if (critical) { /* must defer if in critical code(?) */ close (0); /* kill stdin */ state = LOGOUT; /* die as soon as we can */ } else longjmp (jmpenv,1); /* die now */ } /* Kiss Of Death interrupt * Returns only if critical code in progress */ void kodint (void) { settimeout (0); /* disable all interrupts */ server_init (NIL,NIL,NIL,SIG_IGN,SIG_IGN,SIG_IGN,SIG_IGN,SIG_IGN); logout = goodbye = "Killed (lost mailbox lock)"; if (critical) { /* must defer if in critical code */ close (0); /* kill stdin */ state = LOGOUT; /* die as soon as we can */ } else longjmp (jmpenv,1); /* die now */ } /* Hangup interrupt * Returns only if critical code in progress */ void hupint (void) { settimeout (0); /* disable all interrupts */ server_init (NIL,NIL,NIL,SIG_IGN,SIG_IGN,SIG_IGN,SIG_IGN,SIG_IGN); logout = "Hangup"; goodbye = NIL; /* other end is already gone */ if (critical) { /* must defer if in critical code */ close (0); /* kill stdin */ close (1); /* and stdout */ state = LOGOUT; /* die as soon as we can */ } else longjmp (jmpenv,1); /* die now */ } /* Termination interrupt * Returns only if critical code in progress */ void trmint (void) { settimeout (0); /* disable all interrupts */ server_init (NIL,NIL,NIL,SIG_IGN,SIG_IGN,SIG_IGN,SIG_IGN,SIG_IGN); logout = goodbye = "Killed (terminated)"; /* Make no attempt at graceful closure since a shutdown may be in * progress, and we won't have any time to do mail_close() actions */ stream = NIL; if (critical) { /* must defer if in critical code */ close (0); /* kill stdin */ close (1); /* and stdout */ state = LOGOUT; /* die as soon as we can */ } else longjmp (jmpenv,1); /* die now */ } /* The routines on this and the next page eschew the use of non-syscall libc * routines (especially stdio) for a reason. Also, these hideous #if * condtionals need to be replaced. */ #ifndef unix #define unix 0 #endif /* Status request interrupt * Always returns */ void staint (void) { #if unix int fd; char *s,buf[8*MAILTMPLEN]; unsigned long pid = getpid (); /* build file name */ s = nout (sout (buf,"/tmp/imapd-status."),pid,10); if (user) s = sout (sout (s,"."),user); *s = '\0'; /* tie off file name */ if ((fd = open (buf,O_WRONLY | O_CREAT | O_TRUNC,0666)) >= 0) { fchmod (fd,0666); s = nout (sout (buf,"PID="),pid,10); if (user) s = sout (sout (s,", user="),user); switch (state) { case LOGIN: s = sout (s,", not logged in"); break; case SELECT: s = sout (s,", logged in"); break; case OPEN: s = sout (s,", mailbox open"); break; case LOGOUT: s = sout (s,", logging out"); break; } if (stream && stream->mailbox) s = sout (sout (s,"\nmailbox="),stream->mailbox); *s++ = '\n'; if (status) { s = sout (s,status); if (cmd) s = sout (sout (s,", last command="),cmd); } else s = sout (sout (s,cmd)," in progress"); *s++ = '\n'; write (fd,buf,s-buf); close (fd); } #endif } /* Write string * Accepts: destination string pointer * string * Returns: updated string pointer */ char *sout (char *s,char *t) { while (*t) *s++ = *t++; return s; } /* Write number * Accepts: destination string pointer * number * base * Returns: updated string pointer */ char *nout (char *s,unsigned long n,unsigned long base) { char stack[256]; char *t = stack; /* push PID digits on stack */ do *t++ = (char) (n % base) + '0'; while (n /= base); /* pop digits from stack */ while (t > stack) *s++ = *--t; return s; } /* Slurp a command line * Accepts: buffer pointer * buffer size * input timeout */ void slurp (char *s,int n,unsigned long timeout) { memset (s,'\0',n); /* zap buffer */ if (state != LOGOUT) { /* get a command under timeout */ settimeout (timeout); clearerr (stdin); /* clear stdin errors */ status = "reading line"; if (!PSIN (s,n-1)) ioerror (stdin,status); settimeout (0); /* make sure timeout disabled */ status = NIL; } } /* Read a literal * Accepts: destination buffer (must be size+1 for trailing NUL) * size of buffer (must be less than 4294967295) */ void inliteral (char *s,unsigned long n) { unsigned long i; if (litplus.ok) { /* no more LITERAL+ to worry about */ litplus.ok = NIL; litplus.size = 0; } else { /* otherwise tell client ready for argument */ PSOUT ("+ Ready for argument\015\012"); PFLUSH (); /* dump output buffer */ } clearerr (stdin); /* clear stdin errors */ memset (s,'\0',n+1); /* zap buffer */ status = "reading literal"; while (n) { /* get data under timeout */ if (state == LOGOUT) n = 0; else { settimeout (INPUTTIMEOUT); i = min (n,8192); /* must read at least 8K within timeout */ if (PSINR (s,i)) { s += i; n -= i; } else { ioerror (stdin,status); n = 0; /* in case it continues */ } settimeout (0); /* stop timeout */ } } } /* Flush until newline seen * Returns: NIL, always */ unsigned char *flush (void) { int c; if (state != LOGOUT) { settimeout (INPUTTIMEOUT); clearerr (stdin); /* clear stdin errors */ status = "flushing line"; while ((c = PBIN ()) != '\012') if (c == EOF) ioerror (stdin,status); settimeout (0); /* make sure timeout disabled */ } response = "%.80s BAD Command line too long\015\012"; status = NIL; return NIL; } /* Report command stream error and die * Accepts: stdin or stdout (whichever got the error) * reason (what caller was doing) */ void ioerror (FILE *f,char *reason) { static char msg[MAILTMPLEN]; char *s,*t; if (logout) { /* say nothing if already dying */ settimeout (0); /* disable all interrupts */ server_init (NIL,NIL,NIL,SIG_IGN,SIG_IGN,SIG_IGN,SIG_IGN,SIG_IGN); /* write error string */ for (s = ferror (f) ? strerror (errno) : "Unexpected client disconnect", t = logout = msg; *s; *t++ = *s++); for (s = ", while "; *s; *t++ = *s++); for (s = reason; *s; *t++ = *s++); if (critical) { /* must defer if in critical code */ close (0); /* kill stdin */ close (1); /* and stdout */ state = LOGOUT; /* die as soon as we can */ } else longjmp (jmpenv,1); /* die now */ } } /* Parse an IMAP astring * Accepts: pointer to argument text pointer * pointer to returned size * pointer to returned delimiter * Returns: argument */ unsigned char *parse_astring (unsigned char **arg,unsigned long *size, unsigned char *del) { unsigned long i; unsigned char c,*s,*t,*v; if (!*arg) return NIL; /* better be an argument */ switch (**arg) { /* see what the argument is */ default: /* atom */ for (s = t = *arg, i = 0; (*t > ' ') && (*t < 0x7f) && (*t != '(') && (*t != ')') && (*t != '{') && (*t != '%') && (*t != '*') && (*t != '"') && (*t != '\\'); ++t,++i); if (*size = i) break; /* got atom if non-empty */ case ')': case '%': case '*': case '\\': case '\0': case ' ': return NIL; /* empty atom is a bogon */ case '"': /* hunt for trailing quote */ for (s = t = v = *arg + 1; (c = *t++) != '"'; *v++ = c) { /* quote next character */ if (c == '\\') switch (c = *t++) { case '"': case '\\': break; default: return NIL; /* invalid quote-next */ } /* else must be a CHAR */ if (!c || (c & 0x80)) return NIL; } *v = '\0'; /* tie off string */ *size = v - s; /* return size */ break; case '{': /* literal string */ s = *arg + 1; /* get size */ if (!isdigit (*s)) return NIL; if ((*size = i = strtoul (s,(char **) &t,10)) > MAXCLIENTLIT) { mm_notify (NIL,"Absurdly long client literal",ERROR); syslog (LOG_INFO,"Overlong (%lu) client literal user=%.80s host=%.80s", i,user ? (char *) user : "???",tcp_clienthost ()); return NIL; } switch (*t) { /* validate end of literal */ case '+': /* non-blocking literal */ if (*++t != '}') return NIL; case '}': if (!t[1]) break; /* OK if end of line */ default: return NIL; /* bad literal */ } if (litsp >= LITSTKLEN) { /* make sure don't overflow stack */ mm_notify (NIL,"Too many literals in command",ERROR); return NIL; } /* get a literal buffer */ inliteral (s = litstk[litsp++] = (char *) fs_get (i+1),i); /* get new command tail */ slurp (*arg = t,CMDLEN - (t - cmdbuf),INPUTTIMEOUT); if (!strchr (t,'\012')) return flush (); /* reset strtok mechanism, tie off if done */ if (!strtok (t,"\015\012")) *t = '\0'; /* possible LITERAL+? */ if (((i = strlen (t)) > 3) && (t[i - 1] == '}') && (t[i - 2] == '+') && isdigit (t[i - 3])) { /* back over possible count */ for (i -= 4; i && isdigit (t[i]); i--); if (t[i] == '{') { /* found a literal? */ litplus.ok = T; /* yes, note LITERAL+ in effect, set size */ litplus.size = strtoul (t + i + 1,NIL,10); } } break; } if (*del = *t) { /* have a delimiter? */ *t++ = '\0'; /* yes, stomp on it */ *arg = t; /* update argument pointer */ } else *arg = NIL; /* no more arguments */ return s; } /* Snarf a command argument (simple jacket into parse_astring()) * Accepts: pointer to argument text pointer * Returns: argument */ unsigned char *snarf (unsigned char **arg) { unsigned long i; unsigned char c; unsigned char *s = parse_astring (arg,&i,&c); return ((c == ' ') || !c) ? s : NIL; } /* Snarf a BASE64 argument for SASL-IR * Accepts: pointer to argument text pointer * Returns: argument */ unsigned char *snarf_base64 (unsigned char **arg) { unsigned char *ret = *arg; unsigned char *s = ret + 1; static char base64mask[256] = { 0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0, 0,0,0,0,0,0,0,0,0,0,0,1,0,0,0,1,1,1,1,1,1,1,1,1,1,1,0,0,0,0,0,0, 0,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,0,0,0,0,0, 0,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,0,0,0,0,0, 0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0, 0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0, 0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0, 0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0 }; if (*(ret = *arg) == '='); /* easy case if zero-length argument */ /* must be at least one BASE64 char */ else if (!base64mask[*ret]) return NIL; else { /* quick and dirty */ while (base64mask[*s++]); /* scan until end of BASE64 */ if (*s == '=') ++s; /* allow up to two padding chars */ if (*s == '=') ++s; } switch (*s) { /* anything following the argument? */ case ' ': /* another argument */ *s++ = '\0'; /* tie off previous argument */ *arg = s; /* and update argument pointer */ break; case '\0': /* end of command */ *arg = NIL; break; default: /* syntax error */ return NIL; } return ret; /* return BASE64 string */ } /* Snarf a list command argument (simple jacket into parse_astring()) * Accepts: pointer to argument text pointer * Returns: argument */ unsigned char *snarf_list (unsigned char **arg) { unsigned long i; unsigned char c,*s,*t; if (!*arg) return NIL; /* better be an argument */ switch (**arg) { default: /* atom and/or wildcard chars */ for (s = t = *arg, i = 0; (*t > ' ') && (*t != '(') && (*t != ')') && (*t != '{') && (*t != '"') && (*t != '\\'); ++t,++i); if (c = *t) { /* have a delimiter? */ *t++ = '\0'; /* stomp on it */ *arg = t; /* update argument pointer */ } else *arg = NIL; break; case ')': case '\\': case '\0': case ' ': return NIL; /* empty name is bogus */ case '"': /* quoted string? */ case '{': /* or literal? */ s = parse_astring (arg,&i,&c); break; } return ((c == ' ') || !c) ? s : NIL; } /* Get a list of header lines * Accepts: pointer to string pointer * pointer to list flag * Returns: string list */ STRINGLIST *parse_stringlist (unsigned char **s,int *list) { char c = ' ',*t; unsigned long i; STRINGLIST *ret = NIL,*cur = NIL; if (*s && **s == '(') { /* proper list? */ ++*s; /* for each item in list */ while ((c == ' ') && (t = parse_astring (s,&i,&c))) { /* get new block */ if (cur) cur = cur->next = mail_newstringlist (); else cur = ret = mail_newstringlist (); /* note text */ cur->text.data = (unsigned char *) fs_get (i + 1); memcpy (cur->text.data,t,i); cur->text.size = i; /* and size */ } /* must be end of list */ if (c != ')') mail_free_stringlist (&ret); } if (t = *s) { /* need to reload strtok() state? */ /* end of a list? */ if (*list && (*t == ')') && !t[1]) *list = NIL; else { *--t = ' '; /* patch a space back in */ *--t = 'x'; /* and a hokey character before that */ t = strtok (t," "); /* reset to *s */ } } return ret; } /* Get value of UID * for criteria parsing * Accepts: stream * Returns: maximum UID */ unsigned long uidmax (MAILSTREAM *stream) { return stream->nmsgs ? mail_uid (stream,stream->nmsgs) : 0xffffffff; } /* Parse search criteria * Accepts: search program to write criteria into * pointer to argument text pointer * maximum message number * maximum UID * logical nesting depth * Returns: T if success, NIL if error */ long parse_criteria (SEARCHPGM *pgm,unsigned char **arg,unsigned long maxmsg, unsigned long maxuid,unsigned long depth) { if (arg && *arg) { /* must be an argument */ /* parse criteria */ do if (!parse_criterion (pgm,arg,maxmsg,maxuid,depth)) return NIL; /* as long as a space delimiter */ while (**arg == ' ' && (*arg)++); /* failed if not end of criteria */ if (**arg && **arg != ')') return NIL; } return T; /* success */ } /* Parse a search criterion * Accepts: search program to write criterion into * pointer to argument text pointer * maximum message number * maximum UID * logical nesting depth * Returns: T if success, NIL if error */ long parse_criterion (SEARCHPGM *pgm,unsigned char **arg,unsigned long maxmsg, unsigned long maxuid,unsigned long depth) { unsigned long i; unsigned char c = NIL,*s,*t,*v,*tail,*del; SEARCHSET **set; SEARCHPGMLIST **not; SEARCHOR **or; SEARCHHEADER **hdr; long ret = NIL; /* better be an argument */ if ((depth > 500) || !(arg && *arg)); else if (**arg == '(') { /* list of criteria? */ (*arg)++; /* yes, parse the criteria */ if (parse_criteria (pgm,arg,maxmsg,maxuid,depth+1) && **arg == ')') { (*arg)++; /* skip closing paren */ ret = T; /* successful parse of list */ } } else { /* find end of criterion */ if (!(tail = strpbrk ((s = *arg)," )"))) tail = *arg + strlen (*arg); c = *(del = tail); /* remember the delimiter */ *del = '\0'; /* tie off criterion */ switch (*ucase (s)) { /* dispatch based on character */ case '*': /* sequence */ case '0': case '1': case '2': case '3': case '4': case '5': case '6': case '7': case '8': case '9': if (*(set = &pgm->msgno)){/* already a sequence? */ /* silly, but not as silly as the client! */ for (not = &pgm->not; *not; not = &(*not)->next); *not = mail_newsearchpgmlist (); set = &((*not)->pgm->not = mail_newsearchpgmlist ())->pgm->msgno; } ret = crit_set (set,&s,maxmsg) && (tail == s); break; case 'A': /* possible ALL, ANSWERED */ if (!strcmp (s+1,"LL")) ret = T; else if (!strcmp (s+1,"NSWERED")) ret = pgm->answered = T; break; case 'B': /* possible BCC, BEFORE, BODY */ if (!strcmp (s+1,"CC") && c == ' ' && *++tail) ret = crit_string (&pgm->bcc,&tail); else if (!strcmp (s+1,"EFORE") && c == ' ' && *++tail) ret = crit_date (&pgm->before,&tail); else if (!strcmp (s+1,"ODY") && c == ' ' && *++tail) ret = crit_string (&pgm->body,&tail); break; case 'C': /* possible CC */ if (!strcmp (s+1,"C") && c == ' ' && *++tail) ret = crit_string (&pgm->cc,&tail); break; case 'D': /* possible DELETED */ if (!strcmp (s+1,"ELETED")) ret = pgm->deleted = T; if (!strcmp (s+1,"RAFT")) ret = pgm->draft = T; break; case 'F': /* possible FLAGGED, FROM */ if (!strcmp (s+1,"LAGGED")) ret = pgm->flagged = T; else if (!strcmp (s+1,"ROM") && c == ' ' && *++tail) ret = crit_string (&pgm->from,&tail); break; case 'H': /* possible HEADER */ if (!strcmp (s+1,"EADER") && c == ' ' && *(v = tail + 1) && (s = parse_astring (&v,&i,&c)) && i && c == ' ' && (t = parse_astring (&v,&i,&c))) { for (hdr = &pgm->header; *hdr; hdr = &(*hdr)->next); *hdr = mail_newsearchheader (s,t); /* update tail, restore delimiter */ *(tail = v ? v - 1 : t + i) = c; ret = T; /* success */ } break; case 'K': /* possible KEYWORD */ if (!strcmp (s+1,"EYWORD") && c == ' ' && *++tail) ret = crit_string (&pgm->keyword,&tail); break; case 'L': if (!strcmp (s+1,"ARGER") && c == ' ' && *++tail) ret = crit_number (&pgm->larger,&tail); break; case 'N': /* possible NEW, NOT */ if (!strcmp (s+1,"EW")) ret = pgm->recent = pgm->unseen = T; else if (!strcmp (s+1,"OT") && c == ' ' && *++tail) { for (not = &pgm->not; *not; not = &(*not)->next); *not = mail_newsearchpgmlist (); ret = parse_criterion ((*not)->pgm,&tail,maxmsg,maxuid,depth+1); } break; case 'O': /* possible OLD, ON */ if (!strcmp (s+1,"LD")) ret = pgm->old = T; else if (!strcmp (s+1,"N") && c == ' ' && *++tail) ret = crit_date (&pgm->on,&tail); else if (!strcmp (s+1,"R") && c == ' ') { for (or = &pgm->or; *or; or = &(*or)->next); *or = mail_newsearchor (); ret = *++tail && parse_criterion((*or)->first,&tail,maxmsg,maxuid, depth+1) && (*tail == ' ') && *++tail && parse_criterion ((*or)->second,&tail,maxmsg,maxuid,depth+1); } else if (!strcmp (s+1,"LDER") && c == ' ' && *++tail) ret = crit_number (&pgm->older,&tail); break; case 'R': /* possible RECENT */ if (!strcmp (s+1,"ECENT")) ret = pgm->recent = T; break; case 'S': /* possible SEEN, SINCE, SUBJECT */ if (!strcmp (s+1,"EEN")) ret = pgm->seen = T; else if (!strcmp (s+1,"ENTBEFORE") && c == ' ' && *++tail) ret = crit_date (&pgm->sentbefore,&tail); else if (!strcmp (s+1,"ENTON") && c == ' ' && *++tail) ret = crit_date (&pgm->senton,&tail); else if (!strcmp (s+1,"ENTSINCE") && c == ' ' && *++tail) ret = crit_date (&pgm->sentsince,&tail); else if (!strcmp (s+1,"INCE") && c == ' ' && *++tail) ret = crit_date (&pgm->since,&tail); else if (!strcmp (s+1,"MALLER") && c == ' ' && *++tail) ret = crit_number (&pgm->smaller,&tail); else if (!strcmp (s+1,"UBJECT") && c == ' ' && *++tail) ret = crit_string (&pgm->subject,&tail); break; case 'T': /* possible TEXT, TO */ if (!strcmp (s+1,"EXT") && c == ' ' && *++tail) ret = crit_string (&pgm->text,&tail); else if (!strcmp (s+1,"O") && c == ' ' && *++tail) ret = crit_string (&pgm->to,&tail); break; case 'U': /* possible UID, UN* */ if (!strcmp (s+1,"ID") && c== ' ' && *++tail) { if (*(set = &pgm->uid)){/* already a sequence? */ /* silly, but not as silly as the client! */ for (not = &pgm->not; *not; not = &(*not)->next); *not = mail_newsearchpgmlist (); set = &((*not)->pgm->not = mail_newsearchpgmlist ())->pgm->uid; } ret = crit_set (set,&tail,maxuid); } else if (!strcmp (s+1,"NANSWERED")) ret = pgm->unanswered = T; else if (!strcmp (s+1,"NDELETED")) ret = pgm->undeleted = T; else if (!strcmp (s+1,"NDRAFT")) ret = pgm->undraft = T; else if (!strcmp (s+1,"NFLAGGED")) ret = pgm->unflagged = T; else if (!strcmp (s+1,"NKEYWORD") && c == ' ' && *++tail) ret = crit_string (&pgm->unkeyword,&tail); else if (!strcmp (s+1,"NSEEN")) ret = pgm->unseen = T; break; case 'Y': /* possible YOUNGER */ if (!strcmp (s+1,"OUNGER") && c == ' ' && *++tail) ret = crit_number (&pgm->younger,&tail); break; default: /* oh dear */ break; } if (ret) { /* only bother if success */ *del = c; /* restore delimiter */ *arg = tail; /* update argument pointer */ } } return ret; /* return more to come */ } /* Parse a search date criterion * Accepts: date to write into * pointer to argument text pointer * Returns: T if success, NIL if error */ long crit_date (unsigned short *date,unsigned char **arg) { if (*date) return NIL; /* can't double this value */ /* handle quoted form */ if (**arg != '"') return crit_date_work (date,arg); (*arg)++; /* skip past opening quote */ if (!(crit_date_work (date,arg) && (**arg == '"'))) return NIL; (*arg)++; /* skip closing quote */ return T; } /* Worker routine to parse a search date criterion * Accepts: date to write into * pointer to argument text pointer * Returns: T if success, NIL if error */ long crit_date_work (unsigned short *date,unsigned char **arg) { int d,m,y; /* day */ if (isdigit (d = *(*arg)++) || ((d == ' ') && isdigit (**arg))) { if (d == ' ') d = 0; /* leading space */ else d -= '0'; /* first digit */ if (isdigit (**arg)) { /* if a second digit */ d *= 10; /* slide over first digit */ d += *(*arg)++ - '0'; /* second digit */ } if ((**arg == '-') && (y = *++(*arg))) { m = (y >= 'a' ? y - 'a' : y - 'A') * 1024; if ((y = *++(*arg))) { m += (y >= 'a' ? y - 'a' : y - 'A') * 32; if ((y = *++(*arg))) { m += (y >= 'a' ? y - 'a' : y - 'A'); switch (m) { /* determine the month */ case (('J'-'A') * 1024) + (('A'-'A') * 32) + ('N'-'A'): m = 1; break; case (('F'-'A') * 1024) + (('E'-'A') * 32) + ('B'-'A'): m = 2; break; case (('M'-'A') * 1024) + (('A'-'A') * 32) + ('R'-'A'): m = 3; break; case (('A'-'A') * 1024) + (('P'-'A') * 32) + ('R'-'A'): m = 4; break; case (('M'-'A') * 1024) + (('A'-'A') * 32) + ('Y'-'A'): m = 5; break; case (('J'-'A') * 1024) + (('U'-'A') * 32) + ('N'-'A'): m = 6; break; case (('J'-'A') * 1024) + (('U'-'A') * 32) + ('L'-'A'): m = 7; break; case (('A'-'A') * 1024) + (('U'-'A') * 32) + ('G'-'A'): m = 8; break; case (('S'-'A') * 1024) + (('E'-'A') * 32) + ('P'-'A'): m = 9; break; case (('O'-'A') * 1024) + (('C'-'A') * 32) + ('T'-'A'): m = 10;break; case (('N'-'A') * 1024) + (('O'-'A') * 32) + ('V'-'A'): m = 11;break; case (('D'-'A') * 1024) + (('E'-'A') * 32) + ('C'-'A'): m = 12;break; default: return NIL; } if ((*++(*arg) == '-') && isdigit (*++(*arg))) { y = 0; /* init year */ do { y *= 10; /* add this number */ y += *(*arg)++ - '0'; } while (isdigit (**arg)); /* minimal validity check of date */ if (d < 1 || d > 31 || m < 1 || m > 12 || y < 0) return NIL; /* time began on UNIX in 1970 */ if (y < 100) y += (y >= (BASEYEAR - 1900)) ? 1900 : 2000; /* return value */ *date = mail_shortdate (y - BASEYEAR,m,d); return T; /* success */ } } } } } return NIL; /* else error */ } /* Parse a search set criterion * Accepts: set to write into * pointer to argument text pointer * maximum value permitted * Returns: T if success, NIL if error */ long crit_set (SEARCHSET **set,unsigned char **arg,unsigned long maxima) { unsigned long i = 0; if (*set) return NIL; /* can't double this value */ *set = mail_newsearchset (); /* instantiate a new search set */ if (**arg == '*') { /* maxnum? */ (*arg)++; /* skip past that number */ (*set)->first = maxima; } else if (crit_number (&i,arg) && i) (*set)->first = i; else return NIL; /* bogon */ switch (**arg) { /* decide based on delimiter */ case ':': /* sequence range */ i = 0; /* reset for crit_number() */ if (*++(*arg) == '*') { /* maxnum? */ (*arg)++; /* skip past that number */ (*set)->last = maxima; } else if (crit_number (&i,arg) && i) { if (i < (*set)->first) { /* backwards range */ (*set)->last = (*set)->first; (*set)->first = i; } else (*set)->last = i; /* set last number */ } else return NIL; /* bogon */ if (**arg != ',') break; /* drop into comma case if comma seen */ case ',': (*arg)++; /* skip past delimiter */ return crit_set (&(*set)->next,arg,maxima); default: break; } return T; /* return success */ } /* Parse a search number criterion * Accepts: number to write into * pointer to argument text pointer * Returns: T if success, NIL if error */ long crit_number (unsigned long *number,unsigned char **arg) { /* can't double this value */ if (*number || !isdigit (**arg)) return NIL; *number = 0; while (isdigit (**arg)) { /* found a digit? */ *number *= 10; /* add a decade */ *number += *(*arg)++ - '0'; /* add number */ } return T; } /* Parse a search string criterion * Accepts: date to write into * pointer to argument text pointer * Returns: T if success, NIL if error */ long crit_string (STRINGLIST **string,unsigned char **arg) { unsigned long i; char c; char *s = parse_astring (arg,&i,&c); if (!s) return NIL; /* find tail of list */ while (*string) string = &(*string)->next; *string = mail_newstringlist (); (*string)->text.data = (unsigned char *) fs_get (i + 1); memcpy ((*string)->text.data,s,i); (*string)->text.data[i] = '\0'; (*string)->text.size = i; /* if end of arguments, wrap it up here */ if (!*arg) *arg = (char *) (*string)->text.data + i; else (*--(*arg) = c); /* back up pointer, restore delimiter */ return T; } /* Fetch message data * Accepts: string of data items to be fetched (must be writeable) * UID fetch flag */ #define MAXFETCH 100 void fetch (char *t,unsigned long uid) { fetchfn_t f[MAXFETCH +2]; void *fa[MAXFETCH + 2]; int k; memset ((void *) f,NIL,sizeof (f)); memset ((void *) fa,NIL,sizeof (fa)); fetch_work (t,uid,f,fa); /* do the work */ /* clean up arguments */ for (k = 1; f[k]; k++) if (fa[k]) (*f[k]) (0,fa[k]); } /* Fetch message data worker routine * Accepts: string of data items to be fetched (must be writeable) * UID fetch flag * function dispatch vector * function argument vector */ void fetch_work (char *t,unsigned long uid,fetchfn_t f[],void *fa[]) { unsigned char *s,*v; unsigned long i; unsigned long k = 0; BODY *b; int list = NIL; int parse_envs = NIL; int parse_bodies = NIL; if (uid) { /* need to fetch UIDs? */ fa[k] = NIL; /* no argument */ f[k++] = fetch_uid; /* push a UID fetch on the stack */ } /* process macros */ if (!strcmp (ucase (t),"ALL")) strcpy (t,"(FLAGS INTERNALDATE RFC822.SIZE ENVELOPE)"); else if (!strcmp (t,"FULL")) strcpy (t,"(FLAGS INTERNALDATE RFC822.SIZE ENVELOPE BODY)"); else if (!strcmp (t,"FAST")) strcpy (t,"(FLAGS INTERNALDATE RFC822.SIZE)"); if (list = (*t == '(')) t++; /* skip open paren */ if (s = strtok (t," ")) do { /* parse attribute list */ if (list && (i = strlen (s)) && (s[i-1] == ')')) { list = NIL; /* done with list */ s[i-1] = '\0'; /* tie off last item */ } fa[k] = NIL; /* default to no argument */ if (!strcmp (s,"UID")) { /* no-op if implicit */ if (!uid) f[k++] = fetch_uid; } else if (!strcmp (s,"FLAGS")) f[k++] = fetch_flags; else if (!strcmp (s,"INTERNALDATE")) f[k++] = fetch_internaldate; else if (!strcmp (s,"RFC822.SIZE")) f[k++] = fetch_rfc822_size; else if (!strcmp (s,"ENVELOPE")) { parse_envs = T; /* we will need to parse envelopes */ f[k++] = fetch_envelope; } else if (!strcmp (s,"BODY")) { parse_envs = parse_bodies = T; f[k++] = fetch_body; } else if (!strcmp (s,"BODYSTRUCTURE")) { parse_envs = parse_bodies = T; f[k++] = fetch_bodystructure; } else if (!strcmp (s,"RFC822")) { fa[k] = s[6] ? (void *) FT_PEEK : NIL; f[k++] = fetch_rfc822; } else if (!strcmp (s,"RFC822.HEADER")) f[k++] = fetch_rfc822_header; else if (!strcmp (s,"RFC822.TEXT")) { fa[k] = s[11] ? (void *) FT_PEEK : NIL; f[k++] = fetch_rfc822_text; } else if (!strncmp (s,"BODY[",5) || !strncmp (s,"BODY.PEEK[",10) || !strncmp (s,"BINARY[",7) || !strncmp (s,"BINARY.PEEK[",12) || !strncmp (s,"BINARY.SIZE[",12)) { TEXTARGS *ta = (TEXTARGS *) memset (fs_get (sizeof (TEXTARGS)),0,sizeof (TEXTARGS)); if (s[1] == 'I') { /* body or binary? */ ta->binary = FTB_BINARY;/* binary */ f[k] = fetch_body_part_binary; if (s[6] == '.') { /* wanted peek or size? */ if (s[7] == 'P') ta->flags = FT_PEEK; else ta->binary |= FTB_SIZE; s += 12; /* skip to section specifier */ } else s += 7; /* skip to section specifier */ if (!isdigit (*s)) { /* make sure top-level digit */ fs_give ((void **) &ta); response = badbin; return; } } else { /* body */ f[k] = fetch_body_part_contents; if (s[4] == '.') { /* wanted peek? */ ta->flags = FT_PEEK; s += 10; /* skip to section specifier */ } else s += 5; /* skip to section specifier */ } if (*(v = s) != ']') { /* non-empty section specifier? */ if (isdigit (*v)) { /* have section specifier? */ /* need envelopes and bodies */ parse_envs = parse_bodies = T; while (isdigit (*v)) /* scan to end of section specifier */ if ((*++v == '.') && isdigit (v[1])) v++; /* any IMAP4rev1 stuff following? */ if ((*v == '.') && isalpha (v[1])) { if (ta->binary) { /* not if binary you don't */ fs_give ((void **) &ta); response = badbin; return; } *v++ = '\0'; /* yes, tie off section specifier */ if (!strncmp (v,"MIME",4)) { v += 4; /* found
.MIME */ f[k] = fetch_body_part_mime; } } else if (*v != ']') { /* better be the end if no IMAP4rev1 stuff */ fs_give ((void **) &ta);/* clean up */ response = "%.80s BAD Syntax error in section specifier\015\012"; return; } } if (*v != ']') { /* IMAP4rev1 stuff here? */ if (!strncmp (v,"HEADER",6)) { *v = '\0'; /* tie off in case top level */ v += 6; /* found [
.]HEADER */ f[k] = fetch_body_part_header; /* partial headers wanted? */ if (!strncmp (v,".FIELDS",7)) { v += 7; /* yes */ if (!strncmp (v,".NOT",4)) { v += 4; /* want to exclude named headers */ ta->flags |= FT_NOT; } if (*v || !(v = strtok (NIL,"\015\012")) || !(ta->lines = parse_stringlist (&v,&list))) { fs_give ((void **) &ta);/* clean up */ response = "%.80s BAD Syntax error in header fields\015\012"; return; } } } else if (!strncmp (v,"TEXT",4)) { *v = '\0'; /* tie off in case top level */ v += 4; /* found [
.]TEXT */ f[k] = fetch_body_part_text; } else { fs_give ((void **) &ta);/* clean up */ response = "%.80s BAD Unknown section text specifier\015\012"; return; } } } /* tie off section */ if (*v == ']') *v++ = '\0'; else { /* bogon */ if (ta->lines) mail_free_stringlist (&ta->lines); fs_give ((void **) &ta);/* clean up */ response = "%.80s BAD Section specifier not terminated\015\012"; return; } if ((*v == '<') && /* partial specifier? */ ((ta->binary & FTB_SIZE) || !(isdigit (v[1]) && ((ta->first = strtoul (v+1,(char **) &v,10)) || v) && (*v++ == '.') && (ta->last = strtoul (v,(char **) &v,10)) && (*v++ == '>')))) { if (ta->lines) mail_free_stringlist (&ta->lines); fs_give ((void **) &ta); response ="%.80s BAD Syntax error in partial text specifier\015\012"; return; } switch (*v) { /* what's there now? */ case ' ': /* more follows */ *--v = ' '; /* patch a space back in */ *--v = 'x'; /* and a hokey character before that */ strtok (v," "); /* reset strtok mechanism */ break; case '\0': /* none */ break; case ')': /* end of list */ if (list && !v[1]) { /* make sure of that */ list = NIL; strtok (v," "); /* reset strtok mechanism */ break; /* all done */ } /* otherwise it's a bogon, drop in */ default: /* bogon */ if (ta->lines) mail_free_stringlist (&ta->lines); fs_give ((void **) &ta); response = "%.80s BAD Syntax error after section specifier\015\012"; return; } /* make copy of section specifier */ if (s && *s) ta->section = cpystr (s); fa[k++] = (void *) ta; /* set argument */ } else { /* unknown attribute */ response = badatt; return; } } while ((s = strtok (NIL," ")) && (k < MAXFETCH) && list); else { response = misarg; /* missing attribute list */ return; } if (s) { /* too many attributes? */ response = "%.80s BAD Excessively complex FETCH attribute list\015\012"; return; } if (list) { /* too many attributes? */ response = "%.80s BAD Unterminated FETCH attribute list\015\012"; return; } f[k] = NIL; /* tie off attribute list */ /* c-client clobbers sequence, use spare */ for (i = 1; i <= nmsgs; i++) mail_elt (stream,i)->spare = mail_elt (stream,i)->sequence; /* for each requested message */ for (i = 1; (i <= nmsgs) && (response != loseunknowncte); i++) { /* kill if dying */ if (state == LOGOUT) longjmp (jmpenv,1); if (mail_elt (stream,i)->spare) { /* parse envelope, set body, do warnings */ if (parse_envs) mail_fetchstructure (stream,i,parse_bodies ? &b : NIL); quell_events = T; /* can't do any events now */ PSOUT ("* "); /* leader */ pnum (i); PSOUT (" FETCH ("); (*f[0]) (i,fa[0]); /* do first attribute */ /* for each subsequent attribute */ for (k = 1; f[k] && (response != loseunknowncte); k++) { PBOUT (' '); /* delimit with space */ (*f[k]) (i,fa[k]); /* do that attribute */ } PSOUT (")\015\012"); /* trailer */ quell_events = NIL; /* events alright now */ } } } /* Fetch message body structure (extensible) * Accepts: message number * extra argument */ void fetch_bodystructure (unsigned long i,void *args) { BODY *body; mail_fetchstructure (stream,i,&body); PSOUT ("BODYSTRUCTURE "); pbodystructure (body); /* output body */ } /* Fetch message body structure (non-extensible) * Accepts: message number * extra argument */ void fetch_body (unsigned long i,void *args) { BODY *body; mail_fetchstructure (stream,i,&body); PSOUT ("BODY "); /* output attribute */ pbody (body); /* output body */ } /* Fetch body part MIME header * Accepts: message number * extra argument */ void fetch_body_part_mime (unsigned long i,void *args) { TEXTARGS *ta = (TEXTARGS *) args; if (i) { /* do work? */ SIZEDTEXT st; unsigned long uid = mail_uid (stream,i); char *tmp = (char *) fs_get (100 + strlen (ta->section)); sprintf (tmp,"BODY[%s.MIME]",ta->section); /* try to use remembered text */ if (lastuid && (uid == lastuid) && !strcmp (tmp,lastid)) st = lastst; else { /* get data */ st.data = (unsigned char *) mail_fetch_mime (stream,i,ta->section,&st.size,ta->flags); if (ta->first || ta->last) remember (uid,tmp,&st); } pbodypartstring (i,tmp,&st,NIL,ta); fs_give ((void **) &tmp); } else { /* clean up the arguments */ fs_give ((void **) &ta->section); fs_give ((void **) &args); } } /* Fetch body part contents * Accepts: message number * extra argument */ void fetch_body_part_contents (unsigned long i,void *args) { TEXTARGS *ta = (TEXTARGS *) args; if (i) { /* do work? */ SIZEDTEXT st; char *tmp = (char *) fs_get (100+(ta->section ? strlen (ta->section) : 0)); unsigned long uid = mail_uid (stream,i); sprintf (tmp,"BODY[%s]",ta->section ? ta->section : ""); /* try to use remembered text */ if (lastuid && (uid == lastuid) && !strcmp (tmp,lastid)) st = lastst; /* get data */ else if ((st.data = (unsigned char *) mail_fetch_body (stream,i,ta->section,&st.size, ta->flags | FT_RETURNSTRINGSTRUCT)) && (ta->first || ta->last)) remember (uid,tmp,&st); pbodypartstring (i,tmp,&st,&stream->private.string,ta); fs_give ((void **) &tmp); } else { /* clean up the arguments */ if (ta->section) fs_give ((void **) &ta->section); fs_give ((void **) &args); } } /* Fetch body part binary * Accepts: message number * extra argument * Someday fix this to use stringstruct instead of memory */ void fetch_body_part_binary (unsigned long i,void *args) { TEXTARGS *ta = (TEXTARGS *) args; if (i) { /* do work? */ SIZEDTEXT st,cst; BODY *body = mail_body (stream,i,ta->section); char *tmp = (char *) fs_get (100+(ta->section ? strlen (ta->section) : 0)); unsigned long uid = mail_uid (stream,i); /* try to use remembered text */ if (lastuid && (uid == lastuid) && !strcmp (tmp,lastid)) st = lastst; else { /* get data */ st.data = (unsigned char *) mail_fetch_body (stream,i,ta->section,&st.size,ta->flags); if (ta->first || ta->last) remember (uid,tmp,&st); } /* what encoding was used? */ if (body) switch (body->encoding) { case ENCBASE64: if (cst.data = rfc822_base64 (st.data,st.size,&cst.size)) break; fetch_uid (i,NIL); /* wrote a space, so must do something */ if (lsterr) fs_give ((void **) &lsterr); lsterr = cpystr ("Undecodable BASE64 contents"); response = loseunknowncte; fs_give ((void **) &tmp); return; case ENCQUOTEDPRINTABLE: if (cst.data = rfc822_qprint (st.data,st.size,&cst.size)) break; fetch_uid (i,NIL); /* wrote a space, so must do something */ if (lsterr) fs_give ((void **) &lsterr); lsterr = cpystr ("Undecodable QUOTED-PRINTABLE contents"); response = loseunknowncte; fs_give ((void **) &tmp); return; case ENC7BIT: /* no need to convert any of these */ case ENC8BIT: case ENCBINARY: cst.data = NIL; /* no converted data to free */ break; default: /* unknown encoding, oops */ fetch_uid (i,NIL); /* wrote a space, so must do something */ if (lsterr) fs_give ((void **) &lsterr); lsterr = cpystr ("Unknown Content-Transfer-Encoding"); response = loseunknowncte; fs_give ((void **) &tmp); return; } else { if (lsterr) fs_give ((void **) &lsterr); lsterr = cpystr ("Invalid body part"); response = loseunknowncte; fs_give ((void **) &tmp); return; } /* use decoded version if exists */ if (cst.data) memcpy ((void *) &st,(void *) &cst,sizeof (SIZEDTEXT)); if (ta->binary & FTB_SIZE) {/* just want size? */ sprintf (tmp,"BINARY.SIZE[%s] %lu",ta->section ? ta->section : "", st.size); PSOUT (tmp); } else { /* no, blat binary data */ int f = mail_elt (stream,i)->seen; if (st.data) { /* only if have useful data */ /* partial specifier */ if (ta->first || ta->last) sprintf (tmp,"BINARY[%s]<%lu> ", ta->section ? ta->section : "",ta->first); else sprintf (tmp,"BINARY[%s] ",ta->section ? ta->section : ""); /* in case first byte beyond end of text */ if (st.size <= ta->first) st.size = ta->first = 0; else { /* offset and truncate */ st.data += ta->first; /* move to desired position */ st.size -= ta->first; /* reduced size */ if (ta->last && (st.size > ta->last)) st.size = ta->last; } if (st.size) sprintf (tmp + strlen (tmp),"{%lu}\015\012",st.size); else strcat (tmp,"\"\""); PSOUT (tmp); /* write binary output */ if (st.size && (PSOUTR (&st) == EOF)) ioerror(stdout,"writing binary"); } else { sprintf (tmp,"BINARY[%s] NIL",ta->section ? ta->section : ""); PSOUT (tmp); } changed_flags (i,f); /* write changed flags */ } /* free converted data */ if (cst.data) fs_give ((void **) &cst.data); fs_give ((void **) &tmp); /* and temporary string */ } else { /* clean up the arguments */ if (ta->section) fs_give ((void **) &ta->section); fs_give ((void **) &args); } } /* Fetch MESSAGE/RFC822 body part header * Accepts: message number * extra argument */ void fetch_body_part_header (unsigned long i,void *args) { TEXTARGS *ta = (TEXTARGS *) args; unsigned long len = 100 + (ta->section ? strlen (ta->section) : 0); STRINGLIST *s; for (s = ta->lines; s; s = s->next) len += s->text.size + 1; if (i) { /* do work? */ SIZEDTEXT st; char *tmp = (char *) fs_get (len); PSOUT ("BODY["); /* output attribute */ if (ta->section && *ta->section) { PSOUT (ta->section); PBOUT ('.'); } PSOUT ("HEADER"); if (ta->lines) { PSOUT ((ta->flags & FT_NOT) ? ".FIELDS.NOT " : ".FIELDS "); pastringlist (ta->lines); } strcpy (tmp,"]"); /* close section specifier */ st.data = (unsigned char *) /* get data (no hope in using remember here) */ mail_fetch_header (stream,i,ta->section,ta->lines,&st.size,ta->flags); pbodypartstring (i,tmp,&st,NIL,ta); fs_give ((void **) &tmp); } else { /* clean up the arguments */ if (ta->lines) mail_free_stringlist (&ta->lines); if (ta->section) fs_give ((void **) &ta->section); fs_give ((void **) &args); } } /* Fetch MESSAGE/RFC822 body part text * Accepts: message number * extra argument */ void fetch_body_part_text (unsigned long i,void *args) { TEXTARGS *ta = (TEXTARGS *) args; if (i) { /* do work? */ SIZEDTEXT st; char *tmp = (char *) fs_get (100+(ta->section ? strlen (ta->section) : 0)); unsigned long uid = mail_uid (stream,i); /* output attribute */ if (ta->section && *ta->section) sprintf (tmp,"BODY[%s.TEXT]",ta->section); else strcpy (tmp,"BODY[TEXT]"); /* try to use remembered text */ if (lastuid && (uid == lastuid) && !strcmp (tmp,lastid)) st = lastst; /* get data */ else if ((st.data = (unsigned char *) mail_fetch_text (stream,i,ta->section,&st.size, ta->flags | FT_RETURNSTRINGSTRUCT)) && (ta->first || ta->last)) remember (uid,tmp,&st); pbodypartstring (i,tmp,&st,&stream->private.string,ta); fs_give ((void **) &tmp); } else { /* clean up the arguments */ if (ta->section) fs_give ((void **) &ta->section); fs_give ((void **) &args); } } /* Remember body part text for subsequent partial fetching * Accepts: message UID * body part id * text * string */ void remember (unsigned long uid,char *id,SIZEDTEXT *st) { lastuid = uid; /* remember UID */ if (lastid) fs_give ((void **) &lastid); lastid = cpystr (id); /* remember body part id */ if (lastst.data) fs_give ((void **) &lastst.data); /* remember text */ lastst.data = (unsigned char *) memcpy (fs_get (st->size + 1),st->data,st->size); lastst.size = st->size; } /* Fetch envelope * Accepts: message number * extra argument */ void fetch_envelope (unsigned long i,void *args) { ENVELOPE *env = mail_fetchenvelope (stream,i); PSOUT ("ENVELOPE "); /* output attribute */ penv (env); /* output envelope */ } /* Fetch flags * Accepts: message number * extra argument */ void fetch_flags (unsigned long i,void *args) { unsigned long u; char *t,tmp[MAILTMPLEN]; int c = NIL; MESSAGECACHE *elt = mail_elt (stream,i); if (!elt->valid) { /* have valid flags yet? */ sprintf (tmp,"%lu",i); mail_fetch_flags (stream,tmp,NIL); } PSOUT ("FLAGS ("); /* output attribute */ /* output system flags */ if (elt->recent) put_flag (&c,"\\Recent"); if (elt->seen) put_flag (&c,"\\Seen"); if (elt->deleted) put_flag (&c,"\\Deleted"); if (elt->flagged) put_flag (&c,"\\Flagged"); if (elt->answered) put_flag (&c,"\\Answered"); if (elt->draft) put_flag (&c,"\\Draft"); if (u = elt->user_flags) do /* any user flags? */ if (t = stream->user_flags[find_rightmost_bit (&u)]) put_flag (&c,t); while (u); /* until no more user flags */ PBOUT (')'); /* end of flags */ elt->spare2 = NIL; /* we've sent the update */ } /* Output a flag * Accepts: pointer to current delimiter character * flag to output * Changes delimiter character to space */ void put_flag (int *c,char *s) { if (*c) PBOUT (*c); /* put delimiter */ PSOUT (s); /* dump flag */ *c = ' '; /* change delimiter if necessary */ } /* Output flags if was unseen * Accepts: message number * prior value of Seen flag */ void changed_flags (unsigned long i,int f) { /* was unseen, now seen? */ if (!f && mail_elt (stream,i)->seen) { PBOUT (' '); /* yes, delimit with space */ fetch_flags (i,NIL); /* output flags */ } } /* Fetch message internal date * Accepts: message number * extra argument */ void fetch_internaldate (unsigned long i,void *args) { char tmp[MAILTMPLEN]; MESSAGECACHE *elt = mail_elt (stream,i); if (!elt->day) { /* have internal date yet? */ sprintf (tmp,"%lu",i); mail_fetch_fast (stream,tmp,NIL); } PSOUT ("INTERNALDATE \""); PSOUT (mail_date (tmp,elt)); PBOUT ('"'); } /* Fetch unique identifier * Accepts: message number * extra argument */ void fetch_uid (unsigned long i,void *args) { PSOUT ("UID "); pnum (mail_uid (stream,i)); } /* Fetch complete RFC-822 format message * Accepts: message number * extra argument */ void fetch_rfc822 (unsigned long i,void *args) { if (i) { /* do work? */ int f = mail_elt (stream,i)->seen; #if 0 SIZEDTEXT st; st.data = (unsigned char *) mail_fetch_message (stream,i,&st.size,(long) args); pbodypartstring (i,"RFC822",&st,NIL,NIL); #else /* Yes, this version is bletcherous, but mail_fetch_message() requires too much memory */ SIZEDTEXT txt,hdr; char *s = mail_fetch_header (stream,i,NIL,NIL,&hdr.size,FT_PEEK); hdr.data = (unsigned char *) memcpy (fs_get (hdr.size),s,hdr.size); txt.data = (unsigned char *) mail_fetch_text (stream,i,NIL,&txt.size, ((long) args) | FT_RETURNSTRINGSTRUCT); PSOUT ("RFC822 {"); pnum (hdr.size + txt.size); PSOUT ("}\015\012"); ptext (&hdr,NIL); ptext (&txt,&stream->private.string); fs_give ((void **) &hdr.data); #endif changed_flags (i,f); /* output changed flags */ } } /* Fetch RFC-822 header * Accepts: message number * extra argument */ void fetch_rfc822_header (unsigned long i,void *args) { SIZEDTEXT st; st.data = (unsigned char *) mail_fetch_header (stream,i,NIL,NIL,&st.size,FT_PEEK); pbodypartstring (i,"RFC822.HEADER",&st,NIL,NIL); } /* Fetch RFC-822 message length * Accepts: message number * extra argument */ void fetch_rfc822_size (unsigned long i,void *args) { char tmp[MAILTMPLEN]; MESSAGECACHE *elt = mail_elt (stream,i); if (!elt->rfc822_size) { /* have message size yet? */ sprintf (tmp,"%lu",i); mail_fetch_fast (stream,tmp,NIL); } PSOUT ("RFC822.SIZE "); pnum (elt->rfc822_size); } /* Fetch RFC-822 text only * Accepts: message number * extra argument */ void fetch_rfc822_text (unsigned long i,void *args) { if (i) { /* do work? */ int f = mail_elt (stream,i)->seen; SIZEDTEXT st; st.data = (unsigned char *) mail_fetch_text (stream,i,NIL,&st.size, ((long) args) | FT_RETURNSTRINGSTRUCT); pbodypartstring (i,"RFC822.TEXT",&st,&stream->private.string,NIL); } } /* Print envelope * Accepts: body */ void penv (ENVELOPE *env) { PBOUT ('('); /* delimiter */ if (env) { /* only if there is an envelope */ pnstring (env->date); /* output envelope fields */ PBOUT (' '); pnstring (env->subject); PBOUT (' '); paddr (env->from); PBOUT (' '); paddr (env->sender); PBOUT (' '); paddr (env->reply_to); PBOUT (' '); paddr (env->to); PBOUT (' '); paddr (env->cc); PBOUT (' '); paddr (env->bcc); PBOUT (' '); pnstring (env->in_reply_to); PBOUT (' '); pnstring (env->message_id); } /* no envelope */ else PSOUT ("NIL NIL NIL NIL NIL NIL NIL NIL NIL NIL"); PBOUT (')'); /* end of envelope */ } /* Print body structure (extensible) * Accepts: body */ void pbodystructure (BODY *body) { PBOUT ('('); /* delimiter */ if (body) { /* only if there is a body */ PART *part; /* multipart type? */ if (body->type == TYPEMULTIPART) { /* print each part */ if (part = body->nested.part) for (; part; part = part->next) pbodystructure (&(part->body)); else pbodystructure (NIL); PBOUT (' '); /* space delimiter */ pstring (body->subtype); /* subtype */ PBOUT (' '); pparam (body->parameter); /* multipart body extension data */ PBOUT (' '); if (body->disposition.type) { PBOUT ('('); pstring (body->disposition.type); PBOUT (' '); pparam (body->disposition.parameter); PBOUT (')'); } else PSOUT ("NIL"); PBOUT (' '); pnstringorlist (body->language); PBOUT (' '); pnstring (body->location); } else { /* non-multipart body type */ pstring ((char *) body_types[body->type]); PBOUT (' '); pstring (body->subtype); PBOUT (' '); pparam (body->parameter); PBOUT (' '); pnstring (body->id); PBOUT (' '); pnstring (body->description); PBOUT (' '); pstring ((char *) body_encodings[body->encoding]); PBOUT (' '); pnum (body->size.bytes); switch (body->type) { /* extra stuff depends upon body type */ case TYPEMESSAGE: /* can't do this if not RFC822 */ if (strcmp (body->subtype,"RFC822")) break; PBOUT (' '); penv (body->nested.msg->env); PBOUT (' '); pbodystructure (body->nested.msg->body); case TYPETEXT: PBOUT (' '); pnum (body->size.lines); break; default: break; } PBOUT (' '); pnstring (body->md5); PBOUT (' '); if (body->disposition.type) { PBOUT ('('); pstring (body->disposition.type); PBOUT (' '); pparam (body->disposition.parameter); PBOUT (')'); } else PSOUT ("NIL"); PBOUT (' '); pnstringorlist (body->language); PBOUT (' '); pnstring (body->location); } } /* no body */ else PSOUT ("\"TEXT\" \"PLAIN\" (\"CHARSET\" \"US-ASCII\") NIL NIL \"7BIT\" 0 0 NIL NIL NIL NIL"); PBOUT (')'); /* end of body */ } /* Print body (non-extensible) * Accepts: body */ void pbody (BODY *body) { PBOUT ('('); /* delimiter */ if (body) { /* only if there is a body */ PART *part; /* multipart type? */ if (body->type == TYPEMULTIPART) { /* print each part */ if (part = body->nested.part) for (; part; part = part->next) pbody (&(part->body)); else pbody (NIL); PBOUT (' '); /* space delimiter */ pstring (body->subtype); /* and finally the subtype */ } else { /* non-multipart body type */ pstring ((char *) body_types[body->type]); PBOUT (' '); pstring (body->subtype); PBOUT (' '); pparam (body->parameter); PBOUT (' '); pnstring (body->id); PBOUT (' '); pnstring (body->description); PBOUT (' '); pstring ((char *) body_encodings[body->encoding]); PBOUT (' '); pnum (body->size.bytes); switch (body->type) { /* extra stuff depends upon body type */ case TYPEMESSAGE: /* can't do this if not RFC822 */ if (strcmp (body->subtype,"RFC822")) break; PBOUT (' '); penv (body->nested.msg ? body->nested.msg->env : NIL); PBOUT (' '); pbody (body->nested.msg ? body->nested.msg->body : NIL); case TYPETEXT: PBOUT (' '); pnum (body->size.lines); break; default: break; } } } /* no body */ else PSOUT ("\"TEXT\" \"PLAIN\" (\"CHARSET\" \"US-ASCII\") NIL NIL \"7BIT\" 0 0"); PBOUT (')'); /* end of body */ } /* Print parameter list * Accepts: paramter */ void pparam (PARAMETER *param) { if (param) { /* one specified? */ PBOUT ('('); do { pstring (param->attribute); PBOUT (' '); pstring (param->value); if (param = param->next) PBOUT (' '); } while (param); PBOUT (')'); /* end of parameters */ } else PSOUT ("NIL"); } /* Print address list * Accepts: address list */ void paddr (ADDRESS *a) { if (a) { /* have anything in address? */ PBOUT ('('); /* open the address list */ do { /* for each address */ PBOUT ('('); /* open the address */ pnstring (a->personal); /* personal name */ PBOUT (' '); pnstring (a->adl); /* at-domain-list */ PBOUT (' '); pnstring (a->mailbox); /* mailbox */ PBOUT (' '); pnstring (a->host); /* domain name of mailbox's host */ PBOUT (')'); /* terminate address */ } while (a = a->next); /* until end of address */ PBOUT (')'); /* close address list */ } else PSOUT ("NIL"); /* empty address */ } /* Print set * Accepts: set */ void pset (SEARCHSET **set) { SEARCHSET *cur = *set; while (cur) { /* while there's a set to do */ pnum (cur->first); /* output first value */ if (cur->last) { /* if range, output second value of range */ PBOUT (':'); pnum (cur->last); } if (cur = cur->next) PBOUT (','); } mail_free_searchset (set); /* flush set */ } /* Print number * Accepts: number */ void pnum (unsigned long i) { char tmp[MAILTMPLEN]; sprintf (tmp,"%lu",i); PSOUT (tmp); } /* Print string * Accepts: string */ void pstring (char *s) { SIZEDTEXT st; st.data = (unsigned char *) s;/* set up sized text */ st.size = strlen (s); psizedstring (&st,NIL); /* print string */ } /* Print nstring * Accepts: string or NIL */ void pnstring (char *s) { if (s) pstring (s); /* print string */ else PSOUT ("NIL"); } /* Print atom or string * Accepts: astring */ void pastring (char *s) { char *t; if (!*s) PSOUT ("\"\""); /* empty string */ else { /* see if atom */ for (t = s; (*t > ' ') && !(*t & 0x80) && (*t != '"') && (*t != '\\') && (*t != '(') && (*t != ')') && (*t != '{') && (*t != '%') && (*t != '*'); t++); if (*t) pstring (s); /* not an atom */ else PSOUT (s); /* else plop down as atomic */ } } /* Print sized text as quoted * Accepts: sized text */ void psizedquoted (SIZEDTEXT *s) { PBOUT ('"'); /* use quoted string */ ptext (s,NIL); PBOUT ('"'); } /* Print sized text as literal * Accepts: sized text */ void psizedliteral (SIZEDTEXT *s,STRING *st) { PBOUT ('{'); /* print literal size */ pnum (s->size); PSOUT ("}\015\012"); ptext (s,st); } /* Print sized text as literal or quoted string * Accepts: sized text * alternative stringstruct of text */ void psizedstring (SIZEDTEXT *s,STRING *st) { unsigned char c; unsigned long i; if (s->data) { /* if text, check if must use literal */ for (i = 0; ((i < s->size) && ((c = s->data[i]) & 0xe0) && !(c & 0x80) && (c != '"') && (c != '\\')); ++i); /* must use literal if not all QUOTED-CHAR */ if (i < s->size) psizedliteral (s,st); else psizedquoted (s); } else psizedliteral (s,st); } /* Print sized text as literal or quoted string * Accepts: sized text */ void psizedastring (SIZEDTEXT *s) { unsigned long i; unsigned int atomp = s->size ? T : NIL; for (i = 0; i < s->size; i++){/* check if must use literal */ if (!(s->data[i] & 0xe0) || (s->data[i] & 0x80) || (s->data[i] == '"') || (s->data[i] == '\\')) { psizedliteral (s,NIL); return; } else switch (s->data[i]) { /* else see if any atom-specials */ case '(': case ')': case '{': case ' ': case '%': case '*': /* list-wildcards */ case ']': /* resp-specials */ /* CTL and quoted-specials in literal check */ atomp = NIL; /* not an atom */ } } if (atomp) ptext (s,NIL); /* print as atom */ else psizedquoted (s); /* print as quoted string */ } /* Print string list * Accepts: string list */ void pastringlist (STRINGLIST *s) { PBOUT ('('); /* start list */ do { psizedastring (&s->text); /* output list member */ if (s->next) PBOUT (' '); } while (s = s->next); PBOUT (')'); /* terminate list */ } /* Print nstring or list of strings * Accepts: string / string list */ void pnstringorlist (STRINGLIST *s) { if (!s) PSOUT ("NIL"); /* no argument given */ else if (s->next) { /* output list as list of strings*/ PBOUT ('('); /* start list */ do { /* output list member */ psizedstring (&s->text,NIL); if (s->next) PBOUT (' '); } while (s = s->next); PBOUT (')'); /* terminate list */ } /* and single-element list as string */ else psizedstring (&s->text,NIL); } /* Print body part string * Accepts: message number * body part id (note: must have space at end to append stuff) * sized text of string * alternative stringstruct of string * text printing arguments */ void pbodypartstring (unsigned long msgno,char *id,SIZEDTEXT *st,STRING *bs, TEXTARGS *ta) { int f = mail_elt (stream,msgno)->seen; /* ignore stringstruct if non-initialized */ if (bs && !bs->curpos) bs = NIL; if (ta && st->size) { /* only if have useful data */ /* partial specifier */ if (ta->first || ta->last) sprintf (id + strlen (id),"<%lu>",ta->first); /* in case first byte beyond end of text */ if (st->size <= ta->first) st->size = ta->first = 0; else { if (st->data) { /* offset and truncate */ st->data += ta->first; /* move to desired position */ st->size -= ta->first; /* reduced size */ } else if (bs && (SIZE (bs) >= ta->first)) SETPOS (bs,ta->first + GETPOS (bs)); else st->size = 0; /* shouldn't happen */ if (ta->last && (st->size > ta->last)) st->size = ta->last; } } PSOUT (id); PBOUT (' '); psizedstring (st,bs); /* output string */ changed_flags (msgno,f); /* and changed flags */ } /* RFC 3501 technically forbids NULs in literals. Normally, the delivering * MTA would take care of MIME converting the message text so that it is * NUL-free. If it doesn't, then we have the choice of either violating * IMAP by sending NULs, corrupting the data, or going to lots of work to do * MIME conversion in the IMAP server. */ /* Print raw sized text * Accepts: sizedtext */ void ptext (SIZEDTEXT *txt,STRING *st) { unsigned char c,*s; unsigned long i = txt->size; if (s = txt->data) while (i && ((PBOUT ((c = *s++) ? c : 0x80) != EOF))) --i; else if (st) while (i && (PBOUT ((c = SNX (st)) ? c : 0x80) != EOF)) --i; /* failed to complete? */ if (i) ioerror (stdout,"writing text"); } /* Print thread * Accepts: thread */ void pthread (THREADNODE *thr) { THREADNODE *t; while (thr) { /* for each branch */ PBOUT ('('); /* open branch */ if (thr->num) { /* first node message number */ pnum (thr->num); if (t = thr->next) { /* any subsequent nodes? */ PBOUT (' '); while (t) { /* for each subsequent node */ if (t->branch) { /* branches? */ pthread (t); /* yes, recurse to do branch */ t = NIL; /* done */ } else { /* just output this number */ pnum (t->num); t = t->next; /* and do next message */ } if (t) PBOUT (' '); /* delimit if more to come */ } } } else pthread (thr->next); /* nest for dummy */ PBOUT (')'); /* done with this branch */ thr = thr->branch; /* do next branch */ } } /* Print capabilities * Accepts: option flag */ void pcapability (long flag) { unsigned long i; char *s; struct stat sbuf; AUTHENTICATOR *auth; THREADER *thr = (THREADER *) mail_parameters (NIL,GET_THREADERS,NIL); /* always output protocol level */ PSOUT ("CAPABILITY IMAP4REV1 I18NLEVEL=1 LITERAL+"); #ifdef NETSCAPE_BRAIN_DAMAGE PSOUT (" X-NETSCAPE"); #endif if (flag >= 0) { /* want post-authentication capabilities? */ PSOUT (" IDLE UIDPLUS NAMESPACE CHILDREN MAILBOX-REFERRALS BINARY UNSELECT ESEARCH WITHIN SCAN SORT"); while (thr) { /* threaders */ PSOUT (" THREAD="); PSOUT (thr->name); thr = thr->next; } if (!anonymous) PSOUT (" MULTIAPPEND"); } if (flag <= 0) { /* want pre-authentication capabilities? */ PSOUT (" SASL-IR LOGIN-REFERRALS"); if (s = ssl_start_tls (NIL)) fs_give ((void **) &s); else PSOUT (" STARTTLS"); /* disable plaintext */ if (!(i = !mail_parameters (NIL,GET_DISABLEPLAINTEXT,NIL))) PSOUT (" LOGINDISABLED"); for (auth = mail_lookup_auth (1); auth; auth = auth->next) if (auth->server && !(auth->flags & AU_DISABLE) && !(auth->flags & AU_HIDE) && (i || (auth->flags & AU_SECURE))) { PSOUT (" AUTH="); PSOUT (auth->name); } if (!stat (ANOFILE,&sbuf)) PSOUT (" AUTH=ANONYMOUS"); } } /* Anonymous users may only use these mailboxes in these namespaces */ char *oktab[] = {"#news.", "#ftp/", "#public/", 0}; /* Check if mailbox name is OK * Accepts: reference name * mailbox name */ long nameok (char *ref,char *name) { int i; unsigned char *s,*t; if (!name) return NIL; /* failure if missing name */ if (!anonymous) return T; /* otherwise OK if not anonymous */ /* validate reference */ if (ref && ((*ref == '#') || (*ref == '{'))) for (i = 0; oktab[i]; i++) { for (s = ref, t = oktab[i]; *t && !compare_uchar (*s,*t); s++, t++); if (!*t) { /* reference OK */ if (*name == '#') break;/* check name if override */ else return T; /* otherwise done */ } } /* ordinary names are OK */ if ((*name != '#') && (*name != '{')) return T; for (i = 0; oktab[i]; i++) { /* validate mailbox */ for (s = name, t = oktab[i]; *t && !compare_uchar (*s,*t); s++, t++); if (!*t) return T; /* name is OK */ } response = "%.80s NO Anonymous may not %.80s this name\015\012"; return NIL; } /* Convert possible BBoard name to actual name * Accepts: command * mailbox name * Returns: maibox name */ char *bboardname (char *cmd,char *name) { if (cmd[0] == 'B') { /* want bboard? */ char *s = litstk[litsp++] = (char *) fs_get (strlen (name) + 9); sprintf (s,"#public/%s",(*name == '/') ? name+1 : name); name = s; } return name; } /* Test if name is news proxy * Accepts: name * Returns: T if news proxy, NIL otherwise */ long isnewsproxy (char *name) { return (nntpproxy && (name[0] == '#') && ((name[1] == 'N') || (name[1] == 'n')) && ((name[2] == 'E') || (name[2] == 'e')) && ((name[3] == 'W') || (name[3] == 'w')) && ((name[4] == 'S') || (name[4] == 's')) && (name[5] == '.')) ? LONGT : NIL; } /* News proxy generate canonical pattern * Accepts: reference * pattern * buffer to return canonical pattern * Returns: T on success with pattern in buffer, NIL on failure */ long newsproxypattern (char *ref,char *pat,char *pattern,long flag) { if (!nntpproxy) return NIL; if (strlen (ref) > NETMAXMBX) { sprintf (pattern,"Invalid reference specification: %.80s",ref); mm_log (pattern,ERROR); return NIL; } if (strlen (pat) > NETMAXMBX) { sprintf (pattern,"Invalid pattern specification: %.80s",pat); mm_log (pattern,ERROR); return NIL; } if (flag) { /* prepend proxy specifier */ sprintf (pattern,"{%.300s/nntp}",nntpproxy); pattern += strlen (pattern); } if (*ref) { /* have a reference */ strcpy (pattern,ref); /* copy reference to pattern */ /* # overrides mailbox field in reference */ if (*pat == '#') strcpy (pattern,pat); /* pattern starts, reference ends, with . */ else if ((*pat == '.') && (pattern[strlen (pattern) - 1] == '.')) strcat (pattern,pat + 1); /* append, omitting one of the period */ else strcat (pattern,pat); /* anything else is just appended */ } else strcpy (pattern,pat); /* just have basic name */ return isnewsproxy (pattern); } /* IMAP4rev1 Authentication responder * Accepts: challenge * length of challenge * pointer to response length return location if non-NIL * Returns: response */ #define RESPBUFLEN 8*MAILTMPLEN char *imap_responder (void *challenge,unsigned long clen,unsigned long *rlen) { unsigned long i,j; unsigned char *t,resp[RESPBUFLEN]; if (initial) { /* initial response given? */ if (clen) return NIL; /* not permitted */ /* set up response */ i = strlen ((char *) (t = initial)); initial = NIL; /* no more initial response */ if ((*t == '=') && !t[1]) { /* SASL-IR does this for 0-length response */ if (rlen) *rlen = 0; /* set length zero if empty */ return cpystr (""); /* and return empty string as response */ } } else { /* issue challenge, get response */ PSOUT ("+ "); for (t = rfc822_binary ((void *) challenge,clen,&i),j = 0; j < i; j++) if (t[j] > ' ') PBOUT (t[j]); fs_give ((void **) &t); CRLF; PFLUSH (); /* dump output buffer */ /* slurp response buffer */ slurp ((char *) resp,RESPBUFLEN,INPUTTIMEOUT); if (!(t = (unsigned char *) strchr ((char *) resp,'\012'))) return (char *) flush (); if (t[-1] == '\015') --t; /* remove CR */ *t = '\0'; /* tie off buffer */ if (resp[0] == '*') { cancelled = T; return NIL; } i = t - resp; /* length of response */ t = resp; /* set up for return call */ } return (i % 4) ? NIL : /* return if valid BASE64 */ (char *) rfc822_base64 (t,i,rlen ? rlen : &i); } /* Proxy copy across mailbox formats * Accepts: mail stream * sequence to copy on this stream * destination mailbox * option flags * Returns: T if success, else NIL */ long proxycopy (MAILSTREAM *stream,char *sequence,char *mailbox,long options) { MAILSTREAM *ts; STRING st; MSGDATA md; SEARCHSET *set; char tmp[MAILTMPLEN]; unsigned long i,j; md.stream = stream; md.msgno = 0; md.flags = md.date = NIL; md.message = &st; /* Currently ignores CP_MOVE and CP_DEBUG */ if (!((options & CP_UID) ? /* validate sequence */ mail_uid_sequence (stream,sequence) : mail_sequence (stream,sequence))) return NIL; response = win; /* cancel previous errors */ if (lsterr) fs_give ((void **) &lsterr); /* c-client clobbers sequence, use spare */ for (i = 1,j = 0,set = mail_newsearchset (); i <= nmsgs; i++) if (mail_elt (stream,i)->spare = mail_elt (stream,i)->sequence) { mail_append_set (set,mail_uid (stream,i)); if (!j) md.msgno = (j = i) - 1; } /* only if at least one message to copy */ if (j && !mail_append_multiple (NIL,mailbox,proxy_append,(void *) &md)) { response = trycreate ? losetry : lose; if (set) mail_free_searchset (&set); return NIL; } if (caset) csset = set; /* set for return value now */ else if (set) mail_free_searchset (&set); response = win; /* stomp any previous babble */ if (md.msgno) { /* get new driver name if was dummy */ sprintf (tmp,"Cross-format (%.80s -> %.80s) COPY completed", stream->dtb->name,(ts = mail_open (NIL,mailbox,OP_PROTOTYPE)) ? ts->dtb->name : "unknown"); mm_log (tmp,NIL); } return LONGT; } /* Proxy append message callback * Accepts: MAIL stream * append data package * pointer to return initial flags * pointer to return message internal date * pointer to return stringstruct of message or NIL to stop * Returns: T if success (have message or stop), NIL if error */ long proxy_append (MAILSTREAM *stream,void *data,char **flags,char **date, STRING **message) { MESSAGECACHE *elt; unsigned long i; char *s,*t,tmp[MAILTMPLEN]; MSGDATA *md = (MSGDATA *) data; if (md->flags) fs_give ((void **) &md->flags); if (md->date) fs_give ((void **) &md->date); *message = NIL; /* assume all done */ *flags = *date = NIL; while (++md->msgno <= nmsgs) if ((elt = mail_elt (md->stream,md->msgno))->spare) { if (!(elt->valid && elt->day)) { sprintf (tmp,"%lu",md->msgno); mail_fetch_fast (md->stream,tmp,NIL); } memset (s = tmp,0,MAILTMPLEN); /* copy flags */ if (elt->seen) strcat (s," \\Seen"); if (elt->deleted) strcat (s," \\Deleted"); if (elt->flagged) strcat (s," \\Flagged"); if (elt->answered) strcat (s," \\Answered"); if (elt->draft) strcat (s," \\Draft"); if (i = elt->user_flags) do if ((t = md->stream->user_flags[find_rightmost_bit (&i)]) && *t && (strlen (t) < ((size_t) (MAILTMPLEN-((s += strlen (s))+2-tmp))))) { *s++ = ' '; /* space delimiter */ strcpy (s,t); } while (i); /* until no more user flags */ *message = md->message; /* set up return values */ *flags = md->flags = cpystr (tmp + 1); *date = md->date = cpystr (mail_date (tmp,elt)); INIT (md->message,msg_string,(void *) md,elt->rfc822_size); break; /* process this message */ } return LONGT; } /* Append message callback * Accepts: MAIL stream * append data package * pointer to return initial flags * pointer to return message internal date * pointer to return stringstruct of message or NIL to stop * Returns: T if success (have message or stop), NIL if error */ long append_msg (MAILSTREAM *stream,void *data,char **flags,char **date, STRING **message) { unsigned long i,j; char *t; APPENDDATA *ad = (APPENDDATA *) data; unsigned char *arg = ad->arg; /* flush text of previous message */ if (t = ad->flags) fs_give ((void **) &ad->flags); if (t = ad->date) fs_give ((void **) &ad->date); if (t = ad->msg) fs_give ((void **) &ad->msg); *flags = *date = NIL; /* assume no flags or date */ if (t) { /* have previous message? */ if (!*arg) { /* if least one message, and no more coming */ *message = NIL; /* set stop */ return LONGT; /* return success */ } else if (*arg++ != ' ') { /* must have a delimiter to next argument */ response = misarg; /* oops */ return NIL; } } *message = ad->message; /* return pointer to message stringstruct */ if (*arg == '(') { /* parse optional flag list */ t = ++arg; /* pointer to flag list contents */ while (*arg && (*arg != ')')) arg++; if (*arg) *arg++ = '\0'; if (*arg == ' ') arg++; *flags = ad->flags = cpystr (t); } /* parse optional date */ if (*arg == '"') *date = ad->date = cpystr (snarf (&arg)); if (!arg || (*arg != '{')) /* parse message */ response = "%.80s BAD Missing literal in %.80s\015\012"; else if (!isdigit (arg[1])) response = "%.80s BAD Missing message to %.80s\015\012"; else if (!(i = strtoul (arg+1,&t,10))) response = "%.80s NO Empty message to %.80s\015\012"; else if (i > MAXAPPENDTXT) /* maybe relax this a little */ response = "%.80s NO Excessively large message to %.80s\015\012"; else if (((*t == '+') && (t[1] == '}') && !t[2]) || ((*t == '}') && !t[1])) { /* get a literal buffer */ inliteral (ad->msg = (char *) fs_get (i+1),i); /* get new command tail */ slurp (ad->arg,CMDLEN - (ad->arg - cmdbuf),INPUTTIMEOUT); if (strchr (ad->arg,'\012')) { /* reset strtok mechanism, tie off if done */ if (!strtok (ad->arg,"\015\012")) *ad->arg = '\0'; /* possible LITERAL+? */ if (((j = strlen (ad->arg)) > 3) && (ad->arg[j - 1] == '}') && (ad->arg[j - 2] == '+') && isdigit (ad->arg[j - 3])) { /* back over possible count */ for (j -= 4; j && isdigit (ad->arg[j]); j--); if (ad->arg[j] == '{') {/* found a literal? */ litplus.ok = T; /* yes, note LITERAL+ in effect, set size */ litplus.size = strtoul (ad->arg + j + 1,NIL,10); } } /* initialize stringstruct */ INIT (ad->message,mail_string,(void *) ad->msg,i); return LONGT; /* ready to go */ } flush (); /* didn't find end of line? */ fs_give ((void **) &ad->msg); } else response = badarg; /* not a literal */ return NIL; /* error */ } /* Got COPY UID data * Accepts: MAIL stream * mailbox name * UID validity * source set of UIDs * destination set of UIDs */ void copyuid (MAILSTREAM *stream,char *mailbox,unsigned long uidvalidity, SEARCHSET *sourceset,SEARCHSET *destset) { if (cauidvalidity) fatal ("duplicate COPYUID/APPENDUID data"); cauidvalidity = uidvalidity; csset = sourceset; caset = destset; } /* Got APPEND UID data * Accepts: mailbox name * UID validity * destination set of UIDs */ void appenduid (char *mailbox,unsigned long uidvalidity,SEARCHSET *set) { copyuid (NIL,mailbox,uidvalidity,NIL,set); } /* Got a referral * Accepts: MAIL stream * URL * referral type code */ char *referral (MAILSTREAM *stream,char *url,long code) { if (lstref) fs_give ((void **) &lstref); lstref = cpystr (url); /* set referral */ /* set error if not a logged in referral */ if (code != REFAUTH) response = lose; if (!lsterr) lsterr = cpystr ("Try referral URL"); return NIL; /* don't chase referrals for now */ } /* Co-routines from MAIL library */ /* Message matches a search * Accepts: MAIL stream * message number */ void mm_searched (MAILSTREAM *s,unsigned long msgno) { /* nothing to do here */ } /* Message exists (i.e. there are that many messages in the mailbox) * Accepts: MAIL stream * message number */ void mm_exists (MAILSTREAM *s,unsigned long number) { /* note change in number of messages */ if ((s != tstream) && (nmsgs != number)) { nmsgs = number; /* always update number of messages */ if (quell_events) existsquelled = T; else { PSOUT ("* "); pnum (nmsgs); PSOUT (" EXISTS\015\012"); } recent = 0xffffffff; /* make sure update recent too */ } } /* Message expunged * Accepts: MAIL stream * message number */ void mm_expunged (MAILSTREAM *s,unsigned long number) { if (quell_events) fatal ("Impossible EXPUNGE event"); if (s != tstream) { PSOUT ("* "); pnum (number); PSOUT (" EXPUNGE\015\012"); } nmsgs--; existsquelled = T; /* do EXISTS when command done */ } /* Message status changed * Accepts: MAIL stream * message number */ void mm_flags (MAILSTREAM *s,unsigned long number) { if (s != tstream) mail_elt (s,number)->spare2 = T; } /* Mailbox found * Accepts: hierarchy delimiter * mailbox name * attributes */ void mm_list (MAILSTREAM *stream,int delimiter,char *name,long attributes) { mm_list_work ("LIST",delimiter,name,attributes); } /* Subscribed mailbox found * Accepts: hierarchy delimiter * mailbox name * attributes */ void mm_lsub (MAILSTREAM *stream,int delimiter,char *name,long attributes) { mm_list_work ("LSUB",delimiter,name,attributes); } /* Mailbox status * Accepts: MAIL stream * mailbox name * mailbox status */ void mm_status (MAILSTREAM *stream,char *mailbox,MAILSTATUS *status) { if (!quell_events) { char tmp[MAILTMPLEN]; tmp[0] = tmp[1] = '\0'; if (status->flags & SA_MESSAGES) sprintf (tmp + strlen (tmp)," MESSAGES %lu",status->messages); if (status->flags & SA_RECENT) sprintf (tmp + strlen (tmp)," RECENT %lu",status->recent); if (status->flags & SA_UNSEEN) sprintf (tmp + strlen (tmp)," UNSEEN %lu",status->unseen); if (status->flags & SA_UIDNEXT) sprintf (tmp + strlen (tmp)," UIDNEXT %lu",status->uidnext); if (status->flags & SA_UIDVALIDITY) sprintf (tmp + strlen(tmp)," UIDVALIDITY %lu",status->uidvalidity); PSOUT ("* STATUS "); pastring (mailbox); PSOUT (" ("); PSOUT (tmp+1); PBOUT (')'); CRLF; } } /* Worker routine for LIST and LSUB * Accepts: name of response * hierarchy delimiter * mailbox name * attributes */ void mm_list_work (char *what,int delimiter,char *name,long attributes) { char *s; if (!quell_events) { char tmp[MAILTMPLEN]; if (finding) { PSOUT ("* MAILBOX "); PSOUT (name); } /* new form */ else if ((cmd[0] == 'R') || !(attributes & LATT_REFERRAL)) { PSOUT ("* "); PSOUT (what); PSOUT (" ("); tmp[0] = tmp[1] = '\0'; if (attributes & LATT_NOINFERIORS) strcat (tmp," \\NoInferiors"); if (attributes & LATT_NOSELECT) strcat (tmp," \\NoSelect"); if (attributes & LATT_MARKED) strcat (tmp," \\Marked"); if (attributes & LATT_UNMARKED) strcat (tmp," \\UnMarked"); if (attributes & LATT_HASCHILDREN) strcat (tmp," \\HasChildren"); if (attributes & LATT_HASNOCHILDREN) strcat (tmp," \\HasNoChildren"); PSOUT (tmp+1); switch (delimiter) { case '\\': /* quoted delimiter */ case '"': PSOUT (") \"\\"); PBOUT (delimiter); PBOUT ('"'); break; case '\0': /* no delimiter */ PSOUT (") NIL"); break; default: /* unquoted delimiter */ PSOUT (") \""); PBOUT (delimiter); PBOUT ('"'); break; } PBOUT (' '); /* output mailbox name */ if (proxylist && (s = strchr (name,'}'))) pastring (s+1); else pastring (name); } CRLF; } } /* Notification event * Accepts: MAIL stream * string to log * error flag */ void mm_notify (MAILSTREAM *stream,char *string,long errflg) { SIZEDTEXT msg; char *s,*code; if (!quell_events && (!tstream || (stream != tstream))) { switch (errflg) { case NIL: /* information message, set as OK response */ if ((string[0] == '[') && ((string[1] == 'T') || (string[1] == 't')) && ((string[2] == 'R') || (string[2] == 'r')) && ((string[3] == 'Y') || (string[3] == 'y')) && ((string[4] == 'C') || (string[4] == 'c')) && ((string[5] == 'R') || (string[5] == 'r')) && ((string[6] == 'E') || (string[6] == 'e')) && ((string[7] == 'A') || (string[7] == 'a')) && ((string[8] == 'T') || (string[8] == 't')) && ((string[9] == 'E') || (string[9] == 'e')) && (string[10] == ']')) trycreate = T; case BYE: /* some other server signing off */ case PARSE: /* parse glitch, output unsolicited OK */ code = "* OK "; break; case WARN: /* warning, output unsolicited NO (kludge!) */ code = "* NO "; break; case ERROR: /* error that broke command */ default: /* default should never happen */ code = "* BAD "; break; } PSOUT (code); msg.size = (s = strpbrk ((char *) (msg.data = (unsigned char *) string), "\015\012")) ? (s - string) : strlen (string); PSOUTR (&msg); CRLF; PFLUSH (); /* let client see it immediately */ } } /* Log an event for the user to see * Accepts: string to log * error flag */ void mm_log (char *string,long errflg) { SIZEDTEXT msg; char *s; msg.size = (s = strpbrk ((char *) (msg.data = (unsigned char *) string),"\015\012")) ? (s - string) : strlen (string); switch (errflg) { case NIL: /* information message, set as OK response */ if (response == win) { /* only if no other response yet */ if (lsterr) { /* if there was a previous message */ if (!quell_events) { PSOUT ("* OK "); /* blat it out */ PSOUT (lsterr); CRLF; PFLUSH (); /* let client see it immediately */ } fs_give ((void **) &lsterr); } lsterr = cpystr (string); /* copy string for later use */ if (s) lsterr[s - string] = NIL; } break; case PARSE: /* parse glitch, output unsolicited OK */ if (!quell_events) { PSOUT ("* OK [PARSE] "); PSOUTR (&msg); CRLF; PFLUSH (); /* let client see it immediately */ } break; case WARN: /* warning, output unsolicited NO */ /* ignore "Mailbox is empty" (KLUDGE!) */ if (strcmp (string,"Mailbox is empty")) { if (lstwrn) { /* have previous warning? */ if (!quell_events) { PSOUT ("* NO "); PSOUT (lstwrn); CRLF; PFLUSH (); /* make sure client sees it immediately */ } fs_give ((void **) &lstwrn); } lstwrn = cpystr (string); /* note last warning */ if (s) lstwrn[s - string] = NIL; } break; case ERROR: /* error that broke command */ default: /* default should never happen */ response = trycreate ? losetry : lose; if (lsterr) fs_give ((void **) &lsterr); lsterr = cpystr (string); /* note last error */ if (s) lsterr[s - string] = NIL; break; } } /* Return last error */ char *lasterror (void) { if (lsterr) return lsterr; if (lstwrn) return lstwrn; return ""; } /* Log an event to debugging telemetry * Accepts: string to log */ void mm_dlog (char *string) { mm_log (string,WARN); /* shouldn't happen normally */ } /* Get user name and password for this host * Accepts: parse of network user name * where to return user name * where to return password * trial count */ void mm_login (NETMBX *mb,char *username,char *password,long trial) { /* set user name */ strncpy (username,*mb->user ? mb->user : (char *) user,NETMAXUSER); strncpy (password,pass,256); /* and password */ } /* About to enter critical code * Accepts: stream */ void mm_critical (MAILSTREAM *s) { ++critical; } /* About to exit critical code * Accepts: stream */ void mm_nocritical (MAILSTREAM *s) { /* go non-critical, pending death? */ if (!--critical && (state == LOGOUT)) { /* clean up iff needed */ if (s && (stream != s) && !s->lock && (s->dtb->flags & DR_XPOINT)) s = mail_close (s); longjmp (jmpenv,1); /* die now */ } } /* Disk error found * Accepts: stream * system error code * flag indicating that mailbox may be clobbered * Returns: abort flag */ long mm_diskerror (MAILSTREAM *s,long errcode,long serious) { if (serious) { /* try your damnest if clobberage likely */ mm_notify (s,"Retrying to fix probable mailbox damage!",ERROR); PFLUSH (); /* dump output buffer */ syslog (LOG_ALERT, "Retrying after disk error user=%.80s host=%.80s mbx=%.80s: %.80s", user ? (char *) user : "???",tcp_clienthost (), (stream && stream->mailbox) ? stream->mailbox : "???", strerror (errcode)); settimeout (0); /* make damn sure timeout disabled */ sleep (60); /* give it some time to clear up */ return NIL; } if (!quell_events) { /* otherwise die before more damage is done */ PSOUT ("* NO Disk error: "); PSOUT (strerror (errcode)); CRLF; } return T; } /* Log a fatal error event * Accepts: string to log */ void mm_fatal (char *string) { SIZEDTEXT msg; char *s; msg.size = (s = strpbrk ((char *) (msg.data = (unsigned char *) string),"\015\012")) ? (s - string) : strlen (string); if (!quell_events) { PSOUT ("* BYE [ALERT] IMAP4rev1 server crashing: "); PSOUTR (&msg); CRLF; PFLUSH (); } syslog (LOG_ALERT,"Fatal error user=%.80s host=%.80s mbx=%.80s: %.80s", user ? (char *) user : "???",tcp_clienthost (), (stream && stream->mailbox) ? stream->mailbox : "???",string); } alpine-2.10+dfsg/imap/src/imapd/makefile.nt0000600000175000017500000000301311512502123022257 0ustar paulproteuspaulproteus# ======================================================================== # Copyright 1988-2006 University of Washington # # Licensed under the Apache License, Version 2.0 (the "License"); # you may not use this file except in compliance with the License. # You may obtain a copy of the License at # # http://www.apache.org/licenses/LICENSE-2.0 # # # ======================================================================== # Program: IMAPD Makefile for Windows 9x and Windows NT # # Author: Mark Crispin # Networks and Distributed Computing # Computing & Communications # University of Washington # Administration Building, AG-44 # Seattle, WA 98195 # Internet: MRC@CAC.Washington.EDU # # Date: 5 November 1990 # Last Edited: 30 August 2006 ALERT=\\imapd.alert USERALERT=alert.txt SHUTDOWN=\\nologin ANO=\\anonymous.newsgroups NNTP=\\imapd.nntp C = ..\c-client CCLIENTLIB = $C\cclient.lib LIBS = $(CCLIENTLIB) ws2_32.lib winmm.lib advapi32.lib OSCOMPAT = /DWIN32 /D_WIN32_WINNT=0x0400 VSCOMPAT = /D_CRT_SECURE_NO_DEPRECATE /D_CRT_NONSTDC_NO_DEPRECATE CFLAGS= -I$C /MT /W3 $(OSCOMPAT) $(VSCOMPAT) -nologo $(EXTRACFLAGS) -DALERTFILE=\"$(ALERT)\" -DNNTPFILE=\"$(NNTP)\" -DUSERALERTFILE=\"$(USERALERT)\" -DANOFILE=\"$(ANO)\" -DSHUTDOWNFILE=\"$(SHUTDOWN)\" imapd: $(CCLIENTLIB) imapd.obj LINK /NOLOGO imapd.obj $(LIBS) imapd.obj: $C\mail.h $C\misc.h $C\osdep.h $(CCLIENTLIB): @echo Make c-client first false clean: del *.obj *.exe *.lib *.exp || rem # A monument to a hack of long ago and far away... love: @echo not war? alpine-2.10+dfsg/imap/src/ansilib/0000700000175000017500000000000011512502151020470 5ustar paulproteuspaulproteusalpine-2.10+dfsg/imap/src/ansilib/memmove.c0000600000175000017500000000174111512502122022304 0ustar paulproteuspaulproteus/* ======================================================================== * Copyright 1988-2006 University of Washington * * Licensed under the Apache License, Version 2.0 (the "License"); * you may not use this file except in compliance with the License. * You may obtain a copy of the License at * * http://www.apache.org/licenses/LICENSE-2.0 * * * ======================================================================== */ /* * Program: Memory move * * Author: Mark Crispin * Networks and Distributed Computing * Computing & Communications * University of Washington * Administration Building, AG-44 * Seattle, WA 98195 * Internet: MRC@CAC.Washington.EDU * * Date: 1 August 1988 * Last Edited: 30 August 2006 */ /* Copy memory block * Accepts: destination pointer * source pointer * length * Returns: destination pointer */ void *memmove (void *s,void *ct,size_t n) { bcopy (ct,s,n); /* they should have this one */ return s; } alpine-2.10+dfsg/imap/src/ansilib/strtoul.c0000600000175000017500000000451611512502122022356 0ustar paulproteuspaulproteus/* ======================================================================== * Copyright 1988-2006 University of Washington * * Licensed under the Apache License, Version 2.0 (the "License"); * you may not use this file except in compliance with the License. * You may obtain a copy of the License at * * http://www.apache.org/licenses/LICENSE-2.0 * * * ======================================================================== */ /* * Program: String to unsigned long * * Author: Mark Crispin * Networks and Distributed Computing * Computing & Communications * University of Washington * Administration Building, AG-44 * Seattle, WA 98195 * * Date: 14 February 1995 * Last Edited: 30 August 2006 */ /* * Turn a string unsigned long into the real thing * Accepts: source string * pointer to place to return end pointer * base * Returns: parsed unsigned long integer, end pointer is updated */ unsigned long strtoul (char *t,char **endp,int base) { unsigned long value = 0; /* the accumulated value */ int negative = 0; /* this a negative number? */ unsigned char c,*s = t; if (base && (base < 2 || base > 36)) { errno = EINVAL; /* insist upon valid base */ return value; } while (isspace (*s)) s++; /* skip leading whitespace */ switch (*s) { /* check for leading sign char */ case '-': negative = 1; /* yes, negative #. fall into '+' */ case '+': s++; /* skip the sign character */ } if (!base) { /* base not specified? */ if (*s != '0') base = 10; /* must be decimal if doesn't start with 0 */ /* starts with 0x? */ else if (tolower (*++s) == 'x') { base = 16; /* yes, is hex */ s++; /* skip the x */ } else base = 8; /* ...or octal */ } do { /* convert to numeric form if digit */ if (isdigit (*s)) c = *s - '0'; /* alphabetic conversion */ else if (isalpha (*s)) c = *s - (isupper (*s) ? 'A' : 'a') + 10; else break; /* else no way it's valid */ if (c >= base) break; /* digit out of range for base? */ value = value * base + c; /* accumulate the digit */ } while (*++s); /* loop until non-numeric character */ if (tolower (*s) == 'l') s++; /* ignore 'l' or 'L' marker */ if (endp) *endp = s; /* save users endp to after number */ /* negate number if needed */ return negative ? -value : value; } alpine-2.10+dfsg/imap/src/ansilib/strstr.c0000600000175000017500000000242211512502122022175 0ustar paulproteuspaulproteus/* ======================================================================== * Copyright 1988-2006 University of Washington * * Licensed under the Apache License, Version 2.0 (the "License"); * you may not use this file except in compliance with the License. * You may obtain a copy of the License at * * http://www.apache.org/licenses/LICENSE-2.0 * * * ======================================================================== */ /* * Program: Substring search * * Author: Mark Crispin * Networks and Distributed Computing * Computing & Communications * University of Washington * Administration Building, AG-44 * Seattle, WA 98195 * * Date: 11 May 1989 * Last Edited: 30 August 2006 */ /* Return pointer to first occurance in string of a substring * Accepts: source pointer * substring pointer * Returns: pointer to substring in source or NIL if not found */ char *strstr (char *cs,char *ct) { char *s; char *t; while (cs = strchr (cs,*ct)) {/* for each occurance of the first character */ /* see if remainder of string matches */ for (s = cs + 1, t = ct + 1; *t && *s == *t; s++, t++); if (!*t) return cs; /* if ran out of substring then have match */ cs++; /* try from next character */ } return NIL; /* not found */ } alpine-2.10+dfsg/imap/src/ansilib/memset.c0000600000175000017500000000176211512502122022134 0ustar paulproteuspaulproteus/* ======================================================================== * Copyright 1988-2006 University of Washington * * Licensed under the Apache License, Version 2.0 (the "License"); * you may not use this file except in compliance with the License. * You may obtain a copy of the License at * * http://www.apache.org/licenses/LICENSE-2.0 * * * ======================================================================== */ /* * Program: Set memory * * Author: Mark Crispin * Networks and Distributed Computing * Computing & Communications * University of Washington * Administration Building, AG-44 * Seattle, WA 98195 * * Date: 11 May 1989 * Last Edited: 30 August 2006 */ /* Set a block of memory * Accepts: destination pointer * value to set * length * Returns: destination pointer */ void *memset (void *s,int c,size_t n) { if (c) while (n) s[--n] = c; /* this way if non-zero */ else bzero (s,n); /* they should have this one */ return s; } alpine-2.10+dfsg/imap/src/ansilib/strtok.c0000600000175000017500000000403011512502122022157 0ustar paulproteuspaulproteus/* ======================================================================== * Copyright 1988-2007 University of Washington * * Licensed under the Apache License, Version 2.0 (the "License"); * you may not use this file except in compliance with the License. * You may obtain a copy of the License at * * http://www.apache.org/licenses/LICENSE-2.0 * * * ======================================================================== */ /* * Program: String return successive tokens * * Author: Mark Crispin * Networks and Distributed Computing * Computing & Communications * University of Washington * Administration Building, AG-44 * Seattle, WA 98195 * * Date: 11 May 1989 * Last Edited: 30 January 2007 */ /* Find token in string * Accepts: source pointer or NIL to use previous source * vector of token delimiters pointer * Returns: pointer to next token */ static char *state = NIL; /* string to locate tokens */ char *strtok (char *s,char *ct) { return strtok_r (s,ct,&state);/* jacket into reentrant routine */ } /* Find token in string (reentrant) * Accepts: source pointer or NIL to use previous source * vector of token delimiters pointer * returned state pointer * Returns: pointer to next token */ char *strtok_r (char *s,char *ct,char **r) { char *t,*ts; if (!s) s = *r; /* use previous token if none specified */ *r = NIL; /* default to no returned state */ if (!(s && *s)) return NIL; /* no tokens left */ /* find any leading delimiters */ do for (t = ct, ts = NIL; *t; t++) if (*t == *s) { if (*(ts = ++s)) break; /* yes, restart search if more in string */ return NIL; /* else no more tokens */ } while (ts); /* continue until no more leading delimiters */ /* can we find a new delimiter? */ for (ts = s; *ts; ts++) for (t = ct; *t; t++) if (*t == *ts) { *ts++ = '\0'; /* yes, tie off token at that point */ *r = ts; /* save subsequent tokens for future call */ return s; /* return our token */ } return s; /* return final token */ } alpine-2.10+dfsg/imap/src/ansilib/memmove2.c0000600000175000017500000000250611512502122022366 0ustar paulproteuspaulproteus/* ======================================================================== * Copyright 1988-2006 University of Washington * * Licensed under the Apache License, Version 2.0 (the "License"); * you may not use this file except in compliance with the License. * You may obtain a copy of the License at * * http://www.apache.org/licenses/LICENSE-2.0 * * * ======================================================================== */ /* * Program: Memory move when no bcopy() * * Author: Mark Crispin * Networks and Distributed Computing * Computing & Communications * University of Washington * Administration Building, AG-44 * Seattle, WA 98195 * Internet: MRC@CAC.Washington.EDU * * Date: 11 May 1989 * Last Edited: 30 August 2006 */ /* Copy memory block * Accepts: destination pointer * source pointer * length * Returns: destination pointer */ void *memmove (void *s,void *ct,size_t n) { char *dp,*sp; int i; unsigned long dest = (unsigned long) s; unsigned long src = (unsigned long) ct; if (((dest < src) && ((dest + n) < src)) || ((dest > src) && ((src + n) < dest))) return (void *) memcpy (s,ct,n); dp = (char *) s; sp = (char *) ct; if (dest < src) for (i = 0; i < n; ++i) dp[i] = sp[i]; else if (dest > src) for (i = n - 1; i >= 0; --i) dp[i] = sp[i]; return s; } alpine-2.10+dfsg/imap/src/ansilib/strpbrk.c0000600000175000017500000000214511512502122022325 0ustar paulproteuspaulproteus/* ======================================================================== * Copyright 1988-2006 University of Washington * * Licensed under the Apache License, Version 2.0 (the "License"); * you may not use this file except in compliance with the License. * You may obtain a copy of the License at * * http://www.apache.org/licenses/LICENSE-2.0 * * * ======================================================================== */ /* * Program: String search for break character * * Author: Mark Crispin * Networks and Distributed Computing * Computing & Communications * University of Washington * Administration Building, AG-44 * Seattle, WA 98195 * * Date: 11 May 1989 * Last Edited: 30 August 2006 */ /* Return pointer to first occurance in string of any delimiter * Accepts: source pointer * vector of delimiters pointer * Returns: pointer to delimiter or NIL if not found */ char *strpbrk (char *cs,char *ct) { char *s; /* search for delimiter until end of string */ for (; *cs; cs++) for (s = ct; *s; s++) if (*s == *cs) return cs; return NIL; /* not found */ } alpine-2.10+dfsg/imap/src/c-client/0000700000175000017500000000000012074130635020555 5ustar paulproteuspaulproteusalpine-2.10+dfsg/imap/src/c-client/auth_log.c0000600000175000017500000000665511512502124022531 0ustar paulproteuspaulproteus/* ======================================================================== * Copyright 1988-2006 University of Washington * * Licensed under the Apache License, Version 2.0 (the "License"); * you may not use this file except in compliance with the License. * You may obtain a copy of the License at * * http://www.apache.org/licenses/LICENSE-2.0 * * * ======================================================================== */ /* * Program: Login authenticator * * Author: Mark Crispin * Networks and Distributed Computing * Computing & Communications * University of Washington * Administration Building, AG-44 * Seattle, WA 98195 * Internet: MRC@CAC.Washington.EDU * * Date: 5 December 1995 * Last Edited: 30 August 2006 */ long auth_login_client (authchallenge_t challenger,authrespond_t responder, char *service,NETMBX *mb,void *stream, unsigned long *trial,char *user); char *auth_login_server (authresponse_t responder,int argc,char *argv[]); AUTHENTICATOR auth_log = { AU_HIDE, /* hidden */ "LOGIN", /* authenticator name */ NIL, /* always valid */ auth_login_client, /* client method */ auth_login_server, /* server method */ NIL /* next authenticator */ }; #define PWD_USER "User Name" #define PWD_PWD "Password" /* Client authenticator * Accepts: challenger function * responder function * SASL service name * parsed network mailbox structure * stream argument for functions * pointer to current trial count * returned user name * Returns: T if success, NIL otherwise, number of trials incremented if retry */ long auth_login_client (authchallenge_t challenger,authrespond_t responder, char *service,NETMBX *mb,void *stream, unsigned long *trial,char *user) { char pwd[MAILTMPLEN]; void *challenge; unsigned long clen; long ret = NIL; /* get user name prompt */ if (challenge = (*challenger) (stream,&clen)) { fs_give ((void **) &challenge); pwd[0] = NIL; /* prompt user */ mm_login (mb,user,pwd,*trial); if (!pwd[0]) { /* user requested abort */ (*responder) (stream,NIL,0); *trial = 0; /* cancel subsequent attempts */ ret = LONGT; /* will get a BAD response back */ } /* send user name */ else if ((*responder) (stream,user,strlen (user)) && (challenge = (*challenger) (stream,&clen))) { fs_give ((void **) &challenge); /* send password */ if ((*responder) (stream,pwd,strlen (pwd))) { if (challenge = (*challenger) (stream,&clen)) fs_give ((void **) &challenge); else { ++*trial; /* can try again if necessary */ ret = LONGT; /* check the authentication */ } } } } memset (pwd,0,MAILTMPLEN); /* erase password */ if (!ret) *trial = 65535; /* don't retry if bad protocol */ return ret; } /* Server authenticator * Accepts: responder function * argument count * argument vector * Returns: authenticated user name or NIL */ char *auth_login_server (authresponse_t responder,int argc,char *argv[]) { char *ret = NIL; char *user,*pass,*authuser; if (user = (*responder) (PWD_USER,sizeof (PWD_USER),NIL)) { if (pass = (*responder) (PWD_PWD,sizeof (PWD_PWD),NIL)) { /* delimit user from possible admin */ if (authuser = strchr (user,'*')) *authuser++ = '\0'; if (server_login (user,pass,authuser,argc,argv)) ret = myusername (); fs_give ((void **) &pass); } fs_give ((void **) &user); } return ret; } alpine-2.10+dfsg/imap/src/c-client/flstring.h0000600000175000017500000000143711512502124022555 0ustar paulproteuspaulproteus/* ======================================================================== * Copyright 1988-2006 University of Washington * * Licensed under the Apache License, Version 2.0 (the "License"); * you may not use this file except in compliance with the License. * You may obtain a copy of the License at * * http://www.apache.org/licenses/LICENSE-2.0 * * * ======================================================================== */ /* * Program: File string routines * * Author: Mark Crispin * Networks and Distributed Computing * Computing & Communications * University of Washington * Administration Building, AG-44 * Seattle, WA 98195 * Internet: MRC@CAC.Washington.EDU * * Date: 15 April 1997 * Last Edited: 30 August 2006 */ extern STRINGDRIVER file_string; alpine-2.10+dfsg/imap/src/c-client/utf8.h0000600000175000017500000005466711512502124021630 0ustar paulproteuspaulproteus/* ======================================================================== * Copyright 1988-2008 University of Washington * * Licensed under the Apache License, Version 2.0 (the "License"); * you may not use this file except in compliance with the License. * You may obtain a copy of the License at * * http://www.apache.org/licenses/LICENSE-2.0 * * * ======================================================================== */ /* * Program: UTF-8 routines * * Author: Mark Crispin * Networks and Distributed Computing * Computing & Communications * University of Washington * Administration Building, AG-44 * Seattle, WA 98195 * Internet: MRC@CAC.Washington.EDU * * Date: 11 June 1997 * Last Edited: 17 January 2008 */ /* UTF-8 size and conversion routines from UCS-2 values (thus in the BMP). * Don't use these if UTF-16 data (surrogate pairs) are an issue. * For UCS-4 values, use the utf8_size() and utf8_put() functions. */ #define UTF8_SIZE_BMP(c) ((c & 0xff80) ? ((c & 0xf800) ? 3 : 2) : 1) #define UTF8_PUT_BMP(b,c) { \ if (c & 0xff80) { /* non-ASCII? */ \ if (c & 0xf800) { /* three byte code */ \ *b++ = 0xe0 | (c >> 12); \ *b++ = 0x80 | ((c >> 6) & 0x3f); \ } \ else *b++ = 0xc0 | ((c >> 6) & 0x3f); \ *b++ = 0x80 | (c & 0x3f); \ } \ else *b++ = c; \ } /* utf8_text() flag values */ #define U8T_CASECANON 2 /* canonicalize case */ #define U8T_DECOMPOSE 4 /* decompose */ /* full canonicalization */ #define U8T_CANONICAL (U8T_CASECANON | U8T_DECOMPOSE) /* utf8_get() return values */ /* 0x0000 - 0xffff BMP plane */ #define U8GM_NONBMP 0xffff0000 /* mask for non-BMP values */ /* 0x10000 - 0x10ffff extended planes */ /* 0x110000 - 0x7ffffff non-Unicode */ #define U8G_ERROR 0x80000000 /* error flag */ #define U8G_BADCONT U8G_ERROR+1 /* continuation when not in progress */ #define U8G_INCMPLT U8G_ERROR+2 /* incomplete UTF-8 character */ #define U8G_NOTUTF8 U8G_ERROR+3 /* not a valid UTF-8 octet */ #define U8G_ENDSTRG U8G_ERROR+4 /* end of string */ #define U8G_ENDSTRI U8G_ERROR+5 /* end of string w/ incomplete UTF-8 char */ #define U8G_SURROGA U8G_ERROR+6 /* surrogate codepoint */ #define U8G_NOTUNIC U8G_ERROR+7 /* non-Unicode codepoint */ /* ucs4_width() return values */ #define U4W_ERROR 0x80000000 /* error flags */ #define U4W_NOTUNCD U4W_ERROR+1 /* not a Unicode char */ #define U4W_PRIVATE U4W_ERROR+2 /* private-space plane */ #define U4W_SSPCHAR U4W_ERROR+3 /* Supplementary Special-purpose Plane */ #define U4W_UNASSGN U4W_ERROR+4 /* unassigned space plane */ #define U4W_CONTROL U4W_ERROR+5 /* C0/C1 control */ #define U4W_CTLSRGT U4W_CONTROL /* in case legacy code references this */ /* ISO-2022 engine states */ #define I2S_CHAR 0 /* character */ #define I2S_ESC 1 /* previous character was ESC */ #define I2S_MUL 2 /* previous character was multi-byte code */ #define I2S_INT 3 /* previous character was intermediate */ /* ISO-2022 Gn selections */ #define I2C_G0 0 /* G0 */ #define I2C_G1 1 /* G1 */ #define I2C_G2 2 /* G2 */ #define I2C_G3 3 /* G3 */ #define I2C_SG2 (2 << 2) /* single shift G2 */ #define I2C_SG3 (3 << 2) /* single shift G2 */ /* ISO-2022 octet definitions */ #define I2C_ESC 0x1b /* ESCape */ /* Intermediate character */ #define I2C_STRUCTURE 0x20 /* announce code structure */ #define I2C_C0 0x21 /* C0 */ #define I2C_C1 0x22 /* C1 */ #define I2C_CONTROL 0x23 /* single control function */ #define I2C_MULTI 0x24 /* multi-byte character set */ #define I2C_OTHER 0x25 /* other coding system */ #define I2C_REVISED 0x26 /* revised registration */ #define I2C_G0_94 0x28 /* G0 94-character set */ #define I2C_G1_94 0x29 /* G1 94-character set */ #define I2C_G2_94 0x2A /* G2 94-character set */ #define I2C_G3_94 0x2B /* G3 94-character set */ #define I2C_G0_96 0x2C /* (not in ISO-2022) G0 96-character set */ #define I2C_G1_96 0x2D /* G1 96-character set */ #define I2C_G2_96 0x2E /* G2 96-character set */ #define I2C_G3_96 0x2F /* G3 96-character set */ /* Locking shifts */ #define I2C_SI 0x0f /* lock shift to G0 (Shift In) */ #define I2C_SO 0x0e /* lock shift to G1 (Shift Out) */ /* prefixed by ESC */ #define I2C_LS2 0x6e /* lock shift to G2 */ #define I2C_LS3 0x6f /* lock shift to G3 */ #define I2C_LS1R 0x7e /* lock shift GR to G1 */ #define I2C_LS2R 0x7d /* lock shift GR to G2 */ #define I2C_LS3R 0x7c /* lock shift GR to G3 */ /* Single shifts */ #define I2C_SS2_ALT 0x8e /* single shift to G2 (SS2) */ #define I2C_SS3_ALT 0x8f /* single shift to G3 (SS3) */ #define I2C_SS2_ALT_7 0x19 /* single shift to G2 (SS2) */ #define I2C_SS3_ALT_7 0x1d /* single shift to G3 (SS3) */ /* prefixed by ESC */ #define I2C_SS2 0x4e /* single shift to G2 (SS2) */ #define I2C_SS3 0x4f /* single shift to G3 (SS3) */ /* 94 character sets */ /* 4/0 ISO 646 IRV */ #define I2CS_94_BRITISH 0x41 /* 4/1 ISO 646 British */ #define I2CS_94_ASCII 0x42 /* 4/2 ISO 646 USA (ASCII) */ /* 4/3 NATS Finland/Sweden (primary) */ /* 4/4 NATS Finland/Sweden (secondary) */ /* 4/5 NATS Denmark/Norway (primary) */ /* 4/6 NATS Denmark/Norway (secondary) */ /* 4/7 ISO 646 Swedish SEN 850200 */ /* 4/8 ISO 646 Swedish names */ #define I2CS_94_JIS_BUGROM 0x48 /* 4/8 some buggy software does this */ #define I2CS_94_JIS_KANA 0x49 /* 4/9 JIS X 0201-1976 right half */ #define I2CS_94_JIS_ROMAN 0x4a /* 4/a JIS X 0201-1976 left half */ /* 4/b ISO 646 German */ /* 4/c ISO 646 Portuguese (Olivetti) */ /* 4/d ISO 6438 African */ /* 4/e ISO 5427 Cyrillic (Honeywell-Bull) */ /* 4/f DIN 31624 extended bibliography */ /* 5/0 ISO 5426-1980 Bibliography */ /* 5/1 ISO 5427-1981 Cyrillic*/ /* 5/2 ISO 646 French (withdrawn) */ /* 5/3 ISO 5428-1980 Greek bibliography */ /* 5/4 GB 1988-80 Chinese */ /* 5/5 Latin-Greek (Honeywell-Bull) */ /* 5/6 UK Viewdata/Teletext */ /* 5/7 INIS (IRV subset) */ /* 5/8 ISO 5428 Greek Bibliography */ /* 5/9 ISO 646 Italian (Olivetti) */ /* 5/a ISO 646 Spanish (Olivetti) */ /* 5/b Greek (Olivetti) */ /* 5/c Latin-Greek (Olivetti) */ /* 5/d INIS non-standard extension */ /* 5/e INIS Cyrillic extension */ /* 5/f Arabic CODAR-U IERA */ /* 6/0 ISO 646 Norwegian */ /* 6/1 Norwegian version 2 (withdrawn) */ /* 6/2 Videotex supplementary */ /* 6/3 Videotex supplementary #2 */ /* 6/4 Videotex supplementary #3 */ /* 6/5 APL */ /* 6/6 ISO 646 French */ /* 6/7 ISO 646 Portuguese (IBM) */ /* 6/8 ISO 646 Spanish (IBM) */ /* 6/9 ISO 646 Hungarian */ /* 6/a Greek ELOT (withdrawn) */ /* 6/b ISO 9036 Arabic 7-bit */ /* 6/c ISO 646 IRV supplementary set */ /* 6/d JIS C6229-1984 OCR-A */ /* 6/e JIS C6229-1984 OCR-B */ /* 6/f JIS C6229-1984 OCR-B additional */ /* 7/0 JIS C6229-1984 hand-printed */ /* 7/1 JIS C6229-1984 additional hand-printd */ /* 7/2 JIS C6229-1984 katakana hand-printed */ /* 7/3 E13B Japanese graphic */ /* 7/4 Supplementary Videotex (withdrawn) */ /* 7/5 Teletex primary CCITT T.61 */ /* 7/6 Teletex secondary CCITT T.61 */ /* 7/7 CSA Z 243.4-1985 Alternate primary #1 */ /* 7/8 CSA Z 243.4-1985 Alternate primary #2 */ /* 7/9 Mosaic CCITT T.101 */ /* 7/a Serbocroatian/Slovenian Latin */ /* 7/b Serbocroatian Cyrillic */ /* 7/c Supplementary CCITT T.101 */ /* 7/d Macedonian Cyrillic */ /* 94 character sets - second intermediate byte */ /* 4/0 Greek primary CCITT */ /* 4/1 Cuba */ /* 4/2 ISO/IEC 646 invariant */ /* 4/3 Irish Gaelic 7-bit */ /* 4/4 Turkmen */ /* 94x94 character sets */ #define I2CS_94x94_JIS_OLD 0x40 /* 4/0 JIS X 0208-1978 */ #define I2CS_94x94_GB 0x41 /* 4/1 GB 2312 */ #define I2CS_94x94_JIS_NEW 0x42 /* 4/2 JIS X 0208-1983 */ #define I2CS_94x94_KSC 0x43 /* 4/3 KSC 5601 */ #define I2CS_94x94_JIS_EXT 0x44 /* 4/4 JIS X 0212-1990 */ /* 4/5 CCITT Chinese */ /* 4/6 Blisssymbol Graphic */ #define I2CS_94x94_CNS1 0x47 /* 4/7 CNS 11643 plane 1 */ #define I2CS_94x94_CNS2 0x48 /* 4/8 CNS 11643 plane 2 */ #define I2CS_94x94_CNS3 0x49 /* 4/9 CNS 11643 plane 3 */ #define I2CS_94x94_CNS4 0x4a /* 4/a CNS 11643 plane 4 */ #define I2CS_94x94_CNS5 0x4b /* 4/b CNS 11643 plane 5 */ #define I2CS_94x94_CNS6 0x4c /* 4/c CNS 11643 plane 6 */ #define I2CS_94x94_CNS7 0x4d /* 4/d CNS 11643 plane 7 */ /* 4/e DPRK (North Korea) KGCII */ /* 4/f JGCII plane 1 */ /* 5/0 JGCII plane 2 */ /* 96 character sets */ #define I2CS_96_ISO8859_1 0x41 /* 4/1 Latin-1 (Western Europe) */ #define I2CS_96_ISO8859_2 0x42 /* 4/2 Latin-2 (Czech, Slovak) */ #define I2CS_96_ISO8859_3 0x43 /* 4/3 Latin-3 (Dutch, Turkish) */ #define I2CS_96_ISO8859_4 0x44 /* 4/4 Latin-4 (Scandinavian) */ /* 4/5 CSA Z 243.4-1985 */ #define I2CS_96_ISO8859_7 0x46 /* 4/6 Greek */ #define I2CS_96_ISO8859_6 0x47 /* 4/7 Arabic */ #define I2CS_96_ISO8859_8 0x48 /* 4/8 Hebrew */ /* 4/9 Czechoslovak CSN 369103 */ /* 4/a Supplementary Latin and non-alpha */ /* 4/b Technical */ #define I2CS_96_ISO8859_5 0x4c /* 4/c Cyrillic */ #define I2CS_96_ISO8859_9 0x4d /* 4/d Latin-5 (Finnish, Portuguese) */ /* 4/e ISO 6937-2 residual */ /* 4/f Basic Cyrillic */ /* 5/0 Supplementary Latin 1, 2 and 5 */ /* 5/1 Basic Box */ /* 5/2 Supplementary ISO/IEC 6937 : 1992 */ /* 5/3 CCITT Hebrew supplementary */ #define I2CS_96_TIS620 0x54 /* 5/4 TIS 620 */ /* 5/5 Arabic/French/German */ #define I2CS_96_ISO8859_10 0x56 /* 5/6 Latin-6 (Northern Europe) */ /* 5/7 ??? */ /* 5/8 Sami (Lappish) supplementary */ #define I2CS_96_ISO8859_13 0x59 /* 5/9 Latin-7 (Baltic) */ #define I2CS_96_VSCII 0x5a /* 5/a Vietnamese */ /* 5/b Technical #1 IEC 1289 */ #define I2CS_96_ISO8859_14 0x5c /* 5/c Latin-8 (Celtic) */ /* 5/d Sami supplementary Latin */ /* 5/e Latin/Hebrew */ /* 5/f Celtic supplementary Latin */ /* 6/0 Uralic supplementary Cyrillic */ /* 6/1 Volgaic supplementary Cyrillic */ #define I2CS_96_ISO8859_15 0x62 /* 6/2 Latin-9 (Euro) */ /* 6/3 Latin-1 with Euro */ /* 6/4 Latin-4 with Euro */ /* 6/5 Latin-7 with Euro */ #define I2CS_96_ISO8859_16 0x66 /* 6/6 Latin-10 (Balkan) */ /* 6/7 Ogham */ /* 6/8 Sami supplementary Latin #2 */ /* 7/d Supplementary Mosaic for CCITT 101 */ /* 96x96 character sets */ /* Types of character sets */ #define I2CS_94 0x000 /* 94 character set */ #define I2CS_96 0x100 /* 96 character set */ #define I2CS_MUL 0x200 /* multi-byte */ #define I2CS_94x94 (I2CS_MUL | I2CS_94) #define I2CS_96x96 (I2CS_MUL | I2CS_96) /* Character set identifiers stored in Gn */ #define I2CS_BRITISH (I2CS_94 | I2CS_94_BRITISH) #define I2CS_ASCII (I2CS_94 | I2CS_94_ASCII) #define I2CS_JIS_BUGROM (I2CS_94 | I2CS_94_JIS_BUGROM) #define I2CS_JIS_KANA (I2CS_94 | I2CS_94_JIS_KANA) #define I2CS_JIS_ROMAN (I2CS_94 | I2CS_94_JIS_ROMAN) #define I2CS_JIS_OLD (I2CS_94x94 | I2CS_94x94_JIS_OLD) #define I2CS_GB (I2CS_94x94 | I2CS_94x94_GB) #define I2CS_JIS_NEW (I2CS_94x94 | I2CS_94x94_JIS_NEW) #define I2CS_KSC (I2CS_94x94 | I2CS_94x94_KSC) #define I2CS_JIS_EXT (I2CS_94x94 | I2CS_94x94_JIS_EXT) #define I2CS_CNS1 (I2CS_94x94 | I2CS_94x94_CNS1) #define I2CS_CNS2 (I2CS_94x94 | I2CS_94x94_CNS2) #define I2CS_CNS3 (I2CS_94x94 | I2CS_94x94_CNS3) #define I2CS_CNS4 (I2CS_94x94 | I2CS_94x94_CNS4) #define I2CS_CNS5 (I2CS_94x94 | I2CS_94x94_CNS5) #define I2CS_CNS6 (I2CS_94x94 | I2CS_94x94_CNS6) #define I2CS_CNS7 (I2CS_94x94 | I2CS_94x94_CNS7) #define I2CS_ISO8859_1 (I2CS_96 | I2CS_96_ISO8859_1) #define I2CS_ISO8859_2 (I2CS_96 | I2CS_96_ISO8859_2) #define I2CS_ISO8859_3 (I2CS_96 | I2CS_96_ISO8859_3) #define I2CS_ISO8859_4 (I2CS_96 | I2CS_96_ISO8859_4) #define I2CS_ISO8859_7 (I2CS_96 | I2CS_96_ISO8859_7) #define I2CS_ISO8859_6 (I2CS_96 | I2CS_96_ISO8859_6) #define I2CS_ISO8859_8 (I2CS_96 | I2CS_96_ISO8859_8) #define I2CS_ISO8859_5 (I2CS_96 | I2CS_96_ISO8859_5) #define I2CS_ISO8859_9 (I2CS_96 | I2CS_96_ISO8859_9) #define I2CS_TIS620 (I2CS_96 | I2CS_96_TIS620) #define I2CS_ISO8859_10 (I2CS_96 | I2CS_96_ISO8859_10) #define I2CS_ISO8859_13 (I2CS_96 | I2CS_96_ISO8859_13) #define I2CS_VSCII (I2CS_96 | I2CS_96_VSCII) #define I2CS_ISO8859_14 (I2CS_96 | I2CS_96_ISO8859_14) #define I2CS_ISO8859_15 (I2CS_96 | I2CS_96_ISO8859_15) #define I2CS_ISO8859_16 (I2CS_96 | I2CS_96_ISO8859_16) /* Miscellaneous ISO 2022 definitions */ #define EUC_CS2 0x8e /* single shift CS2 */ #define EUC_CS3 0x8f /* single shift CS3 */ #define BITS7 0x7f /* 7-bit value mask */ #define BIT8 0x80 /* 8th bit mask */ /* The following saves us from having to have yet more charset tables */ /* Unicode codepoints */ #define UCS2_C0CONTROL 0x00 /* first C0 control */ #define UCS2_C0CONTROLEND 0x1F /* last C0 control */ #define UCS2_C1CONTROL 0x80 /* first C1 control */ #define UCS2_C1CONTROLEND 0x9F /* last C1 control */ /* ISO 646 substituted Unicode codepoints */ #define UCS2_POUNDSTERLING 0x00a3 #define UCS2_YEN 0x00a5 #define UCS2_OVERLINE 0x203e #define UCS2_EURO 0x20ac #define UCS2_KATAKANA 0xff61 /* first katakana codepoint */ #define UCS2_BOM 0xfeff /* byte order mark */ #define UCS2_BOGON 0xfffd /* replacement character */ /* next two codepoints are not Unicode chars */ #define UCS2_BOMCHECK 0xfffe /* used to check byte order with UCS2_BOM */ #define UCS2_NOTCHAR 0xffff /* not a character */ #define UCS4_BMPBASE 0x0000 /* Basic Multilingual Plane */ #define UCS4_SMPBASE 0x10000 /* Supplementary Multilinugual Plane */ #define UCS4_SIPBASE 0x20000 /* Supplementary Ideographic Plane */ /* EastAsianWidth says plane 3 is wide */ #define UCS4_UNABASE 0x40000 /* unassigned space */ #define UCS4_SSPBASE 0xe0000 /* Supplementary Special-purpose Plane */ #define UCS4_PVTBASE 0xf0000 /* private-space (two planes) */ #define UCS4_MAXUNICODE 0x10ffff/* highest Unicode codepoint */ #define UTF16_BASE 0x10000 /* base of codepoints needing surrogates */ #define UTF16_SHIFT 10 /* surrogate shift */ #define UTF16_MASK 0x3ff /* surrogate mask */ #define UTF16_SURR 0xd800 /* UTF-16 surrogate area */ #define UTF16_SURRH 0xd800 /* UTF-16 first high surrogate */ #define UTF16_SURRHEND 0xdbff /* UTF-16 last high surrogate */ #define UTF16_SURRL 0xdc00 /* UTF-16 first low surrogate */ #define UTF16_SURRLEND 0xdfff /* UTF-16 last low surrogate */ #define UTF16_MAXSURR 0xdfff /* end of UTF-16 surrogates */ /* UBOGON is used to represent a codepoint in a character set which does not * map to Unicode. It is also used for mapping failures, e.g. incomplete * shift sequences. This name has the same text width as 0x????, for * convenience in the mapping tables. * * NOCHAR is used to represent a codepoint in Unicode which does not map to * the target character set in a reverse mapping table. This name has the * same text width as 0x???? in case we ever add static reverse mapping tables. */ #define UBOGON UCS2_BOGON #define NOCHAR UCS2_NOTCHAR /* Codepoints in non-Unicode character sets */ /* Codepoints in ISO 646 character sets */ /* British ASCII codepoints */ #define BRITISH_POUNDSTERLING 0x23 /* JIS Roman codepoints */ #define JISROMAN_YEN 0x5c #define JISROMAN_OVERLINE 0x7e /* Hankaku katakana codepoints & parameters * * In earlier versions, MAX_KANA_7 and MAX_KANA_8 were the maximum codepoint * values. Although this made sense, it was confusing with the "max ku" and * "max ten" values used in the double-byte tables; there are 1-origin, but * the calculated values used for "ku" and "ten" are 0-origin (derived by * substracting the "base"). What this all meant is that for double byte * characters the limit test is of the form (value < max_ku), but for single * byte characters (which used the same cell to hold the max ku) the limit * test was (value <= max_ku). * * By making MAX_KANA_[78] be maximum+1, the same (value < max_ku) limit test * is used throughout. - 6/15/2006 */ #define MIN_KANA_7 0x21 #define MAX_KANA_7 0x60 /* maximum value + 1 */ #define KANA_7 (UCS2_KATAKANA - MIN_KANA_7) #define MIN_KANA_8 (MIN_KANA_7 | BIT8) #define MAX_KANA_8 (MAX_KANA_7 | BIT8) #define KANA_8 (UCS2_KATAKANA - MIN_KANA_8) /* Charset scripts */ /* The term "script" is used here in a very loose sense, enough to make * purists cringe. Basically, the idea is to give the main program some * idea of how it should treat the characters of text in a charset with * respect to font, drawing routines, etc. * * In some cases, "script" is associated with a charset; in other cases, * it's more closely tied to a language. */ #define SC_UNICODE 0x1 /* Unicode */ #define SC_LATIN_1 0x10 /* Western Europe */ #define SC_LATIN_2 0x20 /* Eastern Europe */ #define SC_LATIN_3 0x40 /* Southern Europe */ #define SC_LATIN_4 0x80 /* Northern Europe */ #define SC_LATIN_5 0x100 /* Turkish */ #define SC_LATIN_6 0x200 /* Nordic */ #define SC_LATIN_7 0x400 /* Baltic */ #define SC_LATIN_8 0x800 /* Celtic */ #define SC_LATIN_9 0x1000 /* Euro */ #define SC_LATIN_0 SC_LATIN_9 /* colloquial name for Latin-9 */ #define SC_ARABIC 0x2000 #define SC_CYRILLIC 0x4000 #define SC_GREEK 0x8000 #define SC_HEBREW 0x10000 #define SC_THAI 0x20000 #define SC_UKRANIAN 0x40000 #define SC_LATIN_10 0x80000 /* Balkan */ #define SC_VIETNAMESE 0x100000 #define SC_CHINESE_SIMPLIFIED 0x1000000 #define SC_CHINESE_TRADITIONAL 0x2000000 #define SC_JAPANESE 0x4000000 #define SC_KOREAN 0x8000000 /* Script table */ typedef struct utf8_scent { char *name; /* script name */ char *description; /* script description */ unsigned long script; /* script bitmask */ } SCRIPT; /* Character set table support */ typedef struct utf8_csent { char *name; /* charset name */ unsigned short type; /* type of charset */ unsigned short flags; /* charset flags */ void *tab; /* additional data */ unsigned long script; /* script(s) implemented by this charset */ char *preferred; /* preferred charset over this one */ } CHARSET; struct utf8_eucparam { unsigned int base_ku : 8; /* base row */ unsigned int base_ten : 8; /* base column */ unsigned int max_ku : 8; /* maximum row */ unsigned int max_ten : 8; /* maximum column */ void *tab; /* conversion table */ }; /* Charset types */ #define CT_UNKNOWN 0 /* unknown 8-bit */ #define CT_ASCII 1 /* 7-bit ASCII no table */ #define CT_UCS2 2 /* 2 byte 16-bit Unicode no table */ #define CT_UCS4 3 /* 4 byte 32-bit Unicode no table */ #define CT_1BYTE0 10 /* 1 byte ISO 8859-1 no table */ #define CT_1BYTE 11 /* 1 byte ASCII + table 0x80-0xff */ #define CT_1BYTE8 12 /* 1 byte table 0x00 - 0xff */ #define CT_EUC 100 /* 2 byte ASCII + utf8_eucparam base/CS2/CS3 */ #define CT_DBYTE 101 /* 2 byte ASCII + utf8_eucparam */ #define CT_DBYTE2 102 /* 2 byte ASCII + utf8_eucparam plane1/2 */ #define CT_UTF16 1000 /* variable UTF-16 encoded Unicode no table */ #define CT_UTF8 1001 /* variable UTF-8 encoded Unicode no table */ #define CT_UTF7 1002 /* variable UTF-7 encoded Unicode no table */ #define CT_2022 10000 /* variable ISO-2022 encoded no table */ #define CT_SJIS 10001 /* 2 byte Shift-JIS encoded JIS no table */ /* Character set flags */ #define CF_PRIMARY 0x1 /* primary name for this charset */ #define CF_DISPLAY 0x2 /* charset used in displays */ #define CF_POSTING 0x4 /* charset used in email posting */ #define CF_UNSUPRT 0x8 /* charset unsupported (can't convert to it) */ #define CF_NOEMAIL 0x10 /* charset not used in email */ /* UTF-7 engine states */ #define U7_ASCII 0 /* ASCII character */ #define U7_PLUS 1 /* plus seen */ #define U7_UNICODE 2 /* Unicode characters */ #define U7_MINUS 3 /* absorbed minus seen */ /* Function prototypes */ typedef unsigned long (*ucs4cn_t) (unsigned long c); typedef unsigned long (*ucs4de_t) (unsigned long c,void **more); SCRIPT *utf8_script (char *script); const CHARSET *utf8_charset (char *charset); char *utf8_badcharset (char *charset); long utf8_text (SIZEDTEXT *text,char *charset,SIZEDTEXT *ret,long flags); long utf8_text_cs (SIZEDTEXT *text,const CHARSET *cs,SIZEDTEXT *ret, ucs4cn_t cv,ucs4de_t de); long utf8_cstext (SIZEDTEXT *text,char *charset,SIZEDTEXT *ret, unsigned long errch); long utf8_cstocstext (SIZEDTEXT *text,char *sc,SIZEDTEXT *ret,char *dc, unsigned long errch); unsigned short *utf8_rmap (char *charset); unsigned short *utf8_rmap_cs (const CHARSET *cs); unsigned short *utf8_rmap_gen (const CHARSET *cs,unsigned short *oldmap); long utf8_rmaptext (SIZEDTEXT *text,unsigned short *rmap,SIZEDTEXT *ret, unsigned long errch,long iso2022jp); unsigned long utf8_rmapsize (SIZEDTEXT *text,unsigned short *rmap, unsigned long errch,long iso2022jp); long ucs4_rmaptext (unsigned long *ucs4,unsigned long len,unsigned short *rmap, SIZEDTEXT *ret,unsigned long errch); long ucs4_rmaplen (unsigned long *ucs4,unsigned long len,unsigned short *rmap, unsigned long errch); long ucs4_rmapbuf (unsigned char *t,unsigned long *ucs4,unsigned long len, unsigned short *rmap,unsigned long errch); unsigned long utf8_get (unsigned char **s,unsigned long *i); unsigned long utf8_get_raw (unsigned char **s,unsigned long *i); unsigned long ucs4_cs_get (CHARSET *cs,unsigned char **s,unsigned long *i); unsigned long *utf8_csvalidmap (char *charsets[]); const CHARSET *utf8_infercharset (SIZEDTEXT *src); long utf8_validate (unsigned char *s,unsigned long i); void utf8_text_1byte0 (SIZEDTEXT *text,SIZEDTEXT *ret,ucs4cn_t cv,ucs4de_t de); void utf8_text_1byte (SIZEDTEXT *text,SIZEDTEXT *ret,void *tab,ucs4cn_t cv, ucs4de_t de); void utf8_text_1byte8 (SIZEDTEXT *text,SIZEDTEXT *ret,void *tab,ucs4cn_t cv, ucs4de_t de); void utf8_text_euc (SIZEDTEXT *text,SIZEDTEXT *ret,void *tab,ucs4cn_t cv, ucs4de_t de); void utf8_text_dbyte (SIZEDTEXT *text,SIZEDTEXT *ret,void *tab,ucs4cn_t cv, ucs4de_t de); void utf8_text_dbyte2 (SIZEDTEXT *text,SIZEDTEXT *ret,void *tab,ucs4cn_t cv, ucs4de_t de); void utf8_text_sjis (SIZEDTEXT *text,SIZEDTEXT *ret,ucs4cn_t cv,ucs4de_t de); void utf8_text_2022 (SIZEDTEXT *text,SIZEDTEXT *ret,ucs4cn_t cv,ucs4de_t de); void utf8_text_utf7 (SIZEDTEXT *text,SIZEDTEXT *ret,ucs4cn_t cv,ucs4de_t de); void utf8_text_utf8 (SIZEDTEXT *text,SIZEDTEXT *ret,ucs4cn_t cv,ucs4de_t de); void utf8_text_ucs2 (SIZEDTEXT *text,SIZEDTEXT *ret,ucs4cn_t cv,ucs4de_t de); void utf8_text_ucs4 (SIZEDTEXT *text,SIZEDTEXT *ret,ucs4cn_t cv,ucs4de_t de); void utf8_text_utf16 (SIZEDTEXT *text,SIZEDTEXT *ret,ucs4cn_t cv,ucs4de_t de); unsigned long utf8_size (unsigned long c); unsigned char *utf8_put (unsigned char *s,unsigned long c); unsigned long ucs4_titlecase (unsigned long c); long ucs4_width (unsigned long c); long utf8_strwidth (unsigned char *s); long utf8_textwidth (SIZEDTEXT *utf8); unsigned long ucs4_decompose (unsigned long c,void **more); unsigned long ucs4_decompose_recursive (unsigned long c,void **more); alpine-2.10+dfsg/imap/src/c-client/newsrc.c0000600000175000017500000004126011512502124022217 0ustar paulproteuspaulproteus/* ======================================================================== * Copyright 1988-2006 University of Washington * * Licensed under the Apache License, Version 2.0 (the "License"); * you may not use this file except in compliance with the License. * You may obtain a copy of the License at * * http://www.apache.org/licenses/LICENSE-2.0 * * * ======================================================================== */ /* * Program: Newsrc manipulation routines * * Author: Mark Crispin * Networks and Distributed Computing * Computing & Communications * University of Washington * Administration Building, AG-44 * Seattle, WA 98195 * Internet: MRC@CAC.Washington.EDU * * Date: 12 September 1994 * Last Edited: 30 August 2006 */ #include #include #include "c-client.h" #include "newsrc.h" #ifndef OLDFILESUFFIX #define OLDFILESUFFIX ".old" #endif /* Error message * Accepts: message format * additional message string * message level * Returns: NIL, always */ long newsrc_error (char *fmt,char *text,long errflg) { char tmp[MAILTMPLEN]; sprintf (tmp,fmt,text); MM_LOG (tmp,errflg); return NIL; } /* Write error message * Accepts: newsrc name * file designator * file designator * Returns: NIL, always */ long newsrc_write_error (char *name,FILE *f1,FILE *f2) { if (f1) fclose (f1); /* close file designators */ if (f2) fclose (f2); return newsrc_error ("Error writing to %.80s",name,ERROR); } /* Create newsrc file in local form * Accepts: MAIL stream * notification flag * Returns: file designator of newsrc */ FILE *newsrc_create (MAILSTREAM *stream,int notify) { char *newsrc = (char *) mail_parameters (stream,GET_NEWSRC,stream); FILE *f = fopen (newsrc,"wb"); if (!f) newsrc_error ("Unable to create news state %.80s",newsrc,ERROR); else if (notify) newsrc_error ("Creating news state %.80s",newsrc,WARN); return f; } /* Write new state in newsrc * Accepts: file designator of newsrc * group * new subscription status character * newline convention * Returns: T if successful, NIL otherwise */ long newsrc_newstate (FILE *f,char *group,char state,char *nl) { long ret = (f && (fputs (group,f) != EOF) && ((putc (state,f)) != EOF) && ((putc (' ',f)) != EOF) && (fputs (nl,f) != EOF)) ? LONGT : NIL; if (fclose (f) == EOF) ret = NIL; return ret; } /* Write messages in newsrc * Accepts: file designator of newsrc * MAIL stream * message number/newsgroup message map * newline convention * Returns: T if successful, NIL otherwise */ long newsrc_newmessages (FILE *f,MAILSTREAM *stream,char *nl) { unsigned long i,j,k; char tmp[MAILTMPLEN]; MESSAGECACHE *elt; int c = ' '; if (stream->nmsgs) { /* have any messages? */ for (i = 1,j = k = (mail_elt (stream,i)->private.uid > 1) ? 1 : 0; i <= stream->nmsgs; ++i) { /* deleted message? */ if ((elt = mail_elt (stream,i))->deleted) { k = elt->private.uid; /* this is the top of the current range */ if (!j) j = k; /* if no range in progress, start one */ } else if (j) { /* unread message, ending a range */ /* calculate end of range */ if (k = elt->private.uid - 1) { /* dump range */ sprintf (tmp,(j == k) ? "%c%ld" : "%c%ld-%ld",c,j,k); if (fputs (tmp,f) == EOF) return NIL; c = ','; /* need a comma after the first time */ } j = 0; /* no more range in progress */ } } if (j) { /* dump trailing range */ sprintf (tmp,(j == k) ? "%c%ld" : "%c%ld-%ld",c,j,k); if (fputs (tmp,f) == EOF) return NIL; } } /* write trailing newline, return */ return (fputs (nl,f) == EOF) ? NIL : LONGT; } /* List subscribed newsgroups * Accepts: MAIL stream * prefix to append name * pattern to search */ void newsrc_lsub (MAILSTREAM *stream,char *pattern) { char *s,*t,*lcl,name[MAILTMPLEN]; int c = ' '; int showuppers = pattern[strlen (pattern) - 1] == '%'; FILE *f = fopen ((char *) mail_parameters (stream,GET_NEWSRC,stream),"rb"); if (f) { /* got file? */ /* remote name? */ if (*(lcl = strcpy (name,pattern)) == '{') lcl = strchr (lcl,'}') + 1; if (*lcl == '#') lcl += 6; /* namespace format name? */ while (c != EOF) { /* yes, read newsrc */ for (s = lcl; (s < (name + MAILTMPLEN - 1)) && ((c = getc (f)) != EOF) && (c != ':') && (c != '!') && (c != '\015') && (c != '\012'); *s++ = c); if (c == ':') { /* found a subscribed newsgroup? */ *s = '\0'; /* yes, tie off name */ /* report if match */ if (pmatch_full (name,pattern,'.')) mm_lsub (stream,'.',name,NIL); else while (showuppers && (t = strrchr (lcl,'.'))) { *t = '\0'; /* tie off the name */ if (pmatch_full (name,pattern,'.')) mm_lsub (stream,'.',name,LATT_NOSELECT); } } while ((c != '\015') && (c != '\012') && (c != EOF)) c = getc (f); } fclose (f); } } /* Update subscription status of newsrc * Accepts: MAIL stream * group * new subscription status character * Returns: T if successful, NIL otherwise */ long newsrc_update (MAILSTREAM *stream,char *group,char state) { char tmp[MAILTMPLEN]; char *newsrc = (char *) mail_parameters (stream,GET_NEWSRC,stream); long ret = NIL; FILE *f = fopen (newsrc,"r+b"); if (f) { /* update existing file */ int c = 0; char *s,nl[3]; long pos = 0; nl[0] = nl[1] = nl[2]='\0'; /* no newline known yet */ do { /* read newsrc */ for (s = tmp; (s < (tmp + MAILTMPLEN - 1)) && ((c = getc (f)) != EOF) && (c != ':') && (c != '!') && (c != '\015') && (c != '\012'); *s++ = c) pos = ftell (f); *s = '\0'; /* tie off name */ /* found the newsgroup? */ if (((c == ':') || (c == '!')) && !strcmp (tmp,group)) { if (c == state) { /* already at that state? */ if (c == ':') newsrc_error("Already subscribed to %.80s",group,WARN); ret = LONGT; /* noop the update */ } /* write the character */ else if (!fseek (f,pos,0)) ret = ((putc (state,f)) == EOF) ? NIL:LONGT; if (fclose (f) == EOF) ret = NIL; f = NIL; /* done with file */ break; } /* gobble remainder of this line */ while ((c != '\015') && (c != '\012') && (c != EOF)) c = getc (f); /* need to know about newlines and found it? */ if (!nl[0] && ((c == '\015') || (c == '\012')) && ((nl[0]=c) == '\015')){ /* sniff and see if an LF */ if ((c = getc (f)) == '\012') nl[1] = c; else ungetc (c,f); /* nope, push it back */ } } while (c != EOF); if (f) { /* still haven't written it yet? */ if (nl[0]) { /* know its newline convention? */ fseek (f,0L,2); /* yes, seek to end of file */ ret = newsrc_newstate (f,group,state,nl); } else { /* can't find a newline convention */ fclose (f); /* punt the file */ /* can't win if read something */ if (pos) newsrc_error ("Unknown newline convention in %.80s", newsrc,ERROR); /* file must have been empty, rewrite it */ else ret = newsrc_newstate(newsrc_create(stream,NIL),group,state,"\n"); } } } /* create new file */ else ret = newsrc_newstate (newsrc_create (stream,T),group,state,"\n"); return ret; /* return with update status */ } /* Update newsgroup status in stream * Accepts: newsgroup name * MAIL stream * Returns: number of recent messages */ long newsrc_read (char *group,MAILSTREAM *stream) { int c = 0; char *s,tmp[MAILTMPLEN]; unsigned long i,j; MESSAGECACHE *elt; unsigned long m = 1,recent = 0,unseen = 0; FILE *f = fopen ((char *) mail_parameters (stream,GET_NEWSRC,stream),"rb"); if (f) do { /* read newsrc */ for (s = tmp; (s < (tmp + MAILTMPLEN - 1)) && ((c = getc (f)) != EOF) && (c != ':') && (c != '!') && (c != '\015') && (c != '\012'); *s++ = c); *s = '\0'; /* tie off name */ if ((c==':') || (c=='!')) { /* found newsgroup? */ if (strcmp (tmp,group)) /* group name match? */ while ((c != '\015') && (c != '\012') && (c != EOF)) c = getc (f); else { /* yes, skip leading whitespace */ while ((c = getc (f)) == ' '); /* only if unprocessed messages */ if (stream->nmsgs) while (f && (m <= stream->nmsgs)) { /* collect a number */ if (isdigit (c)) { /* better have a number */ for (i = 0,j = 0; isdigit (c); c = getc (f)) i = i*10 + (c-'0'); if (c == '-') for (c = getc (f); isdigit (c); c = getc (f)) j = j*10 +(c-'0');/* collect second value if range */ if (!unseen && (mail_elt (stream,m)->private.uid < i)) unseen = m; /* skip messages before first value */ while ((m <= stream->nmsgs) && ((elt = mail_elt (stream,m))->private.uid < i) && m++) elt->valid = T; /* do all messages in range */ while ((m <= stream->nmsgs) && (elt = mail_elt (stream,m)) && (j ? ((elt->private.uid >= i) && (elt->private.uid <= j)) : (elt->private.uid == i)) && m++) elt->valid = elt->deleted = T; } switch (c) { /* what is the delimiter? */ case ',': /* more to come */ c = getc (f); /* get first character of number */ break; default: /* bogus character */ sprintf (tmp,"Bogus character 0x%x in news state",(unsigned int)c); MM_LOG (tmp,ERROR); case EOF: case '\015': case '\012': fclose (f); /* all done - close the file */ f = NIL; break; } } else { /* empty newsgroup */ while ((c != '\015') && (c != '\012') && (c != EOF)) c = getc (f); fclose (f); /* all done - close the file */ f = NIL; } } } } while (f && (c != EOF)); /* until file closed or EOF */ if (f) { /* still have file open? */ sprintf (tmp,"No state for newsgroup %.80s found, reading as new",group); MM_LOG (tmp,WARN); fclose (f); /* close the file */ } if (m <= stream->nmsgs) { /* any messages beyond newsrc range? */ if (!unseen) unseen = m; /* then this must be the first unseen one */ do { elt = mail_elt (stream,m++); elt->valid = elt->recent = T; ++recent; /* count another recent message */ } while (m <= stream->nmsgs); } if (unseen) { /* report first unseen message */ sprintf (tmp,"[UNSEEN] %lu is first unseen message in %.80s",unseen,group); MM_NOTIFY (stream,tmp,(long) NIL); } return recent; } /* Update newsgroup entry in newsrc * Accepts: newsgroup name * MAIL stream * Returns: T if successful, NIL otherwise */ long newsrc_write (char *group,MAILSTREAM *stream) { long ret = NIL; int c = 0,d = EOF; char *newsrc = (char *) mail_parameters (stream,GET_NEWSRC,stream); char *s,tmp[MAILTMPLEN],backup[MAILTMPLEN],nl[3]; FILE *f,*bf; nl[0] = nl[1] = nl[2] = '\0'; /* no newline known yet */ if (f = fopen (newsrc,"rb")) {/* have existing newsrc file? */ if (!(bf = fopen ((strcat (strcpy (backup,newsrc),OLDFILESUFFIX)),"wb"))) { fclose (f); /* punt input file */ return newsrc_error("Can't create backup news state %.80s",backup,ERROR); } /* copy to backup file */ while ((c = getc (f)) != EOF) { /* need to know about newlines and found it? */ if (!nl[0] && ((c == '\015') || (c == '\012')) && ((nl[0]=c) == '\015')){ /* sniff and see if an LF */ if ((c = getc (f)) == '\012') nl[1] = c; ungetc (c,f); /* push it back */ } /* write to backup file */ if ((d = putc (c,bf)) == EOF) { fclose (f); /* punt input file */ return newsrc_error ("Error writing backup news state %.80s", newsrc,ERROR); } } fclose (f); /* close existing file */ if (fclose (bf) == EOF) /* and backup file */ return newsrc_error ("Error closing backup news state %.80s", newsrc,ERROR); if (d == EOF) { /* open for write if empty file */ if (f = newsrc_create (stream,NIL)) bf = NIL; else return NIL; } else if (!nl[0]) /* make sure newlines valid */ return newsrc_error ("Unknown newline convention in %.80s",newsrc,ERROR); /* now read backup file */ else if (!(bf = fopen (backup,"rb"))) return newsrc_error ("Error reading backup news state %.80s", backup,ERROR); /* open newsrc for writing */ else if (!(f = fopen (newsrc,"wb"))) { fclose (bf); /* punt backup */ return newsrc_error ("Can't rewrite news state %.80s",newsrc,ERROR); } } else { /* create new newsrc file */ if (f = newsrc_create (stream,T)) bf = NIL; else return NIL; /* can't create newsrc */ } while (bf) { /* read newsrc */ for (s = tmp; (s < (tmp + MAILTMPLEN - 1)) && ((c = getc (bf)) != EOF) && (c != ':') && (c != '!') && (c != '\015') && (c != '\012'); *s++ = c); *s = '\0'; /* tie off name */ /* saw correct end of group delimiter? */ if (tmp[0] && ((c == ':') || (c == '!'))) { /* yes, write newsgroup name and delimiter */ if ((tmp[0] && (fputs (tmp,f) == EOF)) || ((putc (c,f)) == EOF)) return newsrc_write_error (newsrc,bf,f); if (!strcmp (tmp,group)) {/* found correct group? */ /* yes, write new status */ if (!newsrc_newmessages (f,stream,nl[0] ? nl : "\n")) return newsrc_write_error (newsrc,bf,f); /* skip past old data */ while (((c = getc (bf)) != EOF) && (c != '\015') && (c != '\012')); /* skip past newline */ while ((c == '\015') || (c == '\012')) c = getc (bf); while (c != EOF) { /* copy remainder of file */ if (putc (c,f) == EOF) return newsrc_write_error (newsrc,bf,f); c = getc (bf); /* get next character */ } /* done with file */ if (fclose (f) == EOF) return newsrc_write_error (newsrc,bf,NIL); f = NIL; } /* copy remainder of line */ else while (((c = getc (bf)) != EOF) && (c != '\015') && (c != '\012')) if (putc (c,f) == EOF) return newsrc_write_error (newsrc,bf,f); if (c == '\015') { /* write CR if seen */ if (putc (c,f) == EOF) return newsrc_write_error (newsrc,bf,f); /* sniff to see if LF */ if (((c = getc (bf)) != EOF) && (c != '\012')) ungetc (c,bf); } /* write LF if seen */ if ((c == '\012') && (putc (c,f) == EOF)) return newsrc_write_error (newsrc,bf,f); } if (c == EOF) { /* hit end of file? */ fclose (bf); /* yup, close the file */ bf = NIL; } } if (f) { /* still have newsrc file open? */ ret = ((fputs (group,f) != EOF) && ((putc (':',f)) != EOF) && newsrc_newmessages (f,stream,nl[0] ? nl : "\n")) ? LONGT : NIL; if (fclose (f) == EOF) ret = newsrc_write_error (newsrc,NIL,NIL); } else ret = LONGT; return ret; } /* Get newsgroup state as text stream * Accepts: MAIL stream * newsgroup name * Returns: string containing newsgroup state, or NIL if not found */ char *newsrc_state (MAILSTREAM *stream,char *group) { int c = 0; char *s,tmp[MAILTMPLEN]; long pos; size_t size; FILE *f = fopen ((char *) mail_parameters (stream,GET_NEWSRC,stream),"rb"); if (f) do { /* read newsrc */ for (s = tmp; (s < (tmp + MAILTMPLEN - 1)) && ((c = getc (f)) != EOF) && (c != ':') && (c != '!') && (c != '\015') && (c != '\012'); *s++ = c); *s = '\0'; /* tie off name */ if ((c==':') || (c=='!')) { /* found newsgroup? */ if (strcmp (tmp,group)) /* group name match? */ while ((c != '\015') && (c != '\012') && (c != EOF)) c = getc (f); else { /* yes, skip leading whitespace */ do pos = ftell (f); while ((c = getc (f)) == ' '); /* count characters in state */ for (size = 0; (c != '\015') && (c != '\012') && (c != EOF); size++) c = getc (f); /* now copy it */ s = (char *) fs_get (size + 1); fseek (f,pos,SEEK_SET); fread (s,(size_t) 1,size,f); s[size] = '\0'; /* tie off string */ fclose (f); /* all done - close the file */ return s; } } } while (f && (c != EOF)); /* until file closed or EOF */ sprintf (tmp,"No state for newsgroup %.80s found",group); MM_LOG (tmp,WARN); if (f) fclose (f); /* close the file */ return NIL; /* not found return */ } /* Check UID in newsgroup state * Accepts: newsgroup state string * uid * returned recent count * returned unseen count */ void newsrc_check_uid (unsigned char *state,unsigned long uid, unsigned long *recent,unsigned long *unseen) { unsigned long i,j; while (*state) { /* until run out of state string */ /* collect a number */ for (i = 0; isdigit (*state); i = i*10 + (*state++ - '0')); if (*state != '-') j = i; /* coerce single mesage into range */ else { /* have a range */ for (j = 0; isdigit (*++state); j = j*10 + (*state - '0')); if (!j) j = i; /* guard against -0 */ if (j < i) return; /* bogon if end less than start */ } if (*state == ',') state++; /* skip past comma */ else if (*state) return; /* otherwise it's a bogon */ if (uid <= j) { /* covered by upper bound? */ if (uid < i) ++*unseen; /* unseen if not covered by lower bound */ return; /* don't need to look further */ } } ++*unseen; /* not found in any range, message is unseen */ ++*recent; /* and recent */ } alpine-2.10+dfsg/imap/src/c-client/utf8.c0000600000175000017500000024777711512502124021631 0ustar paulproteuspaulproteus/* ======================================================================== * Copyright 1988-2008 University of Washington * * Licensed under the Apache License, Version 2.0 (the "License"); * you may not use this file except in compliance with the License. * You may obtain a copy of the License at * * http://www.apache.org/licenses/LICENSE-2.0 * * * ======================================================================== */ /* * Program: UTF-8 routines * * Author: Mark Crispin * Networks and Distributed Computing * Computing & Communications * University of Washington * Administration Building, AG-44 * Seattle, WA 98195 * Internet: MRC@CAC.Washington.EDU * * Date: 11 June 1997 * Last Edited: 17 January 2008 */ #include #include #include "c-client.h" /* *** IMPORTANT *** * * There is a very important difference between "character set" and "charset", * and the comments in this file reflect these differences. A "character set" * (also known as "coded character set") is a mapping between codepoints and * characters. A "charset" is as defined in MIME, and incorporates one or more * coded character sets in a character encoding scheme. See RFC 2130 for more * details. */ /* Character set conversion tables */ #include "iso_8859.c" /* 8-bit single-byte coded graphic */ #include "koi8_r.c" /* Cyrillic - Russia */ #include "koi8_u.c" /* Cyrillic - Ukraine */ #include "tis_620.c" /* Thai */ #include "viscii.c" /* Vietnamese */ #include "windows.c" /* Windows */ #include "ibm.c" /* IBM */ #include "gb_2312.c" /* Chinese (PRC) - simplified */ #include "gb_12345.c" /* Chinese (PRC) - traditional */ #include "jis_0208.c" /* Japanese - basic */ #include "jis_0212.c" /* Japanese - supplementary */ #include "ksc_5601.c" /* Korean */ #include "big5.c" /* Taiwanese (ROC) - industrial standard */ #include "cns11643.c" /* Taiwanese (ROC) - national standard */ #include "widths.c" /* Unicode character widths */ #include "tmap.c" /* Unicode titlecase mapping */ #include "decomtab.c" /* Unicode decomposions */ /* EUC parameters */ #ifdef GBTOUNICODE /* PRC simplified Chinese */ static const struct utf8_eucparam gb_param = { BASE_GB2312_KU,BASE_GB2312_TEN,MAX_GB2312_KU,MAX_GB2312_TEN, (void *) gb2312tab}; #endif #ifdef GB12345TOUNICODE /* PRC traditional Chinese */ static const struct utf8_eucparam gbt_param = { BASE_GB12345_KU,BASE_GB12345_TEN,MAX_GB12345_KU,MAX_GB12345_TEN, (void *) gb12345tab}; #endif #ifdef BIG5TOUNICODE /* ROC traditional Chinese */ static const struct utf8_eucparam big5_param[] = { {BASE_BIG5_KU,BASE_BIG5_TEN_0,MAX_BIG5_KU,MAX_BIG5_TEN_0,(void *) big5tab}, {BASE_BIG5_KU,BASE_BIG5_TEN_1,MAX_BIG5_KU,MAX_BIG5_TEN_1,NIL} }; #endif #ifdef JISTOUNICODE /* Japanese */ static const struct utf8_eucparam jis_param[] = { {BASE_JIS0208_KU,BASE_JIS0208_TEN,MAX_JIS0208_KU,MAX_JIS0208_TEN, (void *) jis0208tab}, {MIN_KANA_8,0,MAX_KANA_8,0,(void *) KANA_8}, #ifdef JIS0212TOUNICODE /* Japanese extended */ {BASE_JIS0212_KU,BASE_JIS0212_TEN,MAX_JIS0212_KU,MAX_JIS0212_TEN, (void *) jis0212tab} #else {0,0,0,0,NIL} #endif }; #endif #ifdef KSCTOUNICODE /* Korean */ static const struct utf8_eucparam ksc_param = { BASE_KSC5601_KU,BASE_KSC5601_TEN,MAX_KSC5601_KU,MAX_KSC5601_TEN, (void *) ksc5601tab}; #endif /* List of supported charsets */ static const CHARSET utf8_csvalid[] = { {"US-ASCII",CT_ASCII,CF_PRIMARY | CF_DISPLAY | CF_POSTING, NIL,NIL,NIL}, {"UTF-8",CT_UTF8,CF_PRIMARY | CF_DISPLAY | CF_POSTING, NIL,SC_UNICODE,NIL}, {"UTF-7",CT_UTF7,CF_PRIMARY | CF_POSTING | CF_UNSUPRT, NIL,SC_UNICODE,"UTF-8"}, {"ISO-8859-1",CT_1BYTE0,CF_PRIMARY | CF_DISPLAY | CF_POSTING, NIL,SC_LATIN_1,NIL}, {"ISO-8859-2",CT_1BYTE,CF_PRIMARY | CF_DISPLAY | CF_POSTING, (void *) iso8859_2tab,SC_LATIN_2,NIL}, {"ISO-8859-3",CT_1BYTE,CF_PRIMARY | CF_DISPLAY | CF_POSTING, (void *) iso8859_3tab,SC_LATIN_3,NIL}, {"ISO-8859-4",CT_1BYTE,CF_PRIMARY | CF_DISPLAY | CF_POSTING, (void *) iso8859_4tab,SC_LATIN_4,NIL}, {"ISO-8859-5",CT_1BYTE,CF_PRIMARY | CF_DISPLAY | CF_POSTING, (void *) iso8859_5tab,SC_CYRILLIC,"KOI8-R"}, {"ISO-8859-6",CT_1BYTE,CF_PRIMARY | CF_DISPLAY | CF_POSTING, (void *) iso8859_6tab,SC_ARABIC,NIL}, {"ISO-8859-7",CT_1BYTE,CF_PRIMARY | CF_DISPLAY | CF_POSTING, (void *) iso8859_7tab,SC_GREEK,NIL}, {"ISO-8859-8",CT_1BYTE,CF_PRIMARY | CF_DISPLAY | CF_POSTING, (void *) iso8859_8tab,SC_HEBREW,NIL}, {"ISO-8859-9",CT_1BYTE,CF_PRIMARY | CF_DISPLAY | CF_POSTING, (void *) iso8859_9tab,SC_LATIN_5,NIL}, {"ISO-8859-10",CT_1BYTE,CF_PRIMARY | CF_DISPLAY | CF_POSTING, (void *) iso8859_10tab,SC_LATIN_6,NIL}, {"ISO-8859-11",CT_1BYTE,CF_PRIMARY | CF_DISPLAY | CF_POSTING, (void *) iso8859_11tab,SC_THAI,NIL}, #if 0 /* ISO 8859-12 reserved for ISCII(?) */ {"ISO-8859-12",CT_1BYTE,CF_PRIMARY | CF_DISPLAY | CF_POSTING, (void *) iso8859_12tab,NIL,NIL}, #endif {"ISO-8859-13",CT_1BYTE,CF_PRIMARY | CF_DISPLAY | CF_POSTING, (void *) iso8859_13tab,SC_LATIN_7,NIL}, {"ISO-8859-14",CT_1BYTE,CF_PRIMARY | CF_DISPLAY | CF_POSTING, (void *) iso8859_14tab,SC_LATIN_8,NIL}, {"ISO-8859-15",CT_1BYTE,CF_PRIMARY | CF_DISPLAY | CF_POSTING, (void *) iso8859_15tab,SC_LATIN_9,NIL}, {"ISO-8859-16",CT_1BYTE,CF_PRIMARY | CF_DISPLAY | CF_POSTING, (void *) iso8859_16tab,SC_LATIN_10,NIL}, {"KOI8-R",CT_1BYTE,CF_PRIMARY | CF_DISPLAY | CF_POSTING, (void *) koi8rtab,SC_CYRILLIC,NIL}, {"KOI8-U",CT_1BYTE,CF_PRIMARY | CF_DISPLAY | CF_POSTING, (void *) koi8utab,SC_CYRILLIC | SC_UKRANIAN,NIL}, {"KOI8-RU",CT_1BYTE,CF_DISPLAY, (void *) koi8utab,SC_CYRILLIC | SC_UKRANIAN,"KOI8-U"}, {"TIS-620",CT_1BYTE,CF_PRIMARY | CF_DISPLAY | CF_POSTING, (void *) tis620tab,SC_THAI,"ISO-8859-11"}, {"VISCII",CT_1BYTE8,CF_PRIMARY | CF_DISPLAY | CF_POSTING, (void *) visciitab,SC_VIETNAMESE,NIL}, #ifdef GBTOUNICODE {"GBK",CT_DBYTE,CF_PRIMARY | CF_DISPLAY | CF_POSTING, (void *) &gb_param,SC_CHINESE_SIMPLIFIED,NIL}, {"GB2312",CT_DBYTE,CF_PRIMARY | CF_DISPLAY | CF_POSTING, (void *) &gb_param,SC_CHINESE_SIMPLIFIED,"GBK"}, {"CN-GB",CT_DBYTE,CF_DISPLAY, (void *) &gb_param,SC_CHINESE_SIMPLIFIED,"GBK"}, #ifdef CNS1TOUNICODE {"ISO-2022-CN",CT_2022,CF_PRIMARY | CF_UNSUPRT, NIL,SC_CHINESE_SIMPLIFIED | SC_CHINESE_TRADITIONAL, NIL}, #endif #endif #ifdef GB12345TOUNICODE {"CN-GB-12345",CT_DBYTE,CF_PRIMARY | CF_DISPLAY, (void *) &gbt_param,SC_CHINESE_TRADITIONAL,"BIG5"}, #endif #ifdef BIG5TOUNICODE {"BIG5",CT_DBYTE2,CF_PRIMARY | CF_DISPLAY | CF_POSTING, (void *) big5_param,SC_CHINESE_TRADITIONAL,NIL}, {"CN-BIG5",CT_DBYTE2,CF_DISPLAY, (void *) big5_param,SC_CHINESE_TRADITIONAL,"BIG5"}, {"BIG-5",CT_DBYTE2,CF_DISPLAY, (void *) big5_param,SC_CHINESE_TRADITIONAL,"BIG5"}, #endif #ifdef JISTOUNICODE {"ISO-2022-JP",CT_2022,CF_PRIMARY | CF_DISPLAY | CF_POSTING, NIL,SC_JAPANESE,NIL}, {"EUC-JP",CT_EUC,CF_PRIMARY | CF_DISPLAY, (void *) jis_param,SC_JAPANESE,"ISO-2022-JP"}, {"SHIFT_JIS",CT_SJIS,CF_PRIMARY | CF_DISPLAY, NIL,SC_JAPANESE,"ISO-2022-JP"}, {"SHIFT-JIS",CT_SJIS,CF_PRIMARY | CF_DISPLAY, NIL,SC_JAPANESE,"ISO-2022-JP"}, #ifdef JIS0212TOUNICODE {"ISO-2022-JP-1",CT_2022,CF_UNSUPRT, NIL,SC_JAPANESE,"ISO-2022-JP"}, #ifdef GBTOUNICODE #ifdef KSCTOUNICODE {"ISO-2022-JP-2",CT_2022,CF_UNSUPRT, NIL, SC_LATIN_1 | SC_LATIN_2 | SC_LATIN_3 | SC_LATIN_4 | SC_LATIN_5 | SC_LATIN_6 | SC_LATIN_7 | SC_LATIN_8 | SC_LATIN_9 | SC_LATIN_10 | SC_ARABIC | SC_CYRILLIC | SC_GREEK | SC_HEBREW | SC_THAI | SC_VIETNAMESE | SC_CHINESE_SIMPLIFIED | SC_JAPANESE | SC_KOREAN #ifdef CNS1TOUNICODE | SC_CHINESE_TRADITIONAL #endif ,"UTF-8"}, #endif #endif #endif #endif #ifdef KSCTOUNICODE {"ISO-2022-KR",CT_2022,CF_PRIMARY | CF_DISPLAY | CF_UNSUPRT, NIL,SC_KOREAN,"EUC-KR"}, {"EUC-KR",CT_DBYTE,CF_PRIMARY | CF_DISPLAY | CF_POSTING, (void *) &ksc_param,SC_KOREAN,NIL}, {"KSC5601",CT_DBYTE,CF_PRIMARY | CF_DISPLAY, (void *) &ksc_param,SC_KOREAN,"EUC-KR"}, {"KSC_5601",CT_DBYTE,CF_PRIMARY | CF_DISPLAY, (void *) &ksc_param,SC_KOREAN,"EUC-KR"}, {"KS_C_5601-1987",CT_DBYTE,CF_DISPLAY, (void *) &ksc_param,SC_KOREAN,"EUC-KR"}, {"KS_C_5601-1989",CT_DBYTE,CF_DISPLAY, (void *) &ksc_param,SC_KOREAN,"EUC-KR"}, {"KS_C_5601-1992",CT_DBYTE,CF_DISPLAY, (void *) &ksc_param,SC_KOREAN,"EUC-KR"}, {"KS_C_5601-1997",CT_DBYTE,CF_DISPLAY, (void *) &ksc_param,SC_KOREAN,"EUC-KR"}, #endif /* deep sigh */ {"WINDOWS-874",CT_1BYTE,CF_PRIMARY | CF_DISPLAY, (void *) windows_874tab,SC_THAI,"ISO-8859-11"}, {"CP874",CT_1BYTE,CF_DISPLAY, (void *) windows_874tab,SC_THAI,"ISO-8859-11"}, #ifdef GBTOUNICODE {"WINDOWS-936",CT_DBYTE,CF_PRIMARY | CF_DISPLAY, (void *) &gb_param,SC_CHINESE_SIMPLIFIED,"GBK"}, {"CP936",CT_DBYTE,CF_DISPLAY, (void *) &gb_param,SC_CHINESE_SIMPLIFIED,"GBK"}, #endif #ifdef KSCTOUNICODE {"WINDOWS-949",CT_DBYTE,CF_PRIMARY | CF_DISPLAY, (void *) &ksc_param,SC_KOREAN,"EUC-KR"}, {"CP949",CT_DBYTE,CF_DISPLAY, (void *) &ksc_param,SC_KOREAN,"EUC-KR"}, {"X-WINDOWS-949",CT_DBYTE,CF_PRIMARY | CF_DISPLAY, (void *) &ksc_param,SC_KOREAN,"EUC-KR"}, #endif {"WINDOWS-1250",CT_1BYTE,CF_PRIMARY | CF_DISPLAY, (void *) windows_1250tab,SC_LATIN_2,"ISO-8859-2"}, {"CP1250",CT_1BYTE,CF_DISPLAY, (void *) windows_1250tab,SC_LATIN_2,"ISO-8859-2"}, {"WINDOWS-1251",CT_1BYTE,CF_PRIMARY | CF_DISPLAY | CF_POSTING, (void *) windows_1251tab,SC_CYRILLIC,"KOI8-R"}, {"CP1251",CT_1BYTE,CF_DISPLAY, (void *) windows_1251tab,SC_CYRILLIC,"KOI8-R"}, {"WINDOWS-1252",CT_1BYTE,CF_PRIMARY | CF_DISPLAY, (void *) windows_1252tab,SC_LATIN_1,"ISO-8859-1"}, {"CP1252",CT_1BYTE,CF_DISPLAY, (void *) windows_1252tab,SC_LATIN_1,"ISO-8859-1"}, {"WINDOWS-1253",CT_1BYTE,CF_PRIMARY | CF_DISPLAY, (void *) windows_1253tab,SC_GREEK,"ISO-8859-7"}, {"CP1253",CT_1BYTE,CF_DISPLAY, (void *) windows_1253tab,SC_GREEK,"ISO-8859-7"}, {"WINDOWS-1254",CT_1BYTE,CF_PRIMARY | CF_DISPLAY, (void *) windows_1254tab,SC_LATIN_5,"ISO-8859-9"}, {"CP1254",CT_1BYTE,CF_DISPLAY, (void *) windows_1254tab,SC_LATIN_5,"ISO-8859-9"}, {"WINDOWS-1255",CT_1BYTE,CF_PRIMARY | CF_DISPLAY, (void *) windows_1255tab,SC_HEBREW,"ISO-8859-8"}, {"CP1255",CT_1BYTE,CF_DISPLAY, (void *) windows_1255tab,SC_HEBREW,"ISO-8859-8"}, {"WINDOWS-1256",CT_1BYTE,CF_PRIMARY | CF_DISPLAY, (void *) windows_1256tab,SC_ARABIC,"ISO-8859-6"}, {"CP1256",CT_1BYTE,CF_DISPLAY, (void *) windows_1256tab,SC_ARABIC,"ISO-8859-6"}, {"WINDOWS-1257",CT_1BYTE,CF_PRIMARY | CF_DISPLAY, (void *) windows_1257tab,SC_LATIN_7,"ISO-8859-13"}, {"CP1257",CT_1BYTE,CF_DISPLAY, (void *) windows_1257tab,SC_LATIN_7,"ISO-8859-13"}, {"WINDOWS-1258",CT_1BYTE,CF_PRIMARY | CF_DISPLAY, (void *) windows_1258tab,SC_VIETNAMESE,"VISCII"}, {"CP1258",CT_1BYTE,CF_DISPLAY, (void *) windows_1258tab,SC_VIETNAMESE,"VISCII"}, /* deeper sigh */ {"IBM367",CT_ASCII,CF_PRIMARY | CF_DISPLAY, NIL,NIL,"US-ASCII"}, {"IBM437",CT_1BYTE,CF_PRIMARY | CF_DISPLAY, (void *) ibm_437tab,SC_LATIN_1,"ISO-8859-1"}, {"IBM737",CT_1BYTE,CF_PRIMARY | CF_DISPLAY, (void *) ibm_737tab,SC_GREEK,"ISO-8859-7"}, {"IBM775",CT_1BYTE,CF_PRIMARY | CF_DISPLAY, (void *) ibm_775tab,SC_LATIN_7,"ISO-8859-13"}, {"IBM850",CT_1BYTE,CF_PRIMARY | CF_DISPLAY, (void *) ibm_850tab,SC_LATIN_1,"ISO-8859-1"}, {"IBM852",CT_1BYTE,CF_PRIMARY | CF_DISPLAY, (void *) ibm_852tab,SC_LATIN_2,"ISO-8859-2"}, {"IBM855",CT_1BYTE,CF_PRIMARY | CF_DISPLAY, (void *) ibm_855tab,SC_CYRILLIC,"ISO-8859-5"}, {"IBM857",CT_1BYTE,CF_PRIMARY | CF_DISPLAY, (void *) ibm_857tab,SC_LATIN_5,"ISO-8859-9"}, {"IBM860",CT_1BYTE,CF_PRIMARY | CF_DISPLAY, (void *) ibm_860tab,SC_LATIN_1,"ISO-8859-1"}, {"IBM861",CT_1BYTE,CF_PRIMARY | CF_DISPLAY, (void *) ibm_861tab,SC_LATIN_6,"ISO-8859-10"}, {"IBM862",CT_1BYTE,CF_PRIMARY | CF_DISPLAY, (void *) ibm_862tab,SC_HEBREW,"ISO-8859-8"}, {"IBM863",CT_1BYTE,CF_PRIMARY | CF_DISPLAY, (void *) ibm_863tab,SC_LATIN_1,"ISO-8859-1"}, {"IBM864",CT_1BYTE,CF_PRIMARY | CF_DISPLAY, (void *) ibm_864tab,SC_ARABIC,"ISO-8859-6"}, {"IBM865",CT_1BYTE,CF_PRIMARY | CF_DISPLAY, (void *) ibm_865tab,SC_LATIN_6,"ISO-8859-10"}, {"IBM866",CT_1BYTE,CF_PRIMARY | CF_DISPLAY, (void *) ibm_866tab,SC_CYRILLIC,"KOI8-R"}, {"IBM869",CT_1BYTE,CF_PRIMARY | CF_DISPLAY, (void *) ibm_869tab,SC_GREEK,"ISO-8859-7"}, {"IBM874",CT_1BYTE,CF_PRIMARY | CF_DISPLAY, (void *) ibm_874tab,SC_THAI,"ISO-8859-11"}, /* deepest sigh */ {"ANSI_X3.4-1968",CT_ASCII,CF_DISPLAY, NIL,NIL,"US-ASCII"}, {"UNICODE-1-1-UTF-7",CT_UTF7,CF_UNSUPRT, NIL,SC_UNICODE,"UTF-8"}, /* these should never appear in email */ {"UCS-2",CT_UCS2,CF_PRIMARY | CF_DISPLAY | CF_NOEMAIL, NIL,SC_UNICODE,"UTF-8"}, {"UCS-4",CT_UCS4,CF_PRIMARY | CF_DISPLAY | CF_NOEMAIL, NIL,SC_UNICODE,"UTF-8"}, {"UTF-16",CT_UTF16,CF_PRIMARY | CF_DISPLAY | CF_NOEMAIL, NIL,SC_UNICODE,"UTF-8"}, NIL }; /* Non-Unicode Script table */ static const SCRIPT utf8_scvalid[] = { {"Arabic",NIL,SC_ARABIC}, {"Chinese Simplified","China, Singapore",SC_CHINESE_SIMPLIFIED}, {"Chinese Traditional","Taiwan, Hong Kong, Macao",SC_CHINESE_TRADITIONAL}, {"Cyrillic",NIL,SC_CYRILLIC}, {"Cyrillic Ukranian",NIL,SC_UKRANIAN}, {"Greek",NIL,SC_GREEK}, {"Hebrew",NIL,SC_HEBREW}, {"Japanese",NIL,SC_JAPANESE}, {"Korean",NIL,SC_KOREAN}, {"Latin-1","Western Europe",SC_LATIN_1}, {"Latin-2","Eastern Europe",SC_LATIN_2}, {"Latin-3","Southern Europe",SC_LATIN_3}, {"Latin-4","Northern Europe",SC_LATIN_4}, {"Latin-5","Turkish",SC_LATIN_5}, {"Latin-6","Nordic",SC_LATIN_6}, {"Latin-7","Baltic",SC_LATIN_7}, {"Latin-8","Celtic",SC_LATIN_8}, {"Latin-9","Euro",SC_LATIN_9}, {"Latin-10","Balkan",SC_LATIN_10}, {"Thai",NIL,SC_THAI}, {"Vietnamese",NIL,SC_VIETNAMESE}, NIL }; /* Look up script name or return entire table * Accepts: script name or NIL * Returns: pointer to script table entry or NIL if unknown */ SCRIPT *utf8_script (char *script) { unsigned long i; if (!script) return (SCRIPT *) &utf8_scvalid[0]; else if (*script && (strlen (script) < 128)) for (i = 0; utf8_scvalid[i].name; i++) if (!compare_cstring (script,utf8_scvalid[i].name)) return (SCRIPT *) &utf8_scvalid[i]; return NIL; /* failed */ } /* Look up charset name or return entire table * Accepts: charset name or NIL * Returns: charset table entry or NIL if unknown */ const CHARSET *utf8_charset (char *charset) { unsigned long i; if (!charset) return (CHARSET *) &utf8_csvalid[0]; else if (*charset && (strlen (charset) < 128)) for (i = 0; utf8_csvalid[i].name; i++) if (!compare_cstring (charset,utf8_csvalid[i].name)) return (CHARSET *) &utf8_csvalid[i]; return NIL; /* failed */ } /* Validate charset and generate error message if invalid * Accepts: bad character set * Returns: NIL if good charset, else error message string */ #define BADCSS "[BADCHARSET (" #define BADCSE ")] Unknown charset: " char *utf8_badcharset (char *charset) { char *msg = NIL; if (!utf8_charset (charset)) { char *s,*t; unsigned long i,j; /* calculate size of header, trailer, and bad * charset plus charset names */ for (i = 0, j = sizeof (BADCSS) + sizeof (BADCSE) + strlen (charset) - 2; utf8_csvalid[i].name; i++) j += strlen (utf8_csvalid[i].name) + 1; /* not built right */ if (!i) fatal ("No valid charsets!"); /* header */ for (s = msg = (char *) fs_get (j), t = BADCSS; *t; *s++ = *t++); /* each charset */ for (i = 0; utf8_csvalid[i].name; *s++ = ' ', i++) for (t = utf8_csvalid[i].name; *t; *s++ = *t++); /* back over last space, trailer */ for (t = BADCSE, --s; *t; *s++ = *t++); /* finally bogus charset */ for (t = charset; *t; *s++ = *t++); *s++ = '\0'; /* finally tie off string */ if (s != (msg + j)) fatal ("charset msg botch"); } return msg; } /* Convert charset labelled sized text to UTF-8 * Accepts: source sized text * charset * pointer to returned sized text if non-NIL * flags * Returns: T if successful, NIL if failure */ long utf8_text (SIZEDTEXT *text,char *charset,SIZEDTEXT *ret,long flags) { ucs4cn_t cv = (flags & U8T_CASECANON) ? ucs4_titlecase : NIL; ucs4de_t de = (flags & U8T_DECOMPOSE) ? ucs4_decompose_recursive : NIL; const CHARSET *cs = (charset && *charset) ? utf8_charset (charset) : utf8_infercharset (text); if (cs) return (text && ret) ? utf8_text_cs (text,cs,ret,cv,de) : LONGT; if (ret) { /* no conversion possible */ ret->data = text->data; /* so return source */ ret->size = text->size; } return NIL; /* failure */ } /* Operations used in converting data */ #define UTF8_COUNT_BMP(count,c,cv,de) { \ void *more = NIL; \ if (cv) c = (*cv) (c); \ if (de) c = (*de) (c,&more); \ do count += UTF8_SIZE_BMP(c); \ while (more && (c = (*de) (U8G_ERROR,&more)));\ } #define UTF8_WRITE_BMP(b,c,cv,de) { \ void *more = NIL; \ if (cv) c = (*cv) (c); \ if (de) c = (*de) (c,&more); \ do UTF8_PUT_BMP (b,c) \ while (more && (c = (*de) (U8G_ERROR,&more)));\ } #define UTF8_COUNT(count,c,cv,de) { \ void *more = NIL; \ if (cv) c = (*cv) (c); \ if (de) c = (*de) (c,&more); \ do count += utf8_size (c); \ while (more && (c = (*de) (U8G_ERROR,&more)));\ } #define UTF8_WRITE(b,c,cv,de) { \ void *more = NIL; \ if (cv) c = (*cv) (c); \ if (de) c = (*de) (c,&more); \ do b = utf8_put (b,c); \ while (more && (c = (*de) (U8G_ERROR,&more)));\ } /* Convert sized text to UTF-8 given CHARSET block * Accepts: source sized text * CHARSET block * pointer to returned sized text * canonicalization function * decomposition function * Returns: T if successful, NIL if failure */ long utf8_text_cs (SIZEDTEXT *text,const CHARSET *cs,SIZEDTEXT *ret, ucs4cn_t cv,ucs4de_t de) { ret->data = text->data; /* default to source */ ret->size = text->size; switch (cs->type) { /* convert if type known */ case CT_ASCII: /* 7-bit ASCII no table */ case CT_UTF8: /* variable UTF-8 encoded Unicode no table */ if (cv || de) utf8_text_utf8 (text,ret,cv,de); break; case CT_1BYTE0: /* 1 byte no table */ utf8_text_1byte0 (text,ret,cv,de); break; case CT_1BYTE: /* 1 byte ASCII + table 0x80-0xff */ utf8_text_1byte (text,ret,cs->tab,cv,de); break; case CT_1BYTE8: /* 1 byte table 0x00 - 0xff */ utf8_text_1byte8 (text,ret,cs->tab,cv,de); break; case CT_EUC: /* 2 byte ASCII + utf8_eucparam base/CS2/CS3 */ utf8_text_euc (text,ret,cs->tab,cv,de); break; case CT_DBYTE: /* 2 byte ASCII + utf8_eucparam */ utf8_text_dbyte (text,ret,cs->tab,cv,de); break; case CT_DBYTE2: /* 2 byte ASCII + utf8_eucparam plane1/2 */ utf8_text_dbyte2 (text,ret,cs->tab,cv,de); break; case CT_UTF7: /* variable UTF-7 encoded Unicode no table */ utf8_text_utf7 (text,ret,cv,de); break; case CT_UCS2: /* 2 byte 16-bit Unicode no table */ utf8_text_ucs2 (text,ret,cv,de); break; case CT_UCS4: /* 4 byte 32-bit Unicode no table */ utf8_text_ucs4 (text,ret,cv,de); break; case CT_UTF16: /* variable UTF-16 encoded Unicode no table */ utf8_text_utf16 (text,ret,cv,de); break; case CT_2022: /* variable ISO-2022 encoded no table*/ utf8_text_2022 (text,ret,cv,de); break; case CT_SJIS: /* 2 byte Shift-JIS encoded JIS no table */ utf8_text_sjis (text,ret,cv,de); break; default: /* unknown character set type */ return NIL; } return LONGT; /* return success */ } /* Reverse mapping routines * * These routines only support character sets, not all possible charsets. In * particular, they do not support any Unicode encodings or ISO 2022. * * As a special dispensation, utf8_cstext() and utf8_cstocstext() support * support ISO-2022-JP if EUC-JP can be reverse mapped; and utf8_rmaptext() * will generated ISO-2022-JP using an EUC-JP rmap if flagged to do so. * * No attempt is made to map "equivalent" Unicode characters or Unicode * characters that have the same glyph; nor is there any attempt to handle * combining characters or otherwise do any stringprep. Maybe later. */ /* Convert UTF-8 sized text to charset * Accepts: source sized text * destination charset * pointer to returned sized text * substitute character if not in cs, else NIL to return failure * Returns: T if successful, NIL if failure */ long utf8_cstext (SIZEDTEXT *text,char *charset,SIZEDTEXT *ret, unsigned long errch) { short iso2022jp = !compare_cstring (charset,"ISO-2022-JP"); unsigned short *rmap = utf8_rmap (iso2022jp ? "EUC-JP" : charset); return rmap ? utf8_rmaptext (text,rmap,ret,errch,iso2022jp) : NIL; } /* Convert charset labelled sized text to another charset * Accepts: source sized text * source charset * pointer to returned sized text * destination charset * substitute character if not in dest cs, else NIL to return failure * Returns: T if successful, NIL if failure * * This routine has the same restricts as utf8_cstext(). */ long utf8_cstocstext (SIZEDTEXT *src,char *sc,SIZEDTEXT *dst,char *dc, unsigned long errch) { SIZEDTEXT utf8; const CHARSET *scs,*dcs; unsigned short *rmap; long ret = NIL; long iso2022jp; /* lookup charsets and reverse map */ if ((dc && (dcs = utf8_charset (dc))) && (rmap = (iso2022jp = ((dcs->type == CT_2022) && !compare_cstring (dcs->name,"ISO-2022-JP"))) ? utf8_rmap ("EUC-JP") : utf8_rmap_cs (dcs)) && (scs = (sc && *sc) ? utf8_charset (sc) : utf8_infercharset (src))) { /* init temporary buffer */ memset (&utf8,NIL,sizeof (SIZEDTEXT)); /* source cs equivalent to dest cs? */ if ((scs->type == dcs->type) && (scs->tab == dcs->tab)) { dst->data = src->data; /* yes, just copy pointers */ dst->size = src->size; ret = LONGT; } /* otherwise do the conversion */ else ret = (utf8_text_cs (src,scs,&utf8,NIL,NIL) && utf8_rmaptext (&utf8,rmap,dst,errch,iso2022jp)); /* flush temporary buffer */ if (utf8.data && (utf8.data != src->data) && (utf8.data != dst->data)) fs_give ((void **) &utf8.data); } return ret; } /* Cached rmap */ static const CHARSET *currmapcs = NIL; static unsigned short *currmap = NIL; /* Cache and return map for UTF-8 -> character set * Accepts: character set name * Returns: cached map if character set found, else NIL */ unsigned short *utf8_rmap (char *charset) { return (currmapcs && !compare_cstring (charset,currmapcs->name)) ? currmap : utf8_rmap_cs (utf8_charset (charset)); } /* Cache and return map for UTF-8 -> character set given CHARSET block * Accepts: CHARSET block * Returns: cached map if character set found, else NIL */ unsigned short *utf8_rmap_cs (const CHARSET *cs) { unsigned short *ret = NIL; if (!cs); /* have charset? */ else if (cs == currmapcs) ret = currmap; else if (ret = utf8_rmap_gen (cs,currmap)) { currmapcs = cs; currmap = ret; } return ret; } /* Return map for UTF-8 -> character set given CHARSET block * Accepts: CHARSET block * old map to recycle * Returns: map if character set found, else NIL */ unsigned short *utf8_rmap_gen (const CHARSET *cs,unsigned short *oldmap) { unsigned short u,*tab,*rmap; unsigned int i,m,ku,ten; struct utf8_eucparam *param,*p2; switch (cs->type) { /* is a character set? */ case CT_ASCII: /* 7-bit ASCII no table */ case CT_1BYTE0: /* 1 byte no table */ case CT_1BYTE: /* 1 byte ASCII + table 0x80-0xff */ case CT_1BYTE8: /* 1 byte table 0x00 - 0xff */ case CT_EUC: /* 2 byte ASCII + utf8_eucparam base/CS2/CS3 */ case CT_DBYTE: /* 2 byte ASCII + utf8_eucparam */ case CT_DBYTE2: /* 2 byte ASCII + utf8_eucparam plane1/2 */ case CT_SJIS: /* 2 byte Shift-JIS */ rmap = oldmap ? oldmap : /* recycle old map if supplied else make new */ (unsigned short *) fs_get (65536 * sizeof (unsigned short)); /* initialize table for ASCII */ for (i = 0; i < 128; i++) rmap[i] = (unsigned short) i; /* populate remainder of table with NOCHAR */ #define NOCHARBYTE (NOCHAR & 0xff) #if NOCHAR - ((NOCHARBYTE << 8) | NOCHARBYTE) while (i < 65536) rmap[i++] = NOCHAR; #else memset (rmap + 128,NOCHARBYTE,(65536 - 128) * sizeof (unsigned short)); #endif break; default: /* unsupported charset type */ rmap = NIL; /* no map possible */ } if (rmap) { /* have a map? */ switch (cs->type) { /* additional reverse map actions */ case CT_1BYTE0: /* 1 byte no table */ for (i = 128; i < 256; i++) rmap[i] = (unsigned short) i; break; case CT_1BYTE: /* 1 byte ASCII + table 0x80-0xff */ for (tab = (unsigned short *) cs->tab,i = 128; i < 256; i++) if (tab[i & BITS7] != UBOGON) rmap[tab[i & BITS7]] = (unsigned short)i; break; case CT_1BYTE8: /* 1 byte table 0x00 - 0xff */ for (tab = (unsigned short *) cs->tab,i = 0; i < 256; i++) if (tab[i] != UBOGON) rmap[tab[i]] = (unsigned short) i; break; case CT_EUC: /* 2 byte ASCII + utf8_eucparam base/CS2/CS3 */ for (param = (struct utf8_eucparam *) cs->tab, tab = (unsigned short *) param->tab, ku = 0; ku < param->max_ku; ku++) for (ten = 0; ten < param->max_ten; ten++) if ((u = tab[(ku * param->max_ten) + ten]) != UBOGON) rmap[u] = ((ku + param->base_ku) << 8) + (ten + param->base_ten) + 0x8080; break; case CT_DBYTE: /* 2 byte ASCII + utf8_eucparam */ for (param = (struct utf8_eucparam *) cs->tab, tab = (unsigned short *) param->tab, ku = 0; ku < param->max_ku; ku++) for (ten = 0; ten < param->max_ten; ten++) if ((u = tab[(ku * param->max_ten) + ten]) != UBOGON) rmap[u] = ((ku + param->base_ku) << 8) + (ten + param->base_ten); break; case CT_DBYTE2: /* 2 byte ASCII + utf8_eucparam plane1/2 */ param = (struct utf8_eucparam *) cs->tab; p2 = param + 1; /* plane 2 parameters */ /* only ten parameters should differ */ if ((param->base_ku != p2->base_ku) || (param->max_ku != p2->max_ku)) fatal ("ku definition error for CT_DBYTE2 charset"); /* total codepoints in each ku */ m = param->max_ten + p2->max_ten; tab = (unsigned short *) param->tab; for (ku = 0; ku < param->max_ku; ku++) { for (ten = 0; ten < param->max_ten; ten++) if ((u = tab[(ku * m) + ten]) != UBOGON) rmap[u] = ((ku + param->base_ku) << 8) + (ten + param->base_ten); for (ten = 0; ten < p2->max_ten; ten++) if ((u = tab[(ku * m) + param->max_ten + ten]) != UBOGON) rmap[u] = ((ku + param->base_ku) << 8) + (ten + p2->base_ten); } break; case CT_SJIS: /* 2 byte Shift-JIS */ for (ku = 0; ku < MAX_JIS0208_KU; ku++) for (ten = 0; ten < MAX_JIS0208_TEN; ten++) if ((u = jis0208tab[ku][ten]) != UBOGON) { int sku = ku + BASE_JIS0208_KU; int sten = ten + BASE_JIS0208_TEN; rmap[u] = ((((sku + 1) >> 1) + ((sku < 95) ? 112 : 176)) << 8) + sten + ((sku % 2) ? ((sten > 95) ? 32 : 31) : 126); } /* JIS Roman */ rmap[UCS2_YEN] = JISROMAN_YEN; rmap[UCS2_OVERLINE] = JISROMAN_OVERLINE; /* JIS hankaku katakana */ for (u = 0; u < (MAX_KANA_8 - MIN_KANA_8); u++) rmap[UCS2_KATAKANA + u] = MIN_KANA_8 + u; break; } /* hack: map NBSP to SP if otherwise no map */ if (rmap[0x00a0] == NOCHAR) rmap[0x00a0] = rmap[0x0020]; } return rmap; /* return map */ } /* Convert UTF-8 sized text to charset using rmap * Accepts: source sized text * conversion rmap * pointer to returned sized text * substitute character if not in rmap, else NIL to return failure * ISO-2022-JP conversion flag * Returns T if successful, NIL if failure * * This routine doesn't try to convert to all possible charsets; in particular * it doesn't support other Unicode encodings or any ISO 2022 other than * ISO-2022-JP. */ long utf8_rmaptext (SIZEDTEXT *text,unsigned short *rmap,SIZEDTEXT *ret, unsigned long errch,long iso2022jp) { unsigned long i,u,c; /* get size of buffer */ if (i = utf8_rmapsize (text,rmap,errch,iso2022jp)) { unsigned char *s = text->data; unsigned char *t = ret->data = (unsigned char *) fs_get (i); ret->size = i - 1; /* number of octets in destination buffer */ /* start non-zero ISO-2022-JP state at 1 */ if (iso2022jp) iso2022jp = 1; /* convert string, ignore BOM */ for (i = text->size; i;) if ((u = utf8_get (&s,&i)) != UCS2_BOM) { /* substitute error character for NOCHAR */ if ((u & U8GM_NONBMP) || ((c = rmap[u]) == NOCHAR)) c = errch; switch (iso2022jp) { /* depends upon ISO 2022 mode */ case 0: /* ISO 2022 not in effect */ /* two-byte character */ if (c > 0xff) *t++ = (unsigned char) (c >> 8); /* single-byte or low-byte of two-byte */ *t++ = (unsigned char) (c & 0xff); break; case 1: /* ISO 2022 Roman */ /* */ if (c < 0x80) *t++ = (unsigned char) c; else { /* JIS character */ *t++ = I2C_ESC; /* ESC $ B */ *t++ = I2C_MULTI; *t++ = I2CS_94x94_JIS_NEW; *t++ = (unsigned char) (c >> 8) & 0x7f; *t++ = (unsigned char) c & 0x7f; iso2022jp = 2; /* shift to ISO 2022 JIS */ } break; case 2: /* ISO 2022 JIS */ if (c > 0x7f) { /* */ *t++ = (unsigned char) (c >> 8) & 0x7f; *t++ = (unsigned char) c & 0x7f; } else { /* ASCII character */ *t++ = I2C_ESC; /* ESC ( J */ *t++ = I2C_G0_94; *t++ = I2CS_94_JIS_ROMAN; *t++ = (unsigned char) c; iso2022jp = 1; /* shift to ISO 2022 Roman */ } break; } } if (iso2022jp == 2) { /* ISO-2022-JP string must end in Roman */ *t++ = I2C_ESC; /* ESC ( J */ *t++ = I2C_G0_94; *t++ = I2CS_94_JIS_ROMAN; } *t++ = NIL; /* tie off returned data */ return LONGT; /* return success */ } ret->data = NIL; ret->size = 0; return NIL; /* failure */ } /* Calculate size of convertsion of UTF-8 sized text to charset using rmap * Accepts: source sized text * conversion rmap * pointer to returned sized text * substitute character if not in rmap, else NIL to return failure * ISO-2022-JP conversion flag * Returns size+1 if successful, NIL if failure * * This routine doesn't try to handle to all possible charsets; in particular * it doesn't support other Unicode encodings or any ISO 2022 other than * ISO-2022-JP. */ unsigned long utf8_rmapsize (SIZEDTEXT *text,unsigned short *rmap, unsigned long errch,long iso2022jp) { unsigned long i,u,c; unsigned long ret = 1; /* terminating NUL */ unsigned char *s = text->data; if (iso2022jp) iso2022jp = 1; /* start non-zero ISO-2022-JP state at 1 */ for (i = text->size; i;) if ((u = utf8_get (&s,&i)) != UCS2_BOM) { if ((u & U8GM_NONBMP) || (((c = rmap[u]) == NOCHAR) && !(c = errch))) return NIL; /* not in BMP, or NOCHAR and no err char */ switch (iso2022jp) { /* depends upon ISO 2022 mode */ case 0: /* ISO 2022 not in effect */ ret += (c > 0xff) ? 2 : 1; break; case 1: /* ISO 2022 Roman */ if (c < 0x80) ret += 1; /* */ else { /* JIS character */ ret += 5; /* ESC $ B */ iso2022jp = 2; /* shift to ISO 2022 JIS */ } break; case 2: /* ISO 2022 JIS */ if (c > 0x7f) ret += 2; /* */ else { /* ASCII character */ ret += 4; /* ESC ( J */ iso2022jp = 1; /* shift to ISO 2022 Roman */ } break; } } if (iso2022jp == 2) { /* ISO-2022-JP string must end in Roman */ ret += 3; /* ESC ( J */ iso2022jp = 1; /* reset state to Roman */ } return ret; } /* Convert UCS-4 to charset using rmap * Accepts: source UCS-4 character(s) * numver of UCS-4 characters * conversion rmap * pointer to returned sized text * substitute character if not in rmap, else NIL to return failure * Returns T if successful, NIL if failure * * Currently only supports BMP characters, and does not support ISO-2022 */ long ucs4_rmaptext (unsigned long *ucs4,unsigned long len,unsigned short *rmap, SIZEDTEXT *ret,unsigned long errch) { long size = ucs4_rmaplen (ucs4,len,rmap,errch); return (size >= 0) ? /* build in newly-created buffer */ ucs4_rmapbuf (ret->data = (unsigned char *) fs_get ((ret->size = size) +1), ucs4,len,rmap,errch) : NIL; } /* Return size of UCS-4 string converted to other CS via rmap * Accepts: source UCS-4 character(s) * numver of UCS-4 characters * conversion rmap * substitute character if not in rmap, else NIL to return failure * Returns: length if success, negative if failure (no-convert) */ long ucs4_rmaplen (unsigned long *ucs4,unsigned long len,unsigned short *rmap, unsigned long errch) { long ret; unsigned long i,u,c; /* count non-BOM characters */ for (ret = 0,i = 0; i < len; ++i) if ((u = ucs4[i]) != UCS2_BOM) { if ((u & U8GM_NONBMP) || (((c = rmap[u]) == NOCHAR) && !(c = errch))) return -1; /* not in BMP, or NOCHAR and no err char? */ ret += (c > 0xff) ? 2 : 1; } return ret; } /* Stuff buffer with UCS-4 string converted to other CS via rmap * Accepts: destination buffer * source UCS-4 character(s) * number of UCS-4 characters * conversion rmap * substitute character if not in rmap, else NIL to return failure * Returns: T, always */ long ucs4_rmapbuf (unsigned char *t,unsigned long *ucs4,unsigned long len, unsigned short *rmap,unsigned long errch) { unsigned long i,u,c; /* convert non-BOM characters */ for (i = 0; i < len; ++i) if ((u = ucs4[i]) != UCS2_BOM) { /* substitute error character for NOCHAR */ if ((u & U8GM_NONBMP) || ((c = rmap[u]) == NOCHAR)) c = errch; /* two-byte character? */ if (c > 0xff) *t++ = (unsigned char) (c >> 8); /* single-byte or low-byte of two-byte */ *t++ = (unsigned char) (c & 0xff); } *t++ = NIL; /* tie off returned data */ return LONGT; } /* Return UCS-4 Unicode character from UTF-8 string * Accepts: pointer to string * remaining octets in string * Returns: UCS-4 character with pointer and count updated * or error code with pointer and count unchanged */ unsigned long utf8_get (unsigned char **s,unsigned long *i) { unsigned char *t = *s; unsigned long j = *i; /* decode raw UTF-8 string */ unsigned long ret = utf8_get_raw (&t,&j); if (ret & U8G_ERROR); /* invalid raw UTF-8 decoding? */ /* no, is it surrogate? */ else if ((ret >= UTF16_SURR) && (ret <= UTF16_MAXSURR)) ret = U8G_SURROGA; /* or in non-Unicode ISO 10646 space? */ else if (ret > UCS4_MAXUNICODE) ret = U8G_NOTUNIC; else { *s = t; /* all is well, update pointer */ *i = j; /* and counter */ } return ret; /* return value */ } /* Return raw (including non-Unicode) UCS-4 character from UTF-8 string * Accepts: pointer to string * remaining octets in string * Returns: UCS-4 character with pointer and count updated * or error code with pointer and count unchanged */ unsigned long utf8_get_raw (unsigned char **s,unsigned long *i) { unsigned char c,c1; unsigned char *t = *s; unsigned long j = *i; unsigned long ret = U8G_NOTUTF8; int more = 0; do { /* make sure have source octets available */ if (!j--) return more ? U8G_ENDSTRI : U8G_ENDSTRG; /* UTF-8 continuation? */ else if (((c = *t++) > 0x7f) && (c < 0xc0)) { /* continuation when not in progress */ if (!more) return U8G_BADCONT; --more; /* found a continuation octet */ ret <<= 6; /* shift current value by 6 bits */ ret |= c & 0x3f; /* merge continuation octet */ } /* incomplete UTF-8 character */ else if (more) return U8G_INCMPLT; else { /* start of sequence */ c1 = j ? *t : 0xbf; /* assume valid continuation if incomplete */ if (c < 0x80) ret = c; /* U+0000 - U+007f */ else if (c < 0xc2); /* c0 and c1 never valid */ else if (c < 0xe0) { /* U+0080 - U+07ff */ if (c &= 0x1f) more = 1; } else if (c < 0xf0) { /* U+0800 - U+ffff */ if ((c &= 0x0f) || (c1 >= 0xa0)) more = 2; } else if (c < 0xf8) { /* U+10000 - U+10ffff (and 110000 - 1fffff) */ if ((c &= 0x07) || (c1 >= 0x90)) more = 3; } else if (c < 0xfc) { /* ISO 10646 200000 - 3ffffff */ if ((c &= 0x03) || (c1 >= 0x88)) more = 4; } else if (c < 0xfe) { /* ISO 10646 4000000 - 7fffffff */ if ((c &= 0x01) || (c1 >= 0x84)) more = 5; } /* fe and ff never valid */ if (more) { /* multi-octet, make sure more to come */ if (!j) return U8G_ENDSTRI; ret = c; /* continuation needed, save start bits */ } } } while (more); if (!(ret & U8G_ERROR)) { /* success return? */ *s = t; /* yes, update pointer */ *i = j; /* and counter */ } return ret; /* return value */ } /* Return UCS-4 character from named charset string * Accepts: charset * pointer to string * remaining octets in string * Returns: UCS-4 character with pointer and count updated, negative if error * * Error codes are the same as utf8_get(). */ unsigned long ucs4_cs_get (CHARSET *cs,unsigned char **s,unsigned long *i) { unsigned char c,c1,ku,ten; unsigned long ret,d; unsigned char *t = *s; unsigned long j = *i; struct utf8_eucparam *p1,*p2,*p3; if (j--) c = *t++; /* get first octet */ else return U8G_ENDSTRG; /* empty string */ switch (cs->type) { /* convert if type known */ case CT_UTF8: /* variable UTF-8 encoded Unicode no table */ return utf8_get (s,i); case CT_ASCII: /* 7-bit ASCII no table */ if (c >= 0x80) return U8G_NOTUTF8; case CT_1BYTE0: /* 1 byte no table */ ret = c; /* identity */ break; case CT_1BYTE: /* 1 byte ASCII + table 0x80-0xff */ ret = (c > 0x80) ? ((unsigned short *) cs->tab)[c & BITS7] : c; break; case CT_1BYTE8: /* 1 byte table 0x00 - 0xff */ ret = ((unsigned short *) cs->tab)[c]; break; case CT_EUC: /* 2 byte ASCII + utf8_eucparam base/CS2/CS3 */ if (c & BIT8) { p1 = (struct utf8_eucparam *) cs->tab; p2 = p1 + 1; p3 = p1 + 2; if (j--) c1 = *t++; /* get second octet */ else return U8G_ENDSTRI; if (!(c1 & BIT8)) return U8G_NOTUTF8; switch (c) { /* check 8bit code set */ case EUC_CS2: /* CS2 */ if (p2->base_ku) { /* CS2 set up? */ if (p2->base_ten) { /* yes, multibyte? */ if (j--) c = *t++; /* get second octet */ else return U8G_ENDSTRI; if ((c & BIT8) && ((ku = (c1 & BITS7) - p2->base_ku) < p2->max_ku) && ((ten = (c & BITS7) - p2->base_ten) < p2->max_ten)) { ret = ((unsigned short *) p2->tab)[(ku*p2->max_ten) + ten]; break; } } else if ((c1 >= p2->base_ku) && (c1 < p2->max_ku)) { ret = c1 + ((unsigned long) p2->tab); break; } } return U8G_NOTUTF8; /* CS2 not set up or bogus */ case EUC_CS3: /* CS3 */ if (p3->base_ku) { /* CS3 set up? */ if (p3->base_ten) { /* yes, multibyte? */ if (j--) c = *t++; /* get second octet */ else return U8G_ENDSTRI; if ((c & BIT8) && ((ku = (c1 & BITS7) - p3->base_ku) < p3->max_ku) && ((ten = (c & BITS7) - p3->base_ten) < p3->max_ten)) { ret = ((unsigned short *) p3->tab)[(ku*p3->max_ten) + ten]; break; } } else if ((c1 >= p3->base_ku) && (c1 < p3->max_ku)) { ret = c1 + ((unsigned long) p3->tab); break; } } return U8G_NOTUTF8; /* CS3 not set up or bogus */ default: if (((ku = (c & BITS7) - p1->base_ku) >= p1->max_ku) || ((ten = (c1 & BITS7) - p1->base_ten) >= p1->max_ten)) return U8G_NOTUTF8; ret = ((unsigned short *) p1->tab)[(ku*p1->max_ten) + ten]; /* special hack for JIS X 0212: merge rows less than 10 */ if ((ret == UBOGON) && ku && (ku < 10) && p3->tab && p3->base_ten) ret = ((unsigned short *) p3->tab) [((ku - (p3->base_ku - p1->base_ku))*p3->max_ten) + ten]; break; } } else ret = c; /* ASCII character */ break; case CT_DBYTE: /* 2 byte ASCII + utf8_eucparam */ if (c & BIT8) { /* double-byte character? */ p1 = (struct utf8_eucparam *) cs->tab; if (j--) c1 = *t++; /* get second octet */ else return U8G_ENDSTRI; if (((ku = c - p1->base_ku) < p1->max_ku) && ((ten = c1 - p1->base_ten) < p1->max_ten)) ret = ((unsigned short *) p1->tab)[(ku*p1->max_ten) + ten]; else return U8G_NOTUTF8; } else ret = c; /* ASCII character */ break; case CT_DBYTE2: /* 2 byte ASCII + utf8_eucparam plane1/2 */ if (c & BIT8) { /* double-byte character? */ p1 = (struct utf8_eucparam *) cs->tab; p2 = p1 + 1; if (j--) c1 = *t++; /* get second octet */ else return U8G_ENDSTRI; if (c1 & BIT8) { /* high vs. low plane */ if ((ku = c - p2->base_ku) < p2->max_ku && ((ten = c1 - p2->base_ten) < p2->max_ten)) ret = ((unsigned short *) p1->tab) [(ku*(p1->max_ten + p2->max_ten)) + p1->max_ten + ten]; else return U8G_NOTUTF8; } else if ((ku = c - p1->base_ku) < p1->max_ku && ((ten = c1 - p1->base_ten) < p1->max_ten)) ret = ((unsigned short *) p1->tab) [(ku*(p1->max_ten + p2->max_ten)) + ten]; else return U8G_NOTUTF8; } else ret = c; /* ASCII character */ break; case CT_SJIS: /* 2 byte Shift-JIS encoded JIS no table */ /* compromise - do yen sign but not overline */ if (!(c & BIT8)) ret = (c == JISROMAN_YEN) ? UCS2_YEN : c; /* half-width katakana? */ else if ((c >= MIN_KANA_8) && (c < MAX_KANA_8)) ret = c + KANA_8; else { /* Shift-JIS */ if (j--) c1 = *t++; /* get second octet */ else return U8G_ENDSTRI; SJISTOJIS (c,c1); c = JISTOUNICODE (c,c1,ku,ten); } break; case CT_UCS2: /* 2 byte 16-bit Unicode no table */ ret = c << 8; if (j--) c = *t++; /* get second octet */ else return U8G_ENDSTRI; /* empty string */ ret |= c; break; case CT_UCS4: /* 4 byte 32-bit Unicode no table */ if (c & 0x80) return U8G_NOTUTF8; if (j < 3) return U8G_ENDSTRI; j -= 3; /* count three octets */ ret = c << 24; ret |= (*t++) << 16; ret |= (*t++) << 8; ret |= (*t++); break; case CT_UTF16: /* variable UTF-16 encoded Unicode no table */ ret = c << 8; if (j--) c = *t++; /* get second octet */ else return U8G_ENDSTRI; /* empty string */ ret |= c; /* surrogate? */ if ((ret >= UTF16_SURR) && (ret <= UTF16_MAXSURR)) { /* invalid first surrogate */ if ((ret > UTF16_SURRHEND) || (j < 2)) return U8G_NOTUTF8; j -= 2; /* count two octets */ d = (*t++) << 8; /* first octet of second surrogate */ d |= *t++; /* second octet of second surrogate */ if ((d < UTF16_SURRL) || (d > UTF16_SURRLEND)) return U8G_NOTUTF8; ret = UTF16_BASE + ((ret & UTF16_MASK) << UTF16_SHIFT) + (d & UTF16_MASK); } break; default: /* unknown/unsupported character set type */ return U8G_NOTUTF8; } *s = t; /* update pointer and counter */ *i = j; return ret; } /* Produce charset validity map for BMP * Accepts: list of charsets to map * Returns: validity map, indexed by BMP codepoint * * Bit 0x1 is the "not-CJK" character bit */ unsigned long *utf8_csvalidmap (char *charsets[]) { unsigned short u,*tab; unsigned int m,ku,ten; unsigned long i,csi,csb; struct utf8_eucparam *param,*p2; char *s; const CHARSET *cs; unsigned long *ret = (unsigned long *) fs_get (i = 0x10000 * sizeof (unsigned long)); memset (ret,0,i); /* zero the entire vector */ /* mark all the non-CJK codepoints */ /* U+0000 - U+2E7F non-CJK */ for (i = 0; i < 0x2E7F; ++i) ret[i] = 0x1; /* U+2E80 - U+2EFF CJK Radicals Supplement * U+2F00 - U+2FDF Kangxi Radicals * U+2FE0 - U+2FEF unassigned * U+2FF0 - U+2FFF Ideographic Description Characters * U+3000 - U+303F CJK Symbols and Punctuation * U+3040 - U+309F Hiragana * U+30A0 - U+30FF Katakana * U+3100 - U+312F BoPoMoFo * U+3130 - U+318F Hangul Compatibility Jamo * U+3190 - U+319F Kanbun * U+31A0 - U+31BF BoPoMoFo Extended * U+31C0 - U+31EF CJK Strokes * U+31F0 - U+31FF Katakana Phonetic Extensions * U+3200 - U+32FF Enclosed CJK Letters and Months * U+3300 - U+33FF CJK Compatibility * U+3400 - U+4DBF CJK Unified Ideographs Extension A * U+4DC0 - U+4DFF Yijing Hexagram Symbols * U+4E00 - U+9FFF CJK Unified Ideographs * U+A000 - U+A48F Yi Syllables * U+A490 - U+A4CF Yi Radicals * U+A700 - U+A71F Modifier Tone Letters */ for (i = 0xa720; i < 0xabff; ++i) ret[i] = 0x1; /* U+AC00 - U+D7FF Hangul Syllables */ for (i = 0xd800; i < 0xf8ff; ++i) ret[i] = 0x1; /* U+F900 - U+FAFF CJK Compatibility Ideographs */ for (i = 0xfb00; i < 0xfe2f; ++i) ret[i] = 0x1; /* U+FE30 - U+FE4F CJK Compatibility Forms * U+FE50 - U+FE6F Small Form Variants (for CNS 11643) */ for (i = 0xfe70; i < 0xfeff; ++i) ret[i] = 0x1; /* U+FF00 - U+FFEF CJK Compatibility Ideographs */ for (i = 0xfff0; i < 0x10000; ++i) ret[i] = 0x1; /* for each supplied charset */ for (csi = 1; ret && charsets && (s = charsets[csi - 1]); ++csi) { /* substitute EUC-JP for ISO-2022-JP */ if (!compare_cstring (s,"ISO-2022-JP")) s = "EUC-JP"; /* look up charset */ if (cs = utf8_charset (s)) { csb = 1 << csi; /* charset bit */ switch (cs->type) { case CT_ASCII: /* 7-bit ASCII no table */ case CT_1BYTE0: /* 1 byte no table */ case CT_1BYTE: /* 1 byte ASCII + table 0x80-0xff */ case CT_1BYTE8: /* 1 byte table 0x00 - 0xff */ case CT_EUC: /* 2 byte ASCII + utf8_eucparam base/CS2/CS3 */ case CT_DBYTE: /* 2 byte ASCII + utf8_eucparam */ case CT_DBYTE2: /* 2 byte ASCII + utf8_eucparam plane1/2 */ case CT_SJIS: /* 2 byte Shift-JIS */ /* supported charset type, all ASCII is OK */ for (i = 0; i < 128; ++i) ret[i] |= csb; break; default: /* unsupported charset type */ fs_give ((void **) &ret); break; } /* now do additional operations */ if (ret) switch (cs->type) { case CT_1BYTE0: /* 1 byte no table */ for (i = 128; i < 256; i++) ret[i] |= csb; break; case CT_1BYTE: /* 1 byte ASCII + table 0x80-0xff */ for (tab = (unsigned short *) cs->tab,i = 128; i < 256; i++) if (tab[i & BITS7] != UBOGON) ret[tab[i & BITS7]] |= csb; break; case CT_1BYTE8: /* 1 byte table 0x00 - 0xff */ for (tab = (unsigned short *) cs->tab,i = 0; i < 256; i++) if (tab[i] != UBOGON) ret[tab[i]] |= csb; break; case CT_EUC: /* 2 byte ASCII + utf8_eucparam base/CS2/CS3 */ for (param = (struct utf8_eucparam *) cs->tab, tab = (unsigned short *) param->tab, ku = 0; ku < param->max_ku; ku++) for (ten = 0; ten < param->max_ten; ten++) if ((u = tab[(ku * param->max_ten) + ten]) != UBOGON) ret[u] |= csb; break; case CT_DBYTE: /* 2 byte ASCII + utf8_eucparam */ for (param = (struct utf8_eucparam *) cs->tab, tab = (unsigned short *) param->tab, ku = 0; ku < param->max_ku; ku++) for (ten = 0; ten < param->max_ten; ten++) if ((u = tab[(ku * param->max_ten) + ten]) != UBOGON) ret[u] |= csb; break; case CT_DBYTE2: /* 2 byte ASCII + utf8_eucparam plane1/2 */ param = (struct utf8_eucparam *) cs->tab; p2 = param + 1; /* plane 2 parameters */ /* only ten parameters should differ */ if ((param->base_ku != p2->base_ku) || (param->max_ku != p2->max_ku)) fatal ("ku definition error for CT_DBYTE2 charset"); /* total codepoints in each ku */ m = param->max_ten + p2->max_ten; tab = (unsigned short *) param->tab; for (ku = 0; ku < param->max_ku; ku++) { for (ten = 0; ten < param->max_ten; ten++) if ((u = tab[(ku * m) + ten]) != UBOGON) ret[u] |= csb; for (ten = 0; ten < p2->max_ten; ten++) if ((u = tab[(ku * m) + param->max_ten + ten]) != UBOGON) ret[u] |= csb; } break; case CT_SJIS: /* 2 byte Shift-JIS */ for (ku = 0; ku < MAX_JIS0208_KU; ku++) for (ten = 0; ten < MAX_JIS0208_TEN; ten++) if ((u = jis0208tab[ku][ten]) != UBOGON) ret[u] |= csb; /* JIS hankaku katakana */ for (u = 0; u < (MAX_KANA_8 - MIN_KANA_8); u++) ret[UCS2_KATAKANA + u] |= csb; break; } } /* invalid charset, punt */ else fs_give ((void **) &ret); } return ret; } /* Infer charset from unlabelled sized text * Accepts: sized text * Returns: charset if one inferred, or NIL if unknown */ const CHARSET *utf8_infercharset (SIZEDTEXT *src) { long iso2022jp = NIL; long eightbit = NIL; unsigned long i; /* look for ISO 2022 */ if (src) for (i = 0; i < src->size; i++) { /* ESC sequence? */ if ((src->data[i] == I2C_ESC) && (++i < src->size)) switch (src->data[i]) { case I2C_MULTI: /* yes, multibyte? */ if (++i < src->size) switch (src->data[i]) { case I2CS_94x94_JIS_OLD: /* JIS X 0208-1978 */ case I2CS_94x94_JIS_NEW: /* JIS X 0208-1983 */ case I2CS_94x94_JIS_EXT: /* JIS X 0212-1990 (kludge...) */ iso2022jp = T; /* found an ISO-2022-JP sequence */ break; default: /* other multibyte */ return NIL; /* definitely invalid */ } break; case I2C_G0_94: /* single byte */ if (++i < src->size) switch (src->data[i]) { case I2CS_94_JIS_BUGROM: /* in case old buggy software */ case I2CS_94_JIS_ROMAN: /* JIS X 0201-1976 left half */ case I2CS_94_ASCII: /* ASCII */ case I2CS_94_BRITISH: /* good enough for gov't work */ break; default: /* other 94 single byte */ return NIL; /* definitely invalid */ } } /* if possible UTF-8 and not ISO-2022-JP */ else if (!iso2022jp && (eightbit >= 0) && (src->data[i] & BIT8) && (eightbit = utf8_validate (src->data + i,src->size - i)) > 0) i += eightbit - 1; /* skip past all but last of UTF-8 char */ } /* ISO-2022-JP overrides other guesses */ if (iso2022jp) return utf8_charset ("ISO-2022-JP"); if (eightbit > 0) return utf8_charset ("UTF-8"); return eightbit ? NIL : utf8_charset ("US-ASCII"); } /* Validate that character at this position is UTF-8 * Accepts: string pointer * size of remaining string * Returns: size of UTF-8 character in octets or -1 if not UTF-8 */ long utf8_validate (unsigned char *s,unsigned long i) { unsigned long j = i; return (utf8_get (&s,&i) & U8G_ERROR) ? -1 : j - i; } /* Convert ISO 8859-1 to UTF-8 * Accepts: source sized text * pointer to return sized text * canonicalization function */ void utf8_text_1byte0 (SIZEDTEXT *text,SIZEDTEXT *ret,ucs4cn_t cv,ucs4de_t de) { unsigned long i; unsigned char *s; unsigned int c; for (ret->size = i = 0; i < text->size;) { c = text->data[i++]; UTF8_COUNT_BMP (ret->size,c,cv,de) } (s = ret->data = (unsigned char *) fs_get (ret->size + 1))[ret->size] =NIL; for (i = 0; i < text->size;) { c = text->data[i++]; UTF8_WRITE_BMP (s,c,cv,de) /* convert UCS-2 to UTF-8 */ } } /* Convert single byte ASCII+8bit character set sized text to UTF-8 * Accepts: source sized text * pointer to return sized text * conversion table * canonicalization function */ void utf8_text_1byte (SIZEDTEXT *text,SIZEDTEXT *ret,void *tab,ucs4cn_t cv, ucs4de_t de) { unsigned long i; unsigned char *s; unsigned int c; unsigned short *tbl = (unsigned short *) tab; for (ret->size = i = 0; i < text->size;) { if ((c = text->data[i++]) & BIT8) c = tbl[c & BITS7]; UTF8_COUNT_BMP (ret->size,c,cv,de) } (s = ret->data = (unsigned char *) fs_get (ret->size + 1))[ret->size] =NIL; for (i = 0; i < text->size;) { if ((c = text->data[i++]) & BIT8) c = tbl[c & BITS7]; UTF8_WRITE_BMP (s,c,cv,de) /* convert UCS-2 to UTF-8 */ } } /* Convert single byte 8bit character set sized text to UTF-8 * Accepts: source sized text * pointer to return sized text * conversion table * canonicalization function */ void utf8_text_1byte8 (SIZEDTEXT *text,SIZEDTEXT *ret,void *tab,ucs4cn_t cv, ucs4de_t de) { unsigned long i; unsigned char *s; unsigned int c; unsigned short *tbl = (unsigned short *) tab; for (ret->size = i = 0; i < text->size;) { c = tbl[text->data[i++]]; UTF8_COUNT_BMP (ret->size,c,cv,de) } (s = ret->data = (unsigned char *) fs_get (ret->size + 1))[ret->size] =NIL; for (i = 0; i < text->size;) { c = tbl[text->data[i++]]; UTF8_WRITE_BMP (s,c,cv,de) /* convert UCS-2 to UTF-8 */ } } /* Convert EUC sized text to UTF-8 * Accepts: source sized text * pointer to return sized text * EUC parameter table * canonicalization function */ void utf8_text_euc (SIZEDTEXT *text,SIZEDTEXT *ret,void *tab,ucs4cn_t cv, ucs4de_t de) { unsigned long i; unsigned char *s; unsigned int pass,c,c1,ku,ten; struct utf8_eucparam *p1 = (struct utf8_eucparam *) tab; struct utf8_eucparam *p2 = p1 + 1; struct utf8_eucparam *p3 = p1 + 2; unsigned short *t1 = (unsigned short *) p1->tab; unsigned short *t2 = (unsigned short *) p2->tab; unsigned short *t3 = (unsigned short *) p3->tab; for (pass = 0,s = NIL,ret->size = 0; pass <= 1; pass++) { for (i = 0; i < text->size;) { /* not CS0? */ if ((c = text->data[i++]) & BIT8) { /* yes, must have another high byte */ if ((i >= text->size) || !((c1 = text->data[i++]) & BIT8)) c = UBOGON; /* out of space or bogon */ else switch (c) { /* check 8bit code set */ case EUC_CS2: /* CS2 */ if (p2->base_ku) { /* CS2 set up? */ if (p2->base_ten) /* yes, multibyte? */ c = ((i < text->size) && ((c = text->data[i++]) & BIT8) && ((ku = (c1 & BITS7) - p2->base_ku) < p2->max_ku) && ((ten = (c & BITS7) - p2->base_ten) < p2->max_ten)) ? t2[(ku*p2->max_ten) + ten] : UBOGON; else c = ((c1 >= p2->base_ku) && (c1 < p2->max_ku)) ? c1 + ((unsigned long) p2->tab) : UBOGON; } else { /* CS2 not set up */ c = UBOGON; /* swallow byte, say bogon */ if (i < text->size) i++; } break; case EUC_CS3: /* CS3 */ if (p3->base_ku) { /* CS3 set up? */ if (p3->base_ten) /* yes, multibyte? */ c = ((i < text->size) && ((c = text->data[i++]) & BIT8) && ((ku = (c1 & BITS7) - p3->base_ku) < p3->max_ku) && ((ten = (c & BITS7) - p3->base_ten) < p3->max_ten)) ? t3[(ku*p3->max_ten) + ten] : UBOGON; else c = ((c1 >= p3->base_ku) && (c1 < p3->max_ku)) ? c1 + ((unsigned long) p3->tab) : UBOGON; } else { /* CS3 not set up */ c = UBOGON; /* swallow byte, say bogon */ if (i < text->size) i++; } break; default: if (((ku = (c & BITS7) - p1->base_ku) >= p1->max_ku) || ((ten = (c1 & BITS7) - p1->base_ten) >= p1->max_ten)) c = UBOGON; else if (((c = t1[(ku*p1->max_ten) + ten]) == UBOGON) && /* special hack for JIS X 0212: merge rows less than 10 */ ku && (ku < 10) && t3 && p3->base_ten) c = t3[((ku - (p3->base_ku - p1->base_ku))*p3->max_ten) + ten]; } } /* convert if second pass */ if (pass) UTF8_WRITE_BMP (s,c,cv,de) else UTF8_COUNT_BMP (ret->size,c,cv,de); } if (!pass) (s = ret->data = (unsigned char *) fs_get (ret->size + 1))[ret->size] =NIL; } } /* Convert ASCII + double-byte sized text to UTF-8 * Accepts: source sized text * pointer to return sized text * conversion table * canonicalization function */ void utf8_text_dbyte (SIZEDTEXT *text,SIZEDTEXT *ret,void *tab,ucs4cn_t cv, ucs4de_t de) { unsigned long i; unsigned char *s; unsigned int c,c1,ku,ten; struct utf8_eucparam *p1 = (struct utf8_eucparam *) tab; unsigned short *t1 = (unsigned short *) p1->tab; for (ret->size = i = 0; i < text->size;) { if ((c = text->data[i++]) & BIT8) { /* special hack for GBK: 0x80 is Euro */ if ((c == 0x80) && (t1 == (unsigned short *) gb2312tab)) c = UCS2_EURO; else c = ((i < text->size) && (c1 = text->data[i++]) && ((ku = c - p1->base_ku) < p1->max_ku) && ((ten = c1 - p1->base_ten) < p1->max_ten)) ? t1[(ku*p1->max_ten) + ten] : UBOGON; } UTF8_COUNT_BMP (ret->size,c,cv,de) } (s = ret->data = (unsigned char *) fs_get (ret->size + 1))[ret->size] = NIL; for (i = 0; i < text->size;) { if ((c = text->data[i++]) & BIT8) { /* special hack for GBK: 0x80 is Euro */ if ((c == 0x80) && (t1 == (unsigned short *) gb2312tab)) c = UCS2_EURO; else c = ((i < text->size) && (c1 = text->data[i++]) && ((ku = c - p1->base_ku) < p1->max_ku) && ((ten = c1 - p1->base_ten) < p1->max_ten)) ? t1[(ku*p1->max_ten) + ten] : UBOGON; } UTF8_WRITE_BMP (s,c,cv,de) /* convert UCS-2 to UTF-8 */ } } /* Convert ASCII + double byte 2 plane sized text to UTF-8 * Accepts: source sized text * pointer to return sized text * conversion table * canonicalization function */ void utf8_text_dbyte2 (SIZEDTEXT *text,SIZEDTEXT *ret,void *tab,ucs4cn_t cv, ucs4de_t de) { unsigned long i; unsigned char *s; unsigned int c,c1,ku,ten; struct utf8_eucparam *p1 = (struct utf8_eucparam *) tab; struct utf8_eucparam *p2 = p1 + 1; unsigned short *t = (unsigned short *) p1->tab; for (ret->size = i = 0; i < text->size;) { if ((c = text->data[i++]) & BIT8) { if ((i >= text->size) || !(c1 = text->data[i++])) c = UBOGON; /* out of space or bogon */ else if (c1 & BIT8) /* high vs. low plane */ c = ((ku = c - p2->base_ku) < p2->max_ku && ((ten = c1 - p2->base_ten) < p2->max_ten)) ? t[(ku*(p1->max_ten + p2->max_ten)) + p1->max_ten + ten] :UBOGON; else c = ((ku = c - p1->base_ku) < p1->max_ku && ((ten = c1 - p1->base_ten) < p1->max_ten)) ? t[(ku*(p1->max_ten + p2->max_ten)) + ten] : UBOGON; } UTF8_COUNT_BMP (ret->size,c,cv,de) } (s = ret->data = (unsigned char *) fs_get (ret->size + 1))[ret->size] = NIL; for (i = 0; i < text->size;) { if ((c = text->data[i++]) & BIT8) { if ((i >= text->size) || !(c1 = text->data[i++])) c = UBOGON; /* out of space or bogon */ else if (c1 & BIT8) /* high vs. low plane */ c = ((ku = c - p2->base_ku) < p2->max_ku && ((ten = c1 - p2->base_ten) < p2->max_ten)) ? t[(ku*(p1->max_ten + p2->max_ten)) + p1->max_ten + ten] :UBOGON; else c = ((ku = c - p1->base_ku) < p1->max_ku && ((ten = c1 - p1->base_ten) < p1->max_ten)) ? t[(ku*(p1->max_ten + p2->max_ten)) + ten] : UBOGON; } UTF8_WRITE_BMP (s,c,cv,de) /* convert UCS-2 to UTF-8 */ } } #ifdef JISTOUNICODE /* Japanese */ /* Convert Shift JIS sized text to UTF-8 * Accepts: source sized text * pointer to return sized text * canonicalization function */ void utf8_text_sjis (SIZEDTEXT *text,SIZEDTEXT *ret,ucs4cn_t cv, ucs4de_t de) { unsigned long i; unsigned char *s; unsigned int c,c1,ku,ten; for (ret->size = i = 0; i < text->size;) { if ((c = text->data[i++]) & BIT8) { /* half-width katakana */ if ((c >= MIN_KANA_8) && (c < MAX_KANA_8)) c += KANA_8; else if (i >= text->size) c = UBOGON; else { /* Shift-JIS */ c1 = text->data[i++]; SJISTOJIS (c,c1); c = JISTOUNICODE (c,c1,ku,ten); } } /* compromise - do yen sign but not overline */ else if (c == JISROMAN_YEN) c = UCS2_YEN; UTF8_COUNT_BMP (ret->size,c,cv,de) } (s = ret->data = (unsigned char *) fs_get (ret->size + 1))[ret->size] = NIL; for (i = 0; i < text->size;) { if ((c = text->data[i++]) & BIT8) { /* half-width katakana */ if ((c >= MIN_KANA_8) && (c < MAX_KANA_8)) c += KANA_8; else { /* Shift-JIS */ c1 = text->data[i++]; SJISTOJIS (c,c1); c = JISTOUNICODE (c,c1,ku,ten); } } /* compromise - do yen sign but not overline */ else if (c == JISROMAN_YEN) c = UCS2_YEN; UTF8_WRITE_BMP (s,c,cv,de) /* convert UCS-2 to UTF-8 */ } } #endif /* Convert ISO-2022 sized text to UTF-8 * Accepts: source sized text * pointer to returned sized text * canonicalization function */ void utf8_text_2022 (SIZEDTEXT *text,SIZEDTEXT *ret,ucs4cn_t cv,ucs4de_t de) { unsigned long i; unsigned char *s; unsigned int pass,state,c,co,gi,gl,gr,g[4],ku,ten; for (pass = 0,s = NIL,ret->size = 0; pass <= 1; pass++) { gi = 0; /* quell compiler warnings */ state = I2S_CHAR; /* initialize engine */ g[0]= g[2] = I2CS_ASCII; /* G0 and G2 are ASCII */ g[1]= g[3] = I2CS_ISO8859_1;/* G1 and G3 are ISO-8850-1 */ gl = I2C_G0; gr = I2C_G1; /* left is G0, right is G1 */ for (i = 0; i < text->size;) { c = text->data[i++]; switch (state) { /* dispatch based upon engine state */ case I2S_ESC: /* ESC seen */ switch (c) { /* process intermediate character */ case I2C_MULTI: /* multibyte character? */ state = I2S_MUL; /* mark multibyte flag seen */ break; case I2C_SS2: /* single shift GL to G2 */ case I2C_SS2_ALT: /* Taiwan SeedNet */ gl |= I2C_SG2; break; case I2C_SS3: /* single shift GL to G3 */ case I2C_SS3_ALT: /* Taiwan SeedNet */ gl |= I2C_SG3; break; case I2C_LS2: /* shift GL to G2 */ gl = I2C_G2; break; case I2C_LS3: /* shift GL to G3 */ gl = I2C_G3; break; case I2C_LS1R: /* shift GR to G1 */ gr = I2C_G1; break; case I2C_LS2R: /* shift GR to G2 */ gr = I2C_G2; break; case I2C_LS3R: /* shift GR to G3 */ gr = I2C_G3; break; case I2C_G0_94: case I2C_G1_94: case I2C_G2_94: case I2C_G3_94: g[gi = c - I2C_G0_94] = (state == I2S_MUL) ? I2CS_94x94 : I2CS_94; state = I2S_INT; /* ready for character set */ break; case I2C_G0_96: case I2C_G1_96: case I2C_G2_96: case I2C_G3_96: g[gi = c - I2C_G0_96] = (state == I2S_MUL) ? I2CS_96x96 : I2CS_96; state = I2S_INT; /* ready for character set */ break; default: /* bogon */ if (pass) *s++ = I2C_ESC,*s++ = c; else ret->size += 2; state = I2S_CHAR; /* return to previous state */ } break; case I2S_MUL: /* ESC $ */ switch (c) { /* process multibyte intermediate character */ case I2C_G0_94: case I2C_G1_94: case I2C_G2_94: case I2C_G3_94: g[gi = c - I2C_G0_94] = I2CS_94x94; state = I2S_INT; /* ready for character set */ break; case I2C_G0_96: case I2C_G1_96: case I2C_G2_96: case I2C_G3_96: g[gi = c - I2C_G0_96] = I2CS_96x96; state = I2S_INT; /* ready for character set */ break; default: /* probably omitted I2CS_94x94 */ g[gi = I2C_G0] = I2CS_94x94 | c; state = I2S_CHAR; /* return to character state */ } break; case I2S_INT: state = I2S_CHAR; /* return to character state */ g[gi] |= c; /* set character set */ break; case I2S_CHAR: /* character data */ switch (c) { case I2C_ESC: /* ESC character */ state = I2S_ESC; /* see if ISO-2022 prefix */ break; case I2C_SI: /* shift GL to G0 */ gl = I2C_G0; break; case I2C_SO: /* shift GL to G1 */ gl = I2C_G1; break; case I2C_SS2_ALT: /* single shift GL to G2 */ case I2C_SS2_ALT_7: gl |= I2C_SG2; break; case I2C_SS3_ALT: /* single shift GL to G3 */ case I2C_SS3_ALT_7: gl |= I2C_SG3; break; default: /* ordinary character */ co = c; /* note original character */ if (gl & (3 << 2)) { /* single shifted? */ gi = g[gl >> 2]; /* get shifted character set */ gl &= 0x3; /* cancel shift */ } /* select left or right half */ else gi = (c & BIT8) ? g[gr] : g[gl]; c &= BITS7; /* make 7-bit */ switch (gi) { /* interpret in character set */ case I2CS_ASCII: /* ASCII */ break; /* easy! */ case I2CS_BRITISH: /* British ASCII */ /* Pound sterling sign */ if (c == BRITISH_POUNDSTERLING) c = UCS2_POUNDSTERLING; break; case I2CS_JIS_ROMAN: /* JIS Roman */ case I2CS_JIS_BUGROM: /* old bugs */ switch (c) { /* two exceptions to ASCII */ case JISROMAN_YEN: /* Yen sign */ c = UCS2_YEN; break; /* overline */ case JISROMAN_OVERLINE: c = UCS2_OVERLINE; break; } break; case I2CS_JIS_KANA: /* JIS hankaku katakana */ if ((c >= MIN_KANA_7) && (c < MAX_KANA_7)) c += KANA_7; break; case I2CS_ISO8859_1: /* Latin-1 (West European) */ c |= BIT8; /* just turn on high bit */ break; case I2CS_ISO8859_2: /* Latin-2 (Czech, Slovak) */ c = iso8859_2tab[c]; break; case I2CS_ISO8859_3: /* Latin-3 (Dutch, Turkish) */ c = iso8859_3tab[c]; break; case I2CS_ISO8859_4: /* Latin-4 (Scandinavian) */ c = iso8859_4tab[c]; break; case I2CS_ISO8859_5: /* Cyrillic */ c = iso8859_5tab[c]; break; case I2CS_ISO8859_6: /* Arabic */ c = iso8859_6tab[c]; break; case I2CS_ISO8859_7: /* Greek */ c = iso8859_7tab[c]; break; case I2CS_ISO8859_8: /* Hebrew */ c = iso8859_8tab[c]; break; case I2CS_ISO8859_9: /* Latin-5 (Finnish, Portuguese) */ c = iso8859_9tab[c]; break; case I2CS_TIS620: /* Thai */ c = tis620tab[c]; break; case I2CS_ISO8859_10: /* Latin-6 (Northern Europe) */ c = iso8859_10tab[c]; break; case I2CS_ISO8859_13: /* Latin-7 (Baltic) */ c = iso8859_13tab[c]; break; case I2CS_VSCII: /* Vietnamese */ c = visciitab[c]; break; case I2CS_ISO8859_14: /* Latin-8 (Celtic) */ c = iso8859_14tab[c]; break; case I2CS_ISO8859_15: /* Latin-9 (Euro) */ c = iso8859_15tab[c]; break; case I2CS_ISO8859_16: /* Latin-10 (Baltic) */ c = iso8859_16tab[c]; break; default: /* all other character sets */ /* multibyte character set */ if ((gi & I2CS_MUL) && !(c & BIT8) && isgraph (c)) { c = (i < text->size) ? text->data[i++] : 0; switch (gi) { #ifdef GBTOUNICODE case I2CS_GB: /* GB 2312 */ co |= BIT8; /* make into EUC */ c |= BIT8; c = GBTOUNICODE (co,c,ku,ten); break; #endif #ifdef JISTOUNICODE case I2CS_JIS_OLD:/* JIS X 0208-1978 */ case I2CS_JIS_NEW:/* JIS X 0208-1983 */ c = JISTOUNICODE (co,c,ku,ten); break; #endif #ifdef JIS0212TOUNICODE case I2CS_JIS_EXT:/* JIS X 0212-1990 */ c = JIS0212TOUNICODE (co,c,ku,ten); break; #endif #ifdef KSCTOUNICODE case I2CS_KSC: /* KSC 5601 */ co |= BIT8; /* make into EUC */ c |= BIT8; c = KSCTOUNICODE (co,c,ku,ten); break; #endif #ifdef CNS1TOUNICODE case I2CS_CNS1: /* CNS 11643 plane 1 */ c = CNS1TOUNICODE (co,c,ku,ten); break; #endif #ifdef CNS2TOUNICODE case I2CS_CNS2: /* CNS 11643 plane 2 */ c = CNS2TOUNICODE (co,c,ku,ten); break; #endif #ifdef CNS3TOUNICODE case I2CS_CNS3: /* CNS 11643 plane 3 */ c = CNS3TOUNICODE (co,c,ku,ten); break; #endif #ifdef CNS4TOUNICODE case I2CS_CNS4: /* CNS 11643 plane 4 */ c = CNS4TOUNICODE (co,c,ku,ten); break; #endif #ifdef CNS5TOUNICODE case I2CS_CNS5: /* CNS 11643 plane 5 */ c = CNS5TOUNICODE (co,c,ku,ten); break; #endif #ifdef CNS6TOUNICODE case I2CS_CNS6: /* CNS 11643 plane 6 */ c = CNS6TOUNICODE (co,c,ku,ten); break; #endif #ifdef CNS7TOUNICODE case I2CS_CNS7: /* CNS 11643 plane 7 */ c = CNS7TOUNICODE (co,c,ku,ten); break; #endif default: /* unknown multibyte, treat as UCS-2 */ c |= (co << 8); /* wrong, but nothing else to do */ break; } } else c = co; /* unknown single byte, treat as 8859-1 */ } /* convert if second pass */ if (pass) UTF8_WRITE_BMP (s,c,cv,de) else UTF8_COUNT_BMP (ret->size,c,cv,de); } } } if (!pass) (s = ret->data = (unsigned char *) fs_get (ret->size + 1))[ret->size] = NIL; else if (((unsigned long) (s - ret->data)) != ret->size) fatal ("ISO-2022 to UTF-8 botch"); } } /* Convert UTF-7 sized text to UTF-8 * Accepts: source sized text * pointer to returned sized text * canonicalization function */ void utf8_text_utf7 (SIZEDTEXT *text,SIZEDTEXT *ret,ucs4cn_t cv,ucs4de_t de) { unsigned long i; unsigned char *s; unsigned int c,c1,d,uc,pass,e,e1,state,surrh; for (pass = 0,s = NIL,ret->size = 0; pass <= 1; pass++) { c1 = d = uc = e = e1 = 0; for (i = 0,state = NIL; i < text->size;) { c = text->data[i++]; /* get next byte */ switch (state) { case U7_PLUS: /* previous character was + */ if (c == '-') { /* +- means textual + */ c = '+'; state = U7_ASCII; /* revert to ASCII */ break; } state = U7_UNICODE; /* enter Unicode state */ e = e1 = 0; /* initialize Unicode quantum position */ case U7_UNICODE: /* Unicode state */ if (c == '-') state = U7_MINUS; else { /* decode Unicode */ /* don't use isupper/islower since this is ASCII only */ if ((c >= 'A') && (c <= 'Z')) c -= 'A'; else if ((c >= 'a') && (c <= 'z')) c -= 'a' - 26; else if (isdigit (c)) c -= '0' - 52; else if (c == '+') c = 62; else if (c == '/') c = 63; else state = U7_ASCII;/* end of modified BASE64 */ } break; case U7_MINUS: /* previous character was absorbed - */ state = U7_ASCII; /* revert to ASCII */ case U7_ASCII: /* ASCII state */ if (c == '+') state = U7_PLUS; break; } switch (state) { /* store character if in character mode */ case U7_UNICODE: /* Unicode */ switch (e++) { /* install based on BASE64 state */ case 0: c1 = c << 2; /* byte 1: high 6 bits */ break; case 1: d = c1 | (c >> 4); /* byte 1: low 2 bits */ c1 = c << 4; /* byte 2: high 4 bits */ break; case 2: d = c1 | (c >> 2); /* byte 2: low 4 bits */ c1 = c << 6; /* byte 3: high 2 bits */ break; case 3: d = c | c1; /* byte 3: low 6 bits */ e = 0; /* reinitialize mechanism */ break; } if (e == 1) break; /* done if first BASE64 state */ if (!e1) { /* first byte of UCS-2 character */ uc = (d & 0xff) << 8; /* note first byte */ e1 = T; /* enter second UCS-2 state */ break; /* done */ } c = uc | (d & 0xff); /* build UCS-2 character */ e1 = NIL; /* back to first UCS-2 state, drop in */ /* surrogate pair? */ if ((c >= UTF16_SURR) && (c <= UTF16_MAXSURR)) { /* save high surrogate for later */ if (c < UTF16_SURRL) surrh = c; else c = UTF16_BASE + ((surrh & UTF16_MASK) << UTF16_SHIFT) + (c & UTF16_MASK); break; /* either way with surrogates, we're done */ } case U7_ASCII: /* just install if ASCII */ /* convert if second pass */ if (pass) UTF8_WRITE_BMP (s,c,cv,de) else UTF8_COUNT_BMP (ret->size,c,cv,de); } } if (!pass) (s = ret->data = (unsigned char *) fs_get (ret->size + 1))[ret->size] = NIL; else if (((unsigned long) (s - ret->data)) != ret->size) fatal ("UTF-7 to UTF-8 botch"); } } /* Convert UTF-8 sized text to UTF-8 * Accepts: source sized text * pointer to returned sized text * canonicalization function */ void utf8_text_utf8 (SIZEDTEXT *text,SIZEDTEXT *ret,ucs4cn_t cv,ucs4de_t de) { unsigned long i,c; unsigned char *s,*t; for (ret->size = 0, t = text->data, i = text->size; i;) { if ((c = utf8_get (&t,&i)) & U8G_ERROR) { ret->data = text->data; /* conversion failed */ ret->size = text->size; return; } UTF8_COUNT (ret->size,c,cv,de) } (s = ret->data = (unsigned char *) fs_get (ret->size + 1))[ret->size] =NIL; for (t = text->data, i = text->size; i;) { c = utf8_get (&t,&i); UTF8_WRITE (s,c,cv,de) /* convert UCS-4 to UTF-8 */ } if (((unsigned long) (s - ret->data)) != ret->size) fatal ("UTF-8 to UTF-8 botch"); } /* Convert UCS-2 sized text to UTF-8 * Accepts: source sized text * pointer to returned sized text * canonicalization function */ void utf8_text_ucs2 (SIZEDTEXT *text,SIZEDTEXT *ret,ucs4cn_t cv,ucs4de_t de) { unsigned long i; unsigned char *s,*t; unsigned int c; for (ret->size = 0, t = text->data, i = text->size / 2; i; --i) { c = *t++ << 8; c |= *t++; UTF8_COUNT_BMP (ret->size,c,cv,de); } (s = ret->data = (unsigned char *) fs_get (ret->size + 1))[ret->size] = NIL; for (t = text->data, i = text->size / 2; i; --i) { c = *t++ << 8; c |= *t++; UTF8_WRITE_BMP (s,c,cv,de) /* convert UCS-2 to UTF-8 */ } if (((unsigned long) (s - ret->data)) != ret->size) fatal ("UCS-2 to UTF-8 botch"); } /* Convert UCS-4 sized text to UTF-8 * Accepts: source sized text * pointer to returned sized text * canonicalization function */ void utf8_text_ucs4 (SIZEDTEXT *text,SIZEDTEXT *ret,ucs4cn_t cv,ucs4de_t de) { unsigned long i; unsigned char *s,*t; unsigned long c; for (ret->size = 0, t = text->data, i = text->size / 4; i; --i) { c = *t++ << 24; c |= *t++ << 16; c |= *t++ << 8; c |= *t++; UTF8_COUNT (ret->size,c,cv,de); } (s = ret->data = (unsigned char *) fs_get (ret->size + 1))[ret->size] = NIL; for (t = text->data, i = text->size / 2; i; --i) { c = *t++ << 24; c |= *t++ << 16; c |= *t++ << 8; c |= *t++; UTF8_WRITE (s,c,cv,de) /* convert UCS-4 to UTF-8 */ } if (((unsigned long) (s - ret->data)) != ret->size) fatal ("UCS-4 to UTF-8 botch"); } /* Convert UTF-16 sized text to UTF-8 * Accepts: source sized text * pointer to returned sized text * canonicalization function */ void utf8_text_utf16 (SIZEDTEXT *text,SIZEDTEXT *ret,ucs4cn_t cv,ucs4de_t de) { unsigned long i; unsigned char *s,*t; unsigned long c,d; for (ret->size = 0, t = text->data, i = text->size / 2; i; --i) { c = *t++ << 8; c |= *t++; /* possible surrogate? */ if ((c >= UTF16_SURR) && (c <= UTF16_MAXSURR)) { /* invalid first surrogate */ if ((c > UTF16_SURRHEND) || !i) c = UBOGON; else { /* get second surrogate */ d = *t++ << 8; d |= *t++; --i; /* swallowed another 16-bits */ /* invalid second surrogate */ if ((d < UTF16_SURRL) || (d > UTF16_SURRLEND)) c = UBOGON; else c = UTF16_BASE + ((c & UTF16_MASK) << UTF16_SHIFT) + (d & UTF16_MASK); } } UTF8_COUNT (ret->size,c,cv,de); } (s = ret->data = (unsigned char *) fs_get (ret->size + 1))[ret->size] = NIL; for (t = text->data, i = text->size / 2; i; --i) { c = *t++ << 8; c |= *t++; /* possible surrogate? */ if ((c >= UTF16_SURR) && (c <= UTF16_MAXSURR)) { /* invalid first surrogate */ if ((c > UTF16_SURRHEND) || !i) c = UBOGON; else { /* get second surrogate */ d = *t++ << 8; d |= *t++; --i; /* swallowed another 16-bits */ /* invalid second surrogate */ if ((d < UTF16_SURRL) || (d > UTF16_SURRLEND)) c = UBOGON; else c = UTF16_BASE + ((c & UTF16_MASK) << UTF16_SHIFT) + (d & UTF16_MASK); } } UTF8_WRITE (s,c,cv,de) /* convert UCS-4 to UTF-8 */ } if (((unsigned long) (s - ret->data)) != ret->size) fatal ("UTF-16 to UTF-8 botch"); } /* Size of UCS-4 character, possibly not in BMP, as UTF-8 octets * Accepts: character * Returns: size (0 means bogon) * * Use UTF8_SIZE macro if known to be in the BMP */ unsigned long utf8_size (unsigned long c) { if (c < 0x80) return 1; else if (c < 0x800) return 2; else if (c < 0x10000) return 3; else if (c < 0x200000) return 4; else if (c < 0x4000000) return 5; else if (c < 0x80000000) return 6; return 0; } /* Put UCS-4 character, possibly not in BMP, as UTF-8 octets * Accepts: destination string pointer * character * Returns: updated destination pointer * * Use UTF8_PUT_BMP macro if known to be in the BMP */ unsigned char *utf8_put (unsigned char *s,unsigned long c) { unsigned char mark[6] = {0x00,0xc0,0xe0,0xf0,0xf8,0xfc}; unsigned long size = utf8_size (c); switch (size) { case 6: s[5] = 0x80 | (unsigned char) (c & 0x3f); c >>= 6; case 5: s[4] = 0x80 | (unsigned char) (c & 0x3f); c >>= 6; case 4: s[3] = 0x80 | (unsigned char) (c & 0x3f); c >>= 6; case 3: s[2] = 0x80 | (unsigned char) (c & 0x3f); c >>= 6; case 2: s[1] = 0x80 | (unsigned char) (c & 0x3f); c >>= 6; case 1: *s = mark[size-1] | (unsigned char) (c & 0x7f); break; } return s + size; } /* Return title case of a fixed-width UCS-4 character * Accepts: character * Returns: title case of character */ unsigned long ucs4_titlecase (unsigned long c) { if (c <= UCS4_TMAPMAX) return ucs4_tmaptab[c]; if (c < UCS4_TMAPHIMIN) return c; if (c <= UCS4_TMAPHIMAX) return c - UCS4_TMAPHIMAP; if (c < UCS4_TMAPDESERETMIN) return c; if (c <= UCS4_TMAPDESERETMAX) return c - UCS4_TMAPDESERETMAP; return c; } /* Return width of a fixed-width UCS-4 character in planes 0-2 * Accepts: character * Returns: width (0, 1, 2) or negative error condition if not valid */ long ucs4_width (unsigned long c) { long ret; /* out of range, not-a-char, or surrogates */ if ((c > UCS4_MAXUNICODE) || ((c & 0xfffe) == 0xfffe) || ((c >= UTF16_SURR) && (c <= UTF16_MAXSURR))) ret = U4W_NOTUNCD; /* private-use */ else if (c >= UCS4_PVTBASE) ret = U4W_PRIVATE; /* SSP are not printing characters */ else if (c >= UCS4_SSPBASE) ret = U4W_SSPCHAR; /* unassigned planes */ else if (c >= UCS4_UNABASE) ret = U4W_UNASSGN; /* SIP and reserved plane 3 are wide */ else if (c >= UCS4_SIPBASE) ret = 2; #if (UCS4_WIDLEN != UCS4_SIPBASE) #error "UCS4_WIDLEN != UCS4_SIPBASE" #endif /* C0/C1 controls */ else if ((c <= UCS2_C0CONTROLEND) || ((c >= UCS2_C1CONTROL) && (c <= UCS2_C1CONTROLEND))) ret = U4W_CONTROL; /* BMP and SMP get value from table */ else switch (ret = (ucs4_widthtab[(c >> 2)] >> ((3 - (c & 0x3)) << 1)) &0x3){ case 0: /* zero-width */ if (c == 0x00ad) ret = 1; /* force U+00ad (SOFT HYPHEN) to width 1 */ case 1: /* single-width */ case 2: /* double-width */ break; case 3: /* ambiguous width */ ret = (c >= 0x2100) ? 2 : 1;/* need to do something better than this */ break; } return ret; } /* Return screen width of UTF-8 string * Accepts: string * Returns: width or negative if not valid UTF-8 */ long utf8_strwidth (unsigned char *s) { unsigned long c,i,ret; /* go through string */ for (ret = 0; *s; ret += ucs4_width (c)) { /* It's alright to give a fake value for the byte count to utf8_get() * since the null of a null-terminated string will stop processing anyway. */ i = 6; /* fake value */ if ((c = utf8_get (&s,&i)) & U8G_ERROR) return -1; } return ret; } /* Return screen width of UTF-8 text * Accepts: SIZEDTEXT to string * Returns: width or negative if not valid UTF-8 */ long utf8_textwidth (SIZEDTEXT *utf8) { unsigned long c; unsigned char *s = utf8->data; unsigned long i = utf8->size; unsigned long ret = 0; while (i) { /* while there's a string to process */ if ((c = utf8_get (&s,&i)) & U8G_ERROR) return -1; ret += ucs4_width (c); } return ret; } /* Decomposition (phew!) */ #define MORESINGLE 1 /* single UCS-4 tail value */ #define MOREMULTIPLE 2 /* multiple UCS-2 tail values */ struct decomposemore { short type; /* type of more */ union { unsigned long single; /* single decomposed value */ struct { /* multiple BMP values */ unsigned short *next; unsigned long count; } multiple; } data; }; #define RECURSIVEMORE struct recursivemore RECURSIVEMORE { struct decomposemore *more; RECURSIVEMORE *next; }; /* Return decomposition of a UCS-4 character * Accepts: character or U8G_ERROR to return next from "more" * pointer to returned more * Returns: [next] decomposed value, more set if still more decomposition */ unsigned long ucs4_decompose (unsigned long c,void **more) { unsigned long i,ix,ret; struct decomposemore *m; if (c & U8G_ERROR) { /* want to chase more? */ /* do sanity check */ if (m = (struct decomposemore *) *more) switch (m->type) { case MORESINGLE: /* single value */ ret = m->data.single; fs_give (more); /* no more decomposition */ break; case MOREMULTIPLE: /* multiple value */ ret = *m->data.multiple.next++; if (!--m->data.multiple.count) fs_give (more); break; default: /* uh-oh */ fatal ("invalid more block argument to ucs4_decompose!"); } else fatal ("no more block provided to ucs4_decompose!"); } else { /* start decomposition */ *more = NIL; /* initially set no more */ /* BMP low decompositions */ if (c < UCS4_BMPLOMIN) ret = c; /* fix this someday */ else if (c == UCS4_BMPLOMIN) ret = ucs4_dbmplotab[0]; else if (c <= UCS4_BMPLOMAX) { /* within range - have a decomposition? */ if (i = ucs4_dbmploixtab[c - UCS4_BMPLOMIN]) { /* get first value of decomposition */ ret = ucs4_dbmplotab[ix = i & UCS4_BMPLOIXMASK]; /* has continuation? */ if (i & UCS4_BMPLOSIZEMASK) { m = (struct decomposemore *) (*more = memset (fs_get (sizeof (struct decomposemore)),0, sizeof (struct decomposemore))); m->type = MOREMULTIPLE; m->data.multiple.next = &ucs4_dbmplotab[++ix]; m->data.multiple.count = i >> UCS4_BMPLOSIZESHIFT; } } else ret = c; /* in range but doesn't decompose */ } /* BMP CJK compatibility */ else if (c < UCS4_BMPCJKMIN) ret = c; else if (c <= UCS4_BMPCJKMAX) { if (!(ret = ucs4_bmpcjk1decomptab[c - UCS4_BMPCJKMIN])) ret = c; } /* BMP CJK compatibility - some not in BMP */ #if UCS4_BMPCJK2MIN - (UCS4_BMPCJKMAX + 1) else if (c < UCS4_BMPCJK2MIN) ret = c; #endif else if (c <= UCS4_BMPCJK2MAX) ret = ucs4_bmpcjk2decomptab[c - UCS4_BMPCJK2MIN]; /* BMP high decompositions */ else if (c < UCS4_BMPHIMIN) ret = c; else if (c <= UCS4_BMPHIMAX) { /* within range - have a decomposition? */ if (i = ucs4_dbmphiixtab[c - UCS4_BMPHIMIN]) { /* get first value of decomposition */ ret = ucs4_dbmphitab[ix = i & UCS4_BMPHIIXMASK]; /* has continuation? */ if (i & UCS4_BMPHISIZEMASK) { m = (struct decomposemore *) (*more = memset (fs_get (sizeof (struct decomposemore)),0, sizeof (struct decomposemore))); m->type = MOREMULTIPLE; m->data.multiple.next = &ucs4_dbmphitab[++ix]; m->data.multiple.count = i >> UCS4_BMPHISIZESHIFT; } } else ret = c; /* in range but doesn't decompose */ } /* BMP half and full width forms */ else if (c < UCS4_BMPHALFFULLMIN) ret = c; else if (c <= UCS4_BMPHALFFULLMAX) { if (!(ret = ucs4_bmphalffulldecomptab[c - UCS4_BMPHALFFULLMIN])) ret = c; } /* SMP music */ else if (c < UCS4_SMPMUSIC1MIN) ret = c; else if (c <= UCS4_SMPMUSIC1MAX) { ret = ucs4_smpmusic1decomptab[c -= UCS4_SMPMUSIC1MIN][0]; m = (struct decomposemore *) (*more = memset (fs_get (sizeof (struct decomposemore)),0, sizeof (struct decomposemore))); m->type = MORESINGLE; m->data.single = ucs4_smpmusic1decomptab[c][1]; } else if (c < UCS4_SMPMUSIC2MIN) ret = c; else if (c <= UCS4_SMPMUSIC2MAX) { ret = ucs4_smpmusic2decomptab[c -= UCS4_SMPMUSIC2MIN][0]; m = (struct decomposemore *) (*more = memset (fs_get (sizeof (struct decomposemore)),0, sizeof (struct decomposemore))); m->type = MORESINGLE; m->data.single = ucs4_smpmusic2decomptab[c][1]; } /* SMP mathematical forms */ else if (c < UCS4_SMPMATHMIN) ret = c; else if (c <= UCS4_SMPMATHMAX) { if (!(ret = ucs4_smpmathdecomptab[c - UCS4_SMPMATHMIN])) ret = c; } /* CJK compatibility ideographs in SIP */ else if (!(ret = ((c >= UCS4_SIPMIN) && (c <= UCS4_SIPMAX)) ? ucs4_sipdecomptab[c - UCS4_SIPMIN] : c)) ret = c; } return ret; } /* Return recursive decomposition of a UCS-4 character * Accepts: character or U8G_ERROR to return next from "more" * pointer to returned more * Returns: [next] decomposed value, more set if still more decomposition */ unsigned long ucs4_decompose_recursive (unsigned long c,void **more) { unsigned long c1; void *m,*mn; RECURSIVEMORE *mr; if (c & U8G_ERROR) { /* want to chase more? */ mn = NIL; if (mr = (RECURSIVEMORE *) *more) switch (mr->more->type) { case MORESINGLE: /* decompose single value */ c = ucs4_decompose_recursive (mr->more->data.single,&mn); *more = mr->next; /* done with this more, remove it */ fs_give ((void **) &mr->more); fs_give ((void **) &mr); break; case MOREMULTIPLE: /* decompose current value in multiple */ c = ucs4_decompose_recursive (*mr->more->data.multiple.next++,&mn); /* if done with this multiple decomposition */ if (!--mr->more->data.multiple.count) { *more = mr->next; /* done with this more, remove it */ fs_give ((void **) &mr->more); fs_give ((void **) &mr); } break; default: /* uh-oh */ fatal ("invalid more block argument to ucs4_decompose_recursive!"); } else fatal ("no more block provided to ucs4_decompose_recursive!"); if (mr = mn) { /* did this value recurse on us? */ mr->next = *more; /* yes, insert new more at head */ *more = mr; } } else { /* start decomposition */ *more = NIL; /* initially set no more */ mr = NIL; do { /* repeatedly decompose this codepoint */ c = ucs4_decompose (c1 = c,&m); if (m) { /* multi-byte decomposition */ if (c1 == c) fatal ("endless multiple decomposition!"); /* create a block to stash this more */ mr = memset (fs_get (sizeof (RECURSIVEMORE)),0,sizeof (RECURSIVEMORE)); mr->more = m; /* note the expansion */ mr->next = *more; /* old list is the tail */ *more = mr; /* and this is the new head */ } } while (c1 != c); /* until nothing more to decompose */ } return c; } alpine-2.10+dfsg/imap/src/c-client/auth_ext.c0000600000175000017500000000560011512502124022535 0ustar paulproteuspaulproteus/* ======================================================================== * Copyright 1988-2006 University of Washington * * Licensed under the Apache License, Version 2.0 (the "License"); * you may not use this file except in compliance with the License. * You may obtain a copy of the License at * * http://www.apache.org/licenses/LICENSE-2.0 * * * ======================================================================== */ /* * Program: EXTERNAL authenticator * * Author: Mark Crispin * Networks and Distributed Computing * Computing & Communications * University of Washington * Administration Building, AG-44 * Seattle, WA 98195 * Internet: MRC@CAC.Washington.EDU * * Date: 6 April 2005 * Last Edited: 30 August 2006 */ long auth_external_client (authchallenge_t challenger,authrespond_t responder, char *service,NETMBX *mb,void *stream, unsigned long *trial,char *user); char *auth_external_server (authresponse_t responder,int argc,char *argv[]); AUTHENTICATOR auth_ext = { /* secure, has full auth, hidden */ AU_SECURE | AU_AUTHUSER | AU_HIDE, "EXTERNAL", /* authenticator name */ NIL, /* always valid */ auth_external_client, /* client method */ auth_external_server, /* server method */ NIL /* next authenticator */ }; /* Client authenticator * Accepts: challenger function * responder function * SASL service name * parsed network mailbox structure * stream argument for functions * pointer to current trial count * returned user name * Returns: T if success, NIL otherwise, number of trials incremented if retry */ long auth_external_client (authchallenge_t challenger,authrespond_t responder, char *service,NETMBX *mb,void *stream, unsigned long *trial,char *user) { void *challenge; unsigned long clen; long ret = NIL; *trial = 65535; /* never retry */ if (challenge = (*challenger) (stream,&clen)) { fs_give ((void **) &challenge); /* send authorization id (empty string OK) */ if ((*responder) (stream,strcpy (user,mb->user),strlen (mb->user))) { if (challenge = (*challenger) (stream,&clen)) fs_give ((void **) &challenge); else ret = LONGT; /* check the authentication */ } } return ret; } /* Server authenticator * Accepts: responder function * argument count * argument vector * Returns: authenticated user name or NIL */ char *auth_external_server (authresponse_t responder,int argc,char *argv[]) { unsigned long len; char *authid; char *authenid = (char *) mail_parameters (NIL,GET_EXTERNALAUTHID,NIL); char *ret = NIL; /* get authorization identity */ if (authenid && (authid = (*responder) ("",0,&len))) { /* note: responders null-terminate */ if (*authid ? authserver_login (authid,authenid,argc,argv) : authserver_login (authenid,NIL,argc,argv)) ret = myusername (); fs_give ((void **) &authid); } return ret; } alpine-2.10+dfsg/imap/src/c-client/netmsg.c0000600000175000017500000000560611512502124022217 0ustar paulproteuspaulproteus/* ======================================================================== * Copyright 1988-2006 University of Washington * * Licensed under the Apache License, Version 2.0 (the "License"); * you may not use this file except in compliance with the License. * You may obtain a copy of the License at * * http://www.apache.org/licenses/LICENSE-2.0 * * * ======================================================================== */ /* * Program: Network message (SMTP/NNTP/POP2/POP3) routines * * Author: Mark Crispin * Networks and Distributed Computing * Computing & Communications * University of Washington * Administration Building, AG-44 * Seattle, WA 98195 * Internet: MRC@CAC.Washington.EDU * * Date: 8 June 1995 * Last Edited: 6 December 2006 */ #include #include extern int errno; /* just in case */ #include "c-client.h" #include "netmsg.h" #include "flstring.h" /* Network message read * Accepts: file * number of bytes to read * buffer address * Returns: T if success, NIL otherwise */ long netmsg_read (void *stream,unsigned long count,char *buffer) { return (fread (buffer,(size_t) 1,(size_t) count,(FILE *) stream) == count) ? T : NIL; } /* Slurp dot-terminated text from NET * Accepts: NET stream * place to return size * place to return header size * Returns: file descriptor */ FILE *netmsg_slurp (NETSTREAM *stream,unsigned long *size,unsigned long *hsiz) { unsigned long i; char *s,*t,tmp[MAILTMPLEN]; FILE *f = tmpfile (); if (!f) { sprintf (tmp,".%lx.%lx",(unsigned long) time (0),(unsigned long)getpid ()); if (f = fopen (tmp,"wb+")) unlink (tmp); else { sprintf (tmp,"Unable to create scratch file: %.80s",strerror (errno)); MM_LOG (tmp,ERROR); return NIL; } } *size = 0; /* initially emtpy */ if (hsiz) *hsiz = 0; while (s = net_getline (stream)) { if (*s == '.') { /* possible end of text? */ if (s[1]) t = s + 1; /* pointer to true start of line */ else { fs_give ((void **) &s); /* free the line */ break; /* end of data */ } } else t = s; /* want the entire line */ if (f) { /* copy it to the file */ i = strlen (t); /* size of line */ if ((fwrite (t,(size_t) 1,(size_t) i,f) == i) && (fwrite ("\015\012",(size_t) 1,(size_t) 2,f) == 2)) { *size += i + 2; /* tally up size of data */ /* note header position */ if (!i && hsiz && !*hsiz) *hsiz = *size; } else { sprintf (tmp,"Error writing scratch file at byte %lu",*size); MM_LOG (tmp,ERROR); fclose (f); /* forget it */ f = NIL; /* failure now */ } } fs_give ((void **) &s); /* free the line */ } /* if making a file, rewind to start of file */ if (f) fseek (f,(unsigned long) 0,SEEK_SET); /* header consumes entire message */ if (hsiz && !*hsiz) *hsiz = *size; return f; /* return the file descriptor */ } alpine-2.10+dfsg/imap/src/c-client/newsrc.h0000600000175000017500000000271611512502124022227 0ustar paulproteuspaulproteus/* ======================================================================== * Copyright 1988-2006 University of Washington * * Licensed under the Apache License, Version 2.0 (the "License"); * you may not use this file except in compliance with the License. * You may obtain a copy of the License at * * http://www.apache.org/licenses/LICENSE-2.0 * * * ======================================================================== */ /* * Program: Newsrc manipulation routines * * Author: Mark Crispin * Networks and Distributed Computing * Computing & Communications * University of Washington * Administration Building, AG-44 * Seattle, WA 98195 * Internet: MRC@CAC.Washington.EDU * * Date: 12 September 1994 * Last Edited: 30 August 2006 */ /* Function prototypes */ long newsrc_error (char *fmt,char *text,long errflg); long newsrc_write_error (char *name,FILE *f1,FILE *f2); FILE *newsrc_create (MAILSTREAM *stream,int notify); long newsrc_newstate (FILE *f,char *group,char state,char *nl); long newsrc_newmessages (FILE *f,MAILSTREAM *stream,char *nl); void newsrc_lsub (MAILSTREAM *stream,char *pattern); long newsrc_update (MAILSTREAM *stream,char *group,char state); long newsrc_read (char *group,MAILSTREAM *stream); long newsrc_write (char *group,MAILSTREAM *stream); char *newsrc_state (MAILSTREAM *stream,char *group); void newsrc_check_uid (unsigned char *state,unsigned long uid, unsigned long *recent,unsigned long *unseen); alpine-2.10+dfsg/imap/src/c-client/nl.h0000600000175000017500000000165311512502124021336 0ustar paulproteuspaulproteus/* ======================================================================== * Copyright 1988-2006 University of Washington * * Licensed under the Apache License, Version 2.0 (the "License"); * you may not use this file except in compliance with the License. * You may obtain a copy of the License at * * http://www.apache.org/licenses/LICENSE-2.0 * * * ======================================================================== */ /* * Program: Newline routines * * Author: Mark Crispin * Networks and Distributed Computing * Computing & Communications * University of Washington * Administration Building, AG-44 * Seattle, WA 98195 * Internet: MRC@CAC.Washington.EDU * * Date: 1 August 1988 * Last Edited: 30 August 2006 */ /* Function prototypes */ unsigned long strcrlfcpy (unsigned char **dst,unsigned long *dstl, unsigned char *src,unsigned long srcl); unsigned long strcrlflen (STRING *s); alpine-2.10+dfsg/imap/src/c-client/fs.h0000600000175000017500000000161111512502124021327 0ustar paulproteuspaulproteus/* ======================================================================== * Copyright 1988-2006 University of Washington * * Licensed under the Apache License, Version 2.0 (the "License"); * you may not use this file except in compliance with the License. * You may obtain a copy of the License at * * http://www.apache.org/licenses/LICENSE-2.0 * * * ======================================================================== */ /* * Program: Free storage management routines * * Author: Mark Crispin * Networks and Distributed Computing * Computing & Communications * University of Washington * Administration Building, AG-44 * Seattle, WA 98195 * Internet: MRC@CAC.Washington.EDU * * Date: 1 August 1988 * Last Edited: 30 August 2006 */ /* Function prototypes */ void *fs_get (size_t size); void fs_resize (void **block,size_t size); void fs_give (void **block); alpine-2.10+dfsg/imap/src/c-client/imap4r1.h0000600000175000017500000002001211512502124022170 0ustar paulproteuspaulproteus/* ======================================================================== * Copyright 1988-2007 University of Washington * * Licensed under the Apache License, Version 2.0 (the "License"); * you may not use this file except in compliance with the License. * You may obtain a copy of the License at * * http://www.apache.org/licenses/LICENSE-2.0 * * * ======================================================================== */ /* * Program: Interactive Mail Access Protocol 4rev1 (IMAP4R1) routines * * Author: Mark Crispin * Networks and Distributed Computing * Computing & Communications * University of Washington * Administration Building, AG-44 * Seattle, WA 98195 * Internet: MRC@CAC.Washington.EDU * * Date: 14 October 1988 * Last Edited: 5 September 2007 */ /* This include file is provided for applications which need to look under * the covers at the IMAP driver and in particular want to do different * operations depending upon the IMAP server's protocol level and * capabilities. It is NOT included in the normal c-client.h application * export, and most applications do NOT need the definitions in this file. * * As of October 15, 2003, it is believed that: * * Version RFC Status Known Implementations * ------- --- ------ --------------------- * IMAP1 none extinct experimental TOPS-20 server * IMAP2 1064 extinct old TOPS-20, SUMEX servers * IMAP2 1176 rare TOPS-20, old UW servers * IMAP2bis expired I-D uncommon old UW, Cyrus servers * IMAP3 1203 extinct none (never implemented) * IMAP4 1730 rare old UW, Cyrus, Netscape servers * IMAP4rev1 2060, 3501 ubiquitous UW, Cyrus, and many others * * Most client implementations will only interoperate with an IMAP4rev1 * server. c-client based client implementations can interoperate with IMAP2, * IMAP2bis, IMAP4, and IMAP4rev1 servers, but only if they are very careful. * * The LEVELxxx() macros in this file enable the client to determine the * server protocol level and capabilities. This file also contains a few * backdoor calls into the IMAP driver. */ /* Server protocol level and capabilities */ typedef struct imap_cap { unsigned int rfc1176 : 1; /* server is RFC-1176 IMAP2 */ unsigned int imap2bis : 1; /* server is IMAP2bis */ unsigned int imap4 : 1; /* server is IMAP4 (RFC 1730) */ unsigned int imap4rev1 : 1; /* server is IMAP4rev1 */ unsigned int acl : 1; /* server has ACL (RFC 2086) */ unsigned int quota : 1; /* server has QUOTA (RFC 2087) */ unsigned int litplus : 1; /* server has LITERAL+ (RFC 2088) */ unsigned int idle : 1; /* server has IDLE (RFC 2177) */ unsigned int mbx_ref : 1; /* server has mailbox referrals (RFC 2193) */ unsigned int log_ref : 1; /* server has login referrals (RFC 2221) */ unsigned int authanon : 1; /* server has anonymous SASL (RFC 2245) */ unsigned int namespace :1; /* server has NAMESPACE (RFC 2342) */ unsigned int uidplus : 1; /* server has UIDPLUS (RFC 2359) */ unsigned int starttls : 1; /* server has STARTTLS (RFC 2595) */ /* server disallows LOGIN command (RFC 2595) */ unsigned int logindisabled : 1; unsigned int id : 1; /* server has ID (RFC 2971) */ unsigned int children : 1; /* server has CHILDREN (RFC 3348) */ unsigned int multiappend : 1; /* server has multi-APPEND (RFC 3502) ;*/ unsigned int binary : 1; /* server has BINARY (RFC 3516) */ unsigned int unselect : 1; /* server has UNSELECT */ unsigned int sasl_ir : 1; /* server has SASL-IR initial response */ unsigned int sort : 1; /* server has SORT */ unsigned int scan : 1; /* server has SCAN */ unsigned int urlauth : 1; /* server has URLAUTH (RFC 4467) */ unsigned int catenate : 1; /* server has CATENATE (RFC 4469) */ unsigned int condstore : 1; /* server has CONDSTORE (RFC 4551) */ unsigned int esearch : 1; /* server has ESEARCH (RFC 4731) */ unsigned int within : 1; /* server has WITHIN (RFC 5032) */ unsigned int extlevel; /* extension data level supported by server */ /* supported authenticators */ unsigned int auth : MAXAUTHENTICATORS; THREADER *threader; /* list of threaders */ } IMAPCAP; /* IMAP4rev1 level or better */ #define LEVELIMAP4rev1(stream) imap_cap (stream)->imap4rev1 #define LEVELSTATUS LEVELIMAP4rev1 /* IMAP4 level or better (not including RFC 1730 design mistakes) */ #define LEVELIMAP4(stream) (imap_cap (stream)->imap4rev1 || \ imap_cap (stream)->imap4) /* IMAP4 RFC-1730 level */ #define LEVEL1730(stream) imap_cap (stream)->imap4 /* IMAP2bis level or better */ #define LEVELIMAP2bis(stream) imap_cap (stream)->imap2bis /* IMAP2 RFC-1176 level or better */ #define LEVEL1176(stream) imap_cap (stream)->rfc1176 /* IMAP2 RFC-1064 or better */ #define LEVEL1064(stream) 1 /* Has ACL extension */ #define LEVELACL(stream) imap_cap (stream)->acl /* Has QUOTA extension */ #define LEVELQUOTA(stream) imap_cap (stream)->quota /* Has LITERALPLUS extension */ #define LEVELLITERALPLUS(stream) imap_cap (stream)->litplus /* Has IDLE extension */ #define LEVELIDLE(stream) imap_cap (stream)->idle /* Has mailbox referrals */ #define LEVELMBX_REF(stream) imap_cap (stream)->mbx_ref /* Has login referrals */ #define LEVELLOG_REF(stream) imap_cap (stream)->log_ref /* Has AUTH=ANONYMOUS extension */ #define LEVELANONYMOUS(stream) imap_cap (stream)->authanon /* Has NAMESPACE extension */ #define LEVELNAMESPACE(stream) imap_cap (stream)->namespace /* Has UIDPLUS extension */ #define LEVELUIDPLUS(stream) imap_cap (stream)->uidplus /* Has STARTTLS extension */ #define LEVELSTARTTLS(stream) imap_cap (stream)->starttls /* Has LOGINDISABLED extension */ #define LEVELLOGINDISABLED(stream) imap_cap (stream)->logindisabled /* Has ID extension */ #define LEVELID(stream) imap_cap (stream)->id /* Has CHILDREN extension */ #define LEVELCHILDREN(stream) imap_cap (stream)->children /* Has MULTIAPPEND extension */ #define LEVELMULTIAPPEND(stream) imap_cap (stream)->multiappend /* Has BINARY extension */ #define LEVELBINARY(stream) imap_cap (stream)->binary /* Has UNSELECT extension */ #define LEVELUNSELECT(stream) imap_cap (stream)->unselect /* Has SASL initial response extension */ #define LEVELSASLIR(stream) imap_cap (stream)->sasl_ir /* Has SORT extension */ #define LEVELSORT(stream) imap_cap (stream)->sort /* Has at least one THREAD extension */ #define LEVELTHREAD(stream) ((imap_cap (stream)->threader) ? T : NIL) /* Has SCAN extension */ #define LEVELSCAN(stream) imap_cap (stream)->scan /* Has URLAUTH extension */ #define LEVELURLAUTH(stream) imap_cap (stream)->urlauth /* Has CATENATE extension */ #define LEVELCATENATE(stream) imap_cap (stream)->catenate /* Has CONDSTORE extension */ #define LEVELCONDSTORE(stream) imap_cap (stream)->condstore /* Has ESEARCH extension */ #define LEVELESEARCH(stream) imap_cap (stream)->esearch /* Has WITHIN extension */ #define LEVELWITHIN(stream) imap_cap (stream)->within /* Body structure extension levels */ /* These are in BODYSTRUCTURE order. Note that multipart bodies do not have * body-fld-md5. This is alright, since all subsequent body structure * extensions are in both singlepart and multipart bodies. If that ever * changes, this will have to be split. */ #define BODYEXTMD5 1 /* body-fld-md5 */ #define BODYEXTDSP 2 /* body-fld-dsp */ #define BODYEXTLANG 3 /* body-fld-lang */ #define BODYEXTLOC 4 /* body-fld-loc */ /* Function prototypes */ IMAPCAP *imap_cap (MAILSTREAM *stream); char *imap_host (MAILSTREAM *stream); long imap_cache (MAILSTREAM *stream,unsigned long msgno,char *seg, STRINGLIST *stl,SIZEDTEXT *text); /* Temporary */ long imap_setacl (MAILSTREAM *stream,char *mailbox,char *id,char *rights); long imap_deleteacl (MAILSTREAM *stream,char *mailbox,char *id); long imap_getacl (MAILSTREAM *stream,char *mailbox); long imap_listrights (MAILSTREAM *stream,char *mailbox,char *id); long imap_myrights (MAILSTREAM *stream,char *mailbox); long imap_setquota (MAILSTREAM *stream,char *qroot,STRINGLIST *limits); long imap_getquota (MAILSTREAM *stream,char *qroot); long imap_getquotaroot (MAILSTREAM *stream,char *mailbox); alpine-2.10+dfsg/imap/src/c-client/rfc822.h0000600000175000017500000001245511512502124021735 0ustar paulproteuspaulproteus/* ======================================================================== * Copyright 1988-2006 University of Washington * * Licensed under the Apache License, Version 2.0 (the "License"); * you may not use this file except in compliance with the License. * You may obtain a copy of the License at * * http://www.apache.org/licenses/LICENSE-2.0 * * * ======================================================================== */ /* * Program: RFC 2822 and MIME routines * * Author: Mark Crispin * Networks and Distributed Computing * Computing & Communications * University of Washington * Administration Building, AG-44 * Seattle, WA 98195 * Internet: MRC@CAC.Washington.EDU * * Date: 27 July 1988 * Last Edited: 30 August 2006 * * This original version of this file is * Copyright 1988 Stanford University * and was developed in the Symbolic Systems Resources Group of the Knowledge * Systems Laboratory at Stanford University in 1987-88, and was funded by the * Biomedical Research Technology Program of the NationalInstitutes of Health * under grant number RR-00785. */ #define MAXGROUPDEPTH 50 /* RFC [2]822 doesn't allow any group nesting */ #define MAXMIMEDEPTH 50 /* more than any sane MIMEgram */ /* Output buffering for RFC [2]822 */ typedef long (*soutr_t) (void *stream,char *string); typedef long (*rfc822out_t) (char *tmp,ENVELOPE *env,BODY *body,soutr_t f, void *s,long ok8bit); typedef struct rfc822buffer { soutr_t f; /* I/O flush routine */ void *s; /* stream for I/O routine */ char *beg; /* start of buffer */ char *cur; /* current buffer pointer */ char *end; /* end of buffer */ } RFC822BUFFER; typedef long (*rfc822outfull_t) (RFC822BUFFER *buf,ENVELOPE *env,BODY *body, long ok8bit); /* Function prototypes */ char *rfc822_default_subtype (unsigned short type); void rfc822_parse_msg_full (ENVELOPE **en,BODY **bdy,char *s,unsigned long i, STRING *bs,char *host,unsigned long depth, unsigned long flags); void rfc822_parse_content (BODY *body,STRING *bs,char *h,unsigned long depth, unsigned long flags); void rfc822_parse_content_header (BODY *body,char *name,char *s); void rfc822_parse_parameter (PARAMETER **par,char *text); void rfc822_parse_adrlist (ADDRESS **lst,char *string,char *host); ADDRESS *rfc822_parse_address (ADDRESS **lst,ADDRESS *last,char **string, char *defaulthost,unsigned long depth); ADDRESS *rfc822_parse_group (ADDRESS **lst,ADDRESS *last,char **string, char *defaulthost,unsigned long depth); ADDRESS *rfc822_parse_mailbox (char **string,char *defaulthost); long rfc822_phraseonly (char *end); ADDRESS *rfc822_parse_routeaddr (char *string,char **ret,char *defaulthost); ADDRESS *rfc822_parse_addrspec (char *string,char **ret,char *defaulthost); char *rfc822_parse_domain (char *string,char **end); char *rfc822_parse_phrase (char *string); char *rfc822_parse_word (char *string,const char *delimiters); char *rfc822_cpy (char *src); char *rfc822_quote (char *src); ADDRESS *rfc822_cpy_adr (ADDRESS *adr); void rfc822_skipws (char **s); char *rfc822_skip_comment (char **s,long trim); long rfc822_output_full (RFC822BUFFER *buf,ENVELOPE *env,BODY *body,long ok8); long rfc822_output_flush (RFC822BUFFER *buf); long rfc822_output_header (RFC822BUFFER *buf,ENVELOPE *env,BODY *body, const char *specials,long flags); long rfc822_output_header_line (RFC822BUFFER *buf,char *type,long resent, char *text); long rfc822_output_address_line (RFC822BUFFER *buf,char *type,long resent, ADDRESS *adr,const char *specials); long rfc822_output_address_list (RFC822BUFFER *buf,ADDRESS *adr,long pretty, const char *specials); long rfc822_output_address (RFC822BUFFER *buf,ADDRESS *adr); long rfc822_output_cat (RFC822BUFFER *buf,char *src,const char *specials); long rfc822_output_parameter (RFC822BUFFER *buf,PARAMETER *param); long rfc822_output_stringlist (RFC822BUFFER *buf,STRINGLIST *stl); long rfc822_output_body_header (RFC822BUFFER *buf,BODY *body); void rfc822_encode_body_7bit (ENVELOPE *env,BODY *body); void rfc822_encode_body_8bit (ENVELOPE *env,BODY *body); long rfc822_output_text (RFC822BUFFER *buf,BODY *body); void *rfc822_base64 (unsigned char *src,unsigned long srcl,unsigned long *len); unsigned char *rfc822_binary (void *src,unsigned long srcl,unsigned long *len); unsigned char *rfc822_qprint (unsigned char *src,unsigned long srcl, unsigned long *len); unsigned char *rfc822_8bit (unsigned char *src,unsigned long srcl, unsigned long *len); /* Legacy routines for compatibility with the past */ void rfc822_header (char *header,ENVELOPE *env,BODY *body); void rfc822_header_line (char **header,char *type,ENVELOPE *env,char *text); void rfc822_address_line (char **header,char *type,ENVELOPE *env,ADDRESS *adr); char *rfc822_write_address_full (char *dest,ADDRESS *adr,char *base); void rfc822_address (char *dest,ADDRESS *adr); void rfc822_cat (char *dest,char *src,const char *specials); void rfc822_write_body_header (char **header,BODY *body); long rfc822_output (char *t,ENVELOPE *env,BODY *body,soutr_t f,void *s, long ok8bit); long rfc822_output_body (BODY *body,soutr_t f,void *s); #define rfc822_write_address(dest,adr) \ rfc822_write_address_full (dest,adr,NIL) #define rfc822_parse_msg(en,bdy,s,i,bs,host,flags) \ rfc822_parse_msg_full (en,bdy,s,i,bs,host,0,flags) alpine-2.10+dfsg/imap/src/c-client/smtp.h0000600000175000017500000000475211512502124021713 0ustar paulproteuspaulproteus/* ======================================================================== * Copyright 1988-2007 University of Washington * * Licensed under the Apache License, Version 2.0 (the "License"); * you may not use this file except in compliance with the License. * You may obtain a copy of the License at * * http://www.apache.org/licenses/LICENSE-2.0 * * * ======================================================================== */ /* * Program: Simple Mail Transfer Protocol (SMTP) routines * * Author: Mark Crispin * Networks and Distributed Computing * Computing & Communications * University of Washington * Administration Building, AG-44 * Seattle, WA 98195 * Internet: MRC@CAC.Washington.EDU * * Date: 27 July 1988 * Last Edited: 15 August 2007 * * This original version of this file is * Copyright 1988 Stanford University * and was developed in the Symbolic Systems Resources Group of the Knowledge * Systems Laboratory at Stanford University in 1987-88, and was funded by the * Biomedical Research Technology Program of the NationalInstitutes of Health * under grant number RR-00785. */ /* Constants (should be in smtp.c) */ #define SMTPTCPPORT (long) 25 /* assigned TCP contact port */ #define SUBMITTCPPORT (long) 587/* assigned TCP contact port */ /* SMTP open options * For compatibility with the past, SOP_DEBUG must always be 1. */ #define SOP_DEBUG (long) 1 /* debug protocol negotiations */ #define SOP_DSN (long) 2 /* DSN requested */ /* DSN notification, none set mean NEVER */ #define SOP_DSN_NOTIFY_FAILURE (long) 4 #define SOP_DSN_NOTIFY_DELAY (long) 8 #define SOP_DSN_NOTIFY_SUCCESS (long) 16 /* DSN return full msg vs. header */ #define SOP_DSN_RETURN_FULL (long) 32 #define SOP_8BITMIME (long) 64 /* 8-bit MIME requested */ #define SOP_SECURE (long) 256 /* don't do non-secure authentication */ #define SOP_TRYSSL (long) 512 /* try SSL first */ #define SOP_TRYALT SOP_TRYSSL /* old name */ /* reserved for application use */ #define SOP_RESERVED (unsigned long) 0xff000000 /* Compatibility support names */ #define smtp_open(hostlist,options) \ smtp_open_full (NIL,hostlist,"smtp",NIL,options) /* Function prototypes */ void *smtp_parameters (long function,void *value); SENDSTREAM *smtp_open_full (NETDRIVER *dv,char **hostlist,char *service, unsigned long port,long options); SENDSTREAM *smtp_close (SENDSTREAM *stream); long smtp_mail (SENDSTREAM *stream,char *type,ENVELOPE *msg,BODY *body); long smtp_verbose (SENDSTREAM *stream); alpine-2.10+dfsg/imap/src/c-client/netmsg.h0000600000175000017500000000173311512502124022221 0ustar paulproteuspaulproteus/* ======================================================================== * Copyright 1988-2006 University of Washington * * Licensed under the Apache License, Version 2.0 (the "License"); * you may not use this file except in compliance with the License. * You may obtain a copy of the License at * * http://www.apache.org/licenses/LICENSE-2.0 * * * ======================================================================== */ /* * Program: Network message (SMTP/NNTP/POP2/POP3) routines * * Author: Mark Crispin * Networks and Distributed Computing * Computing & Communications * University of Washington * Administration Building, AG-44 * Seattle, WA 98195 * Internet: MRC@CAC.Washington.EDU * * Date: 8 June 1995 * Last Edited: 30 August 2006 */ /* stream must be void* for use as readfn_t */ long netmsg_read (void *stream,unsigned long count,char *buffer); FILE *netmsg_slurp (NETSTREAM *stream,unsigned long *size,unsigned long *hsiz); alpine-2.10+dfsg/imap/src/c-client/misc.h0000600000175000017500000000642711512502124021664 0ustar paulproteuspaulproteus/* ======================================================================== * Copyright 1988-2006 University of Washington * * Licensed under the Apache License, Version 2.0 (the "License"); * you may not use this file except in compliance with the License. * You may obtain a copy of the License at * * http://www.apache.org/licenses/LICENSE-2.0 * * * ======================================================================== */ /* * Program: Miscellaneous utility routines * * Author: Mark Crispin * Networks and Distributed Computing * Computing & Communications * University of Washington * Administration Building, AG-44 * Seattle, WA 98195 * Internet: MRC@CAC.Washington.EDU * * Date: 5 July 1988 * Last Edited: 30 August 2006 * * This original version of this file is * Copyright 1988 Stanford University * and was developed in the Symbolic Systems Resources Group of the Knowledge * Systems Laboratory at Stanford University in 1987-88, and was funded by the * Biomedical Research Technology Program of the NationalInstitutes of Health * under grant number RR-00785. */ /* Hash table operations */ #define HASHMULT 29 /* hash polynomial multiplier */ #define HASHENT struct hash_entry HASHENT { HASHENT *next; /* next entry with same hash code */ char *name; /* name of this hash entry */ void *data[1]; /* data of this hash entry */ }; #define HASHTAB struct hash_table HASHTAB { size_t size; /* size of this table */ HASHENT *table[1]; /* table */ }; /* KLUDGE ALERT!!! * * Yes, write() is overridden here instead of in osdep. This * is because misc.h is one of the last files that most things #include, so * this should avoid problems with some system #include file. */ #define write safe_write /* Some C compilers have these as macros */ #undef min #undef max /* And some C libraries have these as int functions */ #define min Min #define max Max /* Compatibility definitions */ #define pmatch(s,pat) \ pmatch_full (s,pat,NIL) /* Function prototypes */ unsigned char *ucase (unsigned char *string); unsigned char *lcase (unsigned char *string); char *cpystr (const char *string); char *cpytxt (SIZEDTEXT *dst,char *text,unsigned long size); char *textcpy (SIZEDTEXT *dst,SIZEDTEXT *src); char *textcpystring (SIZEDTEXT *text,STRING *bs); char *textcpyoffstring (SIZEDTEXT *text,STRING *bs,unsigned long offset, unsigned long size); unsigned long find_rightmost_bit (unsigned long *valptr); long min (long i,long j); long max (long i,long j); long search (unsigned char *base,long basec,unsigned char *pat,long patc); long ssearch (unsigned char *base,long basec,unsigned char *pat,long patc); HASHTAB *hash_create (size_t size); void hash_destroy (HASHTAB **hashtab); void hash_reset (HASHTAB *hashtab); unsigned long hash_index (HASHTAB *hashtab,char *key); void **hash_lookup (HASHTAB *hashtab,char *key); HASHENT *hash_add (HASHTAB *hashtab,char *key,void *data,long extra); void **hash_lookup_and_add (HASHTAB *hashtab,char *key,void *data,long extra); unsigned char hex2byte (unsigned char c1,unsigned char c2); int compare_ulong (unsigned long l1,unsigned long l2); int compare_uchar (unsigned char c1,unsigned char c2); int compare_cstring (unsigned char *s1,unsigned char *s2); int compare_csizedtext (unsigned char *s1,SIZEDTEXT *s2); alpine-2.10+dfsg/imap/src/c-client/sslio.h0000600000175000017500000000440511512502124022054 0ustar paulproteuspaulproteus/* ======================================================================== * Copyright 1988-2006 University of Washington * * Licensed under the Apache License, Version 2.0 (the "License"); * you may not use this file except in compliance with the License. * You may obtain a copy of the License at * * http://www.apache.org/licenses/LICENSE-2.0 * * * ======================================================================== */ /* * Program: SSL routines * * Author: Mark Crispin * Networks and Distributed Computing * Computing & Communications * University of Washington * Administration Building, AG-44 * Seattle, WA 98195 * Internet: MRC@CAC.Washington.EDU * * Date: 7 February 2001 * Last Edited: 30 August 2006 */ /* SSL driver */ struct ssl_driver { /* must parallel NETDRIVER in mail.h */ SSLSTREAM *(*open) (char *host,char *service,unsigned long port); SSLSTREAM *(*aopen) (NETMBX *mb,char *service,char *usrbuf); char *(*getline) (SSLSTREAM *stream); long (*getbuffer) (SSLSTREAM *stream,unsigned long size,char *buffer); long (*soutr) (SSLSTREAM *stream,char *string); long (*sout) (SSLSTREAM *stream,char *string,unsigned long size); void (*close) (SSLSTREAM *stream); char *(*host) (SSLSTREAM *stream); char *(*remotehost) (SSLSTREAM *stream); unsigned long (*port) (SSLSTREAM *stream); char *(*localhost) (SSLSTREAM *stream); }; /* SSL stdio stream */ typedef struct ssl_stdiostream { SSLSTREAM *sslstream; /* SSL stream */ int octr; /* output counter */ char *optr; /* output pointer */ char obuf[SSLBUFLEN]; /* output buffer */ } SSLSTDIOSTREAM; /* Function prototypes */ SSLSTREAM *ssl_open (char *host,char *service,unsigned long port); SSLSTREAM *ssl_aopen (NETMBX *mb,char *service,char *usrbuf); char *ssl_getline (SSLSTREAM *stream); long ssl_getbuffer (SSLSTREAM *stream,unsigned long size,char *buffer); long ssl_getdata (SSLSTREAM *stream); long ssl_soutr (SSLSTREAM *stream,char *string); long ssl_sout (SSLSTREAM *stream,char *string,unsigned long size); void ssl_close (SSLSTREAM *stream); char *ssl_host (SSLSTREAM *stream); char *ssl_remotehost (SSLSTREAM *stream); unsigned long ssl_port (SSLSTREAM *stream); char *ssl_localhost (SSLSTREAM *stream); long ssl_server_input_wait (long seconds); alpine-2.10+dfsg/imap/src/c-client/misc.c0000600000175000017500000003253311512502124021654 0ustar paulproteuspaulproteus/* ======================================================================== * Copyright 1988-2006 University of Washington * * Licensed under the Apache License, Version 2.0 (the "License"); * you may not use this file except in compliance with the License. * You may obtain a copy of the License at * * http://www.apache.org/licenses/LICENSE-2.0 * * * ======================================================================== */ /* * Program: Miscellaneous utility routines * * Author: Mark Crispin * Networks and Distributed Computing * Computing & Communications * University of Washington * Administration Building, AG-44 * Seattle, WA 98195 * Internet: MRC@CAC.Washington.EDU * * Date: 5 July 1988 * Last Edited: 6 December 2006 * * This original version of this file is * Copyright 1988 Stanford University * and was developed in the Symbolic Systems Resources Group of the Knowledge * Systems Laboratory at Stanford University in 1987-88, and was funded by the * Biomedical Research Technology Program of the NationalInstitutes of Health * under grant number RR-00785. */ #include #include "c-client.h" /* Convert ASCII string to all uppercase * Accepts: string pointer * Returns: string pointer * * Don't use islower/toupper since this function must be ASCII only. */ unsigned char *ucase (unsigned char *s) { unsigned char *t; /* if lowercase covert to upper */ for (t = s; *t; t++) if ((*t >= 'a') && (*t <= 'z')) *t -= ('a' - 'A'); return s; /* return string */ } /* Convert string to all lowercase * Accepts: string pointer * Returns: string pointer * * Don't use isupper/tolower since this function must be ASCII only. */ unsigned char *lcase (unsigned char *s) { unsigned char *t; /* if uppercase covert to lower */ for (t = s; *t; t++) if ((*t >= 'A') && (*t <= 'Z')) *t += ('a' - 'A'); return s; /* return string */ } /* Copy string to free storage * Accepts: source string * Returns: free storage copy of string */ char *cpystr (const char *string) { return string ? strcpy ((char *) fs_get (1 + strlen (string)),string) : NIL; } /* Copy text/size to free storage as sized text * Accepts: destination sized text * pointer to source text * size of source text * Returns: text as a char * */ char *cpytxt (SIZEDTEXT *dst,char *text,unsigned long size) { /* flush old space */ if (dst->data) fs_give ((void **) &dst->data); /* copy data in sized text */ memcpy (dst->data = (unsigned char *) fs_get ((size_t) (dst->size = size) + 1),text,(size_t) size); dst->data[size] = '\0'; /* tie off text */ return (char *) dst->data; /* convenience return */ } /* Copy sized text to free storage as sized text * Accepts: destination sized text * source sized text * Returns: text as a char * */ char *textcpy (SIZEDTEXT *dst,SIZEDTEXT *src) { /* flush old space */ if (dst->data) fs_give ((void **) &dst->data); /* copy data in sized text */ memcpy (dst->data = (unsigned char *) fs_get ((size_t) (dst->size = src->size) + 1), src->data,(size_t) src->size); dst->data[dst->size] = '\0'; /* tie off text */ return (char *) dst->data; /* convenience return */ } /* Copy stringstruct to free storage as sized text * Accepts: destination sized text * source stringstruct * Returns: text as a char * */ char *textcpystring (SIZEDTEXT *text,STRING *bs) { unsigned long i = 0; /* clear old space */ if (text->data) fs_give ((void **) &text->data); /* make free storage space in sized text */ text->data = (unsigned char *) fs_get ((size_t) (text->size = SIZE (bs)) +1); while (i < text->size) text->data[i++] = SNX (bs); text->data[i] = '\0'; /* tie off text */ return (char *) text->data; /* convenience return */ } /* Copy stringstruct from offset to free storage as sized text * Accepts: destination sized text * source stringstruct * offset into stringstruct * size of source text * Returns: text as a char * */ char *textcpyoffstring (SIZEDTEXT *text,STRING *bs,unsigned long offset, unsigned long size) { unsigned long i = 0; /* clear old space */ if (text->data) fs_give ((void **) &text->data); SETPOS (bs,offset); /* offset the string */ /* make free storage space in sized text */ text->data = (unsigned char *) fs_get ((size_t) (text->size = size) + 1); while (i < size) text->data[i++] = SNX (bs); text->data[i] = '\0'; /* tie off text */ return (char *) text->data; /* convenience return */ } /* Returns index of rightmost bit in word * Accepts: pointer to a 32 bit value * Returns: -1 if word is 0, else index of rightmost bit * * Bit is cleared in the word */ unsigned long find_rightmost_bit (unsigned long *valptr) { unsigned long value = *valptr; unsigned long bit = 0; if (!(value & 0xffffffff)) return 0xffffffff; /* binary search for rightmost bit */ if (!(value & 0xffff)) value >>= 16, bit += 16; if (!(value & 0xff)) value >>= 8, bit += 8; if (!(value & 0xf)) value >>= 4, bit += 4; if (!(value & 0x3)) value >>= 2, bit += 2; if (!(value & 0x1)) value >>= 1, bit += 1; *valptr ^= (1 << bit); /* clear specified bit */ return bit; } /* Return minimum of two integers * Accepts: integer 1 * integer 2 * Returns: minimum */ long min (long i,long j) { return ((i < j) ? i : j); } /* Return maximum of two integers * Accepts: integer 1 * integer 2 * Returns: maximum */ long max (long i,long j) { return ((i > j) ? i : j); } /* Search, case-insensitive for ASCII characters * Accepts: base string * length of base string * pattern string * length of pattern string * Returns: T if pattern exists inside base, else NIL */ long search (unsigned char *base,long basec,unsigned char *pat,long patc) { long i,j,k; int c; unsigned char mask[256]; static unsigned char alphatab[256] = { 255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255, 255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255, 255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255, 255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255, 255,223,223,223,223,223,223,223,223,223,223,223,223,223,223,223, 223,223,223,223,223,223,223,223,223,223,223,255,255,255,255,255, 255,223,223,223,223,223,223,223,223,223,223,223,223,223,223,223, 223,223,223,223,223,223,223,223,223,223,223,255,255,255,255,255, 255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255, 255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255, 255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255, 255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255, 255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255, 255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255, 255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255, 255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255 }; /* validate arguments */ if (base && (basec > 0) && pat && (basec >= patc)) { if (patc <= 0) return T; /* empty pattern always succeeds */ memset (mask,0,256); /* initialize search validity mask */ for (i = 0; i < patc; i++) if (!mask[c = pat[i]]) { /* mark single character if non-alphabetic */ if (alphatab[c] & 0x20) mask[c] = T; /* else mark both cases */ else mask[c & 0xdf] = mask[c | 0x20] = T; } /* Boyer-Moore type search */ for (i = --patc; i < basec; i += (mask[c] ? 1 : (j + 1))) for (j = patc,c = base[k = i]; !((c ^ pat[j]) & alphatab[c]); j--,c = base[--k]) if (!j) return T; /* found a match! */ } return NIL; /* pattern not found */ } /* Boyer-Moore string search * Accepts: base string * length of base string * pattern string * length of pattern string * Returns: T if pattern exists inside base, else NIL */ long ssearch (unsigned char *base,long basec,unsigned char *pat,long patc) { long i,j,k; int c; unsigned char mask[256]; /* validate arguments */ if (base && (basec > 0) && pat && (basec >= patc)) { if (patc <= 0) return T; /* empty pattern always succeeds */ memset (mask,0,256); /* initialize search validity mask */ for (i = 0; i < patc; i++) mask[pat[i]] = T; /* Boyer-Moore type search */ for (i = --patc, c = pat[i]; i < basec; i += (mask[c] ? 1 : (j + 1))) for (j = patc,c = base[k = i]; (c == pat[j]); j--,c = base[--k]) if (!j) return T; /* found a match! */ } return NIL; /* pattern not found */ } /* Create a hash table * Accepts: size of new table (note: should be a prime) * Returns: hash table */ HASHTAB *hash_create (size_t size) { size_t i = sizeof (size_t) + size * sizeof (HASHENT *); HASHTAB *ret = (HASHTAB *) memset (fs_get (i),0,i); ret->size = size; return ret; } /* Destroy hash table * Accepts: hash table */ void hash_destroy (HASHTAB **hashtab) { if (*hashtab) { hash_reset (*hashtab); /* reset hash table */ fs_give ((void **) hashtab); } } /* Reset hash table * Accepts: hash table */ void hash_reset (HASHTAB *hashtab) { size_t i; HASHENT *ent,*nxt; /* free each hash entry */ for (i = 0; i < hashtab->size; i++) if (ent = hashtab->table[i]) for (hashtab->table[i] = NIL; ent; ent = nxt) { nxt = ent->next; /* get successor */ fs_give ((void **) &ent); /* flush this entry */ } } /* Calculate index into hash table * Accepts: hash table * entry name * Returns: index */ unsigned long hash_index (HASHTAB *hashtab,char *key) { unsigned long i,ret; /* polynomial of letters of the word */ for (ret = 0; i = (unsigned int) *key++; ret += i) ret *= HASHMULT; return ret % (unsigned long) hashtab->size; } /* Look up name in hash table * Accepts: hash table * key * Returns: associated data */ void **hash_lookup (HASHTAB *hashtab,char *key) { HASHENT *ret; for (ret = hashtab->table[hash_index (hashtab,key)]; ret; ret = ret->next) if (!strcmp (key,ret->name)) return ret->data; return NIL; } /* Add entry to hash table * Accepts: hash table * key * associated data * number of extra data slots * Returns: hash entry * Caller is responsible for ensuring that entry isn't already in table */ HASHENT *hash_add (HASHTAB *hashtab,char *key,void *data,long extra) { unsigned long i = hash_index (hashtab,key); size_t j = sizeof (HASHENT) + (extra * sizeof (void *)); HASHENT *ret = (HASHENT *) memset (fs_get (j),0,j); ret->next = hashtab->table[i];/* insert as new head in this index */ ret->name = key; /* set up hash key */ ret->data[0] = data; /* and first data */ return hashtab->table[i] = ret; } /* Look up name in hash table * Accepts: hash table * key * associated data * number of extra data slots * Returns: associated data */ void **hash_lookup_and_add (HASHTAB *hashtab,char *key,void *data,long extra) { HASHENT *ret; unsigned long i = hash_index (hashtab,key); size_t j = sizeof (HASHENT) + (extra * sizeof (void *)); for (ret = hashtab->table[i]; ret; ret = ret->next) if (!strcmp (key,ret->name)) return ret->data; ret = (HASHENT *) memset (fs_get (j),0,j); ret->next = hashtab->table[i];/* insert as new head in this index */ ret->name = key; /* set up hash key */ ret->data[0] = data; /* and first data */ return (hashtab->table[i] = ret)->data; } /* Convert two hex characters into byte * Accepts: char for high nybble * char for low nybble * Returns: byte * * Arguments must be isxdigit validated */ unsigned char hex2byte (unsigned char c1,unsigned char c2) { /* merge the two nybbles */ return ((c1 -= (isdigit (c1) ? '0' : ((c1 <= 'Z') ? 'A' : 'a') - 10)) << 4) + (c2 - (isdigit (c2) ? '0' : ((c2 <= 'Z') ? 'A' : 'a') - 10)); } /* Compare two unsigned longs * Accepts: first value * second value * Returns: -1 if l1 < l2, 0 if l1 == l2, 1 if l1 > l2 */ int compare_ulong (unsigned long l1,unsigned long l2) { if (l1 < l2) return -1; if (l1 > l2) return 1; return 0; } /* Compare two unsigned chars, case-independent * Accepts: first value * second value * Returns: -1 if c1 < c2, 0 if c1 == c2, 1 if c1 > c2 * * Don't use isupper/tolower since this function must be ASCII only. */ int compare_uchar (unsigned char c1,unsigned char c2) { return compare_ulong (((c1 >= 'A') && (c1 <= 'Z')) ? c1 + ('a' - 'A') : c1, ((c2 >= 'A') && (c2 <= 'Z')) ? c2 + ('a' - 'A') : c2); } /* Compare two case-independent ASCII strings * Accepts: first string * second string * Returns: -1 if s1 < s2, 0 if s1 == s2, 1 if s1 > s2 */ int compare_cstring (unsigned char *s1,unsigned char *s2) { int i; if (!s1) return s2 ? -1 : 0; /* empty string cases */ else if (!s2) return 1; for (; *s1 && *s2; s1++,s2++) if (i = (compare_uchar (*s1,*s2))) return i; if (*s1) return 1; /* first string is longer */ return *s2 ? -1 : 0; /* second string longer : strings identical */ } /* Compare case-independent string with sized text * Accepts: first string * sized text * Returns: -1 if s1 < s2, 0 if s1 == s2, 1 if s1 > s2 */ int compare_csizedtext (unsigned char *s1,SIZEDTEXT *s2) { int i; unsigned char *s; unsigned long j; if (!s1) return s2 ? -1 : 0; /* null string cases */ else if (!s2) return 1; for (s = (char *) s2->data,j = s2->size; *s1 && j; ++s1,++s,--j) if (i = (compare_uchar (*s1,*s))) return i; if (*s1) return 1; /* first string is longer */ return j ? -1 : 0; /* second string longer : strings identical */ } alpine-2.10+dfsg/imap/src/c-client/flstring.c0000600000175000017500000000457711512502124022560 0ustar paulproteuspaulproteus/* ======================================================================== * Copyright 1988-2006 University of Washington * * Licensed under the Apache License, Version 2.0 (the "License"); * you may not use this file except in compliance with the License. * You may obtain a copy of the License at * * http://www.apache.org/licenses/LICENSE-2.0 * * * ======================================================================== */ /* * Program: File string routines * * Author: Mark Crispin * Networks and Distributed Computing * Computing & Communications * University of Washington * Administration Building, AG-44 * Seattle, WA 98195 * Internet: MRC@CAC.Washington.EDU * * Date: 15 April 1997 * Last Edited: 6 December 2006 */ #include #include "mail.h" #include "flstring.h" /* String driver for stdio file strings */ static void file_string_init (STRING *s,void *data,unsigned long size); static char file_string_next (STRING *s); static void file_string_setpos (STRING *s,unsigned long i); STRINGDRIVER file_string = { file_string_init, /* initialize string structure */ file_string_next, /* get next byte in string structure */ file_string_setpos /* set position in string structure */ }; /* Initialize mail string structure for file * Accepts: string structure * pointer to string * size of string */ static void file_string_init (STRING *s,void *data,unsigned long size) { s->data = data; /* note file descriptor */ /* big enough for one byte */ s->chunk = s->curpos = (char *) &s->data1; s->size = size; /* data size */ s->cursize = s->chunksize = 1;/* always call stdio */ file_string_setpos (s,0); /* initial offset is 0 */ } /* Get next character from string * Accepts: string structure * Returns: character, string structure chunk refreshed */ static char file_string_next (STRING *s) { char ret = *s->curpos; s->offset++; /* advance position */ s->cursize = 1; /* reset size */ *s->curpos = (char) getc ((FILE *) s->data); return ret; } /* Set string pointer position * Accepts: string structure * new position */ static void file_string_setpos (STRING *s,unsigned long i) { s->offset = i; /* note new offset */ fseek ((FILE *) s->data,i,SEEK_SET); /* in case using returnstringstruct hack */ s->chunk = s->curpos = (char *) &s->data1; *s->curpos = (char) getc ((FILE *) s->data); } alpine-2.10+dfsg/imap/src/c-client/smanager.c0000600000175000017500000000705611512502124022520 0ustar paulproteuspaulproteus/* ======================================================================== * Copyright 1988-2006 University of Washington * * Licensed under the Apache License, Version 2.0 (the "License"); * you may not use this file except in compliance with the License. * You may obtain a copy of the License at * * http://www.apache.org/licenses/LICENSE-2.0 * * * ======================================================================== */ /* * Program: Subscription Manager * * Author: Mark Crispin * Networks and Distributed Computing * Computing & Communications * University of Washington * Administration Building, AG-44 * Seattle, WA 98195 * Internet: MRC@CAC.Washington.EDU * * Date: 3 December 1992 * Last Edited: 6 December 2006 */ #include #include #include "c-client.h" /* Subscribe to mailbox * Accepts: mailbox name * Returns: T on success, NIL on failure */ long sm_subscribe (char *mailbox) { FILE *f; char *s,db[MAILTMPLEN],tmp[MAILTMPLEN]; /* canonicalize INBOX */ if (!compare_cstring (mailbox,"INBOX")) mailbox = "INBOX"; SUBSCRIPTIONFILE (db); /* open subscription database */ if (f = fopen (db,"r")) { /* make sure not already there */ while (fgets (tmp,MAILTMPLEN,f)) { if (s = strchr (tmp,'\n')) *s = '\0'; if (!strcmp (tmp,mailbox)) {/* already subscribed? */ sprintf (tmp,"Already subscribed to mailbox %.80s",mailbox); MM_LOG (tmp,ERROR); fclose (f); return NIL; } } fclose (f); } if (!(f = fopen (db,"a"))) { /* append new entry */ MM_LOG ("Can't append to subscription database",ERROR); return NIL; } fprintf (f,"%s\n",mailbox); return (fclose (f) == EOF) ? NIL : T; } /* Unsubscribe from mailbox * Accepts: mailbox name * Returns: T on success, NIL on failure */ long sm_unsubscribe (char *mailbox) { FILE *f,*tf; char *s,tmp[MAILTMPLEN],old[MAILTMPLEN],newname[MAILTMPLEN]; int found = NIL; /* canonicalize INBOX */ if (!compare_cstring (mailbox,"INBOX")) mailbox = "INBOX"; SUBSCRIPTIONFILE (old); /* make file names */ SUBSCRIPTIONTEMP (newname); if (!(f = fopen (old,"r"))) /* open subscription database */ MM_LOG ("No subscriptions",ERROR); else if (!(tf = fopen (newname,"w"))) { MM_LOG ("Can't create subscription temporary file",ERROR); fclose (f); } else { while (fgets (tmp,MAILTMPLEN,f)) { if (s = strchr (tmp,'\n')) *s = '\0'; if (strcmp (tmp,mailbox)) fprintf (tf,"%s\n",tmp); else found = T; /* found the name */ } fclose (f); if (fclose (tf) == EOF) MM_LOG ("Can't write subscription temporary file",ERROR); else if (!found) { sprintf (tmp,"Not subscribed to mailbox %.80s",mailbox); MM_LOG (tmp,ERROR); /* error if at end */ } else if (!unlink (old) && !rename (newname,old)) return LONGT; else MM_LOG ("Can't update subscription database",ERROR); } return NIL; } /* Read subscription database * Accepts: pointer to subscription database handle (handle NIL if first time) * Returns: character string for subscription database or NIL if done */ static char sbname[MAILTMPLEN]; char *sm_read (void **sdb) { FILE *f = (FILE *) *sdb; char *s; if (!f) { /* first time through? */ SUBSCRIPTIONFILE (sbname); /* open subscription database */ /* make sure not already there */ if (f = fopen (sbname,"r")) *sdb = (void *) f; else return NIL; } if (fgets (sbname,MAILTMPLEN,f)) { if (s = strchr (sbname,'\n')) *s = '\0'; return sbname; } fclose (f); /* all done */ *sdb = NIL; /* zap sdb */ return NIL; } alpine-2.10+dfsg/imap/src/c-client/mail.h0000600000175000017500000020560712074130635021664 0ustar paulproteuspaulproteus/* ======================================================================== * Copyright 1988-2008 University of Washington * * Licensed under the Apache License, Version 2.0 (the "License"); * you may not use this file except in compliance with the License. * You may obtain a copy of the License at * * http://www.apache.org/licenses/LICENSE-2.0 * * * ======================================================================== */ /* * Program: Mailbox Access routines * * Author: Mark Crispin * UW Technology * University of Washington * Seattle, WA 98195 * Internet: MRC@Washington.EDU * * Date: 22 November 1989 * Last Edited: 16 December 2008 */ /* The Version */ #define CCLIENTVERSION "2007e" /* Build parameters */ #define CACHEINCREMENT 250 /* cache growth increments */ #define MAILTMPLEN 1024 /* size of a temporary buffer */ #define SENDBUFLEN 16385 /* size of temporary sending buffer, also * used for SMTP commands and NETMBX generation * buffer so shouldn't be made smaller than * MAILTMPLEN. Note that there's a guard byte, * so this is actually len+1. */ #define MAXAUTHENTICATORS 8 /* maximum number of SASL authenticators */ /* maximum number of messages */ #define MAXMESSAGES (unsigned long) 1000000 #define MAXLOGINTRIALS 3 /* maximum number of client login attempts */ #define MAXWILDCARDS 10 /* maximum wildcards allowed in LIST/LSUB */ /* These can't be changed without changing code */ #define NUSERFLAGS 30 /* maximum number of user flags */ #define MAXUSERFLAG 50 /* maximum length of a user flag */ #define BASEYEAR 1970 /* the year time began on Unix DON'T CHANGE */ /* default for unqualified addresses */ #define BADHOST ".MISSING-HOST-NAME." /* default for syntax errors in addresses */ #define ERRHOST ".SYNTAX-ERROR." /* Coddle certain compilers' 6-character symbol limitation */ #ifdef __COMPILER_KCC__ #include "shortsym.h" #endif /* Function status code */ #define NIL 0 /* convenient name */ #define T 1 /* opposite of NIL */ #define LONGT (long) 1 /* long T to pacify some compilers */ #define VOIDT (void *) "" /* void T ditto */ /* Global and Driver Parameters */ /* 0xx: driver and authenticator flags */ #define ENABLE_DRIVER (long) 1 #define DISABLE_DRIVER (long) 2 #define ENABLE_AUTHENTICATOR (long) 3 #define DISABLE_AUTHENTICATOR (long) 4 #define ENABLE_DEBUG (long) 5 #define DISABLE_DEBUG (long) 6 #define HIDE_AUTHENTICATOR (long) 7 #define UNHIDE_AUTHENTICATOR (long) 8 /* 1xx: c-client globals */ #define GET_DRIVERS (long) 101 #define SET_DRIVERS (long) 102 #define GET_GETS (long) 103 #define SET_GETS (long) 104 #define GET_CACHE (long) 105 #define SET_CACHE (long) 106 #define GET_SMTPVERBOSE (long) 107 #define SET_SMTPVERBOSE (long) 108 #define GET_RFC822OUTPUT (long) 109 #define SET_RFC822OUTPUT (long) 110 #define GET_READPROGRESS (long) 111 #define SET_READPROGRESS (long) 112 #define GET_THREADERS (long) 113 #define SET_THREADERS (long) 114 #define GET_NAMESPACE (long) 115 #define SET_NAMESPACE (long) 116 #define GET_MAILPROXYCOPY (long) 117 #define SET_MAILPROXYCOPY (long) 118 #define GET_SERVICENAME (long) 119 #define SET_SERVICENAME (long) 120 #define GET_DRIVER (long) 121 #define SET_DRIVER (long) 122 #define GET_EXPUNGEATPING (long) 123 #define SET_EXPUNGEATPING (long) 124 #define GET_PARSEPHRASE (long) 125 #define SET_PARSEPHRASE (long) 126 #define GET_SSLDRIVER (long) 127 #define SET_SSLDRIVER (long) 128 #define GET_TRYSSLFIRST (long) 129 #define SET_TRYSSLFIRST (long) 130 #define GET_BLOCKNOTIFY (long) 131 #define SET_BLOCKNOTIFY (long) 132 #define GET_SORTRESULTS (long) 133 #define SET_SORTRESULTS (long) 134 #define GET_THREADRESULTS (long) 135 #define SET_THREADRESULTS (long) 136 #define GET_PARSELINE (long) 137 #define SET_PARSELINE (long) 138 #define GET_NEWSRCQUERY (long) 139 #define SET_NEWSRCQUERY (long) 140 #define GET_FREEENVELOPESPAREP (long) 141 #define SET_FREEENVELOPESPAREP (long) 142 #define GET_FREEELTSPAREP (long) 143 #define SET_FREEELTSPAREP (long) 144 #define GET_SSLSTART (long) 145 #define SET_SSLSTART (long) 146 #define GET_DEBUGSENSITIVE (long) 147 #define SET_DEBUGSENSITIVE (long) 148 #define GET_TCPDEBUG (long) 149 #define SET_TCPDEBUG (long) 150 #define GET_FREESTREAMSPAREP (long) 151 #define SET_FREESTREAMSPAREP (long) 152 #define GET_FREEBODYSPAREP (long) 153 #define SET_FREEBODYSPAREP (long) 154 #define GET_COPYUID (long) 155 #define SET_COPYUID (long) 156 #define GET_APPENDUID (long) 157 #define SET_APPENDUID (long) 158 #define GET_RFC822OUTPUTFULL (long) 159 #define SET_RFC822OUTPUTFULL (long) 160 #define GET_BLOCKENVINIT (long) 161 #define SET_BLOCKENVINIT (long) 162 /* 2xx: environment */ #define GET_USERNAME (long) 201 #define SET_USERNAME (long) 202 #define GET_HOMEDIR (long) 203 #define SET_HOMEDIR (long) 204 #define GET_LOCALHOST (long) 205 #define SET_LOCALHOST (long) 206 #define GET_SYSINBOX (long) 207 #define SET_SYSINBOX (long) 208 #define GET_USERPROMPT (long) 209 #define SET_USERPROMPT (long) 210 #define GET_DISABLEPLAINTEXT (long) 211 #define SET_DISABLEPLAINTEXT (long) 212 #define GET_CHROOTSERVER (long) 213 #define SET_CHROOTSERVER (long) 214 #define GET_ADVERTISETHEWORLD (long) 215 #define SET_ADVERTISETHEWORLD (long) 216 #define GET_DISABLEAUTOSHAREDNS (long) 217 #define SET_DISABLEAUTOSHAREDNS (long) 218 #define GET_MAILSUBDIR 219 #define SET_MAILSUBDIR 220 #define GET_DISABLE822TZTEXT 221 #define SET_DISABLE822TZTEXT 222 #define GET_LIMITEDADVERTISE (long) 223 #define SET_LIMITEDADVERTISE (long) 224 #define GET_LOGOUTHOOK (long) 225 #define SET_LOGOUTHOOK (long) 226 #define GET_LOGOUTDATA (long) 227 #define SET_LOGOUTDATA (long) 228 #define GET_EXTERNALAUTHID (long) 229 #define SET_EXTERNALAUTHID (long) 230 #define GET_SSLCAPATH (long) 231 #define SET_SSLCAPATH (long) 232 /* 3xx: TCP/IP */ #define GET_OPENTIMEOUT (long) 300 #define SET_OPENTIMEOUT (long) 301 #define GET_READTIMEOUT (long) 302 #define SET_READTIMEOUT (long) 303 #define GET_WRITETIMEOUT (long) 304 #define SET_WRITETIMEOUT (long) 305 #define GET_CLOSETIMEOUT (long) 306 #define SET_CLOSETIMEOUT (long) 307 #define GET_TIMEOUT (long) 308 #define SET_TIMEOUT (long) 309 #define GET_RSHTIMEOUT (long) 310 #define SET_RSHTIMEOUT (long) 311 #define GET_ALLOWREVERSEDNS (long) 312 #define SET_ALLOWREVERSEDNS (long) 313 #define GET_RSHCOMMAND (long) 314 #define SET_RSHCOMMAND (long) 315 #define GET_RSHPATH (long) 316 #define SET_RSHPATH (long) 317 #define GET_SSHTIMEOUT (long) 318 #define SET_SSHTIMEOUT (long) 319 #define GET_SSHCOMMAND (long) 320 #define SET_SSHCOMMAND (long) 321 #define GET_SSHPATH (long) 322 #define SET_SSHPATH (long) 323 #define GET_SSLCERTIFICATEQUERY (long) 324 #define SET_SSLCERTIFICATEQUERY (long) 325 #define GET_SSLFAILURE (long) 326 #define SET_SSLFAILURE (long) 327 #define GET_NEWSRCCANONHOST (long) 328 #define SET_NEWSRCCANONHOST (long) 329 #define GET_KINIT (long) 330 #define SET_KINIT (long) 331 #define GET_SSLCLIENTCERT (long) 332 #define SET_SSLCLIENTCERT (long) 333 #define GET_SSLCLIENTKEY (long) 334 #define SET_SSLCLIENTKEY (long) 335 #define GET_KERBEROS_CP_SVR_NAME (long) 336 #define SET_KERBEROS_CP_SVR_NAME (long) 337 /* 4xx: network drivers */ #define GET_MAXLOGINTRIALS (long) 400 #define SET_MAXLOGINTRIALS (long) 401 #define GET_LOOKAHEAD (long) 402 #define SET_LOOKAHEAD (long) 403 #define GET_IMAPPORT (long) 404 #define SET_IMAPPORT (long) 405 #define GET_PREFETCH (long) 406 #define SET_PREFETCH (long) 407 #define GET_CLOSEONERROR (long) 408 #define SET_CLOSEONERROR (long) 409 #define GET_POP3PORT (long) 410 #define SET_POP3PORT (long) 411 #define GET_UIDLOOKAHEAD (long) 412 #define SET_UIDLOOKAHEAD (long) 413 #define GET_NNTPPORT (long) 414 #define SET_NNTPPORT (long) 415 #define GET_IMAPENVELOPE (long) 416 #define SET_IMAPENVELOPE (long) 417 #define GET_IMAPREFERRAL (long) 418 #define SET_IMAPREFERRAL (long) 419 #define GET_SSLIMAPPORT (long) 420 #define SET_SSLIMAPPORT (long) 421 #define GET_SSLPOPPORT (long) 422 #define SET_SSLPOPPORT (long) 423 #define GET_SSLNNTPPORT (long) 424 #define SET_SSLNNTPPORT (long) 425 #define GET_SSLSMTPPORT (long) 426 #define SET_SSLSMTPPORT (long) 427 #define GET_SMTPPORT (long) 428 #define SET_SMTPPORT (long) 429 #define GET_IMAPEXTRAHEADERS (long) 430 #define SET_IMAPEXTRAHEADERS (long) 431 #define GET_ACL (long) 432 #define SET_ACL (long) 433 #define GET_LISTRIGHTS (long) 434 #define SET_LISTRIGHTS (long) 435 #define GET_MYRIGHTS (long) 436 #define SET_MYRIGHTS (long) 437 #define GET_QUOTA (long) 438 #define SET_QUOTA (long) 439 #define GET_QUOTAROOT (long) 440 #define SET_QUOTAROOT (long) 441 #define GET_IMAPTRYSSL (long) 442 #define SET_IMAPTRYSSL (long) 443 #define GET_FETCHLOOKAHEAD (long) 444 #define SET_FETCHLOOKAHEAD (long) 445 #define GET_NNTPRANGE (long) 446 #define SET_NNTPRANGE (long) 447 #define GET_NNTPHIDEPATH (long) 448 #define SET_NNTPHIDEPATH (long) 449 #define GET_SENDCOMMAND (long) 450 #define SET_SENDCOMMAND (long) 451 #define GET_IDLETIMEOUT (long) 452 #define SET_IDLETIMEOUT (long) 453 #define GET_FETCHLOOKAHEADLIMIT (long) 454 #define SET_FETCHLOOKAHEADLIMIT (long) 455 /* 5xx: local file drivers */ #define GET_MBXPROTECTION (long) 500 #define SET_MBXPROTECTION (long) 501 #define GET_DIRPROTECTION (long) 502 #define SET_DIRPROTECTION (long) 503 #define GET_LOCKPROTECTION (long) 504 #define SET_LOCKPROTECTION (long) 505 #define GET_FROMWIDGET (long) 506 #define SET_FROMWIDGET (long) 507 #define GET_NEWSACTIVE (long) 508 #define SET_NEWSACTIVE (long) 509 #define GET_NEWSSPOOL (long) 510 #define SET_NEWSSPOOL (long) 511 #define GET_NEWSRC (long) 512 #define SET_NEWSRC (long) 513 #define GET_EXTENSION (long) 514 #define SET_EXTENSION (long) 515 #define GET_DISABLEFCNTLLOCK (long) 516 #define SET_DISABLEFCNTLLOCK (long) 517 #define GET_LOCKEACCESERROR (long) 518 #define SET_LOCKEACCESERROR (long) 519 #define GET_LISTMAXLEVEL (long) 520 #define SET_LISTMAXLEVEL (long) 521 #define GET_ANONYMOUSHOME (long) 522 #define SET_ANONYMOUSHOME (long) 523 #define GET_FTPHOME (long) 524 #define SET_FTPHOME (long) 525 #define GET_PUBLICHOME (long) 526 #define SET_PUBLICHOME (long) 527 #define GET_SHAREDHOME (long) 528 #define SET_SHAREDHOME (long) 529 #define GET_MHPROFILE (long) 530 #define SET_MHPROFILE (long) 531 #define GET_MHPATH (long) 532 #define SET_MHPATH (long) 533 #define GET_ONETIMEEXPUNGEATPING (long) 534 #define SET_ONETIMEEXPUNGEATPING (long) 535 #define GET_USERHASNOLIFE (long) 536 #define SET_USERHASNOLIFE (long) 537 #define GET_FTPPROTECTION (long) 538 #define SET_FTPPROTECTION (long) 539 #define GET_PUBLICPROTECTION (long) 540 #define SET_PUBLICPROTECTION (long) 541 #define GET_SHAREDPROTECTION (long) 542 #define SET_SHAREDPROTECTION (long) 543 #define GET_LOCKTIMEOUT (long) 544 #define SET_LOCKTIMEOUT (long) 545 #define GET_NOTIMEZONES (long) 546 #define SET_NOTIMEZONES (long) 547 #define GET_HIDEDOTFILES (long) 548 #define SET_HIDEDOTFILES (long) 549 #define GET_FTPDIRPROTECTION (long) 550 #define SET_FTPDIRPROTECTION (long) 551 #define GET_PUBLICDIRPROTECTION (long) 552 #define SET_PUBLICDIRPROTECTION (long) 553 #define GET_SHAREDDIRPROTECTION (long) 554 #define SET_SHAREDDIRPROTECTION (long) 555 #define GET_TRUSTDNS (long) 556 #define SET_TRUSTDNS (long) 557 #define GET_SASLUSESPTRNAME (long) 558 #define SET_SASLUSESPTRNAME (long) 559 #define GET_NETFSSTATBUG (long) 560 #define SET_NETFSSTATBUG (long) 561 #define GET_SNARFMAILBOXNAME (long) 562 #define SET_SNARFMAILBOXNAME (long) 563 #define GET_SNARFINTERVAL (long) 564 #define SET_SNARFINTERVAL (long) 565 #define GET_SNARFPRESERVE (long) 566 #define SET_SNARFPRESERVE (long) 567 #define GET_INBOXPATH (long) 568 #define SET_INBOXPATH (long) 569 #define GET_DIRFMTTEST (long) 570 #define SET_DIRFMTTEST (long) 571 #define GET_SCANCONTENTS (long) 572 #define SET_SCANCONTENTS (long) 573 #define GET_MHALLOWINBOX (long) 574 #define SET_MHALLOWINBOX (long) 575 /* Driver flags */ #define DR_DISABLE (long) 0x1 /* driver is disabled */ #define DR_LOCAL (long) 0x2 /* local file driver */ #define DR_MAIL (long) 0x4 /* supports mail */ #define DR_NEWS (long) 0x8 /* supports news */ #define DR_READONLY (long) 0x10 /* driver only allows readonly access */ #define DR_NOFAST (long) 0x20 /* "fast" data is slow (whole msg fetch) */ #define DR_NAMESPACE (long) 0x40/* driver has a special namespace */ #define DR_LOWMEM (long) 0x80 /* low amounts of memory available */ #define DR_LOCKING (long) 0x100 /* driver does locking */ #define DR_CRLF (long) 0x200 /* driver internal form uses CRLF newlines */ #define DR_NOSTICKY (long) 0x400/* driver does not support sticky UIDs */ #define DR_RECYCLE (long) 0x800 /* driver does stream recycling */ #define DR_XPOINT (long) 0x1000 /* needs to be checkpointed */ /* driver has no real internal date */ #define DR_NOINTDATE (long) 0x2000 /* driver does not announce new mail */ #define DR_NONEWMAIL (long) 0x4000 /* driver does not announce new mail when RO */ #define DR_NONEWMAILRONLY (long) 0x8000 /* driver can be halfopen */ #define DR_HALFOPEN (long) 0x10000 #define DR_DIRFMT (long) 0x20000/* driver is a directory-format */ #define DR_MODSEQ (long) 0x40000/* driver supports modseqs */ /* Cache management function codes */ #define CH_INIT (long) 10 /* initialize cache */ #define CH_SIZE (long) 11 /* (re-)size the cache */ #define CH_MAKEELT (long) 30 /* return elt, make if needed */ #define CH_ELT (long) 31 /* return elt if exists */ #define CH_SORTCACHE (long) 35 /* return sortcache entry, make if needed */ #define CH_FREE (long) 40 /* free space used by elt */ /* free space used by sortcache */ #define CH_FREESORTCACHE (long) 43 #define CH_EXPUNGE (long) 45 /* delete elt pointer from list */ /* Mailbox open options * For compatibility with the past, OP_DEBUG must always be 1. */ #define OP_DEBUG (long) 0x1 /* debug protocol negotiations */ #define OP_READONLY (long) 0x2 /* read-only open */ #define OP_ANONYMOUS (long) 0x4 /* anonymous open of newsgroup */ #define OP_SHORTCACHE (long) 0x8/* short (elt-only) caching */ #define OP_SILENT (long) 0x10 /* don't pass up events (internal use) */ #define OP_PROTOTYPE (long) 0x20/* return driver prototype */ #define OP_HALFOPEN (long) 0x40 /* half-open (IMAP connect but no select) */ #define OP_EXPUNGE (long) 0x80 /* silently expunge recycle stream */ #define OP_SECURE (long) 0x100 /* don't do non-secure authentication */ #define OP_TRYSSL (long) 0x200 /* try SSL first */ /* use multiple newsrc files */ #define OP_MULNEWSRC (long) 0x400 #define OP_NOKOD (long) 0x800 /* suppress kiss-of-death */ #define OP_SNIFF (long) 0x1000 /* metadata only open */ /* reserved for application use */ #define OP_RESERVED (unsigned long) 0xff000000 /* Net open options */ /* no error messages */ #define NET_SILENT ((unsigned long) 0x80000000) /* no validation of SSL certificates */ #define NET_NOVALIDATECERT ((unsigned long) 0x40000000) /* no open timeout */ #define NET_NOOPENTIMEOUT ((unsigned long) 0x20000000) /* TLS not SSL */ #define NET_TLSCLIENT ((unsigned long) 0x10000000) /* try SSL mode */ #define NET_TRYSSL ((unsigned long) 0x8000000) /* Close options */ #define CL_EXPUNGE (long) 1 /* expunge silently */ /* Fetch options */ #define FT_UID (long) 0x1 /* argument is a UID */ #define FT_PEEK (long) 0x2 /* peek at data */ #define FT_NOT (long) 0x4 /* NOT flag for header lines fetch */ #define FT_INTERNAL (long) 0x8 /* text can be internal strings */ /* IMAP prefetch text when fetching header */ #define FT_PREFETCHTEXT (long) 0x20 #define FT_NOHDRS (long) 0x40 /* suppress fetching extra headers (note that this breaks news handling) */ #define FT_NEEDENV (long) 0x80 /* (internal use) include envelope */ #define FT_NEEDBODY (long) 0x100/* (internal use) include body structure */ /* no fetch lookahead */ #define FT_NOLOOKAHEAD (long) 0x200 /* (internal use) lookahead in hdr searching */ #define FT_SEARCHLOOKAHEAD (long) 0x400 /* stringstruct return hack */ #define FT_RETURNSTRINGSTRUCT (long) 0x800 /* Flagging options */ #define ST_UID (long) 0x1 /* argument is a UID sequence */ #define ST_SILENT (long) 0x2 /* don't return results */ #define ST_SET (long) 0x4 /* set vs. clear */ /* Expunge options */ #define EX_UID (long) 0x1 /* argument is a UID sequence */ /* Copy options */ #define CP_UID (long) 0x1 /* argument is a UID sequence */ #define CP_MOVE (long) 0x2 /* delete from source after copying */ /* set debug in any created stream */ #define CP_DEBUG (long) 0x20000000 /* Search/sort/thread options */ #define SE_UID (long) 0x1 /* return UID */ #define SE_FREE (long) 0x2 /* free search program after finished */ #define SE_NOPREFETCH (long) 0x4/* no search prefetching */ #define SO_FREE (long) 0x8 /* free sort program after finished */ #define SE_NOSERVER (long) 0x10 /* don't do server-based search/sort/thread */ #define SE_RETAIN (long) 0x20 /* retain previous search results */ #define SO_OVERVIEW (long) 0x40 /* use overviews in searching (NNTP only) */ #define SE_NEEDBODY (long) 0x80 /* include body structure in prefetch */ #define SE_NOHDRS (long) 0x100 /* suppress prefetching extra headers (note that this breaks news handling) */ #define SE_NOLOCAL (long) 0x200 /* no local retry (IMAP only) */ #define SO_NOSERVER SE_NOSERVER /* compatibility name */ #define SE_SILLYOK (long) 0x400 /* allow silly searches */ /* Status options */ #define SA_MESSAGES (long) 0x1 /* number of messages */ #define SA_RECENT (long) 0x2 /* number of recent messages */ #define SA_UNSEEN (long) 0x4 /* number of unseen messages */ #define SA_UIDNEXT (long) 0x8 /* next UID to be assigned */ /* UID validity value */ #define SA_UIDVALIDITY (long) 0x10 /* set OP_DEBUG on any created stream */ #define SA_DEBUG (long) 0x10000000 /* use multiple newsrcs */ #define SA_MULNEWSRC (long) 0x20000000 /* Mailgets flags */ #define MG_UID (long) 0x1 /* message number is a UID */ #define MG_COPY (long) 0x2 /* must return copy of argument */ /* SASL authenticator categories */ #define AU_SECURE (long) 0x1 /* /secure allowed */ #define AU_AUTHUSER (long) 0x2 /* /authuser=xxx allowed */ /* authenticator hidden */ #define AU_HIDE (long) 0x10000000 /* authenticator disabled */ #define AU_DISABLE (long) 0x20000000 /* Garbage collection flags */ #define GC_ELT (long) 0x1 /* message cache elements */ #define GC_ENV (long) 0x2 /* envelopes and bodies */ #define GC_TEXTS (long) 0x4 /* cached texts */ /* mm_log()/mm_notify() condition codes */ #define WARN (long) 1 /* mm_log warning type */ #define ERROR (long) 2 /* mm_log error type */ #define PARSE (long) 3 /* mm_log parse error type */ #define BYE (long) 4 /* mm_notify stream dying */ #define TCPDEBUG (long) 5 /* mm_log TCP debug babble */ /* Bits from mail_parse_flags(). Don't change these, since the header format * used by tenex, mtx, and mbx corresponds to these bits. */ #define fSEEN 0x1 #define fDELETED 0x2 #define fFLAGGED 0x4 #define fANSWERED 0x8 #define fOLD 0x10 #define fDRAFT 0x20 #define fEXPUNGED 0x8000 /* internal flag */ /* Bits for mm_list() and mm_lsub() */ /* Note that (LATT_NOINFERIORS LATT_HASCHILDREN LATT_HASNOCHILDREN) and * (LATT_NOSELECT LATT_MARKED LATT_UNMARKED) each have eight possible states, * but only four of these are valid. The other four are silly states which * while invalid can unfortunately be expressed in the IMAP protocol. */ /* terminal node in hierarchy */ #define LATT_NOINFERIORS (long) 0x1 /* name can not be selected */ #define LATT_NOSELECT (long) 0x2 /* changed since last accessed */ #define LATT_MARKED (long) 0x4 /* accessed since last changed */ #define LATT_UNMARKED (long) 0x8 /* name has referral to remote mailbox */ #define LATT_REFERRAL (long) 0x10 /* has selectable inferiors */ #define LATT_HASCHILDREN (long) 0x20 /* has no selectable inferiors */ #define LATT_HASNOCHILDREN (long) 0x40 /* Sort functions */ #define SORTDATE 0 /* date */ #define SORTARRIVAL 1 /* arrival date */ #define SORTFROM 2 /* from */ #define SORTSUBJECT 3 /* subject */ #define SORTTO 4 /* to */ #define SORTCC 5 /* cc */ #define SORTSIZE 6 /* size */ /* imapreferral_t codes */ #define REFAUTHFAILED (long) 0 /* authentication referral -- not logged in */ #define REFAUTH (long) 1 /* authentication referral -- logged in */ #define REFSELECT (long) 2 /* select referral */ #define REFCREATE (long) 3 #define REFDELETE (long) 4 #define REFRENAME (long) 5 #define REFSUBSCRIBE (long) 6 #define REFUNSUBSCRIBE (long) 7 #define REFSTATUS (long) 8 #define REFCOPY (long) 9 #define REFAPPEND (long) 10 /* sendcommand_t codes */ /* expunge response deferred */ #define SC_EXPUNGEDEFERRED (long) 1 /* Block notification codes */ #define BLOCK_NONE 0 /* not blocked */ #define BLOCK_SENSITIVE 1 /* sensitive code, disallow alarms */ #define BLOCK_NONSENSITIVE 2 /* non-sensitive code, allow alarms */ #define BLOCK_DNSLOOKUP 10 /* blocked on DNS lookup */ #define BLOCK_TCPOPEN 11 /* blocked on TCP open */ #define BLOCK_TCPREAD 12 /* blocked on TCP read */ #define BLOCK_TCPWRITE 13 /* blocked on TCP write */ #define BLOCK_TCPCLOSE 14 /* blocked on TCP close */ #define BLOCK_FILELOCK 20 /* blocked on file locking */ /* In-memory sized-text */ #define SIZEDTEXT struct mail_sizedtext SIZEDTEXT { unsigned char *data; /* text */ unsigned long size; /* size of text in octets */ }; /* String list */ #define STRINGLIST struct string_list STRINGLIST { SIZEDTEXT text; /* string text */ STRINGLIST *next; }; /* Parse results from mail_valid_net_parse */ #define NETMAXHOST 256 #define NETMAXUSER 65 #define NETMAXMBX (MAILTMPLEN/4) #define NETMAXSRV 21 typedef struct net_mailbox { char host[NETMAXHOST]; /* host name (may be canonicalized) */ char orighost[NETMAXHOST]; /* host name before canonicalization */ char user[NETMAXUSER]; /* user name */ char authuser[NETMAXUSER]; /* authentication user name */ char mailbox[NETMAXMBX]; /* mailbox name */ char service[NETMAXSRV]; /* service name */ unsigned long port; /* TCP port number */ unsigned int anoflag : 1; /* anonymous */ unsigned int dbgflag : 1; /* debug flag */ unsigned int secflag : 1; /* secure flag */ unsigned int sslflag : 1; /* SSL driver flag */ unsigned int trysslflag : 1; /* try SSL driver first flag */ unsigned int novalidate : 1; /* don't validate certificates */ unsigned int tlsflag : 1; /* TLS flag */ unsigned int notlsflag : 1; /* do not do TLS flag */ unsigned int readonlyflag : 1;/* want readonly */ unsigned int norsh : 1; /* don't use rsh/ssh */ unsigned int loser : 1; /* server is a loser */ unsigned int tlssslv23 : 1; /* force SSLv23 client method over TLS */ } NETMBX; /* Item in an address list */ #define ADDRESS struct mail_address ADDRESS { char *personal; /* personal name phrase */ char *adl; /* at-domain-list source route */ char *mailbox; /* mailbox name */ char *host; /* domain name of mailbox's host */ char *error; /* error in address from SMTP module */ struct { char *type; /* address type (default "rfc822") */ char *addr; /* address as xtext */ } orcpt; ADDRESS *next; /* pointer to next address in list */ }; /* Message envelope */ typedef struct mail_envelope { unsigned int ngpathexists : 1; /* newsgroups may be bogus */ unsigned int incomplete : 1; /* envelope may be incomplete */ unsigned int imapenvonly : 1; /* envelope only has IMAP envelope */ char *remail; /* remail header if any */ ADDRESS *return_path; /* error return address */ unsigned char *date; /* message composition date string */ ADDRESS *from; /* originator address list */ ADDRESS *sender; /* sender address list */ ADDRESS *reply_to; /* reply address list */ char *subject; /* message subject string */ ADDRESS *to; /* primary recipient list */ ADDRESS *cc; /* secondary recipient list */ ADDRESS *bcc; /* blind secondary recipient list */ char *in_reply_to; /* replied message ID */ char *message_id; /* message ID */ char *newsgroups; /* USENET newsgroups */ char *followup_to; /* USENET reply newsgroups */ char *references; /* USENET references */ void *sparep; /* spare pointer reserved for main program */ } ENVELOPE; /* Primary body types */ /* If you change any of these you must also change body_types in rfc822.c */ #define TYPETEXT 0 /* unformatted text */ #define TYPEMULTIPART 1 /* multiple part */ #define TYPEMESSAGE 2 /* encapsulated message */ #define TYPEAPPLICATION 3 /* application data */ #define TYPEAUDIO 4 /* audio */ #define TYPEIMAGE 5 /* static image */ #define TYPEVIDEO 6 /* video */ #define TYPEMODEL 7 /* model */ #define TYPEOTHER 8 /* unknown */ #define TYPEMAX 15 /* maximum type code */ /* Body encodings */ /* If you change any of these you must also change body_encodings in rfc822.c */ #define ENC7BIT 0 /* 7 bit SMTP semantic data */ #define ENC8BIT 1 /* 8 bit SMTP semantic data */ #define ENCBINARY 2 /* 8 bit binary data */ #define ENCBASE64 3 /* base-64 encoded data */ #define ENCQUOTEDPRINTABLE 4 /* human-readable 8-as-7 bit data */ #define ENCOTHER 5 /* unknown */ #define ENCMAX 10 /* maximum encoding code */ /* Body contents */ #define BODY struct mail_bodystruct #define MESSAGE struct mail_body_message #define PARAMETER struct mail_body_parameter #define PART struct mail_body_part #define PARTTEXT struct mail_body_text /* Message body text */ PARTTEXT { unsigned long offset; /* offset from body origin */ SIZEDTEXT text; /* text */ }; /* Message body structure */ BODY { unsigned short type; /* body primary type */ unsigned short encoding; /* body transfer encoding */ char *subtype; /* subtype string */ PARAMETER *parameter; /* parameter list */ char *id; /* body identifier */ char *description; /* body description */ struct { /* body disposition */ char *type; /* disposition type */ PARAMETER *parameter; /* disposition parameters */ } disposition; STRINGLIST *language; /* body language */ char *location; /* body content URI */ PARTTEXT mime; /* MIME header */ PARTTEXT contents; /* body part contents */ union { /* different ways of accessing contents */ PART *part; /* body part list */ MESSAGE *msg; /* body encapsulated message */ } nested; struct { unsigned long lines; /* size of text in lines */ unsigned long bytes; /* size of text in octets */ } size; char *md5; /* MD5 checksum */ void *sparep; /* spare pointer reserved for main program */ }; /* Parameter list */ PARAMETER { char *attribute; /* parameter attribute name */ char *value; /* parameter value */ PARAMETER *next; /* next parameter in list */ }; /* Multipart content list */ PART { BODY body; /* body information for this part */ PART *next; /* next body part */ }; /* RFC-822 Message */ MESSAGE { ENVELOPE *env; /* message envelope */ BODY *body; /* message body */ PARTTEXT full; /* full message */ STRINGLIST *lines; /* lines used to filter header */ PARTTEXT header; /* header text */ PARTTEXT text; /* body text */ }; /* Entry in the message cache array */ typedef struct message_cache { unsigned long msgno; /* message number */ unsigned int lockcount : 8; /* non-zero if multiple references */ unsigned long rfc822_size; /* # of bytes of message as raw RFC822 */ struct { /* c-client internal use only */ unsigned long uid; /* message unique ID */ unsigned long mod; /* modseq */ PARTTEXT special; /* special text pointers */ MESSAGE msg; /* internal message pointers */ union { /* driver internal use */ unsigned long data; void *ptr; } spare; unsigned int sequence : 1; /* saved sequence bit */ unsigned int dirty : 1; /* driver internal use */ unsigned int filter : 1; /* driver internal use */ unsigned int ghost : 1; /* driver internal use */ } private; /* internal date */ unsigned int day : 5; /* day of month (1-31) */ unsigned int month : 4; /* month of year (1-12) */ unsigned int year : 7; /* year since BASEYEAR (expires in 127 yrs) */ unsigned int hours: 5; /* hours (0-23) */ unsigned int minutes: 6; /* minutes (0-59) */ unsigned int seconds: 6; /* seconds (0-59) */ unsigned int zoccident : 1; /* non-zero if west of UTC */ unsigned int zhours : 4; /* hours from UTC (0-12) */ unsigned int zminutes: 6; /* minutes (0-59) */ /* system flags */ unsigned int seen : 1; /* system Seen flag */ unsigned int deleted : 1; /* system Deleted flag */ unsigned int flagged : 1; /* system Flagged flag */ unsigned int answered : 1; /* system Answered flag */ unsigned int draft : 1; /* system Draft flag */ unsigned int recent : 1; /* system Recent flag */ /* message status */ unsigned int valid : 1; /* elt has valid flags */ unsigned int searched : 1; /* message was searched */ unsigned int sequence : 1; /* message is in sequence */ /* reserved for use by main program */ unsigned int spare : 1; /* first spare bit */ unsigned int spare2 : 1; /* second spare bit */ unsigned int spare3 : 1; /* third spare bit */ unsigned int spare4 : 1; /* fourth spare bit */ unsigned int spare5 : 1; /* fifth spare bit */ unsigned int spare6 : 1; /* sixth spare bit */ unsigned int spare7 : 1; /* seventh spare bit */ unsigned int spare8 : 1; /* eighth spare bit */ void *sparep; /* spare pointer */ unsigned long user_flags; /* user-assignable flags */ } MESSAGECACHE; /* String structure */ #define STRINGDRIVER struct string_driver typedef struct mailstring { void *data; /* driver-dependent data */ unsigned long data1; /* driver-dependent data */ unsigned long size; /* total length of string */ char *chunk; /* base address of chunk */ unsigned long chunksize; /* size of chunk */ unsigned long offset; /* offset of this chunk in base */ char *curpos; /* current position in chunk */ unsigned long cursize; /* number of bytes remaining in chunk */ STRINGDRIVER *dtb; /* driver that handles this type of string */ } STRING; /* Dispatch table for string driver */ STRINGDRIVER { /* initialize string driver */ void (*init) (STRING *s,void *data,unsigned long size); /* get next character in string */ char (*next) (STRING *s); /* set position in string */ void (*setpos) (STRING *s,unsigned long i); }; /* Stringstruct access routines */ #define INIT(s,d,data,size) ((*((s)->dtb = &d)->init) (s,data,size)) #define SIZE(s) ((s)->size - GETPOS (s)) #define CHR(s) (*(s)->curpos) #define SNX(s) (--(s)->cursize ? *(s)->curpos++ : (*(s)->dtb->next) (s)) #define GETPOS(s) ((s)->offset + ((s)->curpos - (s)->chunk)) #define SETPOS(s,i) (*(s)->dtb->setpos) (s,i) /* Search program */ #define SEARCHPGM struct search_program #define SEARCHHEADER struct search_header #define SEARCHSET struct search_set #define SEARCHOR struct search_or #define SEARCHPGMLIST struct search_pgm_list SEARCHHEADER { /* header search */ SIZEDTEXT line; /* header line */ SIZEDTEXT text; /* text in header */ SEARCHHEADER *next; /* next in list */ }; SEARCHSET { /* message set */ unsigned long first; /* sequence number */ unsigned long last; /* last value, if a range */ SEARCHSET *next; /* next in list */ }; SEARCHOR { SEARCHPGM *first; /* first program */ SEARCHPGM *second; /* second program */ SEARCHOR *next; /* next in list */ }; SEARCHPGMLIST { SEARCHPGM *pgm; /* search program */ SEARCHPGMLIST *next; /* next in list */ }; SEARCHPGM { /* search program */ SEARCHSET *msgno; /* message numbers */ SEARCHSET *uid; /* unique identifiers */ SEARCHOR *or; /* or'ed in programs */ SEARCHPGMLIST *not; /* and'ed not program */ SEARCHHEADER *header; /* list of headers */ STRINGLIST *bcc; /* bcc recipients */ STRINGLIST *body; /* text in message body */ STRINGLIST *cc; /* cc recipients */ STRINGLIST *from; /* originator */ STRINGLIST *keyword; /* keywords */ STRINGLIST *unkeyword; /* unkeywords */ STRINGLIST *subject; /* text in subject */ STRINGLIST *text; /* text in headers and body */ STRINGLIST *to; /* to recipients */ unsigned long larger; /* larger than this size */ unsigned long smaller; /* smaller than this size */ unsigned long older; /* older than this interval */ unsigned long younger; /* younger than this interval */ unsigned short sentbefore; /* sent before this date */ unsigned short senton; /* sent on this date */ unsigned short sentsince; /* sent since this date */ unsigned short before; /* before this date */ unsigned short on; /* on this date */ unsigned short since; /* since this date */ unsigned int answered : 1; /* answered messages */ unsigned int unanswered : 1; /* unanswered messages */ unsigned int deleted : 1; /* deleted messages */ unsigned int undeleted : 1; /* undeleted messages */ unsigned int draft : 1; /* message draft */ unsigned int undraft : 1; /* message undraft */ unsigned int flagged : 1; /* flagged messages */ unsigned int unflagged : 1; /* unflagged messages */ unsigned int recent : 1; /* recent messages */ unsigned int old : 1; /* old messages */ unsigned int seen : 1; /* seen messages */ unsigned int unseen : 1; /* unseen messages */ /* These must be simulated in IMAP */ STRINGLIST *return_path; /* error return address */ STRINGLIST *sender; /* sender address list */ STRINGLIST *reply_to; /* reply address list */ STRINGLIST *in_reply_to; /* replied message ID */ STRINGLIST *message_id; /* message ID */ STRINGLIST *newsgroups; /* USENET newsgroups */ STRINGLIST *followup_to; /* USENET reply newsgroups */ STRINGLIST *references; /* USENET references */ }; /* Mailbox status */ typedef struct mbx_status { long flags; /* validity flags */ unsigned long messages; /* number of messages */ unsigned long recent; /* number of recent messages */ unsigned long unseen; /* number of unseen messages */ unsigned long uidnext; /* next UID to be assigned */ unsigned long uidvalidity; /* UID validity value */ } MAILSTATUS; /* Sort program */ typedef void (*postsort_t) (void *sc); #define SORTPGM struct sort_program SORTPGM { unsigned int reverse : 1; /* sort function is to be reversed */ unsigned int abort : 1; /* abort sorting */ short function; /* sort function */ unsigned long nmsgs; /* number of messages being sorted */ struct { unsigned long cached; /* number of messages cached so far */ unsigned long sorted; /* number of messages sorted so far */ unsigned long postsorted; /* number of postsorted messages so far */ } progress; postsort_t postsort; /* post sorter */ SORTPGM *next; /* next function */ }; /* Sort cache */ #define SORTCACHE struct sort_cache SORTCACHE { unsigned int sorted : 1; /* message has been sorted */ unsigned int postsorted : 1; /* message has been postsorted */ unsigned int refwd : 1; /* subject is a re or fwd */ unsigned int dirty : 1; /* has data not written to backup */ SORTPGM *pgm; /* sort program */ unsigned long num; /* message number (sequence or UID) */ unsigned long date; /* sent date */ unsigned long arrival; /* arrival date */ unsigned long size; /* message size */ char *from; /* from string */ char *to; /* to string */ char *cc; /* cc string */ char *subject; /* extracted subject string */ char *message_id; /* message-id string */ char *unique; /* unique string, normally message-id */ STRINGLIST *references; /* references string */ }; /* ACL list */ #define ACLLIST struct acl_list ACLLIST { char *identifier; /* authentication identifier */ char *rights; /* access rights */ ACLLIST *next; }; /* Quota resource list */ #define QUOTALIST struct quota_list QUOTALIST { char *name; /* resource name */ unsigned long usage; /* resource usage */ unsigned long limit; /* resource limit */ QUOTALIST *next; /* next resource */ }; /* Mail Access I/O stream */ /* Structure for mail driver dispatch */ #define DRIVER struct driver /* Mail I/O stream */ typedef struct mail_stream { DRIVER *dtb; /* dispatch table for this driver */ void *local; /* pointer to driver local data */ char *mailbox; /* mailbox name (canonicalized) */ char *original_mailbox; /* mailbox name (non-canonicalized) */ unsigned short use; /* stream use count */ unsigned short sequence; /* stream sequence */ unsigned int inbox : 1; /* stream open on an INBOX */ unsigned int lock : 1; /* stream lock flag */ unsigned int debug : 1; /* stream debug flag */ unsigned int silent : 1; /* don't pass events to main program */ unsigned int rdonly : 1; /* stream read-only flag */ unsigned int anonymous : 1; /* stream anonymous access flag */ unsigned int scache : 1; /* stream short cache flag */ unsigned int halfopen : 1; /* stream half-open flag */ unsigned int secure : 1; /* stream secure flag */ unsigned int tryssl : 1; /* stream tryssl flag */ unsigned int mulnewsrc : 1; /* stream use multiple newsrc files */ unsigned int perm_seen : 1; /* permanent Seen flag */ unsigned int perm_deleted : 1;/* permanent Deleted flag */ unsigned int perm_flagged : 1;/* permanent Flagged flag */ unsigned int perm_answered :1;/* permanent Answered flag */ unsigned int perm_draft : 1; /* permanent Draft flag */ unsigned int kwd_create : 1; /* can create new keywords */ unsigned int uid_nosticky : 1;/* UIDs are not preserved */ unsigned int unhealthy : 1; /* unhealthy protocol negotiations */ unsigned int nokod : 1; /* suppress kiss-of-death */ unsigned int sniff : 1; /* metadata only */ unsigned long perm_user_flags;/* mask of permanent user flags */ unsigned long gensym; /* generated tag */ unsigned long nmsgs; /* # of associated msgs */ unsigned long recent; /* # of recent msgs */ unsigned long uid_validity; /* UID validity sequence */ unsigned long uid_last; /* last assigned UID */ char *user_flags[NUSERFLAGS]; /* pointers to user flags in bit order */ unsigned long cachesize; /* size of message cache */ MESSAGECACHE **cache; /* message cache array */ SORTCACHE **sc; /* sort cache array */ unsigned long msgno; /* message number of `current' message */ ENVELOPE *env; /* scratch buffer for envelope */ BODY *body; /* scratch buffer for body */ SIZEDTEXT text; /* scratch buffer for text */ struct { char *name; /* mailbox name to snarf from */ unsigned long time; /* last snarf time */ long options; /* snarf open options */ } snarf; struct { /* internal use only */ struct { /* search temporaries */ STRINGLIST *string; /* string(s) to search */ long result; /* search result */ char *text; /* cache of fetched text */ } search; STRING string; /* stringstruct return hack */ } private; /* reserved for use by main program */ void *sparep; /* spare pointer */ unsigned int spare : 1; /* first spare bit */ unsigned int spare2 : 1; /* second spare bit */ unsigned int spare3 : 1; /* third spare bit */ unsigned int spare4 : 1; /* fourth spare bit */ unsigned int spare5 : 1; /* fifth spare bit */ unsigned int spare6 : 1; /* sixth spare bit */ unsigned int spare7 : 1; /* seventh spare bit */ unsigned int spare8 : 1; /* eighth spare bit */ } MAILSTREAM; /* Mail I/O stream handle */ typedef struct mail_stream_handle { MAILSTREAM *stream; /* pointer to mail stream */ unsigned short sequence; /* sequence of what we expect stream to be */ } MAILHANDLE; /* Message overview */ typedef struct mail_overview { char *subject; /* message subject string */ ADDRESS *from; /* originator address list */ char *date; /* message composition date string */ char *message_id; /* message ID */ char *references; /* USENET references */ struct { /* may be 0 or NUL if unknown/undefined */ unsigned long octets; /* message octets (probably LF-newline form) */ unsigned long lines; /* message lines */ char *xref; /* cross references */ } optional; } OVERVIEW; /* Network access I/O stream */ /* Structure for network driver dispatch */ #define NETDRIVER struct net_driver /* Network transport I/O stream */ typedef struct net_stream { void *stream; /* driver's I/O stream */ NETDRIVER *dtb; /* network driver */ } NETSTREAM; /* Network transport driver dispatch */ NETDRIVER { void *(*open) (char *host,char *service,unsigned long port); void *(*aopen) (NETMBX *mb,char *service,char *usrbuf); char *(*getline) (void *stream); long (*getbuffer) (void *stream,unsigned long size,char *buffer); long (*soutr) (void *stream,char *string); long (*sout) (void *stream,char *string,unsigned long size); void (*close) (void *stream); char *(*host) (void *stream); char *(*remotehost) (void *stream); unsigned long (*port) (void *stream); char *(*localhost) (void *stream); }; /* Mailgets data identifier */ typedef struct getsdata { MAILSTREAM *stream; unsigned long msgno; char *what; STRINGLIST *stl; unsigned long first; unsigned long last; long flags; } GETS_DATA; #define INIT_GETS(md,s,m,w,f,l) \ md.stream = s, md.msgno = m, md.what = w, md.first = f, md.last = l, \ md.stl = NIL, md.flags = NIL; /* Mail delivery I/O stream */ typedef struct send_stream { NETSTREAM *netstream; /* network I/O stream */ char *host; /* SMTP service host */ char *reply; /* last reply string */ long replycode; /* last reply code */ unsigned int debug : 1; /* stream debug flag */ unsigned int sensitive : 1; /* sensitive data in progress */ unsigned int loser : 1; /* server is a loser */ unsigned int saslcancel : 1; /* SASL cancelled by protocol */ union { /* protocol specific */ struct { /* SMTP specific */ unsigned int ok : 1; /* supports ESMTP */ struct { /* service extensions */ unsigned int send : 1; /* supports SEND */ unsigned int soml : 1; /* supports SOML */ unsigned int saml : 1; /* supports SAML */ unsigned int expn : 1; /* supports EXPN */ unsigned int help : 1; /* supports HELP */ unsigned int turn : 1; /* supports TURN */ unsigned int etrn : 1; /* supports ETRN */ unsigned int starttls:1;/* supports STARTTLS */ unsigned int relay : 1; /* supports relaying */ unsigned int pipe : 1; /* supports pipelining */ unsigned int ensc : 1; /* supports enhanced status codes */ unsigned int bmime : 1; /* supports BINARYMIME */ unsigned int chunk : 1; /* supports CHUNKING */ } service; struct { /* 8-bit MIME transport */ unsigned int ok : 1; /* supports 8-bit MIME */ unsigned int want : 1; /* want 8-bit MIME */ } eightbit; struct { /* delivery status notification */ unsigned int ok : 1; /* supports DSN */ unsigned int want : 1; /* want DSN */ struct { /* notification options */ /* notify on failure */ unsigned int failure : 1; /* notify on delay */ unsigned int delay : 1; /* notify on success */ unsigned int success : 1; } notify; unsigned int full : 1; /* return full headers */ char *envid; /* envelope identifier as xtext */ } dsn; struct { /* size declaration */ unsigned int ok : 1; /* supports SIZE */ unsigned long limit; /* maximum size supported */ } size; struct { /* deliverby declaration */ unsigned int ok : 1; /* supports DELIVERBY */ unsigned long minby; /* minimum by-time */ } deliverby; struct { /* authenticated turn */ unsigned int ok : 1; /* supports ATRN */ char *domains; /* domains */ } atrn; /* supported SASL authenticators */ unsigned int auth : MAXAUTHENTICATORS; } esmtp; struct { /* NNTP specific */ unsigned int post : 1; /* supports POST */ struct { /* NNTP extensions */ unsigned int ok : 1; /* supports extensions */ /* supports LISTGROUP */ unsigned int listgroup : 1; unsigned int over : 1; /* supports OVER */ unsigned int hdr : 1; /* supports HDR */ unsigned int pat : 1; /* supports PAT */ /* supports STARTTLS */ unsigned int starttls : 1; /* server has MULTIDOMAIN */ unsigned int multidomain : 1; /* supports AUTHINFO USER */ unsigned int authuser : 1; /* supported authenticators */ unsigned int sasl : MAXAUTHENTICATORS; } ext; } nntp; } protocol; } SENDSTREAM; /* Jacket into external interfaces */ typedef long (*readfn_t) (void *stream,unsigned long size,char *buffer); typedef char *(*mailgets_t) (readfn_t f,void *stream,unsigned long size, GETS_DATA *md); typedef char *(*readprogress_t) (GETS_DATA *md,unsigned long octets); typedef void *(*mailcache_t) (MAILSTREAM *stream,unsigned long msgno,long op); typedef long (*mailproxycopy_t) (MAILSTREAM *stream,char *sequence, char *mailbox,long options); typedef long (*tcptimeout_t) (long overall,long last, char *host); typedef void *(*authchallenge_t) (void *stream,unsigned long *len); typedef long (*authrespond_t) (void *stream,char *s,unsigned long size); typedef long (*authcheck_t) (void); typedef long (*authclient_t) (authchallenge_t challenger, authrespond_t responder,char *service,NETMBX *mb, void *s,unsigned long *trial,char *user); typedef char *(*authresponse_t) (void *challenge,unsigned long clen, unsigned long *rlen); typedef char *(*authserver_t) (authresponse_t responder,int argc,char *argv[]); typedef void (*smtpverbose_t) (char *buffer); typedef void (*imapenvelope_t) (MAILSTREAM *stream,unsigned long msgno, ENVELOPE *env); typedef char *(*imapreferral_t) (MAILSTREAM *stream,char *url,long code); typedef void (*overview_t) (MAILSTREAM *stream,unsigned long uid,OVERVIEW *ov, unsigned long msgno); typedef unsigned long *(*sorter_t) (MAILSTREAM *stream,char *charset, SEARCHPGM *spg,SORTPGM *pgm,long flags); typedef void (*parseline_t) (ENVELOPE *env,char *hdr,char *data,char *host); typedef ADDRESS *(*parsephrase_t) (char *phrase,char *end,char *host); typedef void *(*blocknotify_t) (int reason,void *data); typedef long (*kinit_t) (char *host,char *reason); typedef void (*sendcommand_t) (MAILSTREAM *stream,char *cmd,long flags); typedef char *(*newsrcquery_t) (MAILSTREAM *stream,char *mulname,char *name); typedef void (*getacl_t) (MAILSTREAM *stream,char *mailbox,ACLLIST *acl); typedef void (*listrights_t) (MAILSTREAM *stream,char *mailbox,char *id, char *alwaysrights,STRINGLIST *possiblerights); typedef void (*myrights_t) (MAILSTREAM *stream,char *mailbox,char *rights); typedef void (*quota_t) (MAILSTREAM *stream,char *qroot,QUOTALIST *qlist); typedef void (*quotaroot_t) (MAILSTREAM *stream,char *mbx,STRINGLIST *qroot); typedef void (*sortresults_t) (MAILSTREAM *stream,unsigned long *list, unsigned long size); typedef char *(*userprompt_t) (void); typedef long (*append_t) (MAILSTREAM *stream,void *data,char **flags, char **date,STRING **message); typedef void (*copyuid_t) (MAILSTREAM *stream,char *mailbox, unsigned long uidvalidity,SEARCHSET *sourceset, SEARCHSET *destset); typedef void (*appenduid_t) (char *mailbox,unsigned long uidvalidity, SEARCHSET *set); typedef long (*dirfmttest_t) (char *name); typedef long (*scancontents_t) (char *name,char *contents,unsigned long csiz, unsigned long fsiz); typedef void (*freeeltsparep_t) (void **sparep); typedef void (*freeenvelopesparep_t) (void **sparep); typedef void (*freebodysparep_t) (void **sparep); typedef void (*freestreamsparep_t) (void **sparep); typedef void *(*sslstart_t) (void *stream,char *host,unsigned long flags); typedef long (*sslcertificatequery_t) (char *reason,char *host,char *cert); typedef void (*sslfailure_t) (char *host,char *reason,unsigned long flags); typedef void (*logouthook_t) (void *data); typedef char *(*sslclientcert_t) (void); typedef char *(*sslclientkey_t) (void); /* Globals */ extern char *body_types[]; /* defined body type strings */ extern char *body_encodings[]; /* defined body encoding strings */ extern const char *days[]; /* day name strings */ extern const char *months[]; /* month name strings */ /* Threading */ /* Thread node */ #define THREADNODE struct thread_node THREADNODE { unsigned long num; /* message number */ SORTCACHE *sc; /* (internal use) sortcache entry */ THREADNODE *branch; /* branch at this point in tree */ THREADNODE *next; /* next node */ }; typedef void (*threadresults_t) (MAILSTREAM *stream,THREADNODE *tree); /* Thread dispatch */ #define THREADER struct threader_list THREADER { char *name; /* name of threader */ THREADNODE *(*dispatch) (MAILSTREAM *stream,char *charset,SEARCHPGM *spg, long flags,sorter_t sorter); THREADER *next; }; /* Container for references threading */ typedef void ** container_t; /* Namespaces */ #define NAMESPACE struct mail_namespace NAMESPACE { char *name; /* name of this namespace */ int delimiter; /* hierarchy delimiter */ PARAMETER *param; /* namespace parameters */ NAMESPACE *next; /* next namespace */ }; /* Authentication */ #define AUTHENTICATOR struct mail_authenticator AUTHENTICATOR { long flags; /* authenticator flags */ char *name; /* name of this authenticator */ authcheck_t valid; /* authenticator valid on this system */ authclient_t client; /* client function that supports it */ authserver_t server; /* server function that supports it */ AUTHENTICATOR *next; /* next authenticator */ }; /* Mail driver dispatch */ DRIVER { char *name; /* driver name */ unsigned long flags; /* driver flags */ DRIVER *next; /* next driver */ /* mailbox is valid for us */ DRIVER *(*valid) (char *mailbox); /* manipulate driver parameters */ void *(*parameters) (long function,void *value); /* scan mailboxes */ void (*scan) (MAILSTREAM *stream,char *ref,char *pat,char *contents); /* list mailboxes */ void (*list) (MAILSTREAM *stream,char *ref,char *pat); /* list subscribed mailboxes */ void (*lsub) (MAILSTREAM *stream,char *ref,char *pat); /* subscribe to mailbox */ long (*subscribe) (MAILSTREAM *stream,char *mailbox); /* unsubscribe from mailbox */ long (*unsubscribe) (MAILSTREAM *stream,char *mailbox); /* create mailbox */ long (*create) (MAILSTREAM *stream,char *mailbox); /* delete mailbox */ long (*mbxdel) (MAILSTREAM *stream,char *mailbox); /* rename mailbox */ long (*mbxren) (MAILSTREAM *stream,char *old,char *newname); /* status of mailbox */ long (*status) (MAILSTREAM *stream,char *mbx,long flags); /* open mailbox */ MAILSTREAM *(*open) (MAILSTREAM *stream); /* close mailbox */ void (*close) (MAILSTREAM *stream,long options); /* fetch message "fast" attributes */ void (*fast) (MAILSTREAM *stream,char *sequence,long flags); /* fetch message flags */ void (*msgflags) (MAILSTREAM *stream,char *sequence,long flags); /* fetch message overview */ long (*overview) (MAILSTREAM *stream,overview_t ofn); /* fetch message envelopes */ ENVELOPE *(*structure) (MAILSTREAM *stream,unsigned long msgno,BODY **body, long flags); /* return RFC-822 header */ char *(*header) (MAILSTREAM *stream,unsigned long msgno, unsigned long *length,long flags); /* return RFC-822 text */ long (*text) (MAILSTREAM *stream,unsigned long msgno,STRING *bs,long flags); /* load cache */ long (*msgdata) (MAILSTREAM *stream,unsigned long msgno,char *section, unsigned long first,unsigned long last,STRINGLIST *lines, long flags); /* return UID for message */ unsigned long (*uid) (MAILSTREAM *stream,unsigned long msgno); /* return message number from UID */ unsigned long (*msgno) (MAILSTREAM *stream,unsigned long uid); /* modify flags */ void (*flag) (MAILSTREAM *stream,char *sequence,char *flag,long flags); /* per-message modify flags */ void (*flagmsg) (MAILSTREAM *stream,MESSAGECACHE *elt); /* search for message based on criteria */ long (*search) (MAILSTREAM *stream,char *charset,SEARCHPGM *pgm,long flags); /* sort messages */ unsigned long *(*sort) (MAILSTREAM *stream,char *charset,SEARCHPGM *spg, SORTPGM *pgm,long flags); /* thread messages */ THREADNODE *(*thread) (MAILSTREAM *stream,char *type,char *charset, SEARCHPGM *spg,long flag); /* ping mailbox to see if still alive */ long (*ping) (MAILSTREAM *stream); /* check for new messages */ void (*check) (MAILSTREAM *stream); /* expunge deleted messages */ long (*expunge) (MAILSTREAM *stream,char *sequence,long options); /* copy messages to another mailbox */ long (*copy) (MAILSTREAM *stream,char *sequence,char *mailbox,long options); /* append string message to mailbox */ long (*append) (MAILSTREAM *stream,char *mailbox,append_t af,void *data); /* garbage collect stream */ void (*gc) (MAILSTREAM *stream,long gcflags); }; #include "linkage.h" /* Compatibility support names for old interfaces */ #define GET_TRYALTFIRST GET_TRYSSLFIRST #define SET_TRYALTFIRST SET_TRYSSLFIRST #define GET_IMAPTRYALT GET_IMAPTRYSSL #define SET_IMAPTRYALT SET_IMAPTRYSSL #define OP_TRYALT OP_TRYSSL #define altflag sslflag #define mail_close(stream) \ mail_close_full (stream,NIL) #define mail_fetchfast(stream,sequence) \ mail_fetch_fast (stream,sequence,NIL) #define mail_fetchfast_full mail_fetch_fast #define mail_fetchflags(stream,sequence) \ mail_fetch_flags (stream,sequence,NIL) #define mail_fetchflags_full mail_fetch_flags #define mail_fetchenvelope(stream,msgno) \ mail_fetch_structure (stream,msgno,NIL,NIL) #define mail_fetchstructure(stream,msgno,body) \ mail_fetch_structure (stream,msgno,body,NIL) #define mail_fetchstructure_full mail_fetch_structure #define mail_fetchheader(stream,msgno) \ mail_fetch_header (stream,msgno,NIL,NIL,NIL,FT_PEEK) #define mail_fetchheader_full(stream,msgno,lines,len,flags) \ mail_fetch_header (stream,msgno,NIL,lines,len,FT_PEEK | (flags)) #define mail_fetchtext(stream,msgno) \ mail_fetch_text (stream,msgno,NIL,NIL,NIL) #define mail_fetchtext_full(stream,msgno,length,flags) \ mail_fetch_text (stream,msgno,NIL,length,flags) #define mail_fetchbody(stream,msgno,section,length) \ mail_fetch_body (stream,msgno,section,length,NIL) #define mail_fetchbody_full mail_fetch_body #define mail_setflag(stream,sequence,flag) \ mail_flag (stream,sequence,flag,ST_SET) #define mail_setflag_full(stream,sequence,flag,flags) \ mail_flag (stream,sequence,flag,ST_SET | (flags)) #define mail_clearflag(stream,sequence,flag) \ mail_flag (stream,sequence,flag,NIL) #define mail_clearflag_full mail_flag #define mail_search(stream,criteria) \ mail_search_full (stream,NIL,mail_criteria (criteria),SE_FREE); #define mail_expunge(stream) \ mail_expunge_full (stream,NIL,NIL) #define mail_copy(stream,sequence,mailbox) \ mail_copy_full (stream,sequence,mailbox,NIL) #define mail_move(stream,sequence,mailbox) \ mail_copy_full (stream,sequence,mailbox,CP_MOVE) #define mail_append(stream,mailbox,message) \ mail_append_full (stream,mailbox,NIL,NIL,message) /* Interfaces for SVR4 locking brain-damage workaround */ /* Driver dispatching */ #define SAFE_DELETE(dtb,stream,mailbox) (*dtb->mbxdel) (stream,mailbox) #define SAFE_RENAME(dtb,stream,old,newname) (*dtb->mbxren) (stream,old,newname) #define SAFE_STATUS(dtb,stream,mbx,flags) (*dtb->status) (stream,mbx,flags) #define SAFE_COPY(dtb,stream,sequence,mailbox,options) \ (*dtb->copy) (stream,sequence,mailbox,options) #define SAFE_APPEND(dtb,stream,mailbox,af,data) \ (*dtb->append) (stream,mailbox,af,data) #define SAFE_SCAN_CONTENTS(dtb,name,contents,csiz,fsiz) \ scan_contents (dtb,name,contents,csiz,fsiz) /* Driver callbacks */ #define MM_EXISTS mm_exists #define MM_EXPUNGED mm_expunged #define MM_FLAGS mm_flags #define MM_NOTIFY mm_notify #define MM_STATUS mm_status #define MM_LOG mm_log #define MM_CRITICAL mm_critical #define MM_NOCRITICAL mm_nocritical #define MM_DISKERROR mm_diskerror #define MM_FATAL mm_fatal #define MM_APPEND(af) (*af) /* Function prototypes */ void mm_searched (MAILSTREAM *stream,unsigned long number); void mm_exists (MAILSTREAM *stream,unsigned long number); void mm_expunged (MAILSTREAM *stream,unsigned long number); void mm_flags (MAILSTREAM *stream,unsigned long number); void mm_notify (MAILSTREAM *stream,char *string,long errflg); void mm_list (MAILSTREAM *stream,int delimiter,char *name,long attributes); void mm_lsub (MAILSTREAM *stream,int delimiter,char *name,long attributes); void mm_status (MAILSTREAM *stream,char *mailbox,MAILSTATUS *status); void mm_log (char *string,long errflg); void mm_dlog (char *string); void mm_login (NETMBX *mb,char *user,char *pwd,long trial); void mm_critical (MAILSTREAM *stream); void mm_nocritical (MAILSTREAM *stream); long mm_diskerror (MAILSTREAM *stream,long errcode,long serious); void mm_fatal (char *string); void *mm_cache (MAILSTREAM *stream,unsigned long msgno,long op); extern STRINGDRIVER mail_string; void mail_versioncheck (char *version); void mail_link (DRIVER *driver); void *mail_parameters (MAILSTREAM *stream,long function,void *value); DRIVER *mail_valid (MAILSTREAM *stream,char *mailbox,char *purpose); DRIVER *mail_valid_net (char *name,DRIVER *drv,char *host,char *mailbox); long mail_valid_net_parse (char *name,NETMBX *mb); long mail_valid_net_parse_work (char *name,NETMBX *mb,char *service); void mail_scan (MAILSTREAM *stream,char *ref,char *pat,char *contents); void mail_list (MAILSTREAM *stream,char *ref,char *pat); void mail_lsub (MAILSTREAM *stream,char *ref,char *pat); long mail_subscribe (MAILSTREAM *stream,char *mailbox); long mail_unsubscribe (MAILSTREAM *stream,char *mailbox); long mail_create (MAILSTREAM *stream,char *mailbox); long mail_delete (MAILSTREAM *stream,char *mailbox); long mail_rename (MAILSTREAM *stream,char *old,char *newname); char *mail_utf7_valid (char *mailbox); long mail_status (MAILSTREAM *stream,char *mbx,long flags); long mail_status_default (MAILSTREAM *stream,char *mbx,long flags); MAILSTREAM *mail_open (MAILSTREAM *stream,char *name,long options); MAILSTREAM *mail_open_work (DRIVER *d,MAILSTREAM *stream,char *name, long options); MAILSTREAM *mail_close_full (MAILSTREAM *stream,long options); MAILHANDLE *mail_makehandle (MAILSTREAM *stream); void mail_free_handle (MAILHANDLE **handle); MAILSTREAM *mail_stream (MAILHANDLE *handle); void mail_fetch_fast (MAILSTREAM *stream,char *sequence,long flags); void mail_fetch_flags (MAILSTREAM *stream,char *sequence,long flags); void mail_fetch_overview (MAILSTREAM *stream,char *sequence,overview_t ofn); void mail_fetch_overview_sequence (MAILSTREAM *stream,char *sequence, overview_t ofn); void mail_fetch_overview_default (MAILSTREAM *stream,overview_t ofn); ENVELOPE *mail_fetch_structure (MAILSTREAM *stream,unsigned long msgno, BODY **body,long flags); char *mail_fetch_message (MAILSTREAM *stream,unsigned long msgno, unsigned long *len,long flags); char *mail_fetch_header (MAILSTREAM *stream,unsigned long msgno,char *section, STRINGLIST *lines,unsigned long *len,long flags); char *mail_fetch_text (MAILSTREAM *stream,unsigned long msgno,char *section, unsigned long *len,long flags); char *mail_fetch_mime (MAILSTREAM *stream,unsigned long msgno,char *section, unsigned long *len,long flags); char *mail_fetch_body (MAILSTREAM *stream,unsigned long msgno,char *section, unsigned long *len,long flags); long mail_partial_text (MAILSTREAM *stream,unsigned long msgno,char *section, unsigned long first,unsigned long last,long flags); long mail_partial_body (MAILSTREAM *stream,unsigned long msgno,char *section, unsigned long first,unsigned long last,long flags); char *mail_fetch_text_return (GETS_DATA *md,SIZEDTEXT *t,unsigned long *len); char *mail_fetch_string_return (GETS_DATA *md,STRING *bs,unsigned long i, unsigned long *len,long flags); long mail_read (void *stream,unsigned long size,char *buffer); unsigned long mail_uid (MAILSTREAM *stream,unsigned long msgno); unsigned long mail_msgno (MAILSTREAM *stream,unsigned long uid); void mail_fetchfrom (char *s,MAILSTREAM *stream,unsigned long msgno, long length); void mail_fetchsubject (char *s,MAILSTREAM *stream,unsigned long msgno, long length); MESSAGECACHE *mail_elt (MAILSTREAM *stream,unsigned long msgno); void mail_flag (MAILSTREAM *stream,char *sequence,char *flag,long flags); long mail_search_full (MAILSTREAM *stream,char *charset,SEARCHPGM *pgm, long flags); long mail_search_default (MAILSTREAM *stream,char *charset,SEARCHPGM *pgm, long flags); long mail_ping (MAILSTREAM *stream); void mail_check (MAILSTREAM *stream); long mail_expunge_full (MAILSTREAM *stream,char *sequence,long options); long mail_copy_full (MAILSTREAM *stream,char *sequence,char *mailbox, long options); long mail_append_full (MAILSTREAM *stream,char *mailbox,char *flags,char *date, STRING *message); long mail_append_multiple (MAILSTREAM *stream,char *mailbox,append_t af, void *data); void mail_gc (MAILSTREAM *stream,long gcflags); void mail_gc_msg (MESSAGE *msg,long gcflags); void mail_gc_body (BODY *body); BODY *mail_body (MAILSTREAM *stream,unsigned long msgno, unsigned char *section); char *mail_date (char *string,MESSAGECACHE *elt); char *mail_cdate (char *string,MESSAGECACHE *elt); long mail_parse_date (MESSAGECACHE *elt,unsigned char *string); void mail_exists (MAILSTREAM *stream,unsigned long nmsgs); void mail_recent (MAILSTREAM *stream,unsigned long recent); void mail_expunged (MAILSTREAM *stream,unsigned long msgno); void mail_lock (MAILSTREAM *stream); void mail_unlock (MAILSTREAM *stream); void mail_debug (MAILSTREAM *stream); void mail_nodebug (MAILSTREAM *stream); void mail_dlog (char *string,long flag); long mail_match_lines (STRINGLIST *lines,STRINGLIST *msglines,long flags); unsigned long mail_filter (char *text,unsigned long len,STRINGLIST *lines, long flags); long mail_search_msg (MAILSTREAM *stream,unsigned long msgno,char *section, SEARCHPGM *pgm); long mail_search_header_text (char *s,STRINGLIST *st); long mail_search_header (SIZEDTEXT *hdr,STRINGLIST *st); long mail_search_text (MAILSTREAM *stream,unsigned long msgno,char *section, STRINGLIST *st,long flags); long mail_search_body (MAILSTREAM *stream,unsigned long msgno,BODY *body, char *prefix,unsigned long section,long flags); long mail_search_string (SIZEDTEXT *s,char *charset,STRINGLIST **st); long mail_search_string_work (SIZEDTEXT *s,STRINGLIST **st); long mail_search_keyword (MAILSTREAM *stream,MESSAGECACHE *elt,STRINGLIST *st, long flag); long mail_search_addr (ADDRESS *adr,STRINGLIST *st); char *mail_search_gets (readfn_t f,void *stream,unsigned long size, GETS_DATA *md); SEARCHPGM *mail_criteria (char *criteria); int mail_criteria_date (unsigned short *date,char **r); int mail_criteria_string (STRINGLIST **s,char **r); unsigned short mail_shortdate (unsigned int year,unsigned int month, unsigned int day); SEARCHSET *mail_parse_set (char *s,char **ret); SEARCHSET *mail_append_set (SEARCHSET *set,unsigned long msgno); unsigned long *mail_sort (MAILSTREAM *stream,char *charset,SEARCHPGM *spg, SORTPGM *pgm,long flags); unsigned long *mail_sort_cache (MAILSTREAM *stream,SORTPGM *pgm,SORTCACHE **sc, long flags); unsigned long *mail_sort_msgs (MAILSTREAM *stream,char *charset,SEARCHPGM *spg, SORTPGM *pgm,long flags); SORTCACHE **mail_sort_loadcache (MAILSTREAM *stream,SORTPGM *pgm); unsigned int mail_strip_subject (char *t,char **ret); char *mail_strip_subject_wsp (char *s); char *mail_strip_subject_blob (char *s); int mail_sort_compare (const void *a1,const void *a2); unsigned long mail_longdate (MESSAGECACHE *elt); THREADNODE *mail_thread (MAILSTREAM *stream,char *type,char *charset, SEARCHPGM *spg,long flags); THREADNODE *mail_thread_msgs (MAILSTREAM *stream,char *type,char *charset, SEARCHPGM *spg,long flags,sorter_t sorter); THREADNODE *mail_thread_orderedsubject (MAILSTREAM *stream,char *charset, SEARCHPGM *spg,long flags, sorter_t sorter); THREADNODE *mail_thread_references (MAILSTREAM *stream,char *charset, SEARCHPGM *spg,long flags, sorter_t sorter); void mail_thread_loadcache (MAILSTREAM *stream,unsigned long uid,OVERVIEW *ov, unsigned long msgno); char *mail_thread_parse_msgid (char *s,char **ss); STRINGLIST *mail_thread_parse_references (char *s,long flag); long mail_thread_check_child (container_t mother,container_t daughter); container_t mail_thread_prune_dummy (container_t msg,container_t ane); container_t mail_thread_prune_dummy_work (container_t msg,container_t ane); THREADNODE *mail_thread_c2node (MAILSTREAM *stream,container_t con,long flags); THREADNODE *mail_thread_sort (THREADNODE *thr,THREADNODE **tc); int mail_thread_compare_date (const void *a1,const void *a2); long mail_sequence (MAILSTREAM *stream,unsigned char *sequence); long mail_uid_sequence (MAILSTREAM *stream,unsigned char *sequence); long mail_parse_flags (MAILSTREAM *stream,char *flag,unsigned long *uf); long mail_usable_network_stream (MAILSTREAM *stream,char *name); MESSAGECACHE *mail_new_cache_elt (unsigned long msgno); ENVELOPE *mail_newenvelope (void); ADDRESS *mail_newaddr (void); BODY *mail_newbody (void); BODY *mail_initbody (BODY *body); PARAMETER *mail_newbody_parameter (void); PART *mail_newbody_part (void); MESSAGE *mail_newmsg (void); STRINGLIST *mail_newstringlist (void); SEARCHPGM *mail_newsearchpgm (void); SEARCHHEADER *mail_newsearchheader (char *line,char *text); SEARCHSET *mail_newsearchset (void); SEARCHOR *mail_newsearchor (void); SEARCHPGMLIST *mail_newsearchpgmlist (void); SORTPGM *mail_newsortpgm (void); THREADNODE *mail_newthreadnode (SORTCACHE *sc); ACLLIST *mail_newacllist (void); QUOTALIST *mail_newquotalist (void); void mail_free_body (BODY **body); void mail_free_body_data (BODY *body); void mail_free_body_parameter (PARAMETER **parameter); void mail_free_body_part (PART **part); void mail_free_cache (MAILSTREAM *stream); void mail_free_elt (MESSAGECACHE **elt); void mail_free_envelope (ENVELOPE **env); void mail_free_address (ADDRESS **address); void mail_free_stringlist (STRINGLIST **string); void mail_free_searchpgm (SEARCHPGM **pgm); void mail_free_searchheader (SEARCHHEADER **hdr); void mail_free_searchset (SEARCHSET **set); void mail_free_searchor (SEARCHOR **orl); void mail_free_searchpgmlist (SEARCHPGMLIST **pgl); void mail_free_namespace (NAMESPACE **n); void mail_free_sortpgm (SORTPGM **pgm); void mail_free_threadnode (THREADNODE **thr); void mail_free_acllist (ACLLIST **al); void mail_free_quotalist (QUOTALIST **ql); void auth_link (AUTHENTICATOR *auth); char *mail_auth (char *mechanism,authresponse_t resp,int argc,char *argv[]); AUTHENTICATOR *mail_lookup_auth (unsigned long i); unsigned int mail_lookup_auth_name (char *mechanism,long flags); NETSTREAM *net_open (NETMBX *mb,NETDRIVER *dv,unsigned long port, NETDRIVER *ssld,char *ssls,unsigned long sslp); NETSTREAM *net_open_work (NETDRIVER *dv,char *host,char *service, unsigned long port,unsigned long portoverride, unsigned long flags); NETSTREAM *net_aopen (NETDRIVER *dv,NETMBX *mb,char *service,char *usrbuf); char *net_getline (NETSTREAM *stream); /* stream must be void* for use as readfn_t */ long net_getbuffer (void *stream,unsigned long size,char *buffer); long net_soutr (NETSTREAM *stream,char *string); long net_sout (NETSTREAM *stream,char *string,unsigned long size); void net_close (NETSTREAM *stream); char *net_host (NETSTREAM *stream); char *net_remotehost (NETSTREAM *stream); unsigned long net_port (NETSTREAM *stream); char *net_localhost (NETSTREAM *stream); long sm_subscribe (char *mailbox); long sm_unsubscribe (char *mailbox); char *sm_read (void **sdb); void ssl_onceonlyinit (void); char *ssl_start_tls (char *s); void ssl_server_init (char *server); /* Server I/O functions */ int PBIN (void); char *PSIN (char *s,int n); long PSINR (char *s,unsigned long n); int PBOUT (int c); long INWAIT (long seconds); int PSOUT (char *s); int PSOUTR (SIZEDTEXT *s); int PFLUSH (void); alpine-2.10+dfsg/imap/src/c-client/rfc822.c0000600000175000017500000023576412074130635021752 0ustar paulproteuspaulproteus/* ======================================================================== * Copyright 1988-2008 University of Washington * * Licensed under the Apache License, Version 2.0 (the "License"); * you may not use this file except in compliance with the License. * You may obtain a copy of the License at * * http://www.apache.org/licenses/LICENSE-2.0 * * * ======================================================================== */ /* * Program: RFC 2822 and MIME routines * * Author: Mark Crispin * UW Technology * University of Washington * Seattle, WA 98195 * Internet: MRC@Washington.EDU * * Date: 27 July 1988 * Last Edited: 14 May 2008 * * This original version of this file is * Copyright 1988 Stanford University * and was developed in the Symbolic Systems Resources Group of the Knowledge * Systems Laboratory at Stanford University in 1987-88, and was funded by the * Biomedical Research Technology Program of the NationalInstitutes of Health * under grant number RR-00785. */ #include #include #include #include "c-client.h" /* Support for deprecated features in earlier specifications. Note that this * module follows RFC 2822, and all use of "rfc822" in function names is * for compatibility. Only the code identified by the conditionals below * follows the earlier documents. */ #define RFC733 1 /* parse "at" */ #define RFC822 0 /* generate A-D-L (MUST be 0 for 2822) */ /* RFC-822 static data */ #define RFC822CONT " " /* RFC 2822 continuation */ /* should have been "Remailed-" */ #define RESENTPREFIX "ReSent-" static char *resentprefix = RESENTPREFIX; /* syntax error host string */ static const char *errhst = ERRHOST; /* Body formats constant strings, must match definitions in mail.h */ char *body_types[TYPEMAX+1] = { "TEXT", "MULTIPART", "MESSAGE", "APPLICATION", "AUDIO", "IMAGE", "VIDEO", "MODEL", "X-UNKNOWN" }; char *body_encodings[ENCMAX+1] = { "7BIT", "8BIT", "BINARY", "BASE64", "QUOTED-PRINTABLE", "X-UNKNOWN" }; /* Token delimiting special characters */ /* RFC 2822 specials */ const char *specials = " ()<>@,;:\\\"[].\1\2\3\4\5\6\7\10\11\12\13\14\15\16\17\20\21\22\23\24\25\26\27\30\31\32\33\34\35\36\37\177"; /* RFC 2822 phrase specials (no space) */ const char *rspecials = "()<>@,;:\\\"[].\1\2\3\4\5\6\7\10\11\12\13\14\15\16\17\20\21\22\23\24\25\26\27\30\31\32\33\34\35\36\37\177"; /* RFC 2822 dot-atom specials (no dot) */ const char *wspecials = " ()<>@,;:\\\"[]\1\2\3\4\5\6\7\10\11\12\13\14\15\16\17\20\21\22\23\24\25\26\27\30\31\32\33\34\35\36\37\177"; /* RFC 2045 MIME body token specials */ const char *tspecials = " ()<>@,;:\\\"[]/?=\1\2\3\4\5\6\7\10\11\12\13\14\15\16\17\20\21\22\23\24\25\26\27\30\31\32\33\34\35\36\37\177"; /* Subtype defaulting (a no-no, but regretably necessary...) * Accepts: type code * Returns: default subtype name */ char *rfc822_default_subtype (unsigned short type) { switch (type) { case TYPETEXT: /* default is TEXT/PLAIN */ return "PLAIN"; case TYPEMULTIPART: /* default is MULTIPART/MIXED */ return "MIXED"; case TYPEMESSAGE: /* default is MESSAGE/RFC822 */ return "RFC822"; case TYPEAPPLICATION: /* default is APPLICATION/OCTET-STREAM */ return "OCTET-STREAM"; case TYPEAUDIO: /* default is AUDIO/BASIC */ return "BASIC"; default: /* others have no default subtype */ return "UNKNOWN"; } } /* RFC 2822 parsing routines */ /* Parse an RFC 2822 message * Accepts: pointer to return envelope * pointer to return body * pointer to header * header byte count * pointer to body stringstruct * pointer to local host name * recursion depth * source driver flags */ void rfc822_parse_msg_full (ENVELOPE **en,BODY **bdy,char *s,unsigned long i, STRING *bs,char *host,unsigned long depth, unsigned long flags) { char c,*t,*d; char *tmp = (char *) fs_get ((size_t) i + 100); ENVELOPE *env = (*en = mail_newenvelope ()); BODY *body = bdy ? (*bdy = mail_newbody ()) : NIL; long MIMEp = -1; /* flag that MIME semantics are in effect */ long PathP = NIL; /* flag that a Path: was seen */ parseline_t pl = (parseline_t) mail_parameters (NIL,GET_PARSELINE,NIL); if (!host) host = BADHOST; /* make sure that host is non-null */ while (i && *s != '\n') { /* until end of header */ t = tmp; /* initialize buffer pointer */ c = ' '; /* and previous character */ while (i && c) { /* collect text until logical end of line */ switch (c = *s++) { /* slurp a character */ case '\015': /* return, possible end of logical line */ if (*s == '\n') break; /* ignore if LF follows */ case '\012': /* LF, possible end of logical line */ /* tie off unless next line starts with WS */ if (*s != ' ' && *s != '\t') *t++ = c = '\0'; break; case '\t': /* tab */ *t++ = ' '; /* coerce to space */ break; default: /* all other characters */ *t++ = c; /* insert the character into the line */ break; } if (!--i) *t++ = '\0'; /* see if end of header */ } /* find header item type */ if (t = d = strchr (tmp,':')) { *d++ = '\0'; /* tie off header item, point at its data */ while (*d == ' ') d++; /* flush whitespace */ while ((tmp < t--) && (*t == ' ')) *t = '\0'; ucase (tmp); /* coerce to uppercase */ /* external callback */ if (pl) (*pl) (env,tmp,d,host); switch (*tmp) { /* dispatch based on first character */ case '>': /* possible >From: */ if (!strcmp (tmp+1,"FROM")) rfc822_parse_adrlist (&env->from,d,host); break; case 'B': /* possible bcc: */ if (!strcmp (tmp+1,"CC")) rfc822_parse_adrlist (&env->bcc,d,host); break; case 'C': /* possible cc: or Content-*/ if (!strcmp (tmp+1,"C")) rfc822_parse_adrlist (&env->cc,d,host); else if ((tmp[1] == 'O') && (tmp[2] == 'N') && (tmp[3] == 'T') && (tmp[4] == 'E') && (tmp[5] == 'N') && (tmp[6] == 'T') && (tmp[7] == '-') && body) switch (MIMEp) { case -1: /* unknown if MIME or not */ if (!(MIMEp = /* see if MIME-Version header exists */ search ((unsigned char *) s-1,i, (unsigned char *)"\012MIME-Version",(long) 13))) { #if 1 /* This is a disgusting kludge, and most of the messages which * benefit from it are spam. */ if (!strcmp (tmp+8,"TRANSFER-ENCODING") || (!strcmp (tmp+8,"TYPE") && strchr (d,'/'))) { MM_LOG ("Warning: MIME header encountered in non-MIME message", PARSE); MIMEp = 1; /* declare MIME now */ } else #endif break; /* non-MIME message */ } case T: /* definitely MIME */ rfc822_parse_content_header (body,tmp+8,d); } break; case 'D': /* possible Date: */ if (!env->date && !strcmp (tmp+1,"ATE")) env->date = cpystr (d); break; case 'F': /* possible From: */ if (!strcmp (tmp+1,"ROM")) rfc822_parse_adrlist (&env->from,d,host); else if (!strcmp (tmp+1,"OLLOWUP-TO")) { t = env->followup_to = (char *) fs_get (1 + strlen (d)); while (c = *d++) if (c != ' ') *t++ = c; *t++ = '\0'; } break; case 'I': /* possible In-Reply-To: */ if (!env->in_reply_to && !strcmp (tmp+1,"N-REPLY-TO")) env->in_reply_to = cpystr (d); break; case 'M': /* possible Message-ID: or MIME-Version: */ if (!env->message_id && !strcmp (tmp+1,"ESSAGE-ID")) env->message_id = cpystr (d); else if (!strcmp (tmp+1,"IME-VERSION")) { /* tie off at end of phrase */ if (t = rfc822_parse_phrase (d)) *t = '\0'; rfc822_skipws (&d); /* skip whitespace */ /* known version? */ if (strcmp (d,"1.0") && strcmp (d,"RFC-XXXX")) MM_LOG ("Warning: message has unknown MIME version",PARSE); MIMEp = T; /* note that we are MIME */ } break; case 'N': /* possible Newsgroups: */ if (!env->newsgroups && !strcmp (tmp+1,"EWSGROUPS")) { t = env->newsgroups = (char *) fs_get (1 + strlen (d)); while (c = *d++) if (c != ' ') *t++ = c; *t++ = '\0'; } break; case 'P': /* possible Path: */ if (!strcmp (tmp+1,"ATH")) env->ngpathexists = T; break; case 'R': /* possible Reply-To: */ if (!strcmp (tmp+1,"EPLY-TO")) rfc822_parse_adrlist (&env->reply_to,d,host); else if (!env->references && !strcmp (tmp+1,"EFERENCES")) env->references = cpystr (d); break; case 'S': /* possible Subject: or Sender: */ if (!env->subject && !strcmp (tmp+1,"UBJECT")) env->subject = cpystr (d); else if (!strcmp (tmp+1,"ENDER")) rfc822_parse_adrlist (&env->sender,d,host); break; case 'T': /* possible To: */ if (!strcmp (tmp+1,"O")) rfc822_parse_adrlist (&env->to,d,host); break; default: break; } } } fs_give ((void **) &tmp); /* done with scratch buffer */ /* default Sender: and Reply-To: to From: */ if (!env->sender) env->sender = rfc822_cpy_adr (env->from); if (!env->reply_to) env->reply_to = rfc822_cpy_adr (env->from); /* now parse the body */ if (body) rfc822_parse_content (body,bs,host,depth,flags); } /* Parse a message body content * Accepts: pointer to body structure * body string * pointer to local host name * recursion depth * source driver flags */ void rfc822_parse_content (BODY *body,STRING *bs,char *h,unsigned long depth, unsigned long flags) { char c,c1,*s,*s1; int f; unsigned long i,j,k,m; PARAMETER *param; PART *part = NIL; if (depth > MAXMIMEDEPTH) { /* excessively deep recursion? */ body->type = TYPETEXT; /* yes, probably a malicious MIMEgram */ MM_LOG ("Ignoring excessively deep MIME recursion",PARSE); } if (!body->subtype) /* default subtype if still unknown */ body->subtype = cpystr (rfc822_default_subtype (body->type)); /* note offset and sizes */ body->contents.offset = GETPOS (bs); /* note internal body size in all cases */ body->size.bytes = body->contents.text.size = i = SIZE (bs); if (!(flags & DR_CRLF)) body->size.bytes = strcrlflen (bs); switch (body->type) { /* see if anything else special to do */ case TYPETEXT: /* text content */ if (!body->parameter) { /* no parameters set */ body->parameter = mail_newbody_parameter (); body->parameter->attribute = cpystr ("CHARSET"); while (i--) { /* count lines and guess charset */ c = SNX (bs); /* get current character */ /* charset still unknown? */ if (!body->parameter->value) { if ((c == I2C_ESC) && (i && i--) && ((c = SNX (bs)) == I2C_MULTI) && (i && i--) && (((c = SNX (bs)) == I2CS_94x94_JIS_NEW) || (c == I2CS_94x94_JIS_OLD))) body->parameter->value = cpystr ("ISO-2022-JP"); else if (c & 0x80) body->parameter->value = cpystr ("X-UNKNOWN"); } if (c == '\n') body->size.lines++; } /* 7-bit content */ if (!body->parameter->value) switch (body->encoding) { case ENC7BIT: /* unadorned 7-bit */ case ENC8BIT: /* unadorned 8-bit (but 7-bit content) */ case ENCBINARY: /* binary (but 7-bit content( */ body->parameter->value = cpystr ("US-ASCII"); break; default: /* QUOTED-PRINTABLE, BASE64, etc. */ body->parameter->value = cpystr ("X-UNKNOWN"); break; } } /* just count lines */ else while (i--) if ((SNX (bs)) == '\n') body->size.lines++; break; case TYPEMESSAGE: /* encapsulated message */ /* encapsulated RFC-822 message? */ if (!strcmp (body->subtype,"RFC822")) { body->nested.msg = mail_newmsg (); switch (body->encoding) { /* make sure valid encoding */ case ENC7BIT: /* these are valid nested encodings */ case ENC8BIT: case ENCBINARY: break; default: MM_LOG ("Ignoring nested encoding of message contents",PARSE); } /* hunt for blank line */ for (c = '\012',j = 0; (i > j) && ((c != '\012') || (CHR(bs) != '\012')); j++) if ((c1 = SNX (bs)) != '\015') c = c1; if (i > j) { /* unless no more text */ c1 = SNX (bs); /* body starts here */ j++; /* advance count */ } /* note body text offset and header size */ body->nested.msg->header.text.size = j; body->nested.msg->text.text.size = body->contents.text.size - j; body->nested.msg->text.offset = GETPOS (bs); body->nested.msg->full.offset = body->nested.msg->header.offset = body->contents.offset; body->nested.msg->full.text.size = body->contents.text.size; /* copy header string */ SETPOS (bs,body->contents.offset); s = (char *) fs_get ((size_t) j + 1); for (s1 = s,k = j; k--; *s1++ = SNX (bs)); s[j] = '\0'; /* tie off string (not really necessary) */ /* now parse the body */ rfc822_parse_msg_full (&body->nested.msg->env,&body->nested.msg->body,s, j,bs,h,depth+1,flags); fs_give ((void **) &s); /* free header string */ /* restore position */ SETPOS (bs,body->contents.offset); } /* count number of lines */ while (i--) if (SNX (bs) == '\n') body->size.lines++; break; case TYPEMULTIPART: /* multiple parts */ switch (body->encoding) { /* make sure valid encoding */ case ENC7BIT: /* these are valid nested encodings */ case ENC8BIT: case ENCBINARY: break; default: MM_LOG ("Ignoring nested encoding of multipart contents",PARSE); } /* remember if digest */ f = !strcmp (body->subtype,"DIGEST"); /* find cookie */ for (s1 = NIL,param = body->parameter; param && !s1; param = param->next) if (!strcmp (param->attribute,"BOUNDARY")) s1 = param->value; if (!s1) s1 = "-"; /* yucky default */ j = strlen (s1) + 2; /* length of cookie and header */ c = '\012'; /* initially at beginning of line */ while (i > j) { /* examine data */ if (m = GETPOS (bs)) m--; /* get position in front of character */ switch (c) { /* examine each line */ case '\015': /* handle CRLF form */ if (CHR (bs) == '\012'){/* following LF? */ c = SNX (bs); i--; /* yes, slurp it */ } case '\012': /* at start of a line, start with -- ? */ if (!(i && i-- && ((c = SNX (bs)) == '-') && i-- && ((c = SNX (bs)) == '-'))) break; /* see if cookie matches */ if (k = j - 2) for (s = s1; i-- && *s++ == (c = SNX (bs)) && --k;); if (k) break; /* strings didn't match if non-zero */ /* terminating delimiter? */ if ((c = ((i && i--) ? (SNX (bs)) : '\012')) == '-') { if ((i && i--) && ((c = SNX (bs)) == '-') && ((i && i--) ? (((c = SNX (bs)) == '\015') || (c=='\012')):T)) { /* if have a final part calculate its size */ if (part) part->body.mime.text.size = (m > part->body.mime.offset) ? (m - part->body.mime.offset) :0; part = NIL; i = 1; /* terminate scan */ } break; } /* swallow trailing whitespace */ while ((c == ' ') || (c == '\t')) c = ((i && i--) ? (SNX (bs)) : '\012'); switch (c) { /* need newline after all of it */ case '\015': /* handle CRLF form */ if (i && CHR (bs) == '\012') { c = SNX (bs); i--;/* yes, slurp it */ } case '\012': /* new line */ if (part) { /* calculate size of previous */ part->body.mime.text.size = (m > part->body.mime.offset) ? (m-part->body.mime.offset) : 0; /* instantiate next */ part = part->next = mail_newbody_part (); } /* otherwise start new list */ else part = body->nested.part = mail_newbody_part (); /* digest has a different default */ if (f) part->body.type = TYPEMESSAGE; /* note offset from main body */ part->body.mime.offset = GETPOS (bs); break; default: /* whatever it was it wasn't valid */ break; } break; default: /* not at a line */ c = SNX (bs); i--; /* get next character */ break; } } /* calculate size of any final part */ if (part) part->body.mime.text.size = i + ((GETPOS(bs) > part->body.mime.offset) ? (GETPOS(bs) - part->body.mime.offset) : 0); /* make a scratch buffer */ s1 = (char *) fs_get ((size_t) (k = MAILTMPLEN)); /* in case empty multipart */ if (!body->nested.part) body->nested.part = mail_newbody_part (); /* parse non-empty body parts */ for (part = body->nested.part; part; part = part->next) { /* part non-empty (header and/or content)? */ if (i = part->body.mime.text.size) { /* move to that part of the body */ SETPOS (bs,part->body.mime.offset); /* until end of header */ while (i && ((c = CHR (bs)) != '\015') && (c != '\012')) { /* collect text until logical end of line */ for (j = 0,c = ' '; c; ) { /* make sure buffer big enough */ if (j > (k - 10)) fs_resize ((void **) &s1,k += MAILTMPLEN); switch (c1 = SNX (bs)) { case '\015': /* return */ if (i && (CHR (bs) == '\012')) { c1 = SNX (bs); /* eat any LF following */ i--; } case '\012': /* newline, possible end of logical line */ /* tie off unless continuation */ if (!i || ((CHR (bs) != ' ') && (CHR (bs) != '\t'))) s1[j] = c = '\0'; break; case '\t': /* tab */ case ' ': /* insert whitespace if not already there */ if (c != ' ') s1[j++] = c = ' '; break; default: /* all other characters */ s1[j++] = c = c1; /* insert the character into the line */ break; } /* end of data ties off the header */ if (!i || !--i) s1[j++] = c = '\0'; } /* find header item type */ if (((s1[0] == 'C') || (s1[0] == 'c')) && ((s1[1] == 'O') || (s1[1] == 'o')) && ((s1[2] == 'N') || (s1[2] == 'n')) && ((s1[3] == 'T') || (s1[3] == 't')) && ((s1[4] == 'E') || (s1[4] == 'e')) && ((s1[5] == 'N') || (s1[5] == 'n')) && ((s1[6] == 'T') || (s1[6] == 't')) && (s1[7] == '-') && (s = strchr (s1+8,':'))) { /* tie off and flush whitespace */ for (*s++ = '\0'; *s == ' '; s++); /* parse the header */ rfc822_parse_content_header (&part->body,ucase (s1+8),s); } } /* skip header trailing (CR)LF */ if (i && (CHR (bs) =='\015')) {i--; c1 = SNX (bs);} if (i && (CHR (bs) =='\012')) {i--; c1 = SNX (bs);} j = bs->size; /* save upper level size */ /* set offset for next level, fake size to i */ bs->size = GETPOS (bs) + i; part->body.mime.text.size -= i; /* now parse it */ rfc822_parse_content (&part->body,bs,h,depth+1,flags); bs->size = j; /* restore current level size */ } else { /* zero-length part, use default subtype */ part->body.subtype = cpystr (rfc822_default_subtype (part->body.type)); /* see if anything else special to do */ switch (part->body.type) { case TYPETEXT: /* text content */ /* default parameters */ if (!part->body.parameter) { part->body.parameter = mail_newbody_parameter (); part->body.parameter->attribute = cpystr ("CHARSET"); /* only assume US-ASCII if 7BIT */ part->body.parameter->value = cpystr ((part->body.encoding == ENC7BIT) ? "US-ASCII" : "X-UNKNOWN"); } break; case TYPEMESSAGE: /* encapsulated message in digest */ part->body.nested.msg = mail_newmsg (); break; default: break; } } } fs_give ((void **) &s1); /* finished with scratch buffer */ break; default: /* nothing special to do in any other case */ break; } } /* Parse RFC 2822 body content header * Accepts: body to write to * possible content name * remainder of header */ void rfc822_parse_content_header (BODY *body,char *name,char *s) { char c,*t,tmp[MAILTMPLEN]; long i; STRINGLIST *stl; rfc822_skipws (&s); /* skip leading comments */ /* flush whitespace */ if (t = strchr (name,' ')) *t = '\0'; switch (*name) { /* see what kind of content */ case 'I': /* possible Content-ID */ if (!(strcmp (name+1,"D") || body->id)) body->id = cpystr (s); break; case 'D': /* possible Content-Description */ if (!(strcmp (name+1,"ESCRIPTION") || body->description)) body->description = cpystr (s); if (!(strcmp (name+1,"ISPOSITION") || body->disposition.type)) { /* get type word */ if (!(name = rfc822_parse_word (s,tspecials))) break; c = *name; /* remember delimiter */ *name = '\0'; /* tie off type */ body->disposition.type = ucase (cpystr (s)); *name = c; /* restore delimiter */ rfc822_skipws (&name); /* skip whitespace */ rfc822_parse_parameter (&body->disposition.parameter,name); } break; case 'L': /* possible Content-Language */ if (!(strcmp (name+1,"ANGUAGE") || body->language)) { stl = NIL; /* process languages */ while (s && (name = rfc822_parse_word (s,tspecials))) { c = *name; /* save delimiter */ *name = '\0'; /* tie off subtype */ if (stl) stl = stl->next = mail_newstringlist (); else stl = body->language = mail_newstringlist (); stl->text.data = (unsigned char *) ucase (cpystr (s)); stl->text.size = strlen ((char *) stl->text.data); *name = c; /* restore delimiter */ rfc822_skipws (&name); /* skip whitespace */ if (*name == ',') { /* any more languages? */ s = ++name; /* advance to it them */ rfc822_skipws (&s); } else s = NIL; /* bogus or end of list */ } } else if (!(strcmp (name+1,"OCATION") || body->location)) body->location = cpystr (s); break; case 'M': /* possible Content-MD5 */ if (!(strcmp (name+1,"D5") || body->md5)) body->md5 = cpystr (s); break; case 'T': /* possible Content-Type/Transfer-Encoding */ if (!(strcmp (name+1,"YPE") || body->subtype || body->parameter)) { /* get type word */ if (!(name = rfc822_parse_word (s,tspecials))) break; c = *name; /* remember delimiter */ *name = '\0'; /* tie off type */ /* search for body type */ for (i = 0,s = rfc822_cpy (s); (i <= TYPEMAX) && body_types[i] && compare_cstring (s,body_types[i]); i++); if (i > TYPEMAX) { /* fell off end of loop? */ body->type = TYPEOTHER; /* coerce to X-UNKNOWN */ sprintf (tmp,"MIME type table overflow: %.100s",s); MM_LOG (tmp,PARSE); } else { /* record body type index */ body->type = (unsigned short) i; /* and name if new type */ if (body_types[body->type]) fs_give ((void **) &s); else { /* major MIME body type unknown to us */ body_types[body->type] = ucase (s); sprintf (tmp,"Unknown MIME type: %.100s",s); MM_LOG (tmp,PARSE); } } *name = c; /* restore delimiter */ rfc822_skipws (&name); /* skip whitespace */ if ((*name == '/') && /* subtype? */ (name = rfc822_parse_word ((s = ++name),tspecials))) { c = *name; /* save delimiter */ *name = '\0'; /* tie off subtype */ rfc822_skipws (&s); /* copy subtype */ if (s) body->subtype = ucase (rfc822_cpy (s)); *name = c; /* restore delimiter */ rfc822_skipws (&name); /* skip whitespace */ } else if (!name) { /* no subtype, was a subtype delimiter? */ name = s; /* barf, restore pointer */ rfc822_skipws (&name); /* skip leading whitespace */ } rfc822_parse_parameter (&body->parameter,name); } else if (!strcmp (name+1,"RANSFER-ENCODING")) { if (!(name = rfc822_parse_word (s,tspecials))) break; c = *name; /* remember delimiter */ *name = '\0'; /* tie off encoding */ /* search for body encoding */ for (i = 0,s = rfc822_cpy (s); (i <= ENCMAX) && body_encodings[i] && compare_cstring (s,body_encodings[i]); i++); if (i > ENCMAX) { /* fell off end of loop? */ body->encoding = ENCOTHER; sprintf (tmp,"MIME encoding table overflow: %.100s",s); MM_LOG (tmp,PARSE); } else { /* record body encoding index */ body->encoding = (unsigned short) i; /* and name if new encoding */ if (body_encodings[body->encoding]) fs_give ((void **) &s); else { body_encodings[body->encoding] = ucase (s); sprintf (tmp,"Unknown MIME transfer encoding: %.100s",s); MM_LOG (tmp,PARSE); } } *name = c; /* restore delimiter */ /* ??check for cruft here?? */ } break; default: /* otherwise unknown */ break; } } /* Parse RFC 2822 body parameter list * Accepts: parameter list to write to * text of list */ void rfc822_parse_parameter (PARAMETER **par,char *text) { char c,*s,tmp[MAILTMPLEN]; PARAMETER *param = NIL; /* parameter list? */ while (text && (*text == ';') && (text = rfc822_parse_word ((s = ++text),tspecials))) { c = *text; /* remember delimiter */ *text = '\0'; /* tie off attribute name */ rfc822_skipws (&s); /* skip leading attribute whitespace */ if (!*s) *text = c; /* must have an attribute name */ else { /* instantiate a new parameter */ if (*par) param = param->next = mail_newbody_parameter (); else param = *par = mail_newbody_parameter (); param->attribute = ucase (cpystr (s)); *text = c; /* restore delimiter */ rfc822_skipws (&text); /* skip whitespace before equal sign */ if ((*text == '=') && /* make sure have value */ (text = rfc822_parse_word ((s = ++text),tspecials))) { c = *text; /* remember delimiter */ *text = '\0'; /* tie off value */ rfc822_skipws (&s); /* skip leading value whitespace */ if (*s) param->value = rfc822_cpy (s); *text = c; /* restore delimiter */ rfc822_skipws (&text); } if (!param->value) { /* value not found? */ param->value = cpystr ("MISSING_PARAMETER_VALUE"); sprintf (tmp,"Missing parameter value: %.80s",param->attribute); MM_LOG (tmp,PARSE); } } } /* string not present */ if (!text) MM_LOG ("Missing parameter",PARSE); else if (*text) { /* must be end of poop */ sprintf (tmp,"Unexpected characters at end of parameters: %.80s",text); MM_LOG (tmp,PARSE); } } /* Parse RFC 2822 address list * Accepts: address list to write to * input string * default host name */ void rfc822_parse_adrlist (ADDRESS **lst,char *string,char *host) { int c; char *s,tmp[MAILTMPLEN]; ADDRESS *last = *lst; ADDRESS *adr; if (!string) return; /* no string */ rfc822_skipws (&string); /* skip leading WS */ if (!*string) return; /* empty string */ /* run to tail of list */ if (last) while (last->next) last = last->next; while (string) { /* loop until string exhausted */ while (*string == ',') { /* RFC 822 allowed null addresses!! */ ++string; /* skip the comma */ rfc822_skipws (&string); /* and any leading WS */ } if (!*string) string = NIL; /* punt if ran out of string */ /* got an address? */ else if (adr = rfc822_parse_address (lst,last,&string,host,0)) { last = adr; /* new tail address */ if (string) { /* analyze what follows */ rfc822_skipws (&string); switch (c = *(unsigned char *) string) { case ',': /* comma? */ ++string; /* then another address follows */ break; default: s = isalnum (c) ? "Must use comma to separate addresses: %.80s" : "Unexpected characters at end of address: %.80s"; sprintf (tmp,s,string); MM_LOG (tmp,PARSE); last = last->next = mail_newaddr (); last->mailbox = cpystr ("UNEXPECTED_DATA_AFTER_ADDRESS"); last->host = cpystr (errhst); /* falls through */ case '\0': /* null-specified address? */ string = NIL; /* punt remainder of parse */ break; } } } else if (string) { /* bad mailbox */ rfc822_skipws (&string); /* skip WS */ if (!*string) strcpy (tmp,"Missing address after comma"); else sprintf (tmp,"Invalid mailbox list: %.80s",string); MM_LOG (tmp,PARSE); string = NIL; (adr = mail_newaddr ())->mailbox = cpystr ("INVALID_ADDRESS"); adr->host = cpystr (errhst); if (last) last = last->next = adr; else *lst = last = adr; break; } } } /* Parse RFC 2822 address * Accepts: address list to write to * tail of address list * pointer to input string * default host name * group nesting depth * Returns: new list tail */ ADDRESS *rfc822_parse_address (ADDRESS **lst,ADDRESS *last,char **string, char *defaulthost,unsigned long depth) { ADDRESS *adr; if (!*string) return NIL; /* no string */ rfc822_skipws (string); /* skip leading WS */ if (!**string) return NIL; /* empty string */ if (adr = rfc822_parse_group (lst,last,string,defaulthost,depth)) last = adr; /* got an address? */ else if (adr = rfc822_parse_mailbox (string,defaulthost)) { if (!*lst) *lst = adr; /* yes, first time through? */ else last->next = adr; /* no, append to the list */ /* set for subsequent linking */ for (last = adr; last->next; last = last->next); } else if (*string) return NIL; return last; } /* Parse RFC 2822 group * Accepts: address list to write to * pointer to tail of address list * pointer to input string * default host name * group nesting depth */ ADDRESS *rfc822_parse_group (ADDRESS **lst,ADDRESS *last,char **string, char *defaulthost,unsigned long depth) { char tmp[MAILTMPLEN]; char *p,*s; ADDRESS *adr; if (depth > MAXGROUPDEPTH) { /* excessively deep recursion? */ MM_LOG ("Ignoring excessively deep group recursion",PARSE); return NIL; /* probably abusive */ } if (!*string) return NIL; /* no string */ rfc822_skipws (string); /* skip leading WS */ if (!**string || /* trailing whitespace or not group */ ((*(p = *string) != ':') && !(p = rfc822_parse_phrase (*string)))) return NIL; s = p; /* end of candidate phrase */ rfc822_skipws (&s); /* find delimiter */ if (*s != ':') return NIL; /* not really a group */ *p = '\0'; /* tie off group name */ p = ++s; /* continue after the delimiter */ rfc822_skipws (&p); /* skip subsequent whitespace */ /* write as address */ (adr = mail_newaddr ())->mailbox = rfc822_cpy (*string); if (!*lst) *lst = adr; /* first time through? */ else last->next = adr; /* no, append to the list */ last = adr; /* set for subsequent linking */ *string = p; /* continue after this point */ while (*string && **string && (**string != ';')) { if (adr = rfc822_parse_address (lst,last,string,defaulthost,depth+1)) { last = adr; /* new tail address */ if (*string) { /* anything more? */ rfc822_skipws (string); /* skip whitespace */ switch (**string) { /* see what follows */ case ',': /* another address? */ ++*string; /* yes, skip past the comma */ case ';': /* end of group? */ case '\0': /* end of string */ break; default: sprintf (tmp,"Unexpected characters after address in group: %.80s", *string); MM_LOG (tmp,PARSE); *string = NIL; /* cancel remainder of parse */ last = last->next = mail_newaddr (); last->mailbox = cpystr ("UNEXPECTED_DATA_AFTER_ADDRESS_IN_GROUP"); last->host = cpystr (errhst); } } } else { /* bogon */ sprintf (tmp,"Invalid group mailbox list: %.80s",*string); MM_LOG (tmp,PARSE); *string = NIL; /* cancel remainder of parse */ (adr = mail_newaddr ())->mailbox = cpystr ("INVALID_ADDRESS_IN_GROUP"); adr->host = cpystr (errhst); last = last->next = adr; } } if (*string) { /* skip close delimiter */ if (**string == ';') ++*string; rfc822_skipws (string); } /* append end of address mark to the list */ last->next = (adr = mail_newaddr ()); last = adr; /* set for subsequent linking */ return last; /* return the tail */ } /* Parse RFC 2822 mailbox * Accepts: pointer to string pointer * default host * Returns: address list * * Updates string pointer */ ADDRESS *rfc822_parse_mailbox (char **string,char *defaulthost) { ADDRESS *adr = NIL; char *s,*end; parsephrase_t pp = (parsephrase_t) mail_parameters (NIL,GET_PARSEPHRASE,NIL); if (!*string) return NIL; /* no string */ rfc822_skipws (string); /* flush leading whitespace */ if (!**string) return NIL; /* empty string */ if (*(s = *string) == '<') /* note start, handle case of phraseless RA */ adr = rfc822_parse_routeaddr (s,string,defaulthost); /* otherwise, expect at least one word */ else if (end = rfc822_parse_phrase (s)) { if ((adr = rfc822_parse_routeaddr (end,string,defaulthost))) { /* phrase is a personal name */ if (adr->personal) fs_give ((void **) &adr->personal); *end = '\0'; /* tie off phrase */ adr->personal = rfc822_cpy (s); } /* call external phraseparser if phrase only */ else if (pp && rfc822_phraseonly (end) && (adr = (*pp) (s,end,defaulthost))) { *string = end; /* update parse pointer */ rfc822_skipws (string); /* skip WS in the normal way */ } else adr = rfc822_parse_addrspec (s,string,defaulthost); } return adr; /* return the address */ } /* Check if address is a phrase only * Accepts: pointer to end of phrase * Returns: T if phrase only, else NIL; */ long rfc822_phraseonly (char *end) { while (*end == ' ') ++end; /* call rfc822_skipws() instead?? */ switch (*end) { case '\0': case ',': case ';': return LONGT; /* is a phrase only */ } return NIL; /* something other than phase is here */ } /* Parse RFC 2822 route-address * Accepts: string pointer * pointer to string pointer to update * Returns: address * * Updates string pointer */ ADDRESS *rfc822_parse_routeaddr (char *string,char **ret,char *defaulthost) { char tmp[MAILTMPLEN]; ADDRESS *adr; char *s,*t,*adl; size_t adllen,i; if (!string) return NIL; rfc822_skipws (&string); /* flush leading whitespace */ /* must start with open broket */ if (*string != '<') return NIL; t = ++string; /* see if A-D-L there */ rfc822_skipws (&t); /* flush leading whitespace */ for (adl = NIL,adllen = 0; /* parse possible A-D-L */ (*t == '@') && (s = rfc822_parse_domain (t+1,&t));) { i = strlen (s) + 2; /* @ plus domain plus delimiter or NUL */ if (adl) { /* have existing A-D-L? */ fs_resize ((void **) &adl,adllen + i); sprintf (adl + adllen - 1,",@%s",s); } /* write initial A-D-L */ else sprintf (adl = (char *) fs_get (i),"@%s",s); adllen += i; /* new A-D-L length */ fs_give ((void **) &s); /* don't need domain any more */ rfc822_skipws (&t); /* skip WS */ if (*t != ',') break; /* put if not comma */ t++; /* skip the comma */ rfc822_skipws (&t); /* skip WS */ } if (adl) { /* got an A-D-L? */ if (*t != ':') { /* make sure syntax good */ sprintf (tmp,"Unterminated at-domain-list: %.80s%.80s",adl,t); MM_LOG (tmp,PARSE); } else string = ++t; /* continue parse from this point */ } /* parse address spec */ if (!(adr = rfc822_parse_addrspec (string,ret,defaulthost))) { if (adl) fs_give ((void **) &adl); return NIL; } if (adl) adr->adl = adl; /* have an A-D-L? */ if (*ret) if (**ret == '>') { /* make sure terminated OK */ ++*ret; /* skip past the broket */ rfc822_skipws (ret); /* flush trailing WS */ if (!**ret) *ret = NIL; /* wipe pointer if at end of string */ return adr; /* return the address */ } sprintf (tmp,"Unterminated mailbox: %.80s@%.80s",adr->mailbox, *adr->host == '@' ? "" : adr->host); MM_LOG (tmp,PARSE); adr->next = mail_newaddr (); adr->next->mailbox = cpystr ("MISSING_MAILBOX_TERMINATOR"); adr->next->host = cpystr (errhst); return adr; /* return the address */ } /* Parse RFC 2822 address-spec * Accepts: string pointer * pointer to string pointer to update * default host * Returns: address * * Updates string pointer */ ADDRESS *rfc822_parse_addrspec (char *string,char **ret,char *defaulthost) { ADDRESS *adr; char c,*s,*t,*v,*end; if (!string) return NIL; /* no string */ rfc822_skipws (&string); /* flush leading whitespace */ if (!*string) return NIL; /* empty string */ /* find end of mailbox */ if (!(t = rfc822_parse_word (string,wspecials))) return NIL; adr = mail_newaddr (); /* create address block */ c = *t; /* remember delimiter */ *t = '\0'; /* tie off mailbox */ /* copy mailbox */ adr->mailbox = rfc822_cpy (string); *t = c; /* restore delimiter */ end = t; /* remember end of mailbox */ rfc822_skipws (&t); /* skip whitespace */ while (*t == '.') { /* some cretin taking RFC 822 too seriously? */ string = ++t; /* skip past the dot and any WS */ rfc822_skipws (&string); /* get next word of mailbox */ if (t = rfc822_parse_word (string,wspecials)) { end = t; /* remember new end of mailbox */ c = *t; /* remember delimiter */ *t = '\0'; /* tie off word */ s = rfc822_cpy (string); /* copy successor part */ *t = c; /* restore delimiter */ /* build new mailbox */ sprintf (v = (char *) fs_get (strlen (adr->mailbox) + strlen (s) + 2), "%s.%s",adr->mailbox,s); fs_give ((void **) &adr->mailbox); adr->mailbox = v; /* new host name */ rfc822_skipws (&t); /* skip WS after mailbox */ } else { /* barf */ MM_LOG ("Invalid mailbox part after .",PARSE); break; } } t = end; /* remember delimiter in case no host */ rfc822_skipws (&end); /* sniff ahead at what follows */ #if RFC733 /* RFC 733 used "at" instead of "@" */ if (((*end == 'a') || (*end == 'A')) && ((end[1] == 't') || (end[1] == 'T')) && ((end[2] == ' ') || (end[2] == '\t') || (end[2] == '\015') || (end[2] == '\012') || (end[2] == '('))) *++end = '@'; #endif if (*end != '@') end = t; /* host name missing */ /* otherwise parse host name */ else if (!(adr->host = rfc822_parse_domain (++end,&end))) adr->host = cpystr (errhst); /* default host if missing */ if (!adr->host) adr->host = cpystr (defaulthost); /* try person name in comments if missing */ if (end && !(adr->personal && *adr->personal)) { while (*end == ' ') ++end; /* see if we can find a person name here */ if ((*end == '(') && (s = rfc822_skip_comment (&end,LONGT)) && strlen (s)) adr->personal = rfc822_cpy (s); rfc822_skipws (&end); /* skip any other WS in the normal way */ } /* set return to end pointer */ *ret = (end && *end) ? end : NIL; return adr; /* return the address we got */ } /* Parse RFC 2822 domain * Accepts: string pointer * pointer to return end of domain * Returns: domain name or NIL if failure */ char *rfc822_parse_domain (char *string,char **end) { char *ret = NIL; char c,*s,*t,*v; rfc822_skipws (&string); /* skip whitespace */ if (*string == '[') { /* domain literal? */ if (!(*end = rfc822_parse_word (string + 1,"]\\"))) MM_LOG ("Empty domain literal",PARSE); else if (**end != ']') MM_LOG ("Unterminated domain literal",PARSE); else { size_t len = ++*end - string; strncpy (ret = (char *) fs_get (len + 1),string,len); ret[len] = '\0'; /* tie off literal */ } } /* search for end of host */ else if (t = rfc822_parse_word (string,wspecials)) { c = *t; /* remember delimiter */ *t = '\0'; /* tie off host */ ret = rfc822_cpy (string); /* copy host */ *t = c; /* restore delimiter */ *end = t; /* remember end of domain */ rfc822_skipws (&t); /* skip WS after host */ while (*t == '.') { /* some cretin taking RFC 822 too seriously? */ string = ++t; /* skip past the dot and any WS */ rfc822_skipws (&string); if (string = rfc822_parse_domain (string,&t)) { *end = t; /* remember new end of domain */ c = *t; /* remember delimiter */ *t = '\0'; /* tie off host */ s = rfc822_cpy (string);/* copy successor part */ *t = c; /* restore delimiter */ /* build new domain */ sprintf (v = (char *) fs_get (strlen (ret) + strlen (s) + 2), "%s.%s",ret,s); fs_give ((void **) &ret); ret = v; /* new host name */ rfc822_skipws (&t); /* skip WS after domain */ } else { /* barf */ MM_LOG ("Invalid domain part after .",PARSE); break; } } } else MM_LOG ("Missing or invalid host name after @",PARSE); return ret; } /* Parse RFC 2822 phrase * Accepts: string pointer * Returns: pointer to end of phrase */ char *rfc822_parse_phrase (char *s) { char *curpos; if (!s) return NIL; /* no-op if no string */ /* find first word of phrase */ curpos = rfc822_parse_word (s,NIL); if (!curpos) return NIL; /* no words means no phrase */ if (!*curpos) return curpos; /* check if string ends with word */ s = curpos; /* sniff past the end of this word and WS */ rfc822_skipws (&s); /* skip whitespace */ /* recurse to see if any more */ return (s = rfc822_parse_phrase (s)) ? s : curpos; } /* Parse RFC 2822 word * Accepts: string pointer * delimiter (or NIL for phrase word parsing) * Returns: pointer to end of word */ char *rfc822_parse_word (char *s,const char *delimiters) { char *st,*str; if (!s) return NIL; /* no string */ rfc822_skipws (&s); /* flush leading whitespace */ if (!*s) return NIL; /* empty string */ str = s; /* hunt pointer for strpbrk */ while (T) { /* look for delimiter, return if none */ if (!(st = strpbrk (str,delimiters ? delimiters : wspecials))) return str + strlen (str); /* ESC in phrase */ if (!delimiters && (*st == I2C_ESC)) { str = ++st; /* always skip past ESC */ switch (*st) { /* special hack for RFC 1468 (ISO-2022-JP) */ case I2C_MULTI: /* multi byte sequence */ switch (*++st) { case I2CS_94x94_JIS_OLD:/* old JIS (1978) */ case I2CS_94x94_JIS_NEW:/* new JIS (1983) */ str = ++st; /* skip past the shift to JIS */ while (st = strchr (st,I2C_ESC)) if ((*++st == I2C_G0_94) && ((st[1] == I2CS_94_ASCII) || (st[1] == I2CS_94_JIS_ROMAN) || (st[1] == I2CS_94_JIS_BUGROM))) { str = st += 2; /* skip past the shift back to ASCII */ break; } /* eats entire text if no shift back */ if (!st || !*st) return str + strlen (str); } break; case I2C_G0_94: /* single byte sequence */ switch (st[1]) { case I2CS_94_ASCII: /* shift to ASCII */ case I2CS_94_JIS_ROMAN: /* shift to JIS-Roman */ case I2CS_94_JIS_BUGROM:/* old buggy definition of JIS-Roman */ str = st + 2; /* skip past the shift */ break; } } } else switch (*st) { /* dispatch based on delimiter */ case '"': /* quoted string */ /* look for close quote */ while (*++st != '"') switch (*st) { case '\0': /* unbalanced quoted string */ return NIL; /* sick sick sick */ case '\\': /* quoted character */ if (!*++st) return NIL; /* skip the next character */ default: /* ordinary character */ break; /* no special action */ } str = ++st; /* continue parse */ break; case '\\': /* quoted character */ /* This is wrong; a quoted-pair can not be part of a word. However, * domain-literal is parsed as a word and quoted-pairs can be used * *there*. Either way, it's pretty pathological. */ if (st[1]) { /* not on NUL though... */ str = st + 2; /* skip quoted character and go on */ break; } default: /* found a word delimiter */ return (st == s) ? NIL : st; } } } /* Copy an RFC 2822 format string * Accepts: string * Returns: copy of string */ char *rfc822_cpy (char *src) { /* copy and unquote */ return rfc822_quote (cpystr (src)); } /* Unquote an RFC 2822 format string * Accepts: string * Returns: string */ char *rfc822_quote (char *src) { char *ret = src; if (strpbrk (src,"\\\"")) { /* any quoting in string? */ char *dst = ret; while (*src) { /* copy string */ if (*src == '\"') src++; /* skip double quote entirely */ else { if (*src == '\\') src++;/* skip over single quote, copy next always */ *dst++ = *src++; /* copy character */ } } *dst = '\0'; /* tie off string */ } return ret; /* return our string */ } /* Copy address list * Accepts: address list * Returns: address list */ ADDRESS *rfc822_cpy_adr (ADDRESS *adr) { ADDRESS *dadr; ADDRESS *ret = NIL; ADDRESS *prev = NIL; while (adr) { /* loop while there's still an MAP adr */ dadr = mail_newaddr (); /* instantiate a new address */ if (!ret) ret = dadr; /* note return */ if (prev) prev->next = dadr;/* tie on to the end of any previous */ dadr->personal = cpystr (adr->personal); dadr->adl = cpystr (adr->adl); dadr->mailbox = cpystr (adr->mailbox); dadr->host = cpystr (adr->host); prev = dadr; /* this is now the previous */ adr = adr->next; /* go to next address in list */ } return (ret); /* return the MTP address list */ } /* Skips RFC 2822 whitespace * Accepts: pointer to string pointer */ void rfc822_skipws (char **s) { while (T) switch (**s) { case ' ': case '\t': case '\015': case '\012': ++*s; /* skip all forms of LWSP */ break; case '(': /* start of comment */ if (rfc822_skip_comment (s,(long) NIL)) break; default: return; /* end of whitespace */ } } /* Skips RFC 2822 comment * Accepts: pointer to string pointer * trim flag * Returns: pointer to first non-blank character of comment */ char *rfc822_skip_comment (char **s,long trim) { char *ret,tmp[MAILTMPLEN]; char *s1 = *s; char *t = NIL; /* skip past whitespace */ for (ret = ++s1; *ret == ' '; ret++); do switch (*s1) { /* get character of comment */ case '(': /* nested comment? */ if (!rfc822_skip_comment (&s1,(long) NIL)) return NIL; t = --s1; /* last significant char at end of comment */ break; case ')': /* end of comment? */ *s = ++s1; /* skip past end of comment */ if (trim) { /* if level 0, must trim */ if (t) t[1] = '\0'; /* tie off comment string */ else *ret = '\0'; /* empty comment */ } return ret; case '\\': /* quote next character? */ if (*++s1) { /* next character non-null? */ t = s1; /* update last significant character pointer */ break; /* all OK */ } case '\0': /* end of string */ sprintf (tmp,"Unterminated comment: %.80s",*s); MM_LOG (tmp,PARSE); **s = '\0'; /* nuke duplicate messages in case reparse */ return NIL; /* this is wierd if it happens */ case ' ': /* whitespace isn't significant */ break; default: /* random character */ t = s1; /* update last significant character pointer */ break; } while (s1++); return NIL; /* impossible, but pacify lint et al */ } /* Buffered output routines */ /* Output character to buffer * Accepts: buffer * character to write * Returns: T if success, NIL if error */ static long rfc822_output_char (RFC822BUFFER *buf,int c) { if ((buf->cur == buf->end) && !rfc822_output_flush (buf)) return NIL; *buf->cur++ = c; /* add character, soutr buffer if full */ return (buf->cur == buf->end) ? rfc822_output_flush (buf) : LONGT; } /* Output data to buffer * Accepts: buffer * data to write * size of data * Returns: T if success, NIL if error */ static long rfc822_output_data (RFC822BUFFER *buf,char *string,long len) { while (len) { /* until request satified */ long i; if (i = min (len,buf->end - buf->cur)) { memcpy (buf->cur,string,i); buf->cur += i; /* blat data */ string += i; len -= i; } /* soutr buffer now if full */ if ((len || (buf->cur == buf->end)) && !rfc822_output_flush (buf)) return NIL; } return LONGT; } /* Output string to buffer * Accepts: buffer * string to write * Returns: T if success, NIL if error */ static long rfc822_output_string (RFC822BUFFER *buf,char *string) { return rfc822_output_data (buf,string,strlen (string)); } /* Flush buffer * Accepts: buffer * I/O routine * stream for I/O routine * Returns: T if success, NIL if error */ long rfc822_output_flush (RFC822BUFFER *buf) { *buf->cur = '\0'; /* tie off buffer at this point */ return (*buf->f) (buf->s,buf->cur = buf->beg); } /* Message writing routines */ /* Output RFC 822 message * Accepts: temporary buffer as a SIZEDTEXT * envelope * body * I/O routine * stream for I/O routine * non-zero if 8-bit output desired * Returns: T if successful, NIL if failure * * This routine always uses standard specials for phrases and does not write * bcc entries, since it is called from the SMTP and NNTP routines. If you * need to do something different you need to arm an rfc822outfull_t and/or * rfc822out_t function. */ long rfc822_output_full (RFC822BUFFER *buf,ENVELOPE *env,BODY *body,long ok8) { rfc822outfull_t r822of = (rfc822outfull_t) mail_parameters (NIL,GET_RFC822OUTPUTFULL,NIL); rfc822out_t r822o = (rfc822out_t) mail_parameters (NIL,GET_RFC822OUTPUT,NIL); /* call external RFC 2822 output generator */ if (r822of) return (*r822of) (buf,env,body,ok8); else if (r822o) return (*r822o) (buf->cur,env,body,buf->f,buf->s,ok8); /* encode body as necessary */ if (ok8) rfc822_encode_body_8bit (env,body); else rfc822_encode_body_7bit (env,body); /* output header and body */ return rfc822_output_header (buf,env,body,NIL,NIL) && rfc822_output_text (buf,body) && rfc822_output_flush (buf); } /* Output RFC 822 header * Accepts: buffer * envelope * body * non-standard specials to be used for phrases if non-NIL * flags (non-zero to include bcc * Returns: T if success, NIL if failure */ long rfc822_output_header (RFC822BUFFER *buf,ENVELOPE *env,BODY *body, const char *specials,long flags) { long i = env->remail ? strlen (env->remail) : 0; return /* write header */ (!i || /* snip extra CRLF from remail header */ rfc822_output_data (buf,env->remail, ((i > 4) && (env->remail[i-4] == '\015')) ? i - 2 : i)) && rfc822_output_header_line (buf,"Newsgroups",i,env->newsgroups) && rfc822_output_header_line (buf,"Date",i,env->date) && rfc822_output_address_line (buf,"From",i,env->from,specials) && rfc822_output_address_line (buf,"Sender",i,env->sender,specials) && rfc822_output_address_line (buf,"Reply-To",i,env->reply_to,specials) && rfc822_output_header_line (buf,"Subject",i,env->subject) && ((env->bcc && !(env->to || env->cc)) ? rfc822_output_string (buf,"To: undisclosed recipients: ;\015\012") : LONGT) && rfc822_output_address_line (buf,"To",i,env->to,specials) && rfc822_output_address_line (buf,"cc",i,env->cc,specials) && (flags ? rfc822_output_address_line (buf,"bcc",i,env->bcc,specials) : T) && rfc822_output_header_line (buf,"In-Reply-To",i,env->in_reply_to) && rfc822_output_header_line (buf,"Message-ID",i,env->message_id) && rfc822_output_header_line (buf,"Followup-to",i,env->followup_to) && rfc822_output_header_line (buf,"References",i,env->references) && (env->remail || !body || (rfc822_output_string (buf,"MIME-Version: 1.0\015\012") && rfc822_output_body_header (buf,body))) && /* write terminating blank line */ rfc822_output_string (buf,"\015\012"); } /* Output RFC 2822 header text line * Accepts: buffer * pointer to header type * non-NIL if resending * pointer to text * Returns: T if success, NIL if failure */ long rfc822_output_header_line (RFC822BUFFER *buf,char *type,long resent, char *text) { return !text || ((resent ? rfc822_output_string (buf,resentprefix) : LONGT) && rfc822_output_string (buf,type) && rfc822_output_string (buf,": ") && rfc822_output_string (buf,text) && rfc822_output_string (buf,"\015\012")); } /* Output RFC 2822 header address line * Accepts: buffer * pointer to header type * non-NIL if resending * address(s) to interpret * non-standard specials to be used for phrases if non-NIL * Returns: T if success, NIL if failure */ long rfc822_output_address_line (RFC822BUFFER *buf,char *type,long resent, ADDRESS *adr,const char *specials) { long pretty = strlen (type); return !adr || ((resent ? rfc822_output_string (buf,resentprefix) : LONGT) && rfc822_output_data (buf,type,pretty) && rfc822_output_string (buf,": ") && rfc822_output_address_list (buf,adr, resent ? pretty + sizeof (RESENTPREFIX) - 1 : pretty,specials) && rfc822_output_string (buf,"\015\012")); } /* Output RFC 2822 address list * Accepts: buffer * pointer to address list * non-zero if pretty-printing * non-standard specials to be used for phrases if non-NIL * Returns: T if success, NIL if failure */ long rfc822_output_address_list (RFC822BUFFER *buf,ADDRESS *adr,long pretty, const char *specials) { long n; /* default to rspecials */ if (!specials) specials = rspecials; for (n = 0; adr; adr = adr->next) { char *base = buf->cur; if (adr->host) { /* ordinary address? */ if (!(pretty && n)) { /* suppress if pretty and in group */ if ( /* use phrase if phrase */ #if RFC822 adr->adl || /* or A-D-L */ #endif (adr->personal && *adr->personal)) { if (!((adr->personal ? rfc822_output_cat (buf,adr->personal, rspecials) : LONGT) && rfc822_output_string (buf," <") && rfc822_output_address (buf,adr) && rfc822_output_string (buf,">"))) return NIL; } else if (!rfc822_output_address (buf,adr)) return NIL; if (adr->next && adr->next->mailbox && !rfc822_output_string (buf,", ")) return NIL; } } else if (adr->mailbox) { /* start of group? */ /* yes, write group */ if (!(rfc822_output_cat (buf,adr->mailbox,rspecials) && rfc822_output_string (buf,": "))) return NIL; ++n; /* in a group now */ } else if (n) { /* must be end of group (but be paranoid) */ if (!rfc822_output_char (buf,';') || ((!--n && adr->next && adr->next->mailbox) && !rfc822_output_string (buf,", "))) return NIL; } if (pretty && adr->next && /* pretty printing? */ ((pretty += ((buf->cur > base) ? buf->cur - base : (buf->end - base) + (buf->cur - buf->beg))) >= 78)) { if (!(rfc822_output_string (buf,"\015\012") && rfc822_output_string (buf,RFC822CONT))) return NIL; base = buf->cur; /* update base for pretty printing */ pretty = sizeof (RFC822CONT) - 1; } } return LONGT; } /* Write RFC 2822 route-address to string * Accepts: buffer * pointer to single address * Returns: T if success, NIL if failure */ long rfc822_output_address (RFC822BUFFER *buf,ADDRESS *adr) { return !adr || !adr->host || ( #if RFC822 /* old code with A-D-L support */ (!adr->adl || (rfc822_output_string (buf,adr->adl) && rfc822_output_char (buf,':'))) && #endif rfc822_output_cat (buf,adr->mailbox,NIL) && ((*adr->host == '@') || /* unless null host (HIGHLY discouraged!) */ (rfc822_output_char (buf,'@') && rfc822_output_cat (buf,adr->host,NIL)))); } /* Output RFC 2822 string with concatenation * Accepts: buffer * string to concatenate * list of special characters or NIL for dot-atom format * Returns: T if success, NIL if failure */ long rfc822_output_cat (RFC822BUFFER *buf,char *src,const char *specials) { char *s; if (!*src || /* empty string or any specials present? */ (specials ? (T && strpbrk (src,specials)) : (strpbrk (src,wspecials) || (*src == '.') || strstr (src,"..") || (src[strlen (src) - 1] == '.')))) { /* yes, write as quoted string*/ if (!rfc822_output_char (buf,'"')) return NIL; /* embedded quote characters? */ for (; s = strpbrk (src,"\\\""); src = s + 1) { /* yes, insert quoting */ if (!(rfc822_output_data (buf,src,s-src) && rfc822_output_char (buf,'\\') && rfc822_output_char (buf,*s))) return NIL; } /* return string and trailing quote*/ return rfc822_output_string (buf,src) && rfc822_output_char (buf,'"'); } /* easy case */ return rfc822_output_string (buf,src); } /* Output MIME parameter list * Accepts: buffer * parameter list * Returns: T if success, NIL if failure */ long rfc822_output_parameter (RFC822BUFFER *buf,PARAMETER *param) { while (param) { if (rfc822_output_string (buf,"; ") && rfc822_output_string (buf,param->attribute) && rfc822_output_char (buf,'=') && rfc822_output_cat (buf,param->value,tspecials)) param = param->next; else return NIL; } return LONGT; } /* Output RFC 2822 stringlist * Accepts: buffer * stringlist * Returns: T if success, NIL if failure */ long rfc822_output_stringlist (RFC822BUFFER *buf,STRINGLIST *stl) { while (stl) if (!rfc822_output_cat (buf,(char *) stl->text.data,tspecials) || ((stl = stl->next) && !rfc822_output_string (buf,", "))) return NIL; return LONGT; } /* Output body content header * Accepts: buffer * body to interpret * Returns: T if success, NIL if failure */ long rfc822_output_body_header (RFC822BUFFER *buf,BODY *body) { return /* type and subtype*/ rfc822_output_string (buf,"Content-Type: ") && rfc822_output_string (buf,body_types[body->type]) && rfc822_output_char (buf,'/') && rfc822_output_string (buf,body->subtype ? body->subtype : rfc822_default_subtype (body->type)) && /* parameters (w/ US-ASCII default */ (body->parameter ? rfc822_output_parameter (buf,body->parameter) : ((body->type != TYPETEXT) || (rfc822_output_string (buf,"; CHARSET=") && rfc822_output_string (buf,(body->encoding == ENC7BIT) ? "US-ASCII" : "X-UNKNOWN")))) && (!body->encoding || /* note: 7BIT never output as encoding! */ (rfc822_output_string (buf,"\015\012Content-Transfer-Encoding: ") && rfc822_output_string (buf,body_encodings[body->encoding]))) && (!body->id || /* identification */ (rfc822_output_string (buf,"\015\012Content-ID: ") && rfc822_output_string (buf,body->id))) && (!body->description || /* description */ (rfc822_output_string (buf,"\015\012Content-Description: ") && rfc822_output_string (buf,body->description))) && (!body->md5 || /* MD5 checksum */ (rfc822_output_string (buf,"\015\012Content-MD5: ") && rfc822_output_string (buf,body->md5))) && (!body->language || /* language */ (rfc822_output_string (buf,"\015\012Content-Language: ") && rfc822_output_stringlist (buf,body->language))) && (!body->location || /* location */ (rfc822_output_string (buf,"\015\012Content-Location: ") && rfc822_output_string (buf,body->location))) && (!body->disposition.type || /* disposition */ (rfc822_output_string (buf,"\015\012Content-Disposition: ") && rfc822_output_string (buf,body->disposition.type) && rfc822_output_parameter (buf,body->disposition.parameter))) && rfc822_output_string (buf,"\015\012"); } /* Encode a body for 7BIT transmittal * Accepts: envelope * body */ void rfc822_encode_body_7bit (ENVELOPE *env,BODY *body) { void *f; PART *part; PARAMETER **param; if (body) switch (body->type) { case TYPEMULTIPART: /* multi-part */ for (param = &body->parameter; *param && strcmp ((*param)->attribute,"BOUNDARY"); param = &(*param)->next); if (!*param) { /* cookie not set up yet? */ char tmp[MAILTMPLEN]; /* make cookie not in BASE64 or QUOTEPRINT*/ sprintf (tmp,"%lu-%lu-%lu=:%lu",(unsigned long) gethostid (), (unsigned long) random (),(unsigned long) time (0), (unsigned long) getpid ()); (*param) = mail_newbody_parameter (); (*param)->attribute = cpystr ("BOUNDARY"); (*param)->value = cpystr (tmp); } part = body->nested.part; /* encode body parts */ do rfc822_encode_body_7bit (env,&part->body); while (part = part->next); /* until done */ break; case TYPEMESSAGE: /* encapsulated message */ switch (body->encoding) { case ENC7BIT: break; case ENC8BIT: MM_LOG ("8-bit included message in 7-bit message body",PARSE); break; case ENCBINARY: MM_LOG ("Binary included message in 7-bit message body",PARSE); break; default: fatal ("Invalid rfc822_encode_body_7bit message encoding"); } break; /* can't change encoding */ default: /* all else has some encoding */ switch (body->encoding) { case ENC8BIT: /* encode 8BIT into QUOTED-PRINTABLE */ /* remember old 8-bit contents */ f = (void *) body->contents.text.data; body->contents.text.data = rfc822_8bit (body->contents.text.data, body->contents.text.size,&body->contents.text.size); body->encoding = ENCQUOTEDPRINTABLE; fs_give (&f); /* flush old binary contents */ break; case ENCBINARY: /* encode binary into BASE64 */ /* remember old binary contents */ f = (void *) body->contents.text.data; body->contents.text.data = rfc822_binary ((void *) body->contents.text.data, body->contents.text.size,&body->contents.text.size); body->encoding = ENCBASE64; fs_give (&f); /* flush old binary contents */ default: /* otherwise OK */ break; } break; } } /* Encode a body for 8BIT transmittal * Accepts: envelope * body */ void rfc822_encode_body_8bit (ENVELOPE *env,BODY *body) { void *f; PART *part; PARAMETER **param; if (body) switch (body->type) { case TYPEMULTIPART: /* multi-part */ for (param = &body->parameter; *param && strcmp ((*param)->attribute,"BOUNDARY"); param = &(*param)->next); if (!*param) { /* cookie not set up yet? */ char tmp[MAILTMPLEN]; /* make cookie not in BASE64 or QUOTEPRINT*/ sprintf (tmp,"%lu-%lu-%lu=:%lu",(unsigned long) gethostid (), (unsigned long) random (),(unsigned long) time (0), (unsigned long) getpid ()); (*param) = mail_newbody_parameter (); (*param)->attribute = cpystr ("BOUNDARY"); (*param)->value = cpystr (tmp); } part = body->nested.part; /* encode body parts */ do rfc822_encode_body_8bit (env,&part->body); while (part = part->next); /* until done */ break; case TYPEMESSAGE: /* encapsulated message */ switch (body->encoding) { case ENC7BIT: case ENC8BIT: break; case ENCBINARY: MM_LOG ("Binary included message in 8-bit message body",PARSE); break; default: fatal ("Invalid rfc822_encode_body_7bit message encoding"); } break; /* can't change encoding */ default: /* other type, encode binary into BASE64 */ if (body->encoding == ENCBINARY) { /* remember old binary contents */ f = (void *) body->contents.text.data; body->contents.text.data = rfc822_binary ((void *) body->contents.text.data, body->contents.text.size,&body->contents.text.size); body->encoding = ENCBASE64; fs_give (&f); /* flush old binary contents */ } break; } } /* Output RFC 822 text * Accepts: buffer * body * Returns: T if successful, NIL if failure */ long rfc822_output_text (RFC822BUFFER *buf,BODY *body) { /* MULTIPART gets special handling */ if (body->type == TYPEMULTIPART) { char *cookie,tmp[MAILTMPLEN]; PARAMETER *param; PART *part; /* find cookie */ for (param = body->parameter; param && strcmp (param->attribute,"BOUNDARY"); param = param->next); if (param) cookie = param->value; else { /* make cookie not in BASE64 or QUOTEPRINT*/ sprintf (cookie = tmp,"%lu-%lu-%lu=:%lu",(unsigned long) gethostid (), (unsigned long) random (),(unsigned long) time (0), (unsigned long) getpid ()); (param = mail_newbody_parameter ())->attribute = cpystr ("BOUNDARY"); param->value = cpystr (tmp); param->next = body->parameter; body->parameter = param; } /* output each part */ for (part = body->nested.part; part; part = part->next) if (!(rfc822_output_string (buf,"--") && rfc822_output_string (buf,cookie) && rfc822_output_string (buf,"\015\012") && rfc822_output_body_header (buf,&part->body) && rfc822_output_string (buf,"\015\012") && rfc822_output_text (buf,&part->body))) return NIL; /* output trailing cookie */ return rfc822_output_string (buf,"--") && rfc822_output_string (buf,cookie) && rfc822_output_string (buf,"--\015\012"); } /* output segment and trailing CRLF */ return (!body->contents.text.data || rfc822_output_string (buf,(char *) body->contents.text.data)) && rfc822_output_string (buf,"\015\012"); } /* Body contents encoding/decoding routines */ /* Convert BASE64 contents to binary * Accepts: source * length of source * pointer to return destination length * Returns: destination as binary or NIL if error */ #define WSP 0176 /* NUL, TAB, LF, FF, CR, SPC */ #define JNK 0177 #define PAD 0100 void *rfc822_base64 (unsigned char *src,unsigned long srcl,unsigned long *len) { char c,*s,tmp[MAILTMPLEN]; void *ret = fs_get ((size_t) ((*len = 4 + ((srcl * 3) / 4))) + 1); char *d = (char *) ret; int e; static char decode[256] = { WSP,JNK,JNK,JNK,JNK,JNK,JNK,JNK,JNK,WSP,WSP,JNK,WSP,WSP,JNK,JNK, JNK,JNK,JNK,JNK,JNK,JNK,JNK,JNK,JNK,JNK,JNK,JNK,JNK,JNK,JNK,JNK, WSP,JNK,JNK,JNK,JNK,JNK,JNK,JNK,JNK,JNK,JNK,076,JNK,JNK,JNK,077, 064,065,066,067,070,071,072,073,074,075,JNK,JNK,JNK,PAD,JNK,JNK, JNK,000,001,002,003,004,005,006,007,010,011,012,013,014,015,016, 017,020,021,022,023,024,025,026,027,030,031,JNK,JNK,JNK,JNK,JNK, JNK,032,033,034,035,036,037,040,041,042,043,044,045,046,047,050, 051,052,053,054,055,056,057,060,061,062,063,JNK,JNK,JNK,JNK,JNK, JNK,JNK,JNK,JNK,JNK,JNK,JNK,JNK,JNK,JNK,JNK,JNK,JNK,JNK,JNK,JNK, JNK,JNK,JNK,JNK,JNK,JNK,JNK,JNK,JNK,JNK,JNK,JNK,JNK,JNK,JNK,JNK, JNK,JNK,JNK,JNK,JNK,JNK,JNK,JNK,JNK,JNK,JNK,JNK,JNK,JNK,JNK,JNK, JNK,JNK,JNK,JNK,JNK,JNK,JNK,JNK,JNK,JNK,JNK,JNK,JNK,JNK,JNK,JNK, JNK,JNK,JNK,JNK,JNK,JNK,JNK,JNK,JNK,JNK,JNK,JNK,JNK,JNK,JNK,JNK, JNK,JNK,JNK,JNK,JNK,JNK,JNK,JNK,JNK,JNK,JNK,JNK,JNK,JNK,JNK,JNK, JNK,JNK,JNK,JNK,JNK,JNK,JNK,JNK,JNK,JNK,JNK,JNK,JNK,JNK,JNK,JNK, JNK,JNK,JNK,JNK,JNK,JNK,JNK,JNK,JNK,JNK,JNK,JNK,JNK,JNK,JNK,JNK }; /* initialize block */ memset (ret,0,((size_t) *len) + 1); *len = 0; /* in case we return an error */ /* simple-minded decode */ for (e = 0; srcl--; ) switch (c = decode[*src++]) { default: /* valid BASE64 data character */ switch (e++) { /* install based on quantum position */ case 0: *d = c << 2; /* byte 1: high 6 bits */ break; case 1: *d++ |= c >> 4; /* byte 1: low 2 bits */ *d = c << 4; /* byte 2: high 4 bits */ break; case 2: *d++ |= c >> 2; /* byte 2: low 4 bits */ *d = c << 6; /* byte 3: high 2 bits */ break; case 3: *d++ |= c; /* byte 3: low 6 bits */ e = 0; /* reinitialize mechanism */ break; } break; case WSP: /* whitespace */ break; case PAD: /* padding */ switch (e++) { /* check quantum position */ case 3: /* one = is good enough in quantum 3 */ /* make sure no data characters in remainder */ for (; srcl; --srcl) switch (decode[*src++]) { /* ignore space, junk and extraneous padding */ case WSP: case JNK: case PAD: break; default: /* valid BASE64 data character */ /* This indicates bad MIME. One way that it can be caused is if a single-section message was BASE64 encoded and then something (e.g. a mailing list processor) appended text. The problem is that in 1 out of 3 cases, there is no padding and hence no way to detect the end of the data. Consequently, prudent software will always encapsulate a BASE64 segment inside a MULTIPART. */ sprintf (tmp,"Possible data truncation in rfc822_base64(): %.80s", (char *) src - 1); if (s = strpbrk (tmp,"\015\012")) *s = NIL; mm_log (tmp,PARSE); srcl = 1; /* don't issue any more messages */ break; } break; case 2: /* expect a second = in quantum 2 */ if (srcl && (*src == '=')) break; default: /* impossible quantum position */ fs_give (&ret); return NIL; } break; case JNK: /* junk character */ fs_give (&ret); return NIL; } *len = d - (char *) ret; /* calculate data length */ *d = '\0'; /* NUL terminate just in case */ return ret; /* return the string */ } /* Convert binary contents to BASE64 * Accepts: source * length of source * pointer to return destination length * Returns: destination as BASE64 */ unsigned char *rfc822_binary (void *src,unsigned long srcl,unsigned long *len) { unsigned char *ret,*d; unsigned char *s = (unsigned char *) src; char *v = "ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz0123456789+/"; unsigned long i = ((srcl + 2) / 3) * 4; *len = i += 2 * ((i / 60) + 1); d = ret = (unsigned char *) fs_get ((size_t) ++i); /* process tuplets */ for (i = 0; srcl >= 3; s += 3, srcl -= 3) { *d++ = v[s[0] >> 2]; /* byte 1: high 6 bits (1) */ /* byte 2: low 2 bits (1), high 4 bits (2) */ *d++ = v[((s[0] << 4) + (s[1] >> 4)) & 0x3f]; /* byte 3: low 4 bits (2), high 2 bits (3) */ *d++ = v[((s[1] << 2) + (s[2] >> 6)) & 0x3f]; *d++ = v[s[2] & 0x3f]; /* byte 4: low 6 bits (3) */ if ((++i) == 15) { /* output 60 characters? */ i = 0; /* restart line break count, insert CRLF */ *d++ = '\015'; *d++ = '\012'; } } if (srcl) { *d++ = v[s[0] >> 2]; /* byte 1: high 6 bits (1) */ /* byte 2: low 2 bits (1), high 4 bits (2) */ *d++ = v[((s[0] << 4) + (--srcl ? (s[1] >> 4) : 0)) & 0x3f]; /* byte 3: low 4 bits (2), high 2 bits (3) */ *d++ = srcl ? v[((s[1] << 2) + (--srcl ? (s[2] >> 6) : 0)) & 0x3f] : '='; /* byte 4: low 6 bits (3) */ *d++ = srcl ? v[s[2] & 0x3f] : '='; if (srcl) srcl--; /* count third character if processed */ if ((++i) == 15) { /* output 60 characters? */ i = 0; /* restart line break count, insert CRLF */ *d++ = '\015'; *d++ = '\012'; } } *d++ = '\015'; *d++ = '\012'; /* insert final CRLF */ *d = '\0'; /* tie off string */ if (((unsigned long) (d - ret)) != *len) fatal ("rfc822_binary logic flaw"); return ret; /* return the resulting string */ } /* Convert QUOTED-PRINTABLE contents to 8BIT * Accepts: source * length of source * pointer to return destination length * Returns: destination as 8-bit text or NIL if error */ unsigned char *rfc822_qprint (unsigned char *src,unsigned long srcl, unsigned long *len) { char tmp[MAILTMPLEN]; unsigned int bogon = NIL; unsigned char *ret = (unsigned char *) fs_get ((size_t) srcl + 1); unsigned char *d = ret; unsigned char *t = d; unsigned char *s = src; unsigned char c,e; *len = 0; /* in case we return an error */ /* until run out of characters */ while (((unsigned long) (s - src)) < srcl) { switch (c = *s++) { /* what type of character is it? */ case '=': /* quoting character */ if (((unsigned long) (s - src)) < srcl) switch (c = *s++) { case '\0': /* end of data */ s--; /* back up pointer */ break; case '\015': /* non-significant line break */ if ((((unsigned long) (s - src)) < srcl) && (*s == '\012')) s++; case '\012': /* bare LF */ t = d; /* accept any leading spaces */ break; default: /* two hex digits then */ if (!(isxdigit (c) && (((unsigned long) (s - src)) < srcl) && (e = *s++) && isxdigit (e))) { /* This indicates bad MIME. One way that it can be caused is if a single-section message was QUOTED-PRINTABLE encoded and then something (e.g. a mailing list processor) appended text. The problem is that there is no way to determine where the encoded data ended and the appended crud began. Consequently, prudent software will always encapsulate a QUOTED-PRINTABLE segment inside a MULTIPART. */ if (!bogon++) { /* only do this once */ sprintf (tmp,"Invalid quoted-printable sequence: =%.80s", (char *) s - 1); mm_log (tmp,PARSE); } *d++ = '='; /* treat = as ordinary character */ *d++ = c; /* and the character following */ t = d; /* note point of non-space */ break; } *d++ = hex2byte (c,e); /* merge the two hex digits */ t = d; /* note point of non-space */ break; } break; case ' ': /* space, possibly bogus */ *d++ = c; /* stash the space but don't update s */ break; case '\015': /* end of line */ case '\012': /* bare LF */ d = t; /* slide back to last non-space, drop in */ default: *d++ = c; /* stash the character */ t = d; /* note point of non-space */ } } *d = '\0'; /* tie off results */ *len = d - ret; /* calculate length */ return ret; /* return the string */ } /* Convert 8BIT contents to QUOTED-PRINTABLE * Accepts: source * length of source * pointer to return destination length * Returns: destination as quoted-printable text */ #define MAXL (size_t) 75 /* 76th position only used by continuation = */ unsigned char *rfc822_8bit (unsigned char *src,unsigned long srcl, unsigned long *len) { unsigned long lp = 0; unsigned char *ret = (unsigned char *) fs_get ((size_t) (3*srcl + 3*(((3*srcl)/MAXL) + 1))); unsigned char *d = ret; char *hex = "0123456789ABCDEF"; unsigned char c; while (srcl--) { /* for each character */ /* true line break? */ if (((c = *src++) == '\015') && (*src == '\012') && srcl) { *d++ = '\015'; *d++ = *src++; srcl--; lp = 0; /* reset line count */ } else { /* not a line break */ /* quoting required? */ if (iscntrl (c) || (c == 0x7f) || (c & 0x80) || (c == '=') || ((c == ' ') && (*src == '\015'))) { if ((lp += 3) > MAXL) { /* yes, would line overflow? */ *d++ = '='; *d++ = '\015'; *d++ = '\012'; lp = 3; /* set line count */ } *d++ = '='; /* quote character */ *d++ = hex[c >> 4]; /* high order 4 bits */ *d++ = hex[c & 0xf]; /* low order 4 bits */ } else { /* ordinary character */ if ((++lp) > MAXL) { /* would line overflow? */ *d++ = '='; *d++ = '\015'; *d++ = '\012'; lp = 1; /* set line count */ } *d++ = c; /* ordinary character */ } } } *d = '\0'; /* tie off destination */ *len = d - ret; /* calculate true size */ /* try to give some space back */ fs_resize ((void **) &ret,(size_t) *len + 1); return ret; } /* Legacy Routines */ /* * WARNING: These routines are for compatibility with old software only. * * Their use in new software is to be avoided. * * These interfaces do not provide satisfactory buffer checking. In * versions of c-client prior to imap-2005, they did not provide any * buffer checking at all. * * As a half-hearted attempt, these new compatability functions for the * legacy interfaces limit what they write to size SENDBUFLEN and will * fatal() if more than that is written. However, that isn't good enough * since several of these functions *append* to the buffer, and return an * updated pointer. Consequently, there is no way of knowing what the * actual available space is in the buffer, yet the function will still * write up to SENDBUFLEN bytes even if there is much less space actually * available. The result is a buffer overflow. * * You won't get a buffer overflow if you never attempt to append using * these interfaces, but you can get the fatal() if it tries to write * more than SENDBUFLEN bytes. * * To avoid this problem, use the corresponding rfc822_output_???() * functions instead, e.g., rfc822_output_address() instead of * rfc822_address(). * */ /* Flush routine, only called if overflow * Accepts: stream * string to output * Returns: never */ static long rfc822_legacy_soutr (void *stream,char *string) { fatal ("rfc822.c legacy routine buffer overflow"); return NIL; } /* Legacy write RFC 2822 header from message structure * Accepts: scratch buffer to write into * message envelope * message body */ void rfc822_header (char *header,ENVELOPE *env,BODY *body) { RFC822BUFFER buf; /* write at start of buffer */ buf.end = (buf.beg = buf.cur = header) + SENDBUFLEN - 1; buf.f = rfc822_legacy_soutr; buf.s = NIL; rfc822_output_header (&buf,env,body,NIL,NIL); *buf.cur = '\0'; /* tie off buffer */ } /* Legacy write RFC 2822 text from header line * Accepts: pointer to destination string pointer * pointer to header type * message to interpret * pointer to text */ void rfc822_header_line (char **header,char *type,ENVELOPE *env,char *text) { RFC822BUFFER buf; /* append to buffer */ buf.end = (buf.beg = buf.cur = *header + strlen (*header)) + SENDBUFLEN - 1; buf.f = rfc822_legacy_soutr; buf.s = NIL; rfc822_output_header_line (&buf,type,env->remail ? LONGT : NIL,text); *(*header = buf.cur) = '\0'; /* tie off buffer */ } /* Legacy write RFC 2822 address from header line * Accepts: pointer to destination string pointer * pointer to header type * message to interpret * address to interpret */ void rfc822_address_line (char **header,char *type,ENVELOPE *env,ADDRESS *adr) { RFC822BUFFER buf; /* append to buffer */ buf.end = (buf.beg = buf.cur = *header + strlen (*header)) + SENDBUFLEN - 1; buf.f = rfc822_legacy_soutr; buf.s = NIL; rfc822_output_address_line (&buf,type,env->remail ? LONGT : NIL,adr,NIL); *(*header = buf.cur) = '\0'; /* tie off buffer */ } /* Legacy write RFC 2822 address list * Accepts: pointer to destination string * address to interpret * header base if pretty-printing * Returns: end of destination string */ char *rfc822_write_address_full (char *dest,ADDRESS *adr,char *base) { RFC822BUFFER buf; /* append to buffer */ buf.end = (buf.beg = buf.cur = dest + strlen (dest)) + SENDBUFLEN - 1; buf.f = rfc822_legacy_soutr; buf.s = NIL; rfc822_output_address_list (&buf,adr,base ? dest - base : 0,NIL); *buf.cur = '\0'; /* tie off buffer */ return buf.cur; } /* Legacy write RFC 2822 route-address to string * Accepts: pointer to destination string * address to interpret */ void rfc822_address (char *dest,ADDRESS *adr) { RFC822BUFFER buf; /* append to buffer */ buf.end = (buf.beg = buf.cur = dest + strlen (dest)) + SENDBUFLEN - 1; buf.f = rfc822_legacy_soutr; buf.s = NIL; rfc822_output_address (&buf,adr); *buf.cur = '\0'; /* tie off buffer */ } /* Concatenate RFC 2822 string * Accepts: pointer to destination string * pointer to string to concatenate * list of special characters or NIL for dot-atom format */ void rfc822_cat (char *dest,char *src,const char *specials) { RFC822BUFFER buf; /* append to buffer */ buf.end = (buf.beg = buf.cur = dest + strlen (dest)) + SENDBUFLEN - 1; buf.f = rfc822_legacy_soutr; buf.s = NIL; rfc822_output_cat (&buf,src,specials); *buf.cur = '\0'; /* tie off buffer */ } /* Legacy write body content header * Accepts: pointer to destination string pointer * pointer to body to interpret */ void rfc822_write_body_header (char **dst,BODY *body) { RFC822BUFFER buf; /* append to buffer */ buf.end = (buf.beg = buf.cur = *dst + strlen (*dst)) + SENDBUFLEN - 1; buf.f = rfc822_legacy_soutr; buf.s = NIL; rfc822_output_body_header (&buf,body); *(*dst = buf.cur) = '\0'; /* tie off buffer */ } /* Legacy output RFC 822 message * Accepts: temporary buffer * envelope * body * I/O routine * stream for I/O routine * non-zero if 8-bit output desired * Returns: T if successful, NIL if failure */ long rfc822_output (char *t,ENVELOPE *env,BODY *body,soutr_t f,void *s, long ok8bit) { long ret; rfc822out_t r822o = (rfc822out_t) mail_parameters (NIL,GET_RFC822OUTPUT,NIL); /* call external RFC 2822 output generator */ if (r822o) ret = (*r822o) (t,env,body,f,s,ok8bit); else { /* output generator not armed */ RFC822BUFFER buf; /* use our own buffer rather than trust */ char tmp[SENDBUFLEN+1]; /* client to give us a big enough one */ buf.f = f; buf.s = s; buf.end = (buf.beg = buf.cur = t) + SENDBUFLEN - 1; tmp[SENDBUFLEN] = '\0'; /* must have additional guard byte */ ret = rfc822_output_full (&buf,env,body,ok8bit); } return ret; } /* Legacy output RFC 822 body * Accepts: body * I/O routine * stream for I/O routine * Returns: T if successful, NIL if failure */ long rfc822_output_body (BODY *body,soutr_t f,void *s) { RFC822BUFFER buf; char tmp[SENDBUFLEN+1]; buf.f = f; buf.s = s; buf.end = (buf.beg = buf.cur = tmp) + SENDBUFLEN; tmp[SENDBUFLEN] = '\0'; /* must have additional guard byte */ return rfc822_output_text (&buf,body) && rfc822_output_flush (&buf); } alpine-2.10+dfsg/imap/src/c-client/tcp.h0000600000175000017500000000335711512502124021516 0ustar paulproteuspaulproteus/* ======================================================================== * Copyright 1988-2007 University of Washington * * Licensed under the Apache License, Version 2.0 (the "License"); * you may not use this file except in compliance with the License. * You may obtain a copy of the License at * * http://www.apache.org/licenses/LICENSE-2.0 * * * ======================================================================== */ /* * Program: TCP/IP routines * * Author: Mark Crispin * Networks and Distributed Computing * Computing & Communications * University of Washington * Administration Building, AG-44 * Seattle, WA 98195 * Internet: MRC@CAC.Washington.EDU * * Date: 1 August 1988 * Last Edited: 31 January 2007 */ /* Dummy definition overridden by TCP routines */ #ifndef TCPSTREAM #define TCPSTREAM void #endif /* Function prototypes */ void *tcp_parameters (long function,void *value); TCPSTREAM *tcp_open (char *host,char *service,unsigned long port); TCPSTREAM *tcp_aopen (NETMBX *mb,char *service,char *usrbuf); char *tcp_getline (TCPSTREAM *stream); long tcp_getbuffer (TCPSTREAM *stream,unsigned long size,char *buffer); long tcp_getdata (TCPSTREAM *stream); long tcp_soutr (TCPSTREAM *stream,char *string); long tcp_sout (TCPSTREAM *stream,char *string,unsigned long size); void tcp_close (TCPSTREAM *stream); char *tcp_host (TCPSTREAM *stream); char *tcp_remotehost (TCPSTREAM *stream); unsigned long tcp_port (TCPSTREAM *stream); char *tcp_localhost (TCPSTREAM *stream); char *tcp_clientaddr (void); char *tcp_clienthost (void); long tcp_clientport (void); char *tcp_serveraddr (void); char *tcp_serverhost (void); long tcp_serverport (void); char *tcp_canonical (char *name); long tcp_isclienthost (char *host); alpine-2.10+dfsg/imap/src/c-client/utf8aux.c0000600000175000017500000003417211512502124022326 0ustar paulproteuspaulproteus/* ======================================================================== * Copyright 1988-2007 University of Washington * * Licensed under the Apache License, Version 2.0 (the "License"); * you may not use this file except in compliance with the License. * You may obtain a copy of the License at * * http://www.apache.org/licenses/LICENSE-2.0 * * * ======================================================================== */ /* * Program: UTF-8 auxillary routines (c-client and MIME2 support) * * Author: Mark Crispin * Networks and Distributed Computing * Computing & Communications * University of Washington * Administration Building, AG-44 * Seattle, WA 98195 * Internet: MRC@CAC.Washington.EDU * * Date: 11 June 1997 * Last Edited: 12 October 2007 */ #include #include #include "c-client.h" /* Convert charset labelled stringlist to UTF-8 in place * Accepts: string list * charset */ static void utf8_stringlist (STRINGLIST *st,char *charset) { SIZEDTEXT txt; /* convert entire stringstruct */ if (st) do if (utf8_text (&st->text,charset,&txt,U8T_CANONICAL)) { fs_give ((void **) &st->text.data); st->text.data = txt.data; /* transfer this text */ st->text.size = txt.size; } while (st = st->next); } /* Convert charset labelled searchpgm to UTF-8 in place * Accepts: search program * charset */ void utf8_searchpgm (SEARCHPGM *pgm,char *charset) { SIZEDTEXT txt; SEARCHHEADER *hl; SEARCHOR *ol; SEARCHPGMLIST *pl; if (pgm) { /* must have a search program */ utf8_stringlist (pgm->bcc,charset); utf8_stringlist (pgm->cc,charset); utf8_stringlist (pgm->from,charset); utf8_stringlist (pgm->to,charset); utf8_stringlist (pgm->subject,charset); for (hl = pgm->header; hl; hl = hl->next) { if (utf8_text (&hl->line,charset,&txt,U8T_CANONICAL)) { fs_give ((void **) &hl->line.data); hl->line.data = txt.data; hl->line.size = txt.size; } if (utf8_text (&hl->text,charset,&txt,U8T_CANONICAL)) { fs_give ((void **) &hl->text.data); hl->text.data = txt.data; hl->text.size = txt.size; } } utf8_stringlist (pgm->body,charset); utf8_stringlist (pgm->text,charset); for (ol = pgm->or; ol; ol = ol->next) { utf8_searchpgm (ol->first,charset); utf8_searchpgm (ol->second,charset); } for (pl = pgm->not; pl; pl = pl->next) utf8_searchpgm (pl->pgm,charset); utf8_stringlist (pgm->return_path,charset); utf8_stringlist (pgm->sender,charset); utf8_stringlist (pgm->reply_to,charset); utf8_stringlist (pgm->in_reply_to,charset); utf8_stringlist (pgm->message_id,charset); utf8_stringlist (pgm->newsgroups,charset); utf8_stringlist (pgm->followup_to,charset); utf8_stringlist (pgm->references,charset); } } /* Convert MIME-2 sized text to UTF-8 * Accepts: source sized text * charset * flags (same as utf8_text()) * Returns: T if successful, NIL if failure */ #define MINENCWORD 9 #define MAXENCWORD 75 /* This resizing algorithm is stupid, but hopefully it should never be triggered * except for a pathological header. The main concern is that we don't get a * buffer overflow. */ #define DSIZE 65536 /* real headers should never be this big */ #define FUZZ 10 /* paranoia fuzz */ long utf8_mime2text (SIZEDTEXT *src,SIZEDTEXT *dst,long flags) { unsigned char *s,*se,*e,*ee,*t,*te; char *cs,*ce,*ls; SIZEDTEXT txt,rtxt; unsigned long i; size_t dsize = min (DSIZE,((src->size / 4) + 1) * 9); /* always create buffer if canonicalizing */ dst->data = (flags & U8T_CANONICAL) ? (unsigned char *) fs_get ((size_t) dsize) : NIL; dst->size = 0; /* nothing written yet */ /* look for encoded words */ for (s = src->data, se = src->data + src->size; s < se; s++) { if (((se - s) > MINENCWORD) && (*s == '=') && (s[1] == '?') && (cs = (char *) mime2_token (s+2,se,(unsigned char **) &ce)) && (e = mime2_token ((unsigned char *) ce+1,se,&ee)) && (te = mime2_text (t = e+2,se)) && (ee == e + 1) && ((te - s) < MAXENCWORD)) { if (mime2_decode (e,t,te,&txt)) { *ce = '\0'; /* temporarily tie off charset */ if (ls = strchr (cs,'*')) *ls = '\0'; /* convert to UTF-8 as best we can */ if (!utf8_text (&txt,cs,&rtxt,flags)) utf8_text (&txt,NIL,&rtxt,flags); if (dst->data) { /* make sure existing buffer fits */ while (dsize <= (dst->size + rtxt.size + FUZZ)) { dsize += DSIZE; /* kick it up */ fs_resize ((void **) &dst->data,dsize); } } else { /* make a new buffer */ while (dsize <= (dst->size + rtxt.size)) dsize += DSIZE; memcpy (dst->data = (unsigned char *) fs_get (dsize),src->data, dst->size = s - src->data); } for (i = 0; i < rtxt.size; i++) dst->data[dst->size++] = rtxt.data[i]; /* all done with converted text */ if (rtxt.data != txt.data) fs_give ((void **) &rtxt.data); if (ls) *ls = '*'; /* restore language tag delimiter */ *ce = '?'; /* restore charset delimiter */ /* all done with decoded text */ fs_give ((void **) &txt.data); s = te+1; /* continue scan after encoded word */ /* skip leading whitespace */ for (t = s + 1; (t < se) && ((*t == ' ') || (*t == '\t')); t++); /* see if likely continuation encoded word */ if (t < (se - MINENCWORD)) switch (*t) { case '=': /* possible encoded word? */ if (t[1] == '?') s = t - 1; break; case '\015': /* CR, eat a following LF */ if (t[1] == '\012') t++; case '\012': /* possible end of logical line */ if ((t[1] == ' ') || (t[1] == '\t')) { do t++; while ((t < (se - MINENCWORD)) && ((t[1] == ' ')||(t[1] == '\t'))); if ((t < (se - MINENCWORD)) && (t[1] == '=') && (t[2] == '?')) s = t; /* definitely looks like continuation */ } } } else { /* restore original text */ if (dst->data) fs_give ((void **) &dst->data); dst->data = src->data; dst->size = src->size; return NIL; /* syntax error: MIME-2 decoding failure */ } } else do if (dst->data) { /* stash ASCII characters until LWSP */ if (dsize < (dst->size + FUZZ)) { dsize += DSIZE; /* kick it up */ fs_resize ((void **) &dst->data,dsize); } /* kludge: assumes ASCII doesn't decompose and titlecases to one byte */ dst->data[dst->size++] = (flags & U8T_CASECANON) ? (unsigned char) ucs4_titlecase (*s) : *s; } while ((*s != ' ') && (*s != '\t') && (*s != '\015') && (*s != '\012') && (++s < se)); } if (dst->data) dst->data[dst->size] = '\0'; else { /* nothing converted, return identity */ dst->data = src->data; dst->size = src->size; } return T; /* success */ } /* Decode MIME-2 text * Accepts: Encoding * text * text end * destination sized text * Returns: T if successful, else NIL */ long mime2_decode (unsigned char *e,unsigned char *t,unsigned char *te, SIZEDTEXT *txt) { unsigned char *q; txt->data = NIL; /* initially no returned data */ switch (*e) { /* dispatch based upon encoding */ case 'Q': case 'q': /* sort-of QUOTED-PRINTABLE */ txt->data = (unsigned char *) fs_get ((size_t) (te - t) + 1); for (q = t,txt->size = 0; q < te; q++) switch (*q) { case '=': /* quoted character */ /* both must be hex */ if (!isxdigit (q[1]) || !isxdigit (q[2])) { fs_give ((void **) &txt->data); return NIL; /* syntax error: bad quoted character */ } /* assemble character */ txt->data[txt->size++] = hex2byte (q[1],q[2]); q += 2; /* advance past quoted character */ break; case '_': /* convert to space */ txt->data[txt->size++] = ' '; break; default: /* ordinary character */ txt->data[txt->size++] = *q; break; } txt->data[txt->size] = '\0'; break; case 'B': case 'b': /* BASE64 */ if (txt->data = (unsigned char *) rfc822_base64 (t,te - t,&txt->size)) break; default: /* any other encoding is unknown */ return NIL; /* syntax error: unknown encoding */ } return T; } /* Get MIME-2 token from encoded word * Accepts: current text pointer * text limit pointer * pointer to returned end pointer * Returns: current text pointer & end pointer if success, else NIL */ unsigned char *mime2_token (unsigned char *s,unsigned char *se, unsigned char **t) { for (*t = s; **t != '?'; ++*t) { if ((*t < se) && isgraph (**t)) switch (**t) { case '(': case ')': case '<': case '>': case '@': case ',': case ';': case ':': case '\\': case '"': case '/': case '[': case ']': case '.': case '=': return NIL; /* none of these are valid in tokens */ } else return NIL; /* out of text or CTL or space */ } return s; } /* Get MIME-2 text from encoded word * Accepts: current text pointer * text limit pointer * pointer to returned end pointer * Returns: end pointer if success, else NIL */ unsigned char *mime2_text (unsigned char *s,unsigned char *se) { unsigned char *t = se - 1; /* search for closing ?, make sure valid */ while ((s < t) && (*s != '?') && isgraph (*s++)); return ((s < t) && (*s == '?') && (s[1] == '=') && ((se == (s + 2)) || (s[2] == ' ') || (s[2] == '\t') || (s[2] == '\015') || (s[2] == '\012'))) ? s : NIL; } /* Convert UTF-16 string to Modified Base64 * Accepts: destination pointer * source string * source length in octets * Returns: updated destination pointer */ static unsigned char *utf16_to_mbase64 (unsigned char *t,unsigned char *s, size_t i) { char *v = "ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz0123456789+,"; *t++ = '&'; /* write shift-in */ while (i >= 3) { /* process tuplets */ *t++ = v[s[0] >> 2]; /* byte 1: high 6 bits (1) */ /* byte 2: low 2 bits (1), high 4 bits (2) */ *t++ = v[((s[0] << 4) + (s[1] >> 4)) & 0x3f]; /* byte 3: low 4 bits (2), high 2 bits (3) */ *t++ = v[((s[1] << 2) + (s[2] >> 6)) & 0x3f]; *t++ = v[s[2] & 0x3f]; /* byte 4: low 6 bits (3) */ s += 3; i -= 3; } if (i) { *t++ = v[s[0] >> 2]; /* byte 1: high 6 bits (1) */ /* byte 2: low 2 bits (1), high 4 bits (2) */ *t++ = v[((s[0] << 4) + (--i ? (s[1] >> 4) : 0)) & 0x3f]; /* byte 3: low 4 bits (2) */ if (i) *t++ = v[(s[1] << 2) & 0x3f]; } *t++ = '-'; /* write shift-out */ return t; } /* Poot a UTF-16 value to a buffer * Accepts: buffer pointer * value * Returns: updated pointer */ static unsigned char *utf16_poot (unsigned char *s,unsigned long c) { *s++ = (unsigned char) (c >> 8); *s++ = (unsigned char) (c & 0xff); return s; } /* Convert UTF-8 to Modified UTF-7 * Accepts: UTF-8 string * Returns: Modified UTF-7 string on success, NIL if invalid UTF-8 */ #define MAXUNIUTF8 4 /* maximum length of Unicode UTF-8 sequence */ unsigned char *utf8_to_mutf7 (unsigned char *src) { unsigned char *u16buf,*utf16; unsigned char *ret,*t; unsigned long j,c; unsigned char *s = src; unsigned long i = 0; int nonascii = 0; while (*s) { /* pass one: count destination octets */ if (*s & 0x80) { /* non-ASCII character? */ j = MAXUNIUTF8; /* get single UCS-4 codepoint */ if ((c = utf8_get (&s,&j)) & U8G_ERROR) return NIL; /* tally number of UTF-16 octets */ nonascii += (c & U8GM_NONBMP) ? 4 : 2; } else { /* ASCII character */ if (nonascii) { /* add pending Modified BASE64 size + shifts */ i += ((nonascii / 3) * 4) + ((j = nonascii % 3) ? j + 1 : 0) + 2; nonascii = 0; /* back to ASCII */ } if (*s == '&') i += 2; /* two octets if the escape */ else ++i; /* otherwise just count another octet */ ++s; /* advance to next source octet */ } } if (nonascii) /* add pending Modified BASE64 size + shifts */ i += ((nonascii / 3) * 4) + ((j = nonascii % 3) ? j + 1 : 0) + 2; /* create return buffer */ t = ret = (unsigned char *) fs_get (i + 1); /* and scratch buffer */ utf16 = u16buf = (unsigned char *) fs_get (i + 1); for (s = src; *s;) { /* pass two: copy destination octets */ if (*s & 0x80) { /* non-ASCII character? */ j = MAXUNIUTF8; /* get single UCS-4 codepoint */ if ((c = utf8_get (&s,&j)) & U8G_ERROR) return NIL; if (c & U8GM_NONBMP) { /* non-BMP? */ c -= UTF16_BASE; /* yes, convert to surrogate */ utf16 = utf16_poot (utf16_poot (utf16,(c >> UTF16_SHIFT)+UTF16_SURRH), (c & UTF16_MASK) + UTF16_SURRL); } else utf16 = utf16_poot (utf16,c); } else { /* ASCII character */ if (utf16 != u16buf) { /* add pending Modified BASE64 size + shifts */ t = utf16_to_mbase64 (t,u16buf,utf16 - u16buf); utf16 = u16buf; /* reset buffer */ } *t++ = *s; /* copy the character */ if (*s == '&') *t++ = '-';/* special sequence if the escape */ ++s; /* advance to next source octet */ } } /* add pending Modified BASE64 size + shifts */ if (utf16 != u16buf) t = utf16_to_mbase64 (t,u16buf,utf16 - u16buf); *t = '\0'; /* tie off destination */ if (i != (t - ret)) fatal ("utf8_to_mutf7 botch"); fs_give ((void **) &u16buf); return ret; } /* Convert Modified UTF-7 to UTF-8 * Accepts: Modified UTF-7 string * Returns: UTF-8 string on success, NIL if invalid Modified UTF-7 */ unsigned char *utf8_from_mutf7 (unsigned char *src) { SIZEDTEXT utf8,utf7; unsigned char *s; int mbase64 = 0; /* disallow bogus strings */ if (mail_utf7_valid (src)) return NIL; /* initialize SIZEDTEXTs */ memset (&utf7,0,sizeof (SIZEDTEXT)); memset (&utf8,0,sizeof (SIZEDTEXT)); /* make copy of source */ for (s = cpytxt (&utf7,src,strlen (src)); *s; ++s) switch (*s) { case '&': /* Modified UTF-7 uses & instead of + */ *s = '+'; mbase64 = T; /* note that we are in Modified BASE64 */ break; case '+': /* temporarily swap text + to & */ if (!mbase64) *s = '&'; break; case '-': /* shift back to ASCII */ mbase64 = NIL; break; case ',': /* Modified UTF-7 uses , instead of / ... */ if (mbase64) *s = '/'; /* ...in Modified BASE64 */ break; } /* do the conversion */ utf8_text_utf7 (&utf7,&utf8,NIL,NIL); /* no longer need copy of source */ fs_give ((void **) &utf7.data); /* post-process: switch & and + */ for (s = utf8.data; *s; ++s) switch (*s) { case '&': *s = '+'; break; case '+': *s = '&'; break; } return utf8.data; } alpine-2.10+dfsg/imap/src/c-client/ftl.h0000600000175000017500000000147111512502124021510 0ustar paulproteuspaulproteus/* ======================================================================== * Copyright 1988-2006 University of Washington * * Licensed under the Apache License, Version 2.0 (the "License"); * you may not use this file except in compliance with the License. * You may obtain a copy of the License at * * http://www.apache.org/licenses/LICENSE-2.0 * * * ======================================================================== */ /* * Program: Crash management routines * * Author: Mark Crispin * Networks and Distributed Computing * Computing & Communications * University of Washington * Administration Building, AG-44 * Seattle, WA 98195 * Internet: MRC@CAC.Washington.EDU * * Date: 1 August 1988 * Last Edited: 30 August 2006 */ /* Function prototypes */ void fatal (char *string); alpine-2.10+dfsg/imap/src/c-client/utf8aux.h0000600000175000017500000000277111512502124022333 0ustar paulproteuspaulproteus/* ======================================================================== * Copyright 1988-2007 University of Washington * * Licensed under the Apache License, Version 2.0 (the "License"); * you may not use this file except in compliance with the License. * You may obtain a copy of the License at * * http://www.apache.org/licenses/LICENSE-2.0 * * * ======================================================================== */ /* * Program: UTF-8 auxillary routines (c-client and MIME2 support) * * Author: Mark Crispin * Networks and Distributed Computing * Computing & Communications * University of Washington * Administration Building, AG-44 * Seattle, WA 98195 * Internet: MRC@CAC.Washington.EDU * * Date: 11 June 1997 * Last Edited: 9 October 2007 */ /* Following routines are in utf8aux.c as these depend upon c-client. * Splitting these routines out makes it possible for pico to link with utf8.o * and a few rump routines (e.g., fs_get()) but not all the rest of c-client * (which pico does not need). */ void utf8_searchpgm (SEARCHPGM *pgm,char *charset); long utf8_mime2text (SIZEDTEXT *src,SIZEDTEXT *dst,long flags); unsigned char *mime2_token (unsigned char *s,unsigned char *se, unsigned char **t); unsigned char *mime2_text (unsigned char *s,unsigned char *se); long mime2_decode (unsigned char *e,unsigned char *t,unsigned char *te, SIZEDTEXT *txt); unsigned char *utf8_to_mutf7 (unsigned char *src); unsigned char *utf8_from_mutf7 (unsigned char *src); alpine-2.10+dfsg/imap/src/c-client/auth_md5.c0000600000175000017500000004123311512502124022424 0ustar paulproteuspaulproteus/* ======================================================================== * Copyright 1988-2007 University of Washington * * Licensed under the Apache License, Version 2.0 (the "License"); * you may not use this file except in compliance with the License. * You may obtain a copy of the License at * * http://www.apache.org/licenses/LICENSE-2.0 * * * ======================================================================== */ /* * Program: CRAM-MD5 authenticator * * Author: Mark Crispin * Networks and Distributed Computing * Computing & Communications * University of Washington * Administration Building, AG-44 * Seattle, WA 98195 * Internet: MRC@CAC.Washington.EDU * * Date: 21 October 1998 * Last Edited: 30 January 2007 */ /* MD5 context */ #define MD5BLKLEN 64 /* MD5 block length */ #define MD5DIGLEN 16 /* MD5 digest length */ typedef struct { unsigned long chigh; /* high 32bits of byte count */ unsigned long clow; /* low 32bits of byte count */ unsigned long state[4]; /* state (ABCD) */ unsigned char buf[MD5BLKLEN]; /* input buffer */ unsigned char *ptr; /* buffer position */ } MD5CONTEXT; /* Prototypes */ long auth_md5_valid (void); long auth_md5_client (authchallenge_t challenger,authrespond_t responder, char *service,NETMBX *mb,void *stream, unsigned long *trial,char *user); char *auth_md5_server (authresponse_t responder,int argc,char *argv[]); char *auth_md5_pwd (char *user); char *apop_login (char *chal,char *user,char *md5,int argc,char *argv[]); char *hmac_md5 (char *text,unsigned long tl,char *key,unsigned long kl); void md5_init (MD5CONTEXT *ctx); void md5_update (MD5CONTEXT *ctx,unsigned char *data,unsigned long len); void md5_final (unsigned char *digest,MD5CONTEXT *ctx); static void md5_transform (unsigned long *state,unsigned char *block); static void md5_encode (unsigned char *dst,unsigned long *src,int len); static void md5_decode (unsigned long *dst,unsigned char *src,int len); /* Authenticator linkage */ AUTHENTICATOR auth_md5 = { AU_SECURE, /* secure authenticator */ "CRAM-MD5", /* authenticator name */ auth_md5_valid, /* check if valid */ auth_md5_client, /* client method */ auth_md5_server, /* server method */ NIL /* next authenticator */ }; /* Check if CRAM-MD5 valid on this system * Returns: T, always */ long auth_md5_valid (void) { struct stat sbuf; /* server forbids MD5 if no MD5 enable file */ if (stat (MD5ENABLE,&sbuf)) auth_md5.server = NIL; return T; /* MD5 is otherwise valid */ } /* Client authenticator * Accepts: challenger function * responder function * SASL service name * parsed network mailbox structure * stream argument for functions * pointer to current trial count * returned user name * Returns: T if success, NIL otherwise, number of trials incremented if retry */ long auth_md5_client (authchallenge_t challenger,authrespond_t responder, char *service,NETMBX *mb,void *stream, unsigned long *trial,char *user) { char pwd[MAILTMPLEN]; void *challenge; unsigned long clen; long ret = NIL; /* get challenge */ if (challenge = (*challenger) (stream,&clen)) { pwd[0] = NIL; /* prompt user */ mm_login (mb,user,pwd,*trial); if (!pwd[0]) { /* user requested abort */ fs_give ((void **) &challenge); (*responder) (stream,NIL,0); *trial = 0; /* cancel subsequent attempts */ ret = LONGT; /* will get a BAD response back */ } else { /* got password, build response */ sprintf (pwd,"%.65s %.33s",user,hmac_md5 (challenge,clen, pwd,strlen (pwd))); fs_give ((void **) &challenge); /* send credentials, allow retry if OK */ if ((*responder) (stream,pwd,strlen (pwd))) { if (challenge = (*challenger) (stream,&clen)) fs_give ((void **) &challenge); else { ++*trial; /* can try again if necessary */ ret = LONGT; /* check the authentication */ } } } } memset (pwd,0,MAILTMPLEN); /* erase password in case not overwritten */ if (!ret) *trial = 65535; /* don't retry if bad protocol */ return ret; } /* Server authenticator * Accepts: responder function * argument count * argument vector * Returns: authenticated user name or NIL * * This is much hairier than it needs to be due to the necessary of zapping * the password data. */ static int md5try = MAXLOGINTRIALS; char *auth_md5_server (authresponse_t responder,int argc,char *argv[]) { char *ret = NIL; char *p,*u,*user,*authuser,*hash,chal[MAILTMPLEN]; unsigned long cl,pl; /* generate challenge */ sprintf (chal,"<%lu.%lu@%s>",(unsigned long) getpid (), (unsigned long) time (0),mylocalhost ()); /* send challenge, get user and hash */ if (user = (*responder) (chal,cl = strlen (chal),NIL)) { /* got user, locate hash */ if (hash = strrchr (user,' ')) { *hash++ = '\0'; /* tie off user */ /* see if authentication user */ if (authuser = strchr (user,'*')) *authuser++ = '\0'; /* get password */ if (p = auth_md5_pwd ((authuser && *authuser) ? authuser : user)) { pl = strlen (p); u = (md5try && !strcmp (hash,hmac_md5 (chal,cl,p,pl))) ? user : NIL; memset (p,0,pl); /* erase sensitive information */ fs_give ((void **) &p); /* flush erased password */ /* now log in for real */ if (u && authserver_login (u,authuser,argc,argv)) ret = myusername (); else if (md5try) --md5try; } } fs_give ((void **) &user); } if (!ret) sleep (3); /* slow down possible cracker */ return ret; } /* Return MD5 password for user * Accepts: user name * Returns: plaintext password if success, else NIL * * This is much hairier than it needs to be due to the necessary of zapping * the password data. That's why we don't use stdio here. */ char *auth_md5_pwd (char *user) { struct stat sbuf; int fd = open (MD5ENABLE,O_RDONLY,NIL); unsigned char *s,*t,*buf,*lusr,*lret; char *r; char *ret = NIL; if (fd >= 0) { /* found the file? */ fstat (fd,&sbuf); /* yes, slurp it into memory */ read (fd,buf = (char *) fs_get (sbuf.st_size + 1),sbuf.st_size); /* see if any uppercase characters in user */ for (s = user; *s && ((*s < 'A') || (*s > 'Z')); s++); /* yes, make lowercase copy */ lusr = *s ? lcase (cpystr (user)) : NIL; for (s = strtok_r ((char *) buf,"\015\012",&r),lret = NIL; s; s = ret ? NIL : strtok_r (NIL,"\015\012",&r)) /* must be valid entry line */ if (*s && (*s != '#') && (t = strchr (s,'\t')) && t[1]) { *t++ = '\0'; /* found tab, tie off user, point to pwd */ if (!strcmp (s,user)) ret = cpystr (t); else if (lusr && !lret) if (!strcmp (s,lusr)) lret = t; } /* accept case-independent name */ if (!ret && lret) ret = cpystr (lret); /* don't need lowercase copy any more */ if (lusr) fs_give ((void **) &lusr); /* erase sensitive information from buffer */ memset (buf,0,sbuf.st_size + 1); fs_give ((void **) &buf); /* flush the buffer */ close (fd); /* don't need file any longer */ } return ret; /* return password */ } /* APOP server login * Accepts: challenge * desired user name * purported MD5 * argument count * argument vector * Returns: authenticated user name or NIL */ char *apop_login (char *chal,char *user,char *md5,int argc,char *argv[]) { int i,j; char *ret = NIL; char *s,*authuser,tmp[MAILTMPLEN]; unsigned char digest[MD5DIGLEN]; MD5CONTEXT ctx; char *hex = "0123456789abcdef"; /* see if authentication user */ if (authuser = strchr (user,'*')) *authuser++ = '\0'; /* get password */ if (s = auth_md5_pwd ((authuser && *authuser) ? authuser : user)) { md5_init (&ctx); /* initialize MD5 context */ /* build string to get MD5 digest */ sprintf (tmp,"%.128s%.128s",chal,s); memset (s,0,strlen (s)); /* erase sensitive information */ fs_give ((void **) &s); /* flush erased password */ md5_update (&ctx,(unsigned char *) tmp,strlen (tmp)); memset (tmp,0,MAILTMPLEN); /* erase sensitive information */ md5_final (digest,&ctx); /* convert to printable hex */ for (i = 0, s = tmp; i < MD5DIGLEN; i++) { *s++ = hex[(j = digest[i]) >> 4]; *s++ = hex[j & 0xf]; } *s = '\0'; /* tie off hash text */ memset (digest,0,MD5DIGLEN);/* erase sensitive information */ if (md5try && !strcmp (md5,tmp) && authserver_login (user,authuser,argc,argv)) ret = cpystr (myusername ()); else if (md5try) --md5try; memset (tmp,0,MAILTMPLEN); /* erase sensitive information */ } if (!ret) sleep (3); /* slow down possible cracker */ return ret; } /* * RFC 2104 HMAC hashing * Accepts: text to hash * text length * key * key length * Returns: hash as text, always */ char *hmac_md5 (char *text,unsigned long tl,char *key,unsigned long kl) { int i,j; static char hshbuf[2*MD5DIGLEN + 1]; char *s; MD5CONTEXT ctx; char *hex = "0123456789abcdef"; unsigned char digest[MD5DIGLEN],k_ipad[MD5BLKLEN+1],k_opad[MD5BLKLEN+1]; if (kl > MD5BLKLEN) { /* key longer than pad length? */ md5_init (&ctx); /* yes, set key as MD5(key) */ md5_update (&ctx,(unsigned char *) key,kl); md5_final (digest,&ctx); key = (char *) digest; kl = MD5DIGLEN; } memcpy (k_ipad,key,kl); /* store key in pads */ memset (k_ipad+kl,0,(MD5BLKLEN+1)-kl); memcpy (k_opad,k_ipad,MD5BLKLEN+1); /* XOR key with ipad and opad values */ for (i = 0; i < MD5BLKLEN; i++) { k_ipad[i] ^= 0x36; k_opad[i] ^= 0x5c; } md5_init (&ctx); /* inner MD5: hash ipad and text */ md5_update (&ctx,k_ipad,MD5BLKLEN); md5_update (&ctx,(unsigned char *) text,tl); md5_final (digest,&ctx); md5_init (&ctx); /* outer MD5: hash opad and inner results */ md5_update (&ctx,k_opad,MD5BLKLEN); md5_update (&ctx,digest,MD5DIGLEN); md5_final (digest,&ctx); /* convert to printable hex */ for (i = 0, s = hshbuf; i < MD5DIGLEN; i++) { *s++ = hex[(j = digest[i]) >> 4]; *s++ = hex[j & 0xf]; } *s = '\0'; /* tie off hash text */ return hshbuf; } /* Everything after this point is derived from the RSA Data Security, Inc. * MD5 Message-Digest Algorithm */ /* You may wonder why these strange "a &= 0xffffffff;" statements are here. * This is to ensure correct results on machines with a unsigned long size of * larger than 32 bits. */ #define RND1(a,b,c,d,x,s,ac) \ a += ((b & c) | (d & ~b)) + x + (unsigned long) ac; \ a &= 0xffffffff; \ a = b + ((a << s) | (a >> (32 - s))); #define RND2(a,b,c,d,x,s,ac) \ a += ((b & d) | (c & ~d)) + x + (unsigned long) ac; \ a &= 0xffffffff; \ a = b + ((a << s) | (a >> (32 - s))); #define RND3(a,b,c,d,x,s,ac) \ a += (b ^ c ^ d) + x + (unsigned long) ac; \ a &= 0xffffffff; \ a = b + ((a << s) | (a >> (32 - s))); #define RND4(a,b,c,d,x,s,ac) \ a += (c ^ (b | ~d)) + x + (unsigned long) ac; \ a &= 0xffffffff; \ a = b + ((a << s) | (a >> (32 - s))); /* Initialize MD5 context * Accepts: context to initialize */ void md5_init (MD5CONTEXT *ctx) { ctx->clow = ctx->chigh = 0; /* initialize byte count to zero */ /* initialization constants */ ctx->state[0] = 0x67452301; ctx->state[1] = 0xefcdab89; ctx->state[2] = 0x98badcfe; ctx->state[3] = 0x10325476; ctx->ptr = ctx->buf; /* reset buffer pointer */ } /* MD5 add data to context * Accepts: context * input data * length of data */ void md5_update (MD5CONTEXT *ctx,unsigned char *data,unsigned long len) { unsigned long i = (ctx->buf + MD5BLKLEN) - ctx->ptr; /* update double precision number of bytes */ if ((ctx->clow += len) < len) ctx->chigh++; while (i <= len) { /* copy/transform data, 64 bytes at a time */ memcpy (ctx->ptr,data,i); /* fill up 64 byte chunk */ md5_transform (ctx->state,ctx->ptr = ctx->buf); data += i,len -= i,i = MD5BLKLEN; } memcpy (ctx->ptr,data,len); /* copy final bit of data in buffer */ ctx->ptr += len; /* update buffer pointer */ } /* MD5 Finalization * Accepts: destination digest * context */ void md5_final (unsigned char *digest,MD5CONTEXT *ctx) { unsigned long i,bits[2]; bits[0] = ctx->clow << 3; /* calculate length in bits (before padding) */ bits[1] = (ctx->chigh << 3) + (ctx->clow >> 29); *ctx->ptr++ = 0x80; /* padding byte */ if ((i = (ctx->buf + MD5BLKLEN) - ctx->ptr) < 8) { memset (ctx->ptr,0,i); /* pad out buffer with zeros */ md5_transform (ctx->state,ctx->buf); /* pad out with zeros, leaving 8 bytes */ memset (ctx->buf,0,MD5BLKLEN - 8); ctx->ptr = ctx->buf + MD5BLKLEN - 8; } else if (i -= 8) { /* need to pad this buffer? */ memset (ctx->ptr,0,i); /* yes, pad out with zeros, leaving 8 bytes */ ctx->ptr += i; } md5_encode (ctx->ptr,bits,2); /* make LSB-first length */ md5_transform (ctx->state,ctx->buf); /* store state in digest */ md5_encode (digest,ctx->state,4); /* erase context */ memset (ctx,0,sizeof (MD5CONTEXT)); } /* MD5 basic transformation * Accepts: state vector * current 64-byte block */ static void md5_transform (unsigned long *state,unsigned char *block) { unsigned long a = state[0],b = state[1],c = state[2],d = state[3],x[16]; md5_decode (x,block,16); /* decode into 16 longs */ /* round 1 */ RND1 (a,b,c,d,x[ 0], 7,0xd76aa478); RND1 (d,a,b,c,x[ 1],12,0xe8c7b756); RND1 (c,d,a,b,x[ 2],17,0x242070db); RND1 (b,c,d,a,x[ 3],22,0xc1bdceee); RND1 (a,b,c,d,x[ 4], 7,0xf57c0faf); RND1 (d,a,b,c,x[ 5],12,0x4787c62a); RND1 (c,d,a,b,x[ 6],17,0xa8304613); RND1 (b,c,d,a,x[ 7],22,0xfd469501); RND1 (a,b,c,d,x[ 8], 7,0x698098d8); RND1 (d,a,b,c,x[ 9],12,0x8b44f7af); RND1 (c,d,a,b,x[10],17,0xffff5bb1); RND1 (b,c,d,a,x[11],22,0x895cd7be); RND1 (a,b,c,d,x[12], 7,0x6b901122); RND1 (d,a,b,c,x[13],12,0xfd987193); RND1 (c,d,a,b,x[14],17,0xa679438e); RND1 (b,c,d,a,x[15],22,0x49b40821); /* round 2 */ RND2 (a,b,c,d,x[ 1], 5,0xf61e2562); RND2 (d,a,b,c,x[ 6], 9,0xc040b340); RND2 (c,d,a,b,x[11],14,0x265e5a51); RND2 (b,c,d,a,x[ 0],20,0xe9b6c7aa); RND2 (a,b,c,d,x[ 5], 5,0xd62f105d); RND2 (d,a,b,c,x[10], 9, 0x2441453); RND2 (c,d,a,b,x[15],14,0xd8a1e681); RND2 (b,c,d,a,x[ 4],20,0xe7d3fbc8); RND2 (a,b,c,d,x[ 9], 5,0x21e1cde6); RND2 (d,a,b,c,x[14], 9,0xc33707d6); RND2 (c,d,a,b,x[ 3],14,0xf4d50d87); RND2 (b,c,d,a,x[ 8],20,0x455a14ed); RND2 (a,b,c,d,x[13], 5,0xa9e3e905); RND2 (d,a,b,c,x[ 2], 9,0xfcefa3f8); RND2 (c,d,a,b,x[ 7],14,0x676f02d9); RND2 (b,c,d,a,x[12],20,0x8d2a4c8a); /* round 3 */ RND3 (a,b,c,d,x[ 5], 4,0xfffa3942); RND3 (d,a,b,c,x[ 8],11,0x8771f681); RND3 (c,d,a,b,x[11],16,0x6d9d6122); RND3 (b,c,d,a,x[14],23,0xfde5380c); RND3 (a,b,c,d,x[ 1], 4,0xa4beea44); RND3 (d,a,b,c,x[ 4],11,0x4bdecfa9); RND3 (c,d,a,b,x[ 7],16,0xf6bb4b60); RND3 (b,c,d,a,x[10],23,0xbebfbc70); RND3 (a,b,c,d,x[13], 4,0x289b7ec6); RND3 (d,a,b,c,x[ 0],11,0xeaa127fa); RND3 (c,d,a,b,x[ 3],16,0xd4ef3085); RND3 (b,c,d,a,x[ 6],23, 0x4881d05); RND3 (a,b,c,d,x[ 9], 4,0xd9d4d039); RND3 (d,a,b,c,x[12],11,0xe6db99e5); RND3 (c,d,a,b,x[15],16,0x1fa27cf8); RND3 (b,c,d,a,x[ 2],23,0xc4ac5665); /* round 4 */ RND4 (a,b,c,d,x[ 0], 6,0xf4292244); RND4 (d,a,b,c,x[ 7],10,0x432aff97); RND4 (c,d,a,b,x[14],15,0xab9423a7); RND4 (b,c,d,a,x[ 5],21,0xfc93a039); RND4 (a,b,c,d,x[12], 6,0x655b59c3); RND4 (d,a,b,c,x[ 3],10,0x8f0ccc92); RND4 (c,d,a,b,x[10],15,0xffeff47d); RND4 (b,c,d,a,x[ 1],21,0x85845dd1); RND4 (a,b,c,d,x[ 8], 6,0x6fa87e4f); RND4 (d,a,b,c,x[15],10,0xfe2ce6e0); RND4 (c,d,a,b,x[ 6],15,0xa3014314); RND4 (b,c,d,a,x[13],21,0x4e0811a1); RND4 (a,b,c,d,x[ 4], 6,0xf7537e82); RND4 (d,a,b,c,x[11],10,0xbd3af235); RND4 (c,d,a,b,x[ 2],15,0x2ad7d2bb); RND4 (b,c,d,a,x[ 9],21,0xeb86d391); /* update state */ state[0] += a; state[1] += b; state[2] += c; state[3] += d; memset (x,0,sizeof (x)); /* erase sensitive data */ } /* You may wonder why these strange "& 0xff" maskings are here. This is to * ensure correct results on machines with a char size of larger than 8 bits. * For example, the KCC compiler on the PDP-10 uses 9-bit chars. */ /* MD5 encode unsigned long into LSB-first bytes * Accepts: destination pointer * source * length of source */ static void md5_encode (unsigned char *dst,unsigned long *src,int len) { int i; for (i = 0; i < len; i++) { *dst++ = (unsigned char) (src[i] & 0xff); *dst++ = (unsigned char) ((src[i] >> 8) & 0xff); *dst++ = (unsigned char) ((src[i] >> 16) & 0xff); *dst++ = (unsigned char) ((src[i] >> 24) & 0xff); } } /* MD5 decode LSB-first bytes into unsigned long * Accepts: destination pointer * source * length of destination */ static void md5_decode (unsigned long *dst,unsigned char *src,int len) { int i, j; for (i = 0, j = 0; i < len; i++, j += 4) dst[i] = ((unsigned long) (src[j] & 0xff)) | (((unsigned long) (src[j+1] & 0xff)) << 8) | (((unsigned long) (src[j+2] & 0xff)) << 16) | (((unsigned long) (src[j+3] & 0xff)) << 24); } alpine-2.10+dfsg/imap/src/c-client/imap4r1.c0000600000175000017500000060243212074130635022207 0ustar paulproteuspaulproteus/* ======================================================================== * Copyright 1988-2008 University of Washington * * Licensed under the Apache License, Version 2.0 (the "License"); * you may not use this file except in compliance with the License. * You may obtain a copy of the License at * * http://www.apache.org/licenses/LICENSE-2.0 * * * ======================================================================== */ /* * Program: Interactive Message Access Protocol 4rev1 (IMAP4R1) routines * * Author: Mark Crispin * UW Technology * University of Washington * Seattle, WA 98195 * Internet: MRC@CAC.Washington.EDU * * Date: 15 June 1988 * Last Edited: 8 May 2008 * * This original version of this file is * Copyright 1988 Stanford University * and was developed in the Symbolic Systems Resources Group of the Knowledge * Systems Laboratory at Stanford University in 1987-88, and was funded by the * Biomedical Research Technology Program of the National Institutes of Health * under grant number RR-00785. */ #include #include #include #include "c-client.h" #include "imap4r1.h" /* Parameters */ #define IMAPLOOKAHEAD 20 /* envelope lookahead */ #define IMAPUIDLOOKAHEAD 1000 /* UID lookahead */ #define IMAPTCPPORT (long) 143 /* assigned TCP contact port */ #define IMAPSSLPORT (long) 993 /* assigned SSL TCP contact port */ #define MAXCOMMAND 1000 /* RFC 2683 guideline for cmd line length */ #define IDLETIMEOUT (long) 30 /* defined in RFC 3501 */ #define MAXSERVERLIT 0x7ffffffe /* maximum server literal size * must be smaller than 4294967295 */ /* Parsed reply message from imap_reply */ typedef struct imap_parsed_reply { unsigned char *line; /* original reply string pointer */ unsigned char *tag; /* command tag this reply is for */ unsigned char *key; /* reply keyword */ unsigned char *text; /* subsequent text */ } IMAPPARSEDREPLY; #define IMAPTMPLEN 16*MAILTMPLEN /* IMAP4 I/O stream local data */ typedef struct imap_local { NETSTREAM *netstream; /* TCP I/O stream */ IMAPPARSEDREPLY reply; /* last parsed reply */ MAILSTATUS *stat; /* status to fill in */ IMAPCAP cap; /* server capabilities */ char *appendmailbox; /* mailbox being appended to */ unsigned int uidsearch : 1; /* UID searching */ unsigned int byeseen : 1; /* saw a BYE response */ /* got implicit capabilities */ unsigned int gotcapability : 1; unsigned int sensitive : 1; /* sensitive data in progress */ unsigned int tlsflag : 1; /* TLS session */ unsigned int tlssslv23 : 1; /* TLS using SSLv23 client method */ unsigned int notlsflag : 1; /* TLS not used in session */ unsigned int sslflag : 1; /* SSL session */ unsigned int novalidate : 1; /* certificate not validated */ unsigned int filter : 1; /* filter SEARCH/SORT/THREAD results */ unsigned int loser : 1; /* server is a loser */ unsigned int saslcancel : 1; /* SASL cancelled by protocol */ long authflags; /* required flags for authenticators */ unsigned long sortsize; /* sort return data size */ unsigned long *sortdata; /* sort return data */ struct { unsigned long uid; /* last UID returned */ unsigned long msgno; /* last msgno returned */ } lastuid; NAMESPACE **namespace; /* namespace return data */ THREADNODE *threaddata; /* thread return data */ char *referral; /* last referral */ char *prefix; /* find prefix */ char *user; /* logged-in user */ char *reform; /* reformed sequence */ char tmp[IMAPTMPLEN]; /* temporary buffer */ SEARCHSET *lookahead; /* fetch lookahead */ } IMAPLOCAL; /* Convenient access to local data */ #define LOCAL ((IMAPLOCAL *) stream->local) /* Arguments to imap_send() */ typedef struct imap_argument { int type; /* argument type */ void *text; /* argument text */ } IMAPARG; /* imap_send() argument types */ #define ATOM 0 #define NUMBER 1 #define FLAGS 2 #define ASTRING 3 #define LITERAL 4 #define LIST 5 #define SEARCHPROGRAM 6 #define SORTPROGRAM 7 #define BODYTEXT 8 #define BODYPEEK 9 #define BODYCLOSE 10 #define SEQUENCE 11 #define LISTMAILBOX 12 #define MULTIAPPEND 13 #define SNLIST 14 #define MULTIAPPENDREDO 15 /* Append data */ typedef struct append_data { append_t af; void *data; char *flags; char *date; STRING *message; } APPENDDATA; /* Function prototypes */ DRIVER *imap_valid (char *name); void *imap_parameters (long function,void *value); void imap_scan (MAILSTREAM *stream,char *ref,char *pat,char *contents); void imap_list (MAILSTREAM *stream,char *ref,char *pat); void imap_lsub (MAILSTREAM *stream,char *ref,char *pat); void imap_list_work (MAILSTREAM *stream,char *cmd,char *ref,char *pat, char *contents); long imap_subscribe (MAILSTREAM *stream,char *mailbox); long imap_unsubscribe (MAILSTREAM *stream,char *mailbox); long imap_create (MAILSTREAM *stream,char *mailbox); long imap_delete (MAILSTREAM *stream,char *mailbox); long imap_rename (MAILSTREAM *stream,char *old,char *newname); long imap_manage (MAILSTREAM *stream,char *mailbox,char *command,char *arg2); long imap_status (MAILSTREAM *stream,char *mbx,long flags); MAILSTREAM *imap_open (MAILSTREAM *stream); IMAPPARSEDREPLY *imap_rimap (MAILSTREAM *stream,char *service,NETMBX *mb, char *usr,char *tmp); long imap_anon (MAILSTREAM *stream,char *tmp); long imap_auth (MAILSTREAM *stream,NETMBX *mb,char *tmp,char *usr); long imap_login (MAILSTREAM *stream,NETMBX *mb,char *pwd,char *usr); void *imap_challenge (void *stream,unsigned long *len); long imap_response (void *stream,char *s,unsigned long size); void imap_close (MAILSTREAM *stream,long options); void imap_fast (MAILSTREAM *stream,char *sequence,long flags); void imap_flags (MAILSTREAM *stream,char *sequence,long flags); long imap_overview (MAILSTREAM *stream,overview_t ofn); ENVELOPE *imap_structure (MAILSTREAM *stream,unsigned long msgno,BODY **body, long flags); long imap_msgdata (MAILSTREAM *stream,unsigned long msgno,char *section, unsigned long first,unsigned long last,STRINGLIST *lines, long flags); unsigned long imap_uid (MAILSTREAM *stream,unsigned long msgno); unsigned long imap_msgno (MAILSTREAM *stream,unsigned long uid); void imap_flag (MAILSTREAM *stream,char *sequence,char *flag,long flags); long imap_search (MAILSTREAM *stream,char *charset,SEARCHPGM *pgm,long flags); unsigned long *imap_sort (MAILSTREAM *stream,char *charset,SEARCHPGM *spg, SORTPGM *pgm,long flags); THREADNODE *imap_thread (MAILSTREAM *stream,char *type,char *charset, SEARCHPGM *spg,long flags); THREADNODE *imap_thread_work (MAILSTREAM *stream,char *type,char *charset, SEARCHPGM *spg,long flags); long imap_ping (MAILSTREAM *stream); void imap_check (MAILSTREAM *stream); long imap_expunge (MAILSTREAM *stream,char *sequence,long options); long imap_copy (MAILSTREAM *stream,char *sequence,char *mailbox,long options); long imap_append (MAILSTREAM *stream,char *mailbox,append_t af,void *data); long imap_append_referral (char *mailbox,char *tmp,append_t af,void *data, char *flags,char *date,STRING *message, APPENDDATA *map,long options); IMAPPARSEDREPLY *imap_append_single (MAILSTREAM *stream,char *mailbox, char *flags,char *date,STRING *message); void imap_gc (MAILSTREAM *stream,long gcflags); void imap_gc_body (BODY *body); void imap_capability (MAILSTREAM *stream); long imap_acl_work (MAILSTREAM *stream,char *command,IMAPARG *args[]); IMAPPARSEDREPLY *imap_send (MAILSTREAM *stream,char *cmd,IMAPARG *args[]); IMAPPARSEDREPLY *imap_sout (MAILSTREAM *stream,char *tag,char *base,char **s); long imap_soutr (MAILSTREAM *stream,char *string); IMAPPARSEDREPLY *imap_send_astring (MAILSTREAM *stream,char *tag,char **s, SIZEDTEXT *as,long wildok,char *limit); IMAPPARSEDREPLY *imap_send_literal (MAILSTREAM *stream,char *tag,char **s, STRING *st); IMAPPARSEDREPLY *imap_send_spgm (MAILSTREAM *stream,char *tag,char *base, char **s,SEARCHPGM *pgm,char *limit); char *imap_send_spgm_trim (char *base,char *s,char *text); IMAPPARSEDREPLY *imap_send_sset (MAILSTREAM *stream,char *tag,char *base, char **s,SEARCHSET *set,char *prefix, char *limit); IMAPPARSEDREPLY *imap_send_slist (MAILSTREAM *stream,char *tag,char *base, char **s,char *name,STRINGLIST *list, char *limit); void imap_send_sdate (char **s,char *name,unsigned short date); IMAPPARSEDREPLY *imap_reply (MAILSTREAM *stream,char *tag); IMAPPARSEDREPLY *imap_parse_reply (MAILSTREAM *stream,char *text); IMAPPARSEDREPLY *imap_fake (MAILSTREAM *stream,char *tag,char *text); long imap_OK (MAILSTREAM *stream,IMAPPARSEDREPLY *reply); void imap_parse_unsolicited (MAILSTREAM *stream,IMAPPARSEDREPLY *reply); void imap_parse_response (MAILSTREAM *stream,char *text,long errflg,long ntfy); NAMESPACE *imap_parse_namespace (MAILSTREAM *stream,unsigned char **txtptr, IMAPPARSEDREPLY *reply); THREADNODE *imap_parse_thread (MAILSTREAM *stream,unsigned char **txtptr); void imap_parse_header (MAILSTREAM *stream,ENVELOPE **env,SIZEDTEXT *hdr, STRINGLIST *stl); void imap_parse_envelope (MAILSTREAM *stream,ENVELOPE **env, unsigned char **txtptr,IMAPPARSEDREPLY *reply); ADDRESS *imap_parse_adrlist (MAILSTREAM *stream,unsigned char **txtptr, IMAPPARSEDREPLY *reply); ADDRESS *imap_parse_address (MAILSTREAM *stream,unsigned char **txtptr, IMAPPARSEDREPLY *reply); void imap_parse_flags (MAILSTREAM *stream,MESSAGECACHE *elt, unsigned char **txtptr); unsigned long imap_parse_user_flag (MAILSTREAM *stream,char *flag); unsigned char *imap_parse_astring (MAILSTREAM *stream,unsigned char **txtptr, IMAPPARSEDREPLY *reply,unsigned long *len); unsigned char *imap_parse_string (MAILSTREAM *stream,unsigned char **txtptr, IMAPPARSEDREPLY *reply,GETS_DATA *md, unsigned long *len,long flags); void imap_parse_body (GETS_DATA *md,char *seg,unsigned char **txtptr, IMAPPARSEDREPLY *reply); void imap_parse_body_structure (MAILSTREAM *stream,BODY *body, unsigned char **txtptr,IMAPPARSEDREPLY *reply); PARAMETER *imap_parse_body_parameter (MAILSTREAM *stream, unsigned char **txtptr, IMAPPARSEDREPLY *reply); void imap_parse_disposition (MAILSTREAM *stream,BODY *body, unsigned char **txtptr,IMAPPARSEDREPLY *reply); STRINGLIST *imap_parse_language (MAILSTREAM *stream,unsigned char **txtptr, IMAPPARSEDREPLY *reply); STRINGLIST *imap_parse_stringlist (MAILSTREAM *stream,unsigned char **txtptr, IMAPPARSEDREPLY *reply); void imap_parse_extension (MAILSTREAM *stream,unsigned char **txtptr, IMAPPARSEDREPLY *reply); void imap_parse_capabilities (MAILSTREAM *stream,char *t); IMAPPARSEDREPLY *imap_fetch (MAILSTREAM *stream,char *sequence,long flags); char *imap_reform_sequence (MAILSTREAM *stream,char *sequence,long flags); /* Driver dispatch used by MAIL */ DRIVER imapdriver = { "imap", /* driver name */ /* driver flags */ DR_MAIL|DR_NEWS|DR_NAMESPACE|DR_CRLF|DR_RECYCLE|DR_HALFOPEN, (DRIVER *) NIL, /* next driver */ imap_valid, /* mailbox is valid for us */ imap_parameters, /* manipulate parameters */ imap_scan, /* scan mailboxes */ imap_list, /* find mailboxes */ imap_lsub, /* find subscribed mailboxes */ imap_subscribe, /* subscribe to mailbox */ imap_unsubscribe, /* unsubscribe from mailbox */ imap_create, /* create mailbox */ imap_delete, /* delete mailbox */ imap_rename, /* rename mailbox */ imap_status, /* status of mailbox */ imap_open, /* open mailbox */ imap_close, /* close mailbox */ imap_fast, /* fetch message "fast" attributes */ imap_flags, /* fetch message flags */ imap_overview, /* fetch overview */ imap_structure, /* fetch message envelopes */ NIL, /* fetch message header */ NIL, /* fetch message body */ imap_msgdata, /* fetch partial message */ imap_uid, /* unique identifier */ imap_msgno, /* message number */ imap_flag, /* modify flags */ NIL, /* per-message modify flags */ imap_search, /* search for message based on criteria */ imap_sort, /* sort messages */ imap_thread, /* thread messages */ imap_ping, /* ping mailbox to see if still alive */ imap_check, /* check for new messages */ imap_expunge, /* expunge deleted messages */ imap_copy, /* copy messages to another mailbox */ imap_append, /* append string message to mailbox */ imap_gc /* garbage collect stream */ }; /* prototype stream */ MAILSTREAM imapproto = {&imapdriver}; /* driver parameters */ static unsigned long imap_maxlogintrials = MAXLOGINTRIALS; static long imap_lookahead = IMAPLOOKAHEAD; static long imap_uidlookahead = IMAPUIDLOOKAHEAD; static long imap_fetchlookaheadlimit = IMAPLOOKAHEAD; static long imap_defaultport = 0; static long imap_sslport = 0; static long imap_tryssl = NIL; static long imap_prefetch = IMAPLOOKAHEAD; static long imap_closeonerror = NIL; static imapenvelope_t imap_envelope = NIL; static imapreferral_t imap_referral = NIL; static char *imap_extrahdrs = NIL; /* constants */ static char *hdrheader[] = { "BODY.PEEK[HEADER.FIELDS (Newsgroups Content-MD5 Content-Disposition Content-Language Content-Location", "BODY.PEEK[HEADER.FIELDS (Newsgroups Content-Disposition Content-Language Content-Location", "BODY.PEEK[HEADER.FIELDS (Newsgroups Content-Language Content-Location", "BODY.PEEK[HEADER.FIELDS (Newsgroups Content-Location", "BODY.PEEK[HEADER.FIELDS (Newsgroups" }; static char *hdrtrailer ="Followup-To References)]"; /* IMAP validate mailbox * Accepts: mailbox name * Returns: our driver if name is valid, NIL otherwise */ DRIVER *imap_valid (char *name) { return mail_valid_net (name,&imapdriver,NIL,NIL); } /* IMAP manipulate driver parameters * Accepts: function code * function-dependent value * Returns: function-dependent return value */ void *imap_parameters (long function,void *value) { switch ((int) function) { case GET_NAMESPACE: if (((IMAPLOCAL *) ((MAILSTREAM *) value)->local)->cap.namespace && !((IMAPLOCAL *) ((MAILSTREAM *) value)->local)->namespace) imap_send (((MAILSTREAM *) value),"NAMESPACE",NIL); value = (void *) &((IMAPLOCAL *) ((MAILSTREAM *) value)->local)->namespace; break; case GET_THREADERS: value = (void *) ((IMAPLOCAL *) ((MAILSTREAM *) value)->local)->cap.threader; break; case SET_FETCHLOOKAHEAD: /* must use pointer from GET_FETCHLOOKAHEAD */ fatal ("SET_FETCHLOOKAHEAD not permitted"); case GET_FETCHLOOKAHEAD: value = (void *) &((IMAPLOCAL *) ((MAILSTREAM *) value)->local)->lookahead; break; case SET_MAXLOGINTRIALS: imap_maxlogintrials = (long) value; break; case GET_MAXLOGINTRIALS: value = (void *) imap_maxlogintrials; break; case SET_LOOKAHEAD: imap_lookahead = (long) value; break; case GET_LOOKAHEAD: value = (void *) imap_lookahead; break; case SET_UIDLOOKAHEAD: imap_uidlookahead = (long) value; break; case GET_UIDLOOKAHEAD: value = (void *) imap_uidlookahead; break; case SET_IMAPPORT: imap_defaultport = (long) value; break; case GET_IMAPPORT: value = (void *) imap_defaultport; break; case SET_SSLIMAPPORT: imap_sslport = (long) value; break; case GET_SSLIMAPPORT: value = (void *) imap_sslport; break; case SET_PREFETCH: imap_prefetch = (long) value; break; case GET_PREFETCH: value = (void *) imap_prefetch; break; case SET_CLOSEONERROR: imap_closeonerror = (long) value; break; case GET_CLOSEONERROR: value = (void *) imap_closeonerror; break; case SET_IMAPENVELOPE: imap_envelope = (imapenvelope_t) value; break; case GET_IMAPENVELOPE: value = (void *) imap_envelope; break; case SET_IMAPREFERRAL: imap_referral = (imapreferral_t) value; break; case GET_IMAPREFERRAL: value = (void *) imap_referral; break; case SET_IMAPEXTRAHEADERS: imap_extrahdrs = (char *) value; break; case GET_IMAPEXTRAHEADERS: value = (void *) imap_extrahdrs; break; case SET_IMAPTRYSSL: imap_tryssl = (long) value; break; case GET_IMAPTRYSSL: value = (void *) imap_tryssl; break; case SET_FETCHLOOKAHEADLIMIT: imap_fetchlookaheadlimit = (long) value; break; case GET_FETCHLOOKAHEADLIMIT: value = (void *) imap_fetchlookaheadlimit; break; case SET_IDLETIMEOUT: fatal ("SET_IDLETIMEOUT not permitted"); case GET_IDLETIMEOUT: value = (void *) IDLETIMEOUT; break; default: value = NIL; /* error case */ break; } return value; } /* IMAP scan mailboxes * Accepts: mail stream * reference * pattern to search * string to scan */ void imap_scan (MAILSTREAM *stream,char *ref,char *pat,char *contents) { imap_list_work (stream,"SCAN",ref,pat,contents); } /* IMAP list mailboxes * Accepts: mail stream * reference * pattern to search */ void imap_list (MAILSTREAM *stream,char *ref,char *pat) { imap_list_work (stream,"LIST",ref,pat,NIL); } /* IMAP list subscribed mailboxes * Accepts: mail stream * reference * pattern to search */ void imap_lsub (MAILSTREAM *stream,char *ref,char *pat) { void *sdb = NIL; char *s,mbx[MAILTMPLEN]; /* do it on the server */ imap_list_work (stream,"LSUB",ref,pat,NIL); if (*pat == '{') { /* if remote pattern, must be IMAP */ if (!imap_valid (pat)) return; ref = NIL; /* good IMAP pattern, punt reference */ } /* if remote reference, must be valid IMAP */ if (ref && (*ref == '{') && !imap_valid (ref)) return; /* kludgy application of reference */ if (ref && *ref) sprintf (mbx,"%s%s",ref,pat); else strcpy (mbx,pat); if (s = sm_read (&sdb)) do if (imap_valid (s) && pmatch (s,mbx)) mm_lsub (stream,NIL,s,NIL); while (s = sm_read (&sdb)); /* until no more subscriptions */ } /* IMAP find list of mailboxes * Accepts: mail stream * list command * reference * pattern to search * string to scan */ void imap_list_work (MAILSTREAM *stream,char *cmd,char *ref,char *pat, char *contents) { MAILSTREAM *st = stream; int pl; char *s,prefix[MAILTMPLEN],mbx[MAILTMPLEN]; IMAPARG *args[4],aref,apat,acont; if (ref && *ref) { /* have a reference? */ if (!(imap_valid (ref) && /* make sure valid IMAP name and open stream */ ((stream && LOCAL && LOCAL->netstream) || (stream = mail_open (NIL,ref,OP_HALFOPEN|OP_SILENT))))) return; /* calculate prefix length */ pl = strchr (ref,'}') + 1 - ref; strncpy (prefix,ref,pl); /* build prefix */ prefix[pl] = '\0'; /* tie off prefix */ ref += pl; /* update reference */ } else { if (!(imap_valid (pat) && /* make sure valid IMAP name and open stream */ ((stream && LOCAL && LOCAL->netstream) || (stream = mail_open (NIL,pat,OP_HALFOPEN|OP_SILENT))))) return; /* calculate prefix length */ pl = strchr (pat,'}') + 1 - pat; strncpy (prefix,pat,pl); /* build prefix */ prefix[pl] = '\0'; /* tie off prefix */ pat += pl; /* update reference */ } LOCAL->prefix = prefix; /* note prefix */ if (contents) { /* want to do a scan? */ if (LEVELSCAN (stream)) { /* make sure permitted */ args[0] = &aref; args[1] = &apat; args[2] = &acont; args[3] = NIL; aref.type = ASTRING; aref.text = (void *) (ref ? ref : ""); apat.type = LISTMAILBOX; apat.text = (void *) pat; acont.type = ASTRING; acont.text = (void *) contents; imap_send (stream,cmd,args); } else mm_log ("Scan not valid on this IMAP server",ERROR); } else if (LEVELIMAP4 (stream)){/* easy if IMAP4 */ args[0] = &aref; args[1] = &apat; args[2] = NIL; aref.type = ASTRING; aref.text = (void *) (ref ? ref : ""); apat.type = LISTMAILBOX; apat.text = (void *) pat; /* referrals armed? */ if (LOCAL->cap.mbx_ref && mail_parameters (stream,GET_IMAPREFERRAL,NIL)) { /* yes, convert LIST -> RLIST */ if (!compare_cstring (cmd,"LIST")) cmd = "RLIST"; /* and convert LSUB -> RLSUB */ else if (!compare_cstring (cmd,"LSUB")) cmd = "RLSUB"; } imap_send (stream,cmd,args); } else if (LEVEL1176 (stream)) {/* convert to IMAP2 format wildcard */ /* kludgy application of reference */ if (ref && *ref) sprintf (mbx,"%s%s",ref,pat); else strcpy (mbx,pat); for (s = mbx; *s; s++) if (*s == '%') *s = '*'; args[0] = &apat; args[1] = NIL; apat.type = LISTMAILBOX; apat.text = (void *) mbx; if (!(strstr (cmd,"LIST") &&/* if list, try IMAP2bis, then RFC-1176 */ strcmp (imap_send (stream,"FIND ALL.MAILBOXES",args)->key,"BAD")) && !strcmp (imap_send (stream,"FIND MAILBOXES",args)->key,"BAD")) LOCAL->cap.rfc1176 = NIL; /* must be RFC-1064 */ } LOCAL->prefix = NIL; /* no more prefix */ /* close temporary stream if we made one */ if (stream != st) mail_close (stream); } /* IMAP subscribe to mailbox * Accepts: mail stream * mailbox to add to subscription list * Returns: T on success, NIL on failure */ long imap_subscribe (MAILSTREAM *stream,char *mailbox) { MAILSTREAM *st = stream; long ret = ((stream && LOCAL && LOCAL->netstream) || (stream = mail_open (NIL,mailbox,OP_HALFOPEN|OP_SILENT))) ? imap_manage (stream,mailbox,LEVELIMAP4 (stream) ? "Subscribe" : "Subscribe Mailbox",NIL) : NIL; /* toss out temporary stream */ if (st != stream) mail_close (stream); return ret; } /* IMAP unsubscribe to mailbox * Accepts: mail stream * mailbox to delete from manage list * Returns: T on success, NIL on failure */ long imap_unsubscribe (MAILSTREAM *stream,char *mailbox) { MAILSTREAM *st = stream; long ret = ((stream && LOCAL && LOCAL->netstream) || (stream = mail_open (NIL,mailbox,OP_HALFOPEN|OP_SILENT))) ? imap_manage (stream,mailbox,LEVELIMAP4 (stream) ? "Unsubscribe" : "Unsubscribe Mailbox",NIL) : NIL; /* toss out temporary stream */ if (st != stream) mail_close (stream); return ret; } /* IMAP create mailbox * Accepts: mail stream * mailbox name to create * Returns: T on success, NIL on failure */ long imap_create (MAILSTREAM *stream,char *mailbox) { return imap_manage (stream,mailbox,"Create",NIL); } /* IMAP delete mailbox * Accepts: mail stream * mailbox name to delete * Returns: T on success, NIL on failure */ long imap_delete (MAILSTREAM *stream,char *mailbox) { return imap_manage (stream,mailbox,"Delete",NIL); } /* IMAP rename mailbox * Accepts: mail stream * old mailbox name * new mailbox name * Returns: T on success, NIL on failure */ long imap_rename (MAILSTREAM *stream,char *old,char *newname) { return imap_manage (stream,old,"Rename",newname); } /* IMAP manage a mailbox * Accepts: mail stream * mailbox to manipulate * command to execute * optional second argument * Returns: T on success, NIL on failure */ long imap_manage (MAILSTREAM *stream,char *mailbox,char *command,char *arg2) { MAILSTREAM *st = stream; IMAPPARSEDREPLY *reply; long ret = NIL; char mbx[MAILTMPLEN],mbx2[MAILTMPLEN]; IMAPARG *args[3],ambx,amb2; imapreferral_t ir = (imapreferral_t) mail_parameters (stream,GET_IMAPREFERRAL,NIL); ambx.type = amb2.type = ASTRING; ambx.text = (void *) mbx; amb2.text = (void *) mbx2; args[0] = &ambx; args[1] = args[2] = NIL; /* require valid names and open stream */ if (mail_valid_net (mailbox,&imapdriver,NIL,mbx) && (arg2 ? mail_valid_net (arg2,&imapdriver,NIL,mbx2) : &imapdriver) && ((stream && LOCAL && LOCAL->netstream) || (stream = mail_open (NIL,mailbox,OP_HALFOPEN|OP_SILENT)))) { if (arg2) args[1] = &amb2; /* second arg present? */ if (!(ret = (imap_OK (stream,reply = imap_send (stream,command,args)))) && ir && LOCAL->referral) { long code = -1; switch (*command) { /* which command was it? */ case 'S': code = REFSUBSCRIBE; break; case 'U': code = REFUNSUBSCRIBE; break; case 'C': code = REFCREATE; break; case 'D': code = REFDELETE; break; case 'R': code = REFRENAME; break; default: fatal ("impossible referral command"); } if ((code >= 0) && (mailbox = (*ir) (stream,LOCAL->referral,code))) ret = imap_manage (NIL,mailbox,command,(*command == 'R') ? (mailbox + strlen (mailbox) + 1) : NIL); } mm_log (reply->text,ret ? NIL : ERROR); /* toss out temporary stream */ if (st != stream) mail_close (stream); } return ret; } /* IMAP status * Accepts: mail stream * mailbox name * status flags * Returns: T on success, NIL on failure */ long imap_status (MAILSTREAM *stream,char *mbx,long flags) { IMAPARG *args[3],ambx,aflg; char tmp[MAILTMPLEN]; NETMBX mb; unsigned long i; long ret = NIL; MAILSTREAM *tstream = NIL; /* use given stream if (rev1 or halfopen) and right host */ if (!((stream && (LEVELIMAP4rev1 (stream) || stream->halfopen) && mail_usable_network_stream (stream,mbx)) || (stream = tstream = mail_open (NIL,mbx,OP_HALFOPEN|OP_SILENT)))) return NIL; /* parse mailbox name */ mail_valid_net_parse (mbx,&mb); args[0] = &ambx;args[1] = NIL;/* set up first argument as mailbox */ ambx.type = ASTRING; ambx.text = (void *) mb.mailbox; if (LEVELIMAP4rev1 (stream)) {/* have STATUS command? */ imapreferral_t ir; aflg.type = FLAGS; aflg.text = (void *) tmp; args[1] = &aflg; args[2] = NIL; tmp[0] = tmp[1] = '\0'; /* build flag list */ if (flags & SA_MESSAGES) strcat (tmp," MESSAGES"); if (flags & SA_RECENT) strcat (tmp," RECENT"); if (flags & SA_UNSEEN) strcat (tmp," UNSEEN"); if (flags & SA_UIDNEXT) strcat (tmp," UIDNEXT"); if (flags & SA_UIDVALIDITY) strcat (tmp," UIDVALIDITY"); tmp[0] = '('; strcat (tmp,")"); /* send "STATUS mailbox flag" */ if (imap_OK (stream,imap_send (stream,"STATUS",args))) ret = T; else if ((ir = (imapreferral_t) mail_parameters (stream,GET_IMAPREFERRAL,NIL)) && LOCAL->referral && (mbx = (*ir) (stream,LOCAL->referral,REFSTATUS))) ret = imap_status (NIL,mbx,flags | (stream->debug ? SA_DEBUG : NIL)); } /* IMAP2 way */ else if (imap_OK (stream,imap_send (stream,"EXAMINE",args))) { MAILSTATUS status; status.flags = flags & ~ (SA_UIDNEXT | SA_UIDVALIDITY); status.messages = stream->nmsgs; status.recent = stream->recent; status.unseen = 0; if (flags & SA_UNSEEN) { /* must search to get unseen messages */ /* clear search vector */ for (i = 1; i <= stream->nmsgs; ++i) mail_elt (stream,i)->searched = NIL; if (imap_OK (stream,imap_send (stream,"SEARCH UNSEEN",NIL))) for (i = 1,status.unseen = 0; i <= stream->nmsgs; i++) if (mail_elt (stream,i)->searched) status.unseen++; } strcpy (strchr (strcpy (tmp,stream->mailbox),'}') + 1,mb.mailbox); /* pass status to main program */ mm_status (stream,tmp,&status); ret = T; /* note success */ } if (tstream) mail_close (tstream); return ret; /* success */ } /* IMAP open * Accepts: stream to open * Returns: stream to use on success, NIL on failure */ MAILSTREAM *imap_open (MAILSTREAM *stream) { unsigned long i,j; char *s,tmp[MAILTMPLEN],usr[MAILTMPLEN]; NETMBX mb; IMAPPARSEDREPLY *reply = NIL; imapreferral_t ir = (imapreferral_t) mail_parameters (stream,GET_IMAPREFERRAL,NIL); /* return prototype for OP_PROTOTYPE call */ if (!stream) return &imapproto; mail_valid_net_parse (stream->mailbox,&mb); usr[0] = '\0'; /* initially no user name */ if (LOCAL) { /* if stream opened earlier by us */ /* recycle if still alive */ if (LOCAL->netstream && (!stream->halfopen || LOCAL->cap.unselect)) { i = stream->silent; /* temporarily mark silent */ stream->silent = T; /* don't give mm_exists() events */ j = imap_ping (stream); /* learn if stream still alive */ stream->silent = i; /* restore prior state */ if (j) { /* was stream still alive? */ sprintf (tmp,"Reusing connection to %s",net_host (LOCAL->netstream)); if (LOCAL->user) sprintf (tmp + strlen (tmp),"/user=\"%s\"", LOCAL->user); if (!stream->silent) mm_log (tmp,(long) NIL); /* unselect if now want halfopen */ if (stream->halfopen) imap_send (stream,"UNSELECT",NIL); } else imap_close (stream,NIL); } else imap_close (stream,NIL); } /* copy flags from name */ if (mb.dbgflag) stream->debug = T; if (mb.readonlyflag) stream->rdonly = T; if (mb.anoflag) stream->anonymous = T; if (mb.secflag) stream->secure = T; if (mb.trysslflag || imap_tryssl) stream->tryssl = T; if (!LOCAL) { /* open new connection if no recycle */ NETDRIVER *ssld = (NETDRIVER *) mail_parameters (NIL,GET_SSLDRIVER,NIL); unsigned long defprt = imap_defaultport ? imap_defaultport : IMAPTCPPORT; unsigned long sslport = imap_sslport ? imap_sslport : IMAPSSLPORT; stream->local = /* instantiate localdata */ (void *) memset (fs_get (sizeof (IMAPLOCAL)),0,sizeof (IMAPLOCAL)); /* assume IMAP2bis server */ LOCAL->cap.imap2bis = LOCAL->cap.rfc1176 = T; /* in case server is a loser */ if (mb.loser) LOCAL->loser = T; /* desirable authenticators */ LOCAL->authflags = (stream->secure ? AU_SECURE : NIL) | (mb.authuser[0] ? AU_AUTHUSER : NIL); /* IMAP connection open logic is more complex than net_open() normally * deals with, because of the simap and rimap hacks. * If the session is anonymous, a specific port is given, or if /ssl or * /tls is set, do net_open() since those conditions override everything * else. */ if (stream->anonymous || mb.port || mb.sslflag || mb.tlsflag) reply = (LOCAL->netstream = net_open (&mb,NIL,defprt,ssld,"*imaps", sslport)) ? imap_reply (stream,NIL) : NIL; /* * No overriding conditions, so get the best connection that we can. In * order, attempt to open via simap, tryssl, rimap, and finally TCP. */ /* try simap */ else if (reply = imap_rimap (stream,"*imap",&mb,usr,tmp)); else if (ssld && /* try tryssl if enabled */ (stream->tryssl || mail_parameters (NIL,GET_TRYSSLFIRST,NIL)) && (LOCAL->netstream = net_open_work (ssld,mb.host,"*imaps",sslport,mb.port, (mb.novalidate ? NET_NOVALIDATECERT : 0) | NET_SILENT | NET_TRYSSL))) { if (net_sout (LOCAL->netstream,"",0)) { mb.sslflag = T; reply = imap_reply (stream,NIL); } else { /* flush fake SSL stream */ net_close (LOCAL->netstream); LOCAL->netstream = NIL; } } /* try rimap first, then TCP */ else if (!(reply = imap_rimap (stream,"imap",&mb,usr,tmp)) && (LOCAL->netstream = net_open (&mb,NIL,defprt,NIL,NIL,NIL))) reply = imap_reply (stream,NIL); /* make sure greeting is good */ if (!reply || strcmp (reply->tag,"*") || (strcmp (reply->key,"OK") && strcmp (reply->key,"PREAUTH"))) { if (reply) mm_log (reply->text,ERROR); return NIL; /* lost during greeting */ } /* if connected and not preauthenticated */ if (LOCAL->netstream && strcmp (reply->key,"PREAUTH")) { sslstart_t stls = (sslstart_t) mail_parameters (NIL,GET_SSLSTART,NIL); /* get server capabilities */ if (!LOCAL->gotcapability) imap_capability (stream); if (LOCAL->netstream && /* does server support STARTTLS? */ stls && LOCAL->cap.starttls && !mb.sslflag && !mb.notlsflag && imap_OK (stream,imap_send (stream,"STARTTLS",NIL))) { mb.tlsflag = T; /* TLS OK, get into TLS at this end */ LOCAL->netstream->dtb = ssld; if (!(LOCAL->netstream->stream = (*stls) (LOCAL->netstream->stream,mb.host, (mb.tlssslv23 ? NIL : NET_TLSCLIENT) | (mb.novalidate ? NET_NOVALIDATECERT : NIL)))) { /* drat, drop this connection */ if (LOCAL->netstream) net_close (LOCAL->netstream); LOCAL->netstream = NIL; } /* get capabilities now that TLS in effect */ if (LOCAL->netstream) imap_capability (stream); } else if (mb.tlsflag) { /* user specified /tls but can't do it */ mm_log ("Unable to negotiate TLS with this server",ERROR); return NIL; } if (LOCAL->netstream) { /* still in the land of the living? */ if ((long) mail_parameters (NIL,GET_TRUSTDNS,NIL)) { /* remote name for authentication */ strncpy (mb.host,(long) mail_parameters(NIL,GET_SASLUSESPTRNAME,NIL)? net_remotehost (LOCAL->netstream) : net_host (LOCAL->netstream),NETMAXHOST-1); mb.host[NETMAXHOST-1] = '\0'; } /* need new capabilities after login */ LOCAL->gotcapability = NIL; if (!(stream->anonymous ? imap_anon (stream,tmp) : (LOCAL->cap.auth ? imap_auth (stream,&mb,tmp,usr) : imap_login (stream,&mb,tmp,usr)))) { /* failed, is there a referral? */ if (ir && LOCAL->referral && (s = (*ir) (stream,LOCAL->referral,REFAUTHFAILED))) { imap_close (stream,NIL); fs_give ((void **) &stream->mailbox); /* set as new mailbox name to open */ stream->mailbox = s; return imap_open (stream); } return NIL; /* authentication failed */ } else if (ir && LOCAL->referral && (s = (*ir) (stream,LOCAL->referral,REFAUTH))) { imap_close (stream,NIL); fs_give ((void **) &stream->mailbox); stream->mailbox = s; /* set as new mailbox name to open */ /* recurse to log in on real site */ return imap_open (stream); } } } /* get server capabilities again */ if (LOCAL->netstream && !LOCAL->gotcapability) imap_capability (stream); /* save state for future recycling */ if (mb.tlsflag) LOCAL->tlsflag = T; if (mb.tlssslv23) LOCAL->tlssslv23 = T; if (mb.notlsflag) LOCAL->notlsflag = T; if (mb.sslflag) LOCAL->sslflag = T; if (mb.novalidate) LOCAL->novalidate = T; if (mb.loser) LOCAL->loser = T; } if (LOCAL->netstream) { /* still have a connection? */ stream->perm_seen = stream->perm_deleted = stream->perm_answered = stream->perm_draft = LEVELIMAP4 (stream) ? NIL : T; stream->perm_user_flags = LEVELIMAP4 (stream) ? NIL : 0xffffffff; stream->sequence++; /* bump sequence number */ sprintf (tmp,"{%s",(long) mail_parameters (NIL,GET_TRUSTDNS,NIL) ? net_host (LOCAL->netstream) : mb.host); if (!((i = net_port (LOCAL->netstream)) & 0xffff0000)) sprintf (tmp + strlen (tmp),":%lu",i); strcat (tmp,"/imap"); if (LOCAL->tlsflag) strcat (tmp,"/tls"); if (LOCAL->tlssslv23) strcat (tmp,"/tls-sslv23"); if (LOCAL->notlsflag) strcat (tmp,"/notls"); if (LOCAL->sslflag) strcat (tmp,"/ssl"); if (LOCAL->novalidate) strcat (tmp,"/novalidate-cert"); if (LOCAL->loser) strcat (tmp,"/loser"); if (stream->secure) strcat (tmp,"/secure"); if (stream->rdonly) strcat (tmp,"/readonly"); if (stream->anonymous) strcat (tmp,"/anonymous"); else { /* record user name */ if (!LOCAL->user && usr[0]) LOCAL->user = cpystr (usr); if (LOCAL->user) sprintf (tmp + strlen (tmp),"/user=\"%s\"", LOCAL->user); } strcat (tmp,"}"); if (!stream->halfopen) { /* wants to open a mailbox? */ IMAPARG *args[2]; IMAPARG ambx; ambx.type = ASTRING; ambx.text = (void *) mb.mailbox; args[0] = &ambx; args[1] = NIL; stream->nmsgs = 0; if (imap_OK (stream,reply = imap_send (stream,stream->rdonly ? "EXAMINE": "SELECT",args))) { strcat (tmp,mb.mailbox);/* mailbox name */ if (!stream->nmsgs && !stream->silent) mm_log ("Mailbox is empty",(long) NIL); /* note if an INBOX or not */ stream->inbox = !compare_cstring (mb.mailbox,"INBOX"); } else if (ir && LOCAL->referral && (s = (*ir) (stream,LOCAL->referral,REFSELECT))) { imap_close (stream,NIL); fs_give ((void **) &stream->mailbox); stream->mailbox = s; /* set as new mailbox name to open */ return imap_open (stream); } else { mm_log (reply->text,ERROR); if (imap_closeonerror) return NIL; stream->halfopen = T; /* let him keep it half-open */ } } if (stream->halfopen) { /* half-open connection? */ strcat (tmp,""); /* make sure dummy message counts */ mail_exists (stream,(long) 0); mail_recent (stream,(long) 0); } fs_give ((void **) &stream->mailbox); stream->mailbox = cpystr (tmp); } /* success if stream open */ return LOCAL->netstream ? stream : NIL; } /* IMAP rimap connect * Accepts: MAIL stream * NETMBX specification * service to use * user name * scratch buffer * Returns: parsed reply if success, else NIL */ IMAPPARSEDREPLY *imap_rimap (MAILSTREAM *stream,char *service,NETMBX *mb, char *usr,char *tmp) { unsigned long i; char c[2]; NETSTREAM *tstream; IMAPPARSEDREPLY *reply = NIL; /* try rimap open */ if (!mb->norsh && (tstream = net_aopen (NIL,mb,service,usr))) { /* if success, see if reasonable banner */ if (net_getbuffer (tstream,(long) 1,c) && (*c == '*')) { i = 0; /* copy to buffer */ do tmp[i++] = *c; while (net_getbuffer (tstream,(long) 1,c) && (*c != '\015') && (*c != '\012') && (i < (MAILTMPLEN-1))); tmp[i] = '\0'; /* tie off */ /* snarfed a valid greeting? */ if ((*c == '\015') && net_getbuffer (tstream,(long) 1,c) && (*c == '\012') && !strcmp ((reply = imap_parse_reply (stream,cpystr (tmp)))->tag,"*")){ /* parse line as IMAP */ imap_parse_unsolicited (stream,reply); /* make sure greeting is good */ if (!strcmp (reply->key,"OK") || !strcmp (reply->key,"PREAUTH")) { LOCAL->netstream = tstream; return reply; /* return success */ } } } net_close (tstream); /* failed, punt the temporary netstream */ } return NIL; } /* IMAP log in as anonymous * Accepts: stream to authenticate * scratch buffer * Returns: T on success, NIL on failure */ long imap_anon (MAILSTREAM *stream,char *tmp) { IMAPPARSEDREPLY *reply; char *s = net_localhost (LOCAL->netstream); if (LOCAL->cap.authanon) { char tag[16]; unsigned long i; char *broken = "[CLOSED] IMAP connection broken (anonymous auth)"; sprintf (tag,"%08lx",0xffffffff & (stream->gensym++)); /* build command */ sprintf (tmp,"%s AUTHENTICATE ANONYMOUS",tag); if (!imap_soutr (stream,tmp)) { mm_log (broken,ERROR); return NIL; } if (imap_challenge (stream,&i)) imap_response (stream,s,strlen (s)); /* get response */ if (!(reply = &LOCAL->reply)->tag) reply = imap_fake (stream,tag,broken); /* what we wanted? */ if (compare_cstring (reply->tag,tag)) { /* abort if don't have tagged response */ while (compare_cstring ((reply = imap_reply (stream,tag))->tag,tag)) imap_soutr (stream,"*"); } } else { IMAPARG *args[2]; IMAPARG ausr; ausr.type = ASTRING; ausr.text = (void *) s; args[0] = &ausr; args[1] = NIL; /* send "LOGIN anonymous " */ reply = imap_send (stream,"LOGIN ANONYMOUS",args); } /* success if reply OK */ if (imap_OK (stream,reply)) return T; mm_log (reply->text,ERROR); return NIL; } /* IMAP authenticate * Accepts: stream to authenticate * parsed network mailbox structure * scratch buffer * place to return user name * Returns: T on success, NIL on failure */ long imap_auth (MAILSTREAM *stream,NETMBX *mb,char *tmp,char *usr) { unsigned long trial,ua; int ok; char tag[16]; char *lsterr = NIL; AUTHENTICATOR *at; IMAPPARSEDREPLY *reply; for (ua = LOCAL->cap.auth, LOCAL->saslcancel = NIL; LOCAL->netstream && ua && (at = mail_lookup_auth (find_rightmost_bit (&ua) + 1));) { if (lsterr) { /* previous authenticator failed? */ sprintf (tmp,"Retrying using %s authentication after %.80s", at->name,lsterr); mm_log (tmp,NIL); fs_give ((void **) &lsterr); } trial = 0; /* initial trial count */ tmp[0] = '\0'; /* no error */ do { /* gensym a new tag */ if (lsterr) { /* previous attempt with this one failed? */ sprintf (tmp,"Retrying %s authentication after %.80s",at->name,lsterr); mm_log (tmp,WARN); fs_give ((void **) &lsterr); } LOCAL->saslcancel = NIL; sprintf (tag,"%08lx",0xffffffff & (stream->gensym++)); /* build command */ sprintf (tmp,"%s AUTHENTICATE %s",tag,at->name); if (imap_soutr (stream,tmp)) { /* hide client authentication responses */ if (!(at->flags & AU_SECURE)) LOCAL->sensitive = T; ok = (*at->client) (imap_challenge,imap_response,"imap",mb,stream, &trial,usr); LOCAL->sensitive = NIL; /* unhide */ /* make sure have a response */ if (!(reply = &LOCAL->reply)->tag) reply = imap_fake (stream,tag, "[CLOSED] IMAP connection broken (authenticate)"); else if (compare_cstring (reply->tag,tag)) while (compare_cstring ((reply = imap_reply (stream,tag))->tag,tag)) imap_soutr (stream,"*"); /* good if SASL ok and success response */ if (ok && imap_OK (stream,reply)) return T; if (!trial) { /* if main program requested cancellation */ mm_log ("IMAP Authentication cancelled",ERROR); return NIL; } /* no error if protocol-initiated cancel */ lsterr = cpystr (reply->text); } } while (LOCAL->netstream && !LOCAL->byeseen && trial && (trial < imap_maxlogintrials)); } if (lsterr) { /* previous authenticator failed? */ if (!LOCAL->saslcancel) { /* don't do this if a cancel */ sprintf (tmp,"Can not authenticate to IMAP server: %.80s",lsterr); mm_log (tmp,ERROR); } fs_give ((void **) &lsterr); } return NIL; /* ran out of authenticators */ } /* IMAP login * Accepts: stream to login * parsed network mailbox structure * scratch buffer of length MAILTMPLEN * place to return user name * Returns: T on success, NIL on failure */ long imap_login (MAILSTREAM *stream,NETMBX *mb,char *pwd,char *usr) { unsigned long trial = 0; IMAPPARSEDREPLY *reply; IMAPARG *args[3]; IMAPARG ausr,apwd; long ret = NIL; if (stream->secure) /* never do LOGIN if want security */ mm_log ("Can't do secure authentication with this server",ERROR); /* never do LOGIN if server disabled it */ else if (LOCAL->cap.logindisabled) mm_log ("Server disables LOGIN, no recognized SASL authenticator",ERROR); else if (mb->authuser[0]) /* never do LOGIN with /authuser */ mm_log ("Can't do /authuser with this server",ERROR); else { /* OK to try login */ ausr.type = apwd.type = ASTRING; ausr.text = (void *) usr; apwd.text = (void *) pwd; args[0] = &ausr; args[1] = &apwd; args[2] = NIL; do { pwd[0] = 0; /* prompt user for password */ mm_login (mb,usr,pwd,trial++); if (pwd[0]) { /* send login command if have password */ LOCAL->sensitive = T; /* hide this command */ /* send "LOGIN usr pwd" */ if (imap_OK (stream,reply = imap_send (stream,"LOGIN",args))) ret = LONGT; /* success */ else { mm_log (reply->text,WARN); if (!LOCAL->referral && (trial == imap_maxlogintrials)) mm_log ("Too many login failures",ERROR); } LOCAL->sensitive = NIL; /* unhide */ } /* user refused to give password */ else mm_log ("Login aborted",ERROR); } while (!ret && pwd[0] && (trial < imap_maxlogintrials) && LOCAL->netstream && !LOCAL->byeseen && !LOCAL->referral); } memset (pwd,0,MAILTMPLEN); /* erase password */ return ret; } /* Get challenge to authenticator in binary * Accepts: stream * pointer to returned size * Returns: challenge or NIL if not challenge */ void *imap_challenge (void *s,unsigned long *len) { char tmp[MAILTMPLEN]; void *ret = NIL; MAILSTREAM *stream = (MAILSTREAM *) s; IMAPPARSEDREPLY *reply = NIL; /* get tagged response or challenge */ while (stream && LOCAL->netstream && (reply = imap_parse_reply (stream,net_getline (LOCAL->netstream))) && !strcmp (reply->tag,"*")) imap_parse_unsolicited (stream,reply); /* parse challenge if have one */ if (stream && LOCAL->netstream && reply && reply->tag && (*reply->tag == '+') && !reply->tag[1] && reply->text && !(ret = rfc822_base64 ((unsigned char *) reply->text, strlen (reply->text),len))) { sprintf (tmp,"IMAP SERVER BUG (invalid challenge): %.80s", (char *) reply->text); mm_log (tmp,ERROR); } return ret; } /* Send authenticator response in BASE64 * Accepts: MAIL stream * string to send * length of string * Returns: T if successful, else NIL */ long imap_response (void *s,char *response,unsigned long size) { MAILSTREAM *stream = (MAILSTREAM *) s; unsigned long i,j,ret; char *t,*u; if (response) { /* make CRLFless BASE64 string */ if (size) { for (t = (char *) rfc822_binary ((void *) response,size,&i),u = t,j = 0; j < i; j++) if (t[j] > ' ') *u++ = t[j]; *u = '\0'; /* tie off string for mm_dlog() */ if (stream->debug) mail_dlog (t,LOCAL->sensitive); /* append CRLF */ *u++ = '\015'; *u++ = '\012'; ret = net_sout (LOCAL->netstream,t,u - t); fs_give ((void **) &t); } else ret = imap_soutr (stream,""); } else { /* abort requested */ ret = imap_soutr (stream,"*"); LOCAL->saslcancel = T; /* mark protocol-requested SASL cancel */ } return ret; } /* IMAP close * Accepts: MAIL stream * option flags */ void imap_close (MAILSTREAM *stream,long options) { THREADER *thr,*t; IMAPPARSEDREPLY *reply; if (stream && LOCAL) { /* send "LOGOUT" */ if (!LOCAL->byeseen) { /* don't even think of doing it if saw a BYE */ /* expunge silently if requested */ if (options & CL_EXPUNGE) imap_send (stream,LEVELIMAP4 (stream) ? "CLOSE" : "EXPUNGE",NIL); if (LOCAL->netstream && !imap_OK (stream,reply = imap_send (stream,"LOGOUT",NIL))) mm_log (reply->text,WARN); } /* close NET connection if still open */ if (LOCAL->netstream) net_close (LOCAL->netstream); LOCAL->netstream = NIL; /* free up memory */ if (LOCAL->sortdata) fs_give ((void **) &LOCAL->sortdata); if (LOCAL->namespace) { mail_free_namespace (&LOCAL->namespace[0]); mail_free_namespace (&LOCAL->namespace[1]); mail_free_namespace (&LOCAL->namespace[2]); fs_give ((void **) &LOCAL->namespace); } if (LOCAL->threaddata) mail_free_threadnode (&LOCAL->threaddata); /* flush threaders */ if (thr = LOCAL->cap.threader) while (t = thr) { fs_give ((void **) &t->name); thr = t->next; fs_give ((void **) &t); } if (LOCAL->referral) fs_give ((void **) &LOCAL->referral); if (LOCAL->user) fs_give ((void **) &LOCAL->user); if (LOCAL->reply.line) fs_give ((void **) &LOCAL->reply.line); if (LOCAL->reform) fs_give ((void **) &LOCAL->reform); /* nuke the local data */ fs_give ((void **) &stream->local); } } /* IMAP fetch fast information * Accepts: MAIL stream * sequence * option flags * * Generally, imap_structure is preferred */ void imap_fast (MAILSTREAM *stream,char *sequence,long flags) { IMAPPARSEDREPLY *reply = imap_fetch (stream,sequence,flags & FT_UID); if (!imap_OK (stream,reply)) mm_log (reply->text,ERROR); } /* IMAP fetch flags * Accepts: MAIL stream * sequence * option flags */ void imap_flags (MAILSTREAM *stream,char *sequence,long flags) { /* send "FETCH sequence FLAGS" */ char *cmd = (LEVELIMAP4 (stream) && (flags & FT_UID)) ? "UID FETCH":"FETCH"; IMAPPARSEDREPLY *reply; IMAPARG *args[3],aseq,aatt; if (LOCAL->loser) sequence = imap_reform_sequence (stream,sequence, flags & FT_UID); aseq.type = SEQUENCE; aseq.text = (void *) sequence; aatt.type = ATOM; aatt.text = (void *) "FLAGS"; args[0] = &aseq; args[1] = &aatt; args[2] = NIL; if (!imap_OK (stream,reply = imap_send (stream,cmd,args))) mm_log (reply->text,ERROR); } /* IMAP fetch overview * Accepts: MAIL stream, sequence bits set * pointer to overview return function * Returns: T if successful, NIL otherwise */ long imap_overview (MAILSTREAM *stream,overview_t ofn) { MESSAGECACHE *elt; ENVELOPE *env; OVERVIEW ov; char *s,*t; unsigned long i,start,last,len,slen; if (!LOCAL->netstream) return NIL; /* build overview sequence */ for (i = 1,len = start = last = 0,s = t = NIL; i <= stream->nmsgs; ++i) if ((elt = mail_elt (stream,i))->sequence) { if (!elt->private.msg.env) { if (s) { /* continuing a sequence */ if (i == last + 1) last = i; else { /* end of range */ if (last != start) sprintf (t,":%lu,%lu",last,i); else sprintf (t,",%lu",i); if ((len - (slen = (t += strlen (t)) - s)) < 20) { fs_resize ((void **) &s,len += MAILTMPLEN); t = s + slen; /* relocate current pointer */ } start = last = i; /* begin a new range */ } } else { /* first time, start new buffer */ s = (char *) fs_get (len = MAILTMPLEN); sprintf (s,"%lu",start = last = i); t = s + strlen (s); /* end of buffer */ } } } /* last sequence */ if (last != start) sprintf (t,":%lu",last); if (s) { /* prefetch as needed */ imap_fetch (stream,s,FT_NEEDENV); fs_give ((void **) &s); } ov.optional.lines = 0; /* now overview each message */ ov.optional.xref = NIL; if (ofn) for (i = 1; i <= stream->nmsgs; i++) if (((elt = mail_elt (stream,i))->sequence) && (env = mail_fetch_structure (stream,i,NIL,NIL)) && ofn) { ov.subject = env->subject; ov.from = env->from; ov.date = env->date; ov.message_id = env->message_id; ov.references = env->references; ov.optional.octets = elt->rfc822_size; (*ofn) (stream,mail_uid (stream,i),&ov,i); } return LONGT; } /* IMAP fetch structure * Accepts: MAIL stream * message # to fetch * pointer to return body * option flags * Returns: envelope of this message, body returned in body value * * Fetches the "fast" information as well */ ENVELOPE *imap_structure (MAILSTREAM *stream,unsigned long msgno,BODY **body, long flags) { unsigned long i,j,k,x; char *s,seq[MAILTMPLEN],tmp[MAILTMPLEN]; MESSAGECACHE *elt; ENVELOPE **env; BODY **b; IMAPPARSEDREPLY *reply = NIL; IMAPARG *args[3],aseq,aatt; SEARCHSET *set = LOCAL->lookahead; LOCAL->lookahead = NIL; args[0] = &aseq; args[1] = &aatt; args[2] = NIL; aseq.type = SEQUENCE; aseq.text = (void *) seq; aatt.type = ATOM; aatt.text = NIL; if (flags & FT_UID) /* see if can find msgno from UID */ for (i = 1; i <= stream->nmsgs; i++) if ((elt = mail_elt (stream,i))->private.uid == msgno) { msgno = i; /* found msgno, use it from now on */ flags &= ~FT_UID; /* no longer a UID fetch */ } sprintf (s = seq,"%lu",msgno);/* initial sequence */ if (LEVELIMAP4 (stream) && (flags & FT_UID)) { /* UID fetching is requested and we can't map the UID to a message sequence * number. Assume that the message isn't cached at all. */ if (!imap_OK (stream,reply = imap_fetch (stream,seq,FT_NEEDENV + (body ? FT_NEEDBODY : NIL) + (flags & (FT_UID + FT_NOHDRS))))) mm_log (reply->text,ERROR); /* now hunt for this UID */ for (i = 1; i <= stream->nmsgs; i++) if ((elt = mail_elt (stream,i))->private.uid == msgno) { if (body) *body = elt->private.msg.body; return elt->private.msg.env; } if (body) *body = NIL; /* can't find the UID */ return NIL; } elt = mail_elt (stream,msgno);/* get cache pointer */ if (stream->scache) { /* short caching? */ env = &stream->env; /* use temporaries on the stream */ b = &stream->body; if (msgno != stream->msgno){/* flush old poop if a different message */ mail_free_envelope (env); mail_free_body (b); stream->msgno = msgno; /* this is now the current short cache msg */ } } else { /* normal cache */ env = &elt->private.msg.env;/* get envelope and body pointers */ b = &elt->private.msg.body; /* prefetch if don't have envelope */ if (!(flags & FT_NOLOOKAHEAD) && ((!*env || (*env)->incomplete) || (body && !*b && LEVELIMAP2bis (stream)))) { if (set) { /* have a lookahead list? */ MESSAGE *msg; for (k = imap_fetchlookaheadlimit; k && set && (((s += strlen (s)) - seq) < (MAXCOMMAND - 30)); set = set->next) { i = (set->first == 0xffffffff) ? stream->nmsgs : min (set->first,stream->nmsgs); if (j = (set->last == 0xffffffff) ? stream->nmsgs : min (set->last,stream->nmsgs)) { if (i > j) { /* swap the range if backwards */ x = i; i = j; j = x; } /* find first message not msgno or in cache */ while (((i == msgno) || ((msg = &(mail_elt (stream,i)->private.msg))->env && (!body || msg->body))) && (i++ < j)); /* until range or lookahead finished */ while (k && (i <= j)) { /* find first cached message in range */ for (x = i + 1; (x <= j) && !((msg = &(mail_elt (stream,x)->private.msg))->env && (!body || msg->body)); x++); if (i == --x) { /* only one message? */ sprintf (s += strlen (s),",%lu",i++); k--; /* prefetching one message */ } else { /* a range to prefetch */ sprintf (s += strlen (s),",%lu:%lu",i,x); i = 1 + x - i; /* number of messages in this range */ /* still can look ahead some more? */ if (k = (k > i) ? k - i : 0) /* yes, scan further in this range */ for (i = x + 2; (i <= j) && ((i == msgno) || ((msg = &(mail_elt (stream,i)->private.msg))->env && (!body || msg->body))); i++); } } } else if ((i != msgno) && !mail_elt (stream,i)->private.msg.env) { sprintf (s += strlen (s),",%lu",i); k--; /* prefetching one message */ } } } /* build message number list */ else for (i = msgno+1,k = imap_lookahead; k && (i <= stream->nmsgs); i++) if (!mail_elt (stream,i)->private.msg.env) { s += strlen (s); /* find string end, see if nearing end */ if ((s - seq) > (MAILTMPLEN - 20)) break; sprintf (s,",%lu",i); /* append message */ for (j = i + 1, k--; /* hunt for last message without an envelope */ k && (j <= stream->nmsgs) && !mail_elt (stream,j)->private.msg.env; j++, k--); /* if different, make a range */ if (i != --j) sprintf (s + strlen (s),":%lu",i = j); } } } if (!stream->lock) { /* no-op if stream locked */ /* Build the fetch attributes. Unlike imap_fetch(), this tries not to * fetch data that is already cached. However, since it is based on the * message requested and not on any of the prefetched messages, it can * goof, either by fetching data already cached or not prefetching data * that isn't cached (but was cached in the message requested). * Fortunately, no great harm is done. If it doesn't prefetch the data, * it will get it when the affected message(s) are requested. */ if (!elt->private.uid && LEVELIMAP4 (stream)) strcpy (tmp," UID"); else tmp[0] = '\0'; /* initialize command */ /* need envelope? */ if (!*env || (*env)->incomplete) { strcat (tmp," ENVELOPE"); /* yes, get it and possible extra poop */ if (!(flags & FT_NOHDRS) && LEVELIMAP4rev1 (stream)) { if (imap_extrahdrs) sprintf (tmp + strlen (tmp)," %s %s %s", hdrheader[LOCAL->cap.extlevel], imap_extrahdrs,hdrtrailer); else sprintf (tmp + strlen (tmp)," %s %s", hdrheader[LOCAL->cap.extlevel],hdrtrailer); } } /* need body? */ if (body && !*b && LEVELIMAP2bis (stream)) strcat (tmp,LEVELIMAP4 (stream) ? " BODYSTRUCTURE" : " BODY"); if (!elt->day) strcat (tmp," INTERNALDATE"); if (!elt->rfc822_size) strcat (tmp," RFC822.SIZE"); if (tmp[0]) { /* anything to do? */ tmp[0] = '('; /* make into a list */ strcat (tmp," FLAGS)"); /* always get current flags */ aatt.text = (void *) tmp; /* do the built command */ if (!imap_OK (stream,reply = imap_send (stream,"FETCH",args))) { /* failed, probably RFC-1176 server */ if (!LEVELIMAP4 (stream) && LEVELIMAP2bis (stream) && body && !*b){ aatt.text = (void *) "ALL"; if (imap_OK (stream,reply = imap_send (stream,"FETCH",args))) /* doesn't have body capabilities */ LOCAL->cap.imap2bis = NIL; else mm_log (reply->text,ERROR); } else mm_log (reply->text,ERROR); } } } if (body) { /* wants to return body */ if (!*b && !LEVELIMAP2bis (stream)) { /* simulate body structure fetch for IMAP2 */ *b = mail_initbody (mail_newbody ()); (*b)->subtype = cpystr (rfc822_default_subtype ((*b)->type)); ((*b)->parameter = mail_newbody_parameter ())->attribute = cpystr ("CHARSET"); (*b)->parameter->value = cpystr ("US-ASCII"); s = mail_fetch_text (stream,msgno,NIL,&i,flags); (*b)->size.bytes = i; while (i--) if (*s++ == '\n') (*b)->size.lines++; } *body = *b; /* return the body */ } return *env; /* return the envelope */ } /* IMAP fetch message data * Accepts: MAIL stream * message number * section specifier * offset of first designated byte or 0 to start at beginning * maximum number of bytes or 0 for all bytes * lines to fetch if header * flags * Returns: T on success, NIL on failure */ long imap_msgdata (MAILSTREAM *stream,unsigned long msgno,char *section, unsigned long first,unsigned long last,STRINGLIST *lines, long flags) { int i; char *t,tmp[MAILTMPLEN],partial[40],seq[40]; char *noextend,*nopartial,*nolines,*nopeek,*nononpeek; char *cmd = (LEVELIMAP4 (stream) && (flags & FT_UID)) ? "UID FETCH":"FETCH"; IMAPPARSEDREPLY *reply; IMAPARG *args[5],*auxargs[3],aseq,aatt,alns,acls,aflg; noextend = nopartial = nolines = nopeek = nononpeek = NIL; /* does searching desire a lookahead? */ if ((flags & FT_SEARCHLOOKAHEAD) && (msgno < stream->nmsgs) && !stream->scache) { sprintf (seq,"%lu:%lu",msgno, (unsigned long) min (msgno + IMAPLOOKAHEAD,stream->nmsgs)); aseq.type = SEQUENCE; aseq.text = (void *) seq; } else { /* no, do it the easy way */ aseq.type = NUMBER; aseq.text = (void *) msgno; } aatt.type = ATOM; /* assume atomic attribute */ alns.type = LIST; alns.text = (void *) lines; acls.type = BODYCLOSE; acls.text = (void *) partial; aflg.type = ATOM; aflg.text = (void *) "FLAGS"; args[0] = &aseq; args[1] = &aatt; args[2] = args[3] = args[4] = NIL; auxargs[0] = &aseq; auxargs[1] = &aflg; auxargs[2] = NIL; partial[0] = '\0'; /* initially no partial specifier */ if (LEVELIMAP4rev1 (stream)) {/* easy if IMAP4rev1 server */ /* HEADER fetching with special handling? */ if (!strcmp (section,"HEADER") && (lines || (flags & FT_PREFETCHTEXT))) { if (lines) { /* want specific header lines? */ aatt.type = (flags & FT_PEEK) ? BODYPEEK : BODYTEXT; aatt.text = (void *) ((flags & FT_NOT) ? "HEADER.FIELDS.NOT" : "HEADER.FIELDS"); args[2] = &alns; args[3] = &acls; } /* must be prefetching */ else aatt.text = (void *) ((flags & FT_PEEK) ? "(BODY.PEEK[HEADER] BODY.PEEK[TEXT])" : "(BODY[HEADER] BODY[TEXT])"); } else { /* simple case */ aatt.type = (flags & FT_PEEK) ? BODYPEEK : BODYTEXT; aatt.text = (void *) section; args[2] = &acls; } if (first || last) sprintf (partial,"<%lu.%lu>",first,last ? last:-1); } /* IMAP4 did not have: * . HEADER body part (can simulate with BODY[0] or BODY.PEEK[0]) * . TEXT body part (can simulate top-level with RFC822.TEXT or * RFC822.TEXT.PEEK) * . MIME body part * . (usable) partial fetching * . (usable) selective header line fetching */ else if (LEVEL1730 (stream)) {/* IMAP4 (RFC 1730) compatibility */ /* BODY[HEADER] becomes BODY.PEEK[0] */ if (!strcmp (section,"HEADER")) aatt.text = (void *) ((flags & FT_PREFETCHTEXT) ? ((flags & FT_PEEK) ? "(BODY.PEEK[0] RFC822.TEXT.PEEK)" : "(BODY[0] RFC822.TEXT)") : ((flags & FT_PEEK) ? "BODY.PEEK[0]" : "BODY[0]")); /* BODY[TEXT] becomes RFC822.TEXT */ else if (!strcmp (section,"TEXT")) aatt.text = (void *) ((flags & FT_PEEK) ? "RFC822.TEXT.PEEK" : "RFC822.TEXT"); else if (!section[0]) /* BODY[] becomes RFC822 */ aatt.text = (void *) ((flags & FT_PEEK) ? "RFC822.PEEK" : "RFC822"); /* nested header */ else if (t = strstr (section,".HEADER")) { aatt.type = (flags & FT_PEEK) ? BODYPEEK : BODYTEXT; args[2] = &acls; /* will need to close section */ aatt.text = (void *) tmp; /* convert .HEADER to .0 */ strncpy (tmp,section,t-section); strcpy (tmp+(t-section),".0"); } else { /* IMAP4 body part */ aatt.type = (flags & FT_PEEK) ? BODYPEEK : BODYTEXT; args[2] = &acls; /* will need to close section */ aatt.text = (void *) section; } if (strstr (section,".MIME") || strstr (section,".TEXT")) noextend = "4"; if (first || last) nopartial = "4"; if (lines) nolines = "4"; } /* IMAP2bis did not have: * . HEADER body part (can simulate peeking top-level with RFC822.HEADER) * . TEXT body part (can simulate non-peeking top-level with RFC822.TEXT) * . MIME body part * . partial fetching * . selective header line fetching * . non-peeking header fetching * . peeking body fetching */ /* IMAP2bis compatibility */ else if (LEVELIMAP2bis (stream)) { /* BODY[HEADER] becomes RFC822.HEADER */ if (!strcmp (section,"HEADER")) { aatt.text = (void *) ((flags & FT_PREFETCHTEXT) ? "(RFC822.HEADER RFC822.TEXT)" : "RFC822.HEADER"); if (flags & FT_PEEK) flags &= ~FT_PEEK; else nononpeek = "2bis"; } /* BODY[TEXT] becomes RFC822.TEXT */ else if (!strcmp (section,"TEXT")) aatt.text = (void *) "RFC822.TEXT"; /* BODY[] becomes RFC822 */ else if (!section[0]) aatt.text = (void *) "RFC822"; else { /* IMAP2bis body part */ aatt.type = BODYTEXT; args[2] = &acls; /* will need to close section */ aatt.text = (void *) section; } if (strstr (section,".HEADER") || strstr (section,".MIME") || strstr (section,".TEXT")) noextend = "2bis"; if (first || last) nopartial = "2bis"; if (lines) nolines = "2bis"; if (flags & FT_PEEK) nopeek = "2bis"; } /* IMAP2 did not have: * . HEADER body part (can simulate peeking top-level with RFC822.HEADER) * . TEXT body part (can simulate non-peeking top-level with RFC822.TEXT) * . MIME body part * . multiple body parts (can simulate BODY[1] with RFC822.TEXT) * . partial fetching * . selective header line fetching * . non-peeking header fetching * . peeking body fetching */ else { /* IMAP2 (RFC 1176/1064) compatibility */ /* BODY[HEADER] */ if (!strcmp (section,"HEADER")) { aatt.text = (void *) ((flags & FT_PREFETCHTEXT) ? "(RFC822.HEADER RFC822.TEXT)" : "RFC822.HEADER"); if (flags & FT_PEEK) flags &= ~FT_PEEK; nononpeek = "2"; } /* BODY[TEXT] becomes RFC822.TEXT */ else if (!strcmp (section,"TEXT")) aatt.text = (void *) "RFC822.TEXT"; /* BODY[1] treated like RFC822.TEXT */ else if (!strcmp (section,"1")) { SIZEDTEXT text; MESSAGECACHE *elt = mail_elt (stream,msgno); /* have a cached RFC822.TEXT? */ if (elt->private.msg.text.text.data) { text.size = elt->private.msg.text.text.size; /* should move instead of copy */ text.data = memcpy (fs_get (text.size+1), elt->private.msg.text.text.data,text.size); (t = (char *) text.data)[text.size] = '\0'; imap_cache (stream,msgno,"1",NIL,&text); return LONGT; /* don't have to do any fetches */ } /* otherwise do RFC822.TEXT */ aatt.text = (void *) "RFC822.TEXT"; } /* BODY[] becomes RFC822 */ else if (!section[0]) aatt.text = (void *) "RFC822"; else noextend = "2"; /* how did we get here? */ if (flags & FT_PEEK) nopeek = "2"; if (first || last) nopartial = "2"; if (lines) nolines = "2"; } /* Report unavailable functionalities. The application can use the helpful * LEVELIMAPREV1, LEVELIMAP4, and LEVELIMAP2bis operations provided in * imap4r1.h to avoid triggering these errors. There aren't any workarounds * for these restrictions. */ if (noextend) { sprintf (tmp,"[NOTIMAP4REV1] IMAP%s server can't do extended body fetch", noextend); mm_log (tmp,ERROR); return NIL; /* can't do anything close either */ } if (nopartial) { sprintf (tmp,"[NOTIMAP4REV1] IMAP%s server can't do partial fetch", nopartial); mm_notify (stream,tmp,WARN); } if (nolines) { sprintf(tmp,"[NOTIMAP4REV1] IMAP%s server can't do selective header fetch", nolines); mm_notify (stream,tmp,WARN); } /* trying to do unsupported peek behavior? */ if ((t = nopeek) || (t = nononpeek)) { /* get most recent \Seen setting */ if (!imap_OK (stream,reply = imap_send (stream,cmd,auxargs))) mm_log (reply->text,WARN); /* note current setting of \Seen flag */ if (!(i = mail_elt (stream,msgno)->seen)) { sprintf (tmp,nopeek ? /* only babble if \Seen not set */ "[NOTIMAP4] Simulating peeking fetch in IMAP%s" : "[NOTIMAP4] Simulating non-peeking header fetch in IMAP%s",t); mm_notify (stream,tmp,NIL); } /* send the fetch command */ if (!imap_OK (stream,reply = imap_send (stream,cmd,args))) { mm_log (reply->text,ERROR); return NIL; /* failure */ } /* send command if need to reset \Seen */ if (((nopeek && !i && mail_elt (stream,msgno)->seen && (aflg.text = "-FLAGS \\Seen")) || ((nononpeek && !mail_elt (stream,msgno)->seen) && (aflg.text = "+FLAGS \\Seen"))) && !imap_OK (stream,reply = imap_send (stream,"STORE",auxargs))) mm_log (reply->text,WARN); } /* simple case if traditional behavior */ else if (!imap_OK (stream,reply = imap_send (stream,cmd,args))) { mm_log (reply->text,ERROR); return NIL; /* failure */ } /* simulate BODY[1] return for RFC 1064/1176 */ if (!LEVELIMAP2bis (stream) && !strcmp (section,"1")) { SIZEDTEXT text; MESSAGECACHE *elt = mail_elt (stream,msgno); text.size = elt->private.msg.text.text.size; /* should move instead of copy */ text.data = memcpy (fs_get (text.size+1),elt->private.msg.text.text.data, text.size); (t = (char *) text.data)[text.size] = '\0'; imap_cache (stream,msgno,"1",NIL,&text); } return LONGT; } /* IMAP fetch UID * Accepts: MAIL stream * message number * Returns: UID */ unsigned long imap_uid (MAILSTREAM *stream,unsigned long msgno) { MESSAGECACHE *elt; IMAPPARSEDREPLY *reply; IMAPARG *args[3],aseq,aatt; char *s,seq[MAILTMPLEN]; unsigned long i,j,k; /* IMAP2 didn't have UIDs */ if (!LEVELIMAP4 (stream)) return msgno; /* do we know its UID yet? */ if (!(elt = mail_elt (stream,msgno))->private.uid) { aseq.type = SEQUENCE; aseq.text = (void *) seq; aatt.type = ATOM; aatt.text = (void *) "UID"; args[0] = &aseq; args[1] = &aatt; args[2] = NIL; sprintf (seq,"%lu",msgno); if (k = imap_uidlookahead) {/* build UID list */ for (i = msgno + 1, s = seq; k && (i <= stream->nmsgs); i++) if (!mail_elt (stream,i)->private.uid) { s += strlen (s); /* find string end, see if nearing end */ if ((s - seq) > (MAILTMPLEN - 20)) break; sprintf (s,",%lu",i); /* append message */ for (j = i + 1, k--; /* hunt for last message without a UID */ k && (j <= stream->nmsgs) && !mail_elt (stream,j)->private.uid; j++, k--); /* if different, make a range */ if (i != --j) sprintf (s + strlen (s),":%lu",i = j); } } /* send "FETCH msgno UID" */ if (!imap_OK (stream,reply = imap_send (stream,"FETCH",args))) mm_log (reply->text,ERROR); } return elt->private.uid; /* return our UID now */ } /* IMAP fetch message number from UID * Accepts: MAIL stream * UID * Returns: message number */ unsigned long imap_msgno (MAILSTREAM *stream,unsigned long uid) { IMAPPARSEDREPLY *reply; IMAPARG *args[3],aseq,aatt; char seq[MAILTMPLEN]; int holes = 0; unsigned long i,msgno; /* IMAP2 didn't have UIDs */ if (!LEVELIMAP4 (stream)) return uid; /* This really should be a binary search, but since there are likely to be * holes in the msgno->UID map it's hard to do. */ for (msgno = 1; msgno <= stream->nmsgs; msgno++) { if (!(i = mail_elt (stream,msgno)->private.uid)) holes = T; else if (i == uid) return msgno; } if (holes) { /* have holes in cache? */ /* yes, have server hunt for UID */ LOCAL->lastuid.uid = LOCAL->lastuid.msgno = 0; aseq.type = SEQUENCE; aseq.text = (void *) seq; aatt.type = ATOM; aatt.text = (void *) "UID"; args[0] = &aseq; args[1] = &aatt; args[2] = NIL; sprintf (seq,"%lu",uid); /* send "UID FETCH uid UID" */ if (!imap_OK (stream,reply = imap_send (stream,"UID FETCH",args))) mm_log (reply->text,ERROR); if (LOCAL->lastuid.uid) { /* got any results from FETCH? */ if ((LOCAL->lastuid.uid == uid) && /* what, me paranoid? */ (LOCAL->lastuid.msgno <= stream->nmsgs) && (mail_elt (stream,LOCAL->lastuid.msgno)->private.uid == uid)) /* got it the easy way */ return LOCAL->lastuid.msgno; /* sigh, do another linear search... */ for (msgno = 1; msgno <= stream->nmsgs; msgno++) if (mail_elt (stream,msgno)->private.uid == uid) return msgno; } } return 0; /* didn't find the UID anywhere */ } /* IMAP modify flags * Accepts: MAIL stream * sequence * flag(s) * option flags */ void imap_flag (MAILSTREAM *stream,char *sequence,char *flag,long flags) { char *cmd = (LEVELIMAP4 (stream) && (flags & ST_UID)) ? "UID STORE":"STORE"; IMAPPARSEDREPLY *reply; IMAPARG *args[4],aseq,ascm,aflg; if (LOCAL->loser) sequence = imap_reform_sequence (stream,sequence, flags & ST_UID); aseq.type = SEQUENCE; aseq.text = (void *) sequence; ascm.type = ATOM; ascm.text = (void *) ((flags & ST_SET) ? ((LEVELIMAP4 (stream) && (flags & ST_SILENT)) ? "+Flags.silent" : "+Flags") : ((LEVELIMAP4 (stream) && (flags & ST_SILENT)) ? "-Flags.silent" : "-Flags")); aflg.type = FLAGS; aflg.text = (void *) flag; args[0] = &aseq; args[1] = &ascm; args[2] = &aflg; args[3] = NIL; /* send "STORE sequence +Flags flag" */ if (!imap_OK (stream,reply = imap_send (stream,cmd,args))) mm_log (reply->text,ERROR); } /* IMAP search for messages * Accepts: MAIL stream * character set * search program * option flags * Returns: T on success, NIL on failure */ long imap_search (MAILSTREAM *stream,char *charset,SEARCHPGM *pgm,long flags) { unsigned long i,j,k; char *s; IMAPPARSEDREPLY *reply; MESSAGECACHE *elt; if ((flags & SE_NOSERVER) || /* if want to do local search */ LOCAL->loser || /* or loser */ (!LEVELIMAP4 (stream) && /* or old server but new functions... */ (charset || (flags & SE_UID) || pgm->msgno || pgm->uid || pgm->or || pgm->not || pgm->header || pgm->larger || pgm->smaller || pgm->sentbefore || pgm->senton || pgm->sentsince || pgm->draft || pgm->undraft || pgm->return_path || pgm->sender || pgm->reply_to || pgm->message_id || pgm->in_reply_to || pgm->newsgroups || pgm->followup_to || pgm->references)) || (!LEVELWITHIN (stream) && (pgm->older || pgm->younger))) { if ((flags & SE_NOLOCAL) || !mail_search_default (stream,charset,pgm,flags | SE_NOSERVER)) return NIL; } /* do silly ALL or seq-only search locally */ else if (!(flags & (SE_NOLOCAL|SE_SILLYOK)) && !(pgm->uid || pgm->or || pgm->not || pgm->header || pgm->from || pgm->to || pgm->cc || pgm->bcc || pgm->subject || pgm->body || pgm->text || pgm->larger || pgm->smaller || pgm->sentbefore || pgm->senton || pgm->sentsince || pgm->before || pgm->on || pgm->since || pgm->answered || pgm->unanswered || pgm->deleted || pgm->undeleted || pgm->draft || pgm->undraft || pgm->flagged || pgm->unflagged || pgm->recent || pgm->old || pgm->seen || pgm->unseen || pgm->keyword || pgm->unkeyword || pgm->return_path || pgm->sender || pgm->reply_to || pgm->in_reply_to || pgm->message_id || pgm->newsgroups || pgm->followup_to || pgm->references)) { if (!mail_search_default (stream,NIL,pgm,flags | SE_NOSERVER)) fatal ("impossible mail_search_default() failure"); } else { /* do server-based SEARCH */ char *cmd = (flags & SE_UID) ? "UID SEARCH" : "SEARCH"; IMAPARG *args[4],apgm,aatt,achs; SEARCHSET *ss,*set; args[1] = args[2] = args[3] = NIL; apgm.type = SEARCHPROGRAM; apgm.text = (void *) pgm; if (charset) { /* optional charset argument requested */ args[0] = &aatt; args[1] = &achs; args[2] = &apgm; aatt.type = ATOM; aatt.text = (void *) "CHARSET"; achs.type = ASTRING; achs.text = (void *) charset; } else args[0] = &apgm; /* no charset argument */ /* tell receiver that these will be UIDs */ LOCAL->uidsearch = (flags & SE_UID) ? T : NIL; reply = imap_send (stream,cmd,args); /* did server barf with that searchpgm? */ if (!(flags & SE_UID) && pgm && (ss = pgm->msgno) && !strcmp (reply->key,"BAD")) { LOCAL->filter = T; /* retry, filtering SEARCH results */ for (i = 1; i <= stream->nmsgs; i++) mail_elt (stream,i)->private.filter = NIL; for (set = ss; set; set = set->next) if (i = set->first) { /* single message becomes one-message range */ if (!(j = set->last)) j = i; else if (j < i) { /* swap reversed range */ i = set->last; j = set->first; } while (i <= j) mail_elt (stream,i++)->private.filter = T; } pgm->msgno = NIL; /* and without the searchset */ reply = imap_send (stream,cmd,args); pgm->msgno = ss; /* restore searchset */ LOCAL->filter = NIL; /* turn off filtering */ } LOCAL->uidsearch = NIL; /* do locally if server won't grok */ if (!strcmp (reply->key,"BAD")) { if ((flags & SE_NOLOCAL) || !mail_search_default (stream,charset,pgm,flags | SE_NOSERVER)) return NIL; } else if (!imap_OK (stream,reply)) { mm_log (reply->text,ERROR); return NIL; } } /* can never pre-fetch with a short cache */ if ((k = imap_prefetch) && !(flags & (SE_NOPREFETCH | SE_UID)) && !stream->scache) { /* only if prefetching permitted */ s = LOCAL->tmp; /* build sequence in temporary buffer */ *s = '\0'; /* initially nothing */ /* search through mailbox */ for (i = 1; k && (i <= stream->nmsgs); ++i) /* for searched messages with no envelope */ if ((elt = mail_elt (stream,i)) && elt->searched && !mail_elt (stream,i)->private.msg.env) { /* prepend with comma if not first time */ if (LOCAL->tmp[0]) *s++ = ','; sprintf (s,"%lu",j = i);/* output message number */ s += strlen (s); /* point at end of string */ k--; /* count one up */ /* search for possible end of range */ while (k && (i < stream->nmsgs) && (elt = mail_elt (stream,i+1))->searched && !elt->private.msg.env) i++,k--; if (i != j) { /* if a range */ sprintf (s,":%lu",i); /* output delimiter and end of range */ s += strlen (s); /* point at end of string */ } if ((s - LOCAL->tmp) > (IMAPTMPLEN - 50)) break; } if (LOCAL->tmp[0]) { /* anything to pre-fetch? */ /* pre-fetch envelopes for the first imap_prefetch number of messages */ if (!imap_OK (stream,reply = imap_fetch (stream,s = cpystr (LOCAL->tmp),FT_NEEDENV + ((flags & SE_NOHDRS) ? FT_NOHDRS : NIL) + ((flags & SE_NEEDBODY) ? FT_NEEDBODY : NIL)))) mm_log (reply->text,ERROR); fs_give ((void **) &s); /* flush copy of sequence */ } } return LONGT; } /* IMAP sort messages * Accepts: mail stream * character set * search program * sort program * option flags * Returns: vector of sorted message sequences or NIL if error */ unsigned long *imap_sort (MAILSTREAM *stream,char *charset,SEARCHPGM *spg, SORTPGM *pgm,long flags) { unsigned long i,j,start,last; unsigned long *ret = NIL; pgm->nmsgs = 0; /* start off with no messages */ /* can use server-based sort? */ if (LEVELSORT (stream) && !(flags & SE_NOSERVER) && (!spg || (LEVELWITHIN (stream) || !(spg->older || spg->younger)))) { char *cmd = (flags & SE_UID) ? "UID SORT" : "SORT"; IMAPARG *args[4],apgm,achs,aspg; IMAPPARSEDREPLY *reply; SEARCHSET *ss = NIL; SEARCHPGM *tsp = NIL; apgm.type = SORTPROGRAM; apgm.text = (void *) pgm; achs.type = ASTRING; achs.text = (void *) (charset ? charset : "US-ASCII"); aspg.type = SEARCHPROGRAM; /* did he provide a searchpgm? */ if (!(aspg.text = (void *) spg)) { for (i = 1,start = last = 0; i <= stream->nmsgs; ++i) if (mail_elt (stream,i)->searched) { if (ss) { /* continuing a sequence */ if (i == last + 1) last = i; else { /* end of range */ if (last != start) ss->last = last; (ss = ss->next = mail_newsearchset ())->first = i; start = last = i; /* begin a new range */ } } else { /* first time, start new searchpgm */ (tsp = mail_newsearchpgm ())->msgno = ss = mail_newsearchset (); ss->first = start = last = i; } } /* nothing to sort if no messages */ if (!(aspg.text = (void *) tsp)) return NIL; /* else install last sequence */ if (last != start) ss->last = last; } args[0] = &apgm; args[1] = &achs; args[2] = &aspg; args[3] = NIL; /* ask server to do it */ reply = imap_send (stream,cmd,args); if (tsp) { /* was there a temporary searchpgm? */ aspg.text = NIL; /* yes, flush it */ mail_free_searchpgm (&tsp); /* did server barf with that searchpgm? */ if (!(flags & SE_UID) && !strcmp (reply->key,"BAD")) { LOCAL->filter = T; /* retry, filtering SORT/THREAD results */ reply = imap_send (stream,cmd,args); LOCAL->filter = NIL; /* turn off filtering */ } } /* do locally if server barfs */ if (!strcmp (reply->key,"BAD")) return (flags & SE_NOLOCAL) ? NIL : imap_sort (stream,charset,spg,pgm,flags | SE_NOSERVER); /* server sorted OK? */ else if (imap_OK (stream,reply)) { pgm->nmsgs = LOCAL->sortsize; ret = LOCAL->sortdata; LOCAL->sortdata = NIL; /* mail program is responsible for flushing */ } else mm_log (reply->text,ERROR); } /* not much can do if short caching */ else if (stream->scache) ret = mail_sort_msgs (stream,charset,spg,pgm,flags); else { /* try to be a bit more clever */ char *s,*t; unsigned long len; MESSAGECACHE *elt; SORTCACHE **sc; SORTPGM *sp; long ftflags = 0; /* see if need envelopes */ for (sp = pgm; sp && !ftflags; sp = sp->next) switch (sp->function) { case SORTDATE: case SORTFROM: case SORTSUBJECT: case SORTTO: case SORTCC: ftflags = FT_NEEDENV + ((flags & SE_NOHDRS) ? FT_NOHDRS : NIL); } if (spg) { /* only if a search needs to be done */ int silent = stream->silent; stream->silent = T; /* don't pass up mm_searched() events */ /* search for messages */ mail_search_full (stream,charset,spg,flags & SE_NOSERVER); stream->silent = silent; /* restore silence state */ } /* initialize progress counters */ pgm->nmsgs = pgm->progress.cached = 0; /* pass 1: count messages to sort */ for (i = 1,len = start = last = 0,s = t = NIL; i <= stream->nmsgs; ++i) if ((elt = mail_elt (stream,i))->searched) { pgm->nmsgs++; if (ftflags ? !elt->private.msg.env : !elt->day) { if (s) { /* continuing a sequence */ if (i == last + 1) last = i; else { /* end of range */ if (last != start) sprintf (t,":%lu,%lu",last,i); else sprintf (t,",%lu",i); start = last = i; /* begin a new range */ if ((len - (j = ((t += strlen (t)) - s)) < 20)) { fs_resize ((void **) &s,len += MAILTMPLEN); t = s + j; /* relocate current pointer */ } } } else { /* first time, start new buffer */ s = (char *) fs_get (len = MAILTMPLEN); sprintf (s,"%lu",start = last = i); t = s + strlen (s); /* end of buffer */ } } } /* last sequence */ if (last != start) sprintf (t,":%lu",last); if (s) { /* load cache for all messages being sorted */ imap_fetch (stream,s,ftflags); fs_give ((void **) &s); } if (pgm->nmsgs) { /* pass 2: sort cache */ sortresults_t sr = (sortresults_t) mail_parameters (NIL,GET_SORTRESULTS,NIL); sc = mail_sort_loadcache (stream,pgm); /* pass 3: sort messages */ if (!pgm->abort) ret = mail_sort_cache (stream,pgm,sc,flags); fs_give ((void **) &sc); /* don't need sort vector any more */ /* also return via callback if requested */ if (sr) (*sr) (stream,ret,pgm->nmsgs); } } return ret; } /* IMAP thread messages * Accepts: mail stream * thread type * character set * search program * option flags * Returns: thread node tree or NIL if error */ THREADNODE *imap_thread (MAILSTREAM *stream,char *type,char *charset, SEARCHPGM *spg,long flags) { THREADER *thr; if (!(flags & SE_NOSERVER) && (!spg || (LEVELWITHIN (stream) || !(spg->older || spg->younger)))) /* does server have this threader type? */ for (thr = LOCAL->cap.threader; thr; thr = thr->next) if (!compare_cstring (thr->name,type)) return imap_thread_work (stream,type,charset,spg,flags); /* server doesn't support it, do locally */ return (flags & SE_NOLOCAL) ? NIL: mail_thread_msgs (stream,type,charset,spg,flags | SE_NOSERVER,imap_sort); } /* IMAP thread messages worker routine * Accepts: mail stream * thread type * character set * search program * option flags * Returns: thread node tree */ THREADNODE *imap_thread_work (MAILSTREAM *stream,char *type,char *charset, SEARCHPGM *spg,long flags) { unsigned long i,start,last; char *cmd = (flags & SE_UID) ? "UID THREAD" : "THREAD"; IMAPARG *args[4],apgm,achs,aspg; IMAPPARSEDREPLY *reply; THREADNODE *ret = NIL; SEARCHSET *ss = NIL; SEARCHPGM *tsp = NIL; apgm.type = ATOM; apgm.text = (void *) type; achs.type = ASTRING; achs.text = (void *) (charset ? charset : "US-ASCII"); aspg.type = SEARCHPROGRAM; /* did he provide a searchpgm? */ if (!(aspg.text = (void *) spg)) { for (i = 1,start = last = 0; i <= stream->nmsgs; ++i) if (mail_elt (stream,i)->searched) { if (ss) { /* continuing a sequence */ if (i == last + 1) last = i; else { /* end of range */ if (last != start) ss->last = last; (ss = ss->next = mail_newsearchset ())->first = i; start = last =i; /* begin a new range */ } } else { /* first time, start new searchpgm */ (tsp = mail_newsearchpgm ())->msgno = ss = mail_newsearchset (); ss->first = start = last = i; } } /* nothing to sort if no messages */ if (!(aspg.text = (void *) tsp)) return NIL; /* else install last sequence */ if (last != start) ss->last = last; } args[0] = &apgm; args[1] = &achs; args[2] = &aspg; args[3] = NIL; /* ask server to do it */ reply = imap_send (stream,cmd,args); if (tsp) { /* was there a temporary searchpgm? */ aspg.text = NIL; /* yes, flush it */ mail_free_searchpgm (&tsp); /* did server barf with that searchpgm? */ if (!(flags & SE_UID) && !strcmp (reply->key,"BAD")) { LOCAL->filter = T; /* retry, filtering SORT/THREAD results */ reply = imap_send (stream,cmd,args); LOCAL->filter = NIL; /* turn off filtering */ } } /* do locally if server barfs */ if (!strcmp (reply->key,"BAD")) ret = (flags & SE_NOLOCAL) ? NIL: mail_thread_msgs (stream,type,charset,spg,flags | SE_NOSERVER,imap_sort); /* server threaded OK? */ else if (imap_OK (stream,reply)) { ret = LOCAL->threaddata; LOCAL->threaddata = NIL; /* mail program is responsible for flushing */ } else mm_log (reply->text,ERROR); return ret; } /* IMAP ping mailbox * Accepts: MAIL stream * Returns: T if stream still alive, else NIL */ long imap_ping (MAILSTREAM *stream) { return (LOCAL->netstream && /* send "NOOP" */ imap_OK (stream,imap_send (stream,"NOOP",NIL))) ? T : NIL; } /* IMAP check mailbox * Accepts: MAIL stream */ void imap_check (MAILSTREAM *stream) { /* send "CHECK" */ IMAPPARSEDREPLY *reply = imap_send (stream,"CHECK",NIL); mm_log (reply->text,imap_OK (stream,reply) ? (long) NIL : ERROR); } /* IMAP expunge mailbox * Accepts: MAIL stream * sequence to expunge if non-NIL * expunge options * Returns: T if success, NIL if failure */ long imap_expunge (MAILSTREAM *stream,char *sequence,long options) { long ret = NIL; IMAPPARSEDREPLY *reply = NIL; if (sequence) { /* wants selective expunging? */ if (options & EX_UID) { /* UID EXPUNGE form? */ if (LEVELUIDPLUS (stream)) {/* server support UIDPLUS? */ IMAPARG *args[2],aseq; aseq.type = SEQUENCE; aseq.text = (void *) sequence; args[0] = &aseq; args[1] = NIL; ret = imap_OK (stream,reply = imap_send (stream,"UID EXPUNGE",args)); } else mm_log ("[NOTUIDPLUS] Can't do UID EXPUNGE with this server",ERROR); } /* otherwise try to make into UID EXPUNGE */ else if (mail_sequence (stream,sequence)) { unsigned long i,j; char *t = (char *) fs_get (IMAPTMPLEN); char *s = t; /* search through mailbox */ for (*s = '\0', i = 1; i <= stream->nmsgs; ++i) if (mail_elt (stream,i)->sequence) { if (t[0]) *s++ = ','; /* prepend with comma if not first time */ sprintf (s,"%lu",mail_uid (stream,j = i)); s += strlen (s); /* point at end of string */ /* search for possible end of range */ while ((i < stream->nmsgs) && mail_elt (stream,i+1)->sequence) i++; if (i != j) { /* output end of range */ sprintf (s,":%lu",mail_uid (stream,i)); s += strlen (s); /* point at end of string */ } if ((s - t) > (IMAPTMPLEN - 50)) { mm_log ("Excessively complex sequence",ERROR); return NIL; } } /* now do as UID EXPUNGE */ ret = imap_expunge (stream,t,EX_UID); fs_give ((void **) &t); } } /* ordinary EXPUNGE */ else ret = imap_OK (stream,reply = imap_send (stream,"EXPUNGE",NIL)); if (reply) mm_log (reply->text,ret ? (long) NIL : ERROR); return ret; } /* IMAP copy message(s) * Accepts: MAIL stream * sequence * destination mailbox * option flags * Returns: T if successful else NIL */ long imap_copy (MAILSTREAM *stream,char *sequence,char *mailbox,long flags) { char *cmd = (LEVELIMAP4 (stream) && (flags & CP_UID)) ? "UID COPY" : "COPY"; char *s; long ret = NIL; IMAPPARSEDREPLY *reply; IMAPARG *args[3],aseq,ambx; imapreferral_t ir = (imapreferral_t) mail_parameters (stream,GET_IMAPREFERRAL,NIL); mailproxycopy_t pc = (mailproxycopy_t) mail_parameters (stream,GET_MAILPROXYCOPY,NIL); if (LOCAL->loser) sequence = imap_reform_sequence (stream,sequence, flags & CP_UID); aseq.type = SEQUENCE; aseq.text = (void *) sequence; ambx.type = ASTRING; ambx.text = (void *) mailbox; args[0] = &aseq; args[1] = &ambx; args[2] = NIL; /* note mailbox in case APPENDUID */ LOCAL->appendmailbox = mailbox; /* send "COPY sequence mailbox" */ ret = imap_OK (stream,reply = imap_send (stream,cmd,args)); LOCAL->appendmailbox = NIL; /* no longer appending */ if (ret) { /* success, delete messages if move */ if (flags & CP_MOVE) imap_flag (stream,sequence,"\\Deleted", ST_SET + ((flags&CP_UID) ? ST_UID : NIL)); } /* failed, do referral action if any */ else if (ir && pc && LOCAL->referral && mail_sequence (stream,sequence) && (s = (*ir) (stream,LOCAL->referral,REFCOPY))) ret = (*pc) (stream,sequence,s,flags | (stream->debug ? CP_DEBUG : NIL)); /* otherwise issue error message */ else mm_log (reply->text,ERROR); return ret; } /* IMAP mail append message from stringstruct * Accepts: MAIL stream * destination mailbox * append callback * data for callback * Returns: T if append successful, else NIL */ long imap_append (MAILSTREAM *stream,char *mailbox,append_t af,void *data) { MAILSTREAM *st = stream; IMAPARG *args[3],ambx,amap; IMAPPARSEDREPLY *reply = NIL; APPENDDATA map; char tmp[MAILTMPLEN]; long debug = stream ? stream->debug : NIL; long ret = NIL; imapreferral_t ir = (imapreferral_t) mail_parameters (stream,GET_IMAPREFERRAL,NIL); /* mailbox must be good */ if (mail_valid_net (mailbox,&imapdriver,NIL,tmp)) { /* create a stream if given one no good */ if ((stream && LOCAL && LOCAL->netstream) || (stream = mail_open (NIL,mailbox,OP_HALFOPEN|OP_SILENT | (debug ? OP_DEBUG : NIL)))) { /* note mailbox in case APPENDUID */ LOCAL->appendmailbox = mailbox; /* use multi-append? */ if (LEVELMULTIAPPEND (stream)) { ambx.type = ASTRING; ambx.text = (void *) tmp; amap.type = MULTIAPPEND; amap.text = (void *) ↦ map.af = af; map.data = data; args[0] = &ambx; args[1] = &amap; args[2] = NIL; /* success if OK */ ret = imap_OK (stream,reply = imap_send (stream,"APPEND",args)); LOCAL->appendmailbox = NIL; } /* do succession of single appends */ else while ((*af) (stream,data,&map.flags,&map.date,&map.message) && map.message && (ret = imap_OK (stream,reply = imap_append_single (stream,tmp,map.flags, map.date,map.message)))); LOCAL->appendmailbox = NIL; /* don't do referrals if success or no reply */ if (ret || !reply) mailbox = NIL; /* otherwise generate referral */ else if (!(mailbox = (ir && LOCAL->referral) ? (*ir) (stream,LOCAL->referral,REFAPPEND) : NIL)) mm_log (reply->text,ERROR); /* close temporary stream */ if (st != stream) stream = mail_close (stream); if (mailbox) /* chase referral if any */ ret = imap_append_referral (mailbox,tmp,af,data,map.flags,map.date, map.message,&map,debug); } else mm_log ("Can't access server for append",ERROR); } return ret; /* return */ } /* IMAP mail append message referral retry * Accepts: destination mailbox * temporary buffer * append callback * data for callback * flags from previous attempt * date from previous attempt * message stringstruct from previous attempt * options (currently non-zero to set OP_DEBUG) * Returns: T if append successful, else NIL */ long imap_append_referral (char *mailbox,char *tmp,append_t af,void *data, char *flags,char *date,STRING *message, APPENDDATA *map,long options) { MAILSTREAM *stream; IMAPARG *args[3],ambx,amap; IMAPPARSEDREPLY *reply; imapreferral_t ir = (imapreferral_t) mail_parameters (NIL,GET_IMAPREFERRAL,NIL); /* barf if bad mailbox */ while (mailbox && mail_valid_net (mailbox,&imapdriver,NIL,tmp)) { /* create a stream if given one no good */ if (!(stream = mail_open (NIL,mailbox,OP_HALFOPEN|OP_SILENT | (options ? OP_DEBUG : NIL)))) { sprintf (tmp,"Can't access referral server: %.80s",mailbox); mm_log (tmp,ERROR); return NIL; } /* got referral server, use multi-append? */ if (LEVELMULTIAPPEND (stream)) { ambx.type = ASTRING; ambx.text = (void *) tmp; amap.type = MULTIAPPENDREDO; amap.text = (void *) map; args[0] = &ambx; args[1] = &amap; args[2] = NIL; /* do multiappend on referral site */ if (imap_OK (stream,reply = imap_send (stream,"APPEND",args))) { mail_close (stream); /* multiappend OK, close stream */ return LONGT; /* all done */ } } /* do multiple single appends */ else while (imap_OK (stream,reply = imap_append_single (stream,tmp,flags,date,message))) if (!((*af) (stream,data,&flags,&date,&message) && message)) { mail_close (stream); /* last message, close stream */ return LONGT; /* all done */ } /* generate error if no nested referral */ if (!(mailbox = (ir && LOCAL->referral) ? (*ir) (stream,LOCAL->referral,REFAPPEND) : NIL)) mm_log (reply->text,ERROR); mail_close (stream); /* close previous referral stream */ } return NIL; /* bogus mailbox */ } /* IMAP append single message * Accepts: mail stream * destination mailbox * initial flags * internal date * stringstruct of message to append * Returns: reply from append */ IMAPPARSEDREPLY *imap_append_single (MAILSTREAM *stream,char *mailbox, char *flags,char *date,STRING *message) { MESSAGECACHE elt; IMAPARG *args[5],ambx,aflg,adat,amsg; IMAPPARSEDREPLY *reply; char tmp[MAILTMPLEN]; int i; ambx.type = ASTRING; ambx.text = (void *) mailbox; args[i = 0] = &ambx; if (flags) { aflg.type = FLAGS; aflg.text = (void *) flags; args[++i] = &aflg; } if (date) { /* ensure date in INTERNALDATE format */ if (!mail_parse_date (&elt,date)) { /* flush previous reply */ if (LOCAL->reply.line) fs_give ((void **) &LOCAL->reply.line); /* build new fake reply */ LOCAL->reply.tag = LOCAL->reply.line = cpystr ("*"); LOCAL->reply.key = "BAD"; LOCAL->reply.text = "Bad date in append"; return &LOCAL->reply; } adat.type = ASTRING; adat.text = (void *) (date = mail_date (tmp,&elt)); args[++i] = &adat; } amsg.type = LITERAL; amsg.text = (void *) message; args[++i] = &amsg; args[++i] = NIL; /* easy if IMAP4[rev1] */ if (LEVELIMAP4 (stream)) reply = imap_send (stream,"APPEND",args); else { /* try the IMAP2bis way */ args[1] = &amsg; args[2] = NIL; reply = imap_send (stream,"APPEND",args); } return reply; } /* IMAP garbage collect stream * Accepts: Mail stream * garbage collection flags */ void imap_gc (MAILSTREAM *stream,long gcflags) { unsigned long i; MESSAGECACHE *elt; mailcache_t mc = (mailcache_t) mail_parameters (NIL,GET_CACHE,NIL); /* make sure the cache is large enough */ (*mc) (stream,stream->nmsgs,CH_SIZE); if (gcflags & GC_TEXTS) { /* garbage collect texts? */ if (!stream->scache) for (i = 1; i <= stream->nmsgs; ++i) if (elt = (MESSAGECACHE *) (*mc) (stream,i,CH_ELT)) imap_gc_body (elt->private.msg.body); imap_gc_body (stream->body); } /* gc cache if requested and unlocked */ if (gcflags & GC_ELT) for (i = 1; i <= stream->nmsgs; ++i) if ((elt = (MESSAGECACHE *) (*mc) (stream,i,CH_ELT)) && (elt->lockcount == 1)) (*mc) (stream,i,CH_FREE); } /* IMAP garbage collect body texts * Accepts: body to GC */ void imap_gc_body (BODY *body) { PART *part; if (body) { /* have a body? */ if (body->mime.text.data) /* flush MIME data */ fs_give ((void **) &body->mime.text.data); /* flush text contents */ if (body->contents.text.data) fs_give ((void **) &body->contents.text.data); body->mime.text.size = body->contents.text.size = 0; /* multipart? */ if (body->type == TYPEMULTIPART) for (part = body->nested.part; part; part = part->next) imap_gc_body (&part->body); /* MESSAGE/RFC822? */ else if ((body->type == TYPEMESSAGE) && !strcmp (body->subtype,"RFC822")) { imap_gc_body (body->nested.msg->body); if (body->nested.msg->full.text.data) fs_give ((void **) &body->nested.msg->full.text.data); if (body->nested.msg->header.text.data) fs_give ((void **) &body->nested.msg->header.text.data); if (body->nested.msg->text.text.data) fs_give ((void **) &body->nested.msg->text.text.data); body->nested.msg->full.text.size = body->nested.msg->header.text.size = body->nested.msg->text.text.size = 0; } } } /* IMAP get capabilities * Accepts: mail stream */ void imap_capability (MAILSTREAM *stream) { THREADER *thr,*t; LOCAL->gotcapability = NIL; /* flush any previous capabilities */ /* request new capabilities */ imap_send (stream,"CAPABILITY",NIL); if (!LOCAL->gotcapability) { /* did server get any? */ /* no, flush threaders just in case */ if (thr = LOCAL->cap.threader) while (t = thr) { fs_give ((void **) &t->name); thr = t->next; fs_give ((void **) &t); } /* zap most capabilities */ memset (&LOCAL->cap,0,sizeof (LOCAL->cap)); /* assume IMAP2bis server if failure */ LOCAL->cap.imap2bis = LOCAL->cap.rfc1176 = T; } } /* IMAP set ACL * Accepts: mail stream * mailbox name * authentication identifer * new access rights * Returns: T on success, NIL on failure */ long imap_setacl (MAILSTREAM *stream,char *mailbox,char *id,char *rights) { IMAPARG *args[4],ambx,aid,art; ambx.type = aid.type = art.type = ASTRING; ambx.text = (void *) mailbox; aid.text = (void *) id; art.text = (void *) rights; args[0] = &ambx; args[1] = &aid; args[2] = &art; args[3] = NIL; return imap_acl_work (stream,"SETACL",args); } /* IMAP delete ACL * Accepts: mail stream * mailbox name * authentication identifer * Returns: T on success, NIL on failure */ long imap_deleteacl (MAILSTREAM *stream,char *mailbox,char *id) { IMAPARG *args[3],ambx,aid; ambx.type = aid.type = ASTRING; ambx.text = (void *) mailbox; aid.text = (void *) id; args[0] = &ambx; args[1] = &aid; args[2] = NIL; return imap_acl_work (stream,"DELETEACL",args); } /* IMAP get ACL * Accepts: mail stream * mailbox name * Returns: T on success with data returned via callback, NIL on failure */ long imap_getacl (MAILSTREAM *stream,char *mailbox) { IMAPARG *args[2],ambx; ambx.type = ASTRING; ambx.text = (void *) mailbox; args[0] = &ambx; args[1] = NIL; return imap_acl_work (stream,"GETACL",args); } /* IMAP list rights * Accepts: mail stream * mailbox name * authentication identifer * Returns: T on success with data returned via callback, NIL on failure */ long imap_listrights (MAILSTREAM *stream,char *mailbox,char *id) { IMAPARG *args[3],ambx,aid; ambx.type = aid.type = ASTRING; ambx.text = (void *) mailbox; aid.text = (void *) id; args[0] = &ambx; args[1] = &aid; args[2] = NIL; return imap_acl_work (stream,"LISTRIGHTS",args); } /* IMAP my rights * Accepts: mail stream * mailbox name * Returns: T on success with data returned via callback, NIL on failure */ long imap_myrights (MAILSTREAM *stream,char *mailbox) { IMAPARG *args[2],ambx; ambx.type = ASTRING; ambx.text = (void *) mailbox; args[0] = &ambx; args[1] = NIL; return imap_acl_work (stream,"MYRIGHTS",args); } /* IMAP ACL worker routine * Accepts: mail stream * command * command arguments * Returns: T on success, NIL on failure */ long imap_acl_work (MAILSTREAM *stream,char *command,IMAPARG *args[]) { long ret = NIL; if (LEVELACL (stream)) { /* send command */ IMAPPARSEDREPLY *reply; if (imap_OK (stream,reply = imap_send (stream,command,args))) ret = LONGT; else mm_log (reply->text,ERROR); } else mm_log ("ACL not available on this IMAP server",ERROR); return ret; } /* IMAP set quota * Accepts: mail stream * quota root name * resource limit list as a stringlist * Returns: T on success with data returned via callback, NIL on failure */ long imap_setquota (MAILSTREAM *stream,char *qroot,STRINGLIST *limits) { long ret = NIL; if (LEVELQUOTA (stream)) { /* send "SETQUOTA" */ IMAPPARSEDREPLY *reply; IMAPARG *args[3],aqrt,alim; aqrt.type = ASTRING; aqrt.text = (void *) qroot; alim.type = SNLIST; alim.text = (void *) limits; args[0] = &aqrt; args[1] = &alim; args[2] = NIL; if (imap_OK (stream,reply = imap_send (stream,"SETQUOTA",args))) ret = LONGT; else mm_log (reply->text,ERROR); } else mm_log ("Quota not available on this IMAP server",ERROR); return ret; } /* IMAP get quota * Accepts: mail stream * quota root name * Returns: T on success with data returned via callback, NIL on failure */ long imap_getquota (MAILSTREAM *stream,char *qroot) { long ret = NIL; if (LEVELQUOTA (stream)) { /* send "GETQUOTA" */ IMAPPARSEDREPLY *reply; IMAPARG *args[2],aqrt; aqrt.type = ASTRING; aqrt.text = (void *) qroot; args[0] = &aqrt; args[1] = NIL; if (imap_OK (stream,reply = imap_send (stream,"GETQUOTA",args))) ret = LONGT; else mm_log (reply->text,ERROR); } else mm_log ("Quota not available on this IMAP server",ERROR); return ret; } /* IMAP get quota root * Accepts: mail stream * mailbox name * Returns: T on success with data returned via callback, NIL on failure */ long imap_getquotaroot (MAILSTREAM *stream,char *mailbox) { long ret = NIL; if (LEVELQUOTA (stream)) { /* send "GETQUOTAROOT" */ IMAPPARSEDREPLY *reply; IMAPARG *args[2],ambx; ambx.type = ASTRING; ambx.text = (void *) mailbox; args[0] = &ambx; args[1] = NIL; if (imap_OK (stream,reply = imap_send (stream,"GETQUOTAROOT",args))) ret = LONGT; else mm_log (reply->text,ERROR); } else mm_log ("Quota not available on this IMAP server",ERROR); return ret; } /* Internal routines */ /* IMAP send command * Accepts: MAIL stream * command * argument list * Returns: parsed reply */ #define CMDBASE LOCAL->tmp /* command base */ IMAPPARSEDREPLY *imap_send (MAILSTREAM *stream,char *cmd,IMAPARG *args[]) { IMAPPARSEDREPLY *reply; IMAPARG *arg,**arglst; SORTPGM *spg; STRINGLIST *list; SIZEDTEXT st; APPENDDATA *map; sendcommand_t sc = (sendcommand_t) mail_parameters (NIL,GET_SENDCOMMAND,NIL); size_t i; void *a; char c,*s,*t,tag[10]; stream->unhealthy = NIL; /* make stream healthy again */ /* gensym a new tag */ sprintf (tag,"%08lx",0xffffffff & (stream->gensym++)); if (!LOCAL->netstream) /* make sure have a session */ return imap_fake (stream,tag,"[CLOSED] IMAP connection lost"); mail_lock (stream); /* lock up the stream */ if (sc) /* tell client sending a command */ (*sc) (stream,cmd,((compare_cstring (cmd,"FETCH") && compare_cstring (cmd,"STORE") && compare_cstring (cmd,"SEARCH")) ? NIL : SC_EXPUNGEDEFERRED)); /* ignore referral from previous command */ if (LOCAL->referral) fs_give ((void **) &LOCAL->referral); sprintf (CMDBASE,"%s %s",tag,cmd); s = CMDBASE + strlen (CMDBASE); if (arglst = args) while (arg = *arglst++) { *s++ = ' '; /* delimit argument with space */ switch (arg->type) { case ATOM: /* atom */ for (t = (char *) arg->text; *t; *s++ = *t++); break; case NUMBER: /* number */ sprintf (s,"%lu",(unsigned long) arg->text); s += strlen (s); break; case FLAGS: /* flag list as a single string */ if (*(t = (char *) arg->text) != '(') { *s++ = '('; /* wrap parens around string */ while (*t) *s++ = *t++; *s++ = ')'; /* wrap parens around string */ } else while (*t) *s++ = *t++; break; case ASTRING: /* atom or string, must be literal? */ st.size = strlen ((char *) (st.data = (unsigned char *) arg->text)); if (reply = imap_send_astring (stream,tag,&s,&st,NIL,CMDBASE+MAXCOMMAND)) return reply; break; case LITERAL: /* literal, as a stringstruct */ if (reply = imap_send_literal (stream,tag,&s,arg->text)) return reply; break; case LIST: /* list of strings */ list = (STRINGLIST *) arg->text; c = '('; /* open paren */ do { /* for each list item */ *s++ = c; /* write prefix character */ if (reply = imap_send_astring (stream,tag,&s,&list->text,NIL, CMDBASE+MAXCOMMAND)) return reply; c = ' '; /* prefix character for subsequent strings */ } while (list = list->next); *s++ = ')'; /* close list */ break; case SEARCHPROGRAM: /* search program */ if (reply = imap_send_spgm (stream,tag,CMDBASE,&s,arg->text, CMDBASE+MAXCOMMAND)) return reply; break; case SORTPROGRAM: /* search program */ c = '('; /* open paren */ for (spg = (SORTPGM *) arg->text; spg; spg = spg->next) { *s++ = c; /* write prefix */ if (spg->reverse) for (t = "REVERSE "; *t; *s++ = *t++); switch (spg->function) { case SORTDATE: for (t = "DATE"; *t; *s++ = *t++); break; case SORTARRIVAL: for (t = "ARRIVAL"; *t; *s++ = *t++); break; case SORTFROM: for (t = "FROM"; *t; *s++ = *t++); break; case SORTSUBJECT: for (t = "SUBJECT"; *t; *s++ = *t++); break; case SORTTO: for (t = "TO"; *t; *s++ = *t++); break; case SORTCC: for (t = "CC"; *t; *s++ = *t++); break; case SORTSIZE: for (t = "SIZE"; *t; *s++ = *t++); break; default: fatal ("Unknown sort program function in imap_send()!"); } c = ' '; /* prefix character for subsequent items */ } *s++ = ')'; /* close list */ break; case BODYTEXT: /* body section */ for (t = "BODY["; *t; *s++ = *t++); for (t = (char *) arg->text; *t; *s++ = *t++); break; case BODYPEEK: /* body section */ for (t = "BODY.PEEK["; *t; *s++ = *t++); for (t = (char *) arg->text; *t; *s++ = *t++); break; case BODYCLOSE: /* close bracket and possible length */ s[-1] = ']'; /* no leading space */ for (t = (char *) arg->text; *t; *s++ = *t++); break; case SEQUENCE: /* sequence */ if ((i = strlen (t = (char *) arg->text)) <= (size_t) MAXCOMMAND) while (*t) *s++ = *t++; /* easy case */ else { mail_unlock (stream); /* unlock stream */ a = arg->text; /* save original sequence pointer */ arg->type = ATOM; /* make recursive call be faster */ do { /* break up into multiple commands */ if (i <= MAXCOMMAND) {/* final part? */ reply = imap_send (stream,cmd,args); i = 0; /* and mark as done */ } else { /* still needs to be split further */ if (!(t = strchr (t + MAXCOMMAND - 30,',')) || ((t - (char *) arg->text) > MAXCOMMAND)) fatal ("impossible over-long sequence"); *t = '\0'; /* tie off sequence at point of split*/ /* recurse to do this part */ reply = imap_send (stream,cmd,args); *t++ = ','; /* restore the comma in case something cares */ /* punt if error */ if (!imap_OK (stream,reply)) break; /* calculate size of remaining sequence */ i -= (t - (char *) arg->text); /* point to new remaining sequence */ arg->text = (void *) t; } } while (i); arg->type = SEQUENCE; /* restore in case something cares */ arg->text = a; return reply; /* return result */ } break; case LISTMAILBOX: /* astring with wildcards */ st.size = strlen ((char *) (st.data = (unsigned char *) arg->text)); if (reply = imap_send_astring (stream,tag,&s,&st,T,CMDBASE+MAXCOMMAND)) return reply; break; case MULTIAPPEND: /* append multiple messages */ /* get package pointer */ map = (APPENDDATA *) arg->text; if (!(*map->af) (stream,map->data,&map->flags,&map->date,&map->message)|| !map->message) { STRING es; INIT (&es,mail_string,"",0); return (reply = imap_send_literal (stream,tag,&s,&es)) ? reply : imap_fake (stream,tag,"Server zero-length literal error"); } case MULTIAPPENDREDO: /* redo multiappend */ /* get package pointer */ map = (APPENDDATA *) arg->text; do { /* make sure date valid if given */ char datetmp[MAILTMPLEN]; MESSAGECACHE elt; STRING es; if (!map->date || mail_parse_date (&elt,map->date)) { if (t = map->flags) { /* flags given? */ if (*t != '(') { *s++ = '('; /* wrap parens around string */ while (*t) *s++ = *t++; *s++ = ')'; /* wrap parens around string */ } else while (*t) *s++ = *t++; *s++ = ' '; /* delimit with space */ } if (map->date) { /* date given? */ st.size = strlen ((char *) (st.data = (unsigned char *) mail_date (datetmp,&elt))); if (reply = imap_send_astring (stream,tag,&s,&st,NIL, CMDBASE+MAXCOMMAND)) return reply; *s++ = ' '; /* delimit with space */ } if (reply = imap_send_literal (stream,tag,&s,map->message)) return reply; /* get next message */ if ((*map->af) (stream,map->data,&map->flags,&map->date, &map->message)) { /* have a message, delete next in command */ if (map->message) *s++ = ' '; continue; /* loop back for next message */ } } /* bad date or need to abort */ INIT (&es,mail_string,"",0); return (reply = imap_send_literal (stream,tag,&s,&es)) ? reply : imap_fake (stream,tag,"Server zero-length literal error"); break; /* exit the loop */ } while (map->message); break; case SNLIST: /* list of string/number pairs */ list = (STRINGLIST *) arg->text; c = '('; /* open paren */ do { /* for each list item */ *s++ = c; /* write prefix character */ if (list) { /* sigh, QUOTA has bizarre syntax! */ for (t = (char *) list->text.data; *t; *s++ = *t++); sprintf (s," %lu",list->text.size); s += strlen (s); c = ' '; /* prefix character for subsequent strings */ } } while (list = list->next); *s++ = ')'; /* close list */ break; default: fatal ("Unknown argument type in imap_send()!"); } } /* send the command */ reply = imap_sout (stream,tag,CMDBASE,&s); mail_unlock (stream); /* unlock stream */ return reply; } /* IMAP send atom-string * Accepts: MAIL stream * reply tag * pointer to current position pointer of output bigbuf * atom-string to output * flag if list_wildcards allowed * maximum to write as atom or qstring * Returns: error reply or NIL if success */ IMAPPARSEDREPLY *imap_send_astring (MAILSTREAM *stream,char *tag,char **s, SIZEDTEXT *as,long wildok,char *limit) { unsigned long j; char c; STRING st; /* default to atom unless empty or loser */ int qflag = (as->size && !LOCAL->loser) ? NIL : T; /* in case needed */ INIT (&st,mail_string,(void *) as->data,as->size); /* always write literal if no space */ if ((*s + as->size) > limit) return imap_send_literal (stream,tag,s,&st); for (j = 0; j < as->size; j++) switch (c = as->data[j]) { default: /* all other characters */ if (!(c & 0x80)) { /* must not be 8bit */ if (c <= ' ') qflag = T; /* must quote if a CTL */ break; } case '\0': /* not a CHAR */ case '\012': case '\015': /* not a TEXT-CHAR */ case '"': case '\\': /* quoted-specials (IMAP2 required this) */ return imap_send_literal (stream,tag,s,&st); case '*': case '%': /* list_wildcards */ if (wildok) break; /* allowed if doing the wild thing */ /* atom_specials */ case '(': case ')': case '{': case ' ': case 0x7f: #if 0 case '"': case '\\': /* quoted-specials (could work in IMAP4) */ #endif qflag = T; /* must use quoted string format */ break; } if (qflag) *(*s)++ = '"'; /* write open quote */ for (j = 0; j < as->size; j++) *(*s)++ = as->data[j]; if (qflag) *(*s)++ = '"'; /* write close quote */ return NIL; } /* IMAP send literal * Accepts: MAIL stream * reply tag * pointer to current position pointer of output bigbuf * literal to output as stringstruct * Returns: error reply or NIL if success */ IMAPPARSEDREPLY *imap_send_literal (MAILSTREAM *stream,char *tag,char **s, STRING *st) { IMAPPARSEDREPLY *reply; unsigned long i = SIZE (st); unsigned long j; sprintf (*s,"{%lu}",i); /* write literal count */ *s += strlen (*s); /* size of literal count */ /* send the command */ reply = imap_sout (stream,tag,CMDBASE,s); if (strcmp (reply->tag,"+")) {/* prompt for more data? */ mail_unlock (stream); /* no, give up */ return reply; } while (i) { /* dump the text */ if (st->cursize) { /* if text to do in this chunk */ /* RFC 3501 technically forbids NULs in literals. Normally, the * delivering MTA would take care of MIME converting the message text * so that it is NUL-free. If it doesn't, then we have the choice of * either violating IMAP by sending NULs, corrupting the data, or going * to lots of work to do MIME conversion in the IMAP server. * * No current stringstruct driver objects to having its buffer patched. * If this ever changes, it will be necessary to change this kludge. */ /* patch NULs to C1 control */ for (j = 0; j < st->cursize; ++j) if (!st->curpos[j]) st->curpos[j] = 0x80; if (!net_sout (LOCAL->netstream,st->curpos,st->cursize)) { mail_unlock (stream); return imap_fake (stream,tag,"[CLOSED] IMAP connection broken (data)"); } i -= st->cursize; /* note that we wrote out this much */ st->curpos += (st->cursize - 1); st->cursize = 0; } (*st->dtb->next) (st); /* advance to next buffer's worth */ } return NIL; /* success */ } /* IMAP send search program * Accepts: MAIL stream * reply tag * base pointer if trimming needed * pointer to current position pointer of output bigbuf * search program to output * pointer to limit guideline * Returns: error reply or NIL if success */ IMAPPARSEDREPLY *imap_send_spgm (MAILSTREAM *stream,char *tag,char *base, char **s,SEARCHPGM *pgm,char *limit) { IMAPPARSEDREPLY *reply; SEARCHHEADER *hdr; SEARCHOR *pgo; SEARCHPGMLIST *pgl; char *t; /* trim if called recursively */ if (base) *s = imap_send_spgm_trim (base,*s,NIL); base = *s; /* this is the new base */ /* default searchpgm */ for (t = "ALL"; *t; *(*s)++ = *t++); if (!pgm) return NIL; /* done if NIL searchpgm */ if ((pgm->msgno && /* message sequences */ (pgm->msgno->next || /* trim away first:last */ (pgm->msgno->first != 1) || (pgm->msgno->last != stream->nmsgs)) && (reply = imap_send_sset (stream,tag,base,s,pgm->msgno," ",limit))) || (pgm->uid && (reply = imap_send_sset (stream,tag,base,s,pgm->uid," UID ",limit)))) return reply; /* message sizes */ if (pgm->larger) { sprintf (*s," LARGER %lu",pgm->larger); *s += strlen (*s); } if (pgm->smaller) { sprintf (*s," SMALLER %lu",pgm->smaller); *s += strlen (*s); } /* message flags */ if (pgm->answered) for (t = " ANSWERED"; *t; *(*s)++ = *t++); if (pgm->unanswered) for (t =" UNANSWERED"; *t; *(*s)++ = *t++); if (pgm->deleted) for (t =" DELETED"; *t; *(*s)++ = *t++); if (pgm->undeleted) for (t =" UNDELETED"; *t; *(*s)++ = *t++); if (pgm->draft) for (t =" DRAFT"; *t; *(*s)++ = *t++); if (pgm->undraft) for (t =" UNDRAFT"; *t; *(*s)++ = *t++); if (pgm->flagged) for (t =" FLAGGED"; *t; *(*s)++ = *t++); if (pgm->unflagged) for (t =" UNFLAGGED"; *t; *(*s)++ = *t++); if (pgm->recent) for (t =" RECENT"; *t; *(*s)++ = *t++); if (pgm->old) for (t =" OLD"; *t; *(*s)++ = *t++); if (pgm->seen) for (t =" SEEN"; *t; *(*s)++ = *t++); if (pgm->unseen) for (t =" UNSEEN"; *t; *(*s)++ = *t++); if ((pgm->keyword && /* keywords */ (reply = imap_send_slist (stream,tag,base,s," KEYWORD ",pgm->keyword, limit))) || (pgm->unkeyword && (reply = imap_send_slist (stream,tag,base,s," UNKEYWORD ", pgm->unkeyword,limit)))) return reply; /* sent date ranges */ if (pgm->sentbefore) imap_send_sdate (s,"SENTBEFORE",pgm->sentbefore); if (pgm->senton) imap_send_sdate (s,"SENTON",pgm->senton); if (pgm->sentsince) imap_send_sdate (s,"SENTSINCE",pgm->sentsince); /* internal date ranges */ if (pgm->before) imap_send_sdate (s,"BEFORE",pgm->before); if (pgm->on) imap_send_sdate (s,"ON",pgm->on); if (pgm->since) imap_send_sdate (s,"SINCE",pgm->since); if (pgm->older) { sprintf (*s," OLDER %lu",pgm->older); *s += strlen (*s); } if (pgm->younger) { sprintf (*s," YOUNGER %lu",pgm->younger); *s += strlen (*s); } /* search texts */ if ((pgm->bcc && (reply = imap_send_slist (stream,tag,base,s," BCC ", pgm->bcc,limit))) || (pgm->cc && (reply = imap_send_slist (stream,tag,base,s," CC ",pgm->cc, limit))) || (pgm->from && (reply = imap_send_slist (stream,tag,base,s," FROM ", pgm->from,limit))) || (pgm->to && (reply = imap_send_slist (stream,tag,base,s," TO ",pgm->to, limit)))) return reply; if ((pgm->subject && (reply = imap_send_slist (stream,tag,base,s," SUBJECT ", pgm->subject,limit))) || (pgm->body && (reply = imap_send_slist (stream,tag,base,s," BODY ", pgm->body,limit))) || (pgm->text && (reply = imap_send_slist (stream,tag,base,s," TEXT ", pgm->text,limit)))) return reply; /* Note that these criteria are not supported by IMAP and have to be emulated */ if ((pgm->return_path && (reply = imap_send_slist (stream,tag,base,s," HEADER Return-Path ", pgm->return_path,limit))) || (pgm->sender && (reply = imap_send_slist (stream,tag,base,s," HEADER Sender ", pgm->sender,limit))) || (pgm->reply_to && (reply = imap_send_slist (stream,tag,base,s," HEADER Reply-To ", pgm->reply_to,limit))) || (pgm->in_reply_to && (reply = imap_send_slist (stream,tag,base,s," HEADER In-Reply-To ", pgm->in_reply_to,limit))) || (pgm->message_id && (reply = imap_send_slist (stream,tag,base,s," HEADER Message-ID ", pgm->message_id,limit))) || (pgm->newsgroups && (reply = imap_send_slist (stream,tag,base,s," HEADER Newsgroups ", pgm->newsgroups,limit))) || (pgm->followup_to && (reply = imap_send_slist (stream,tag,base,s," HEADER Followup-To ", pgm->followup_to,limit))) || (pgm->references && (reply = imap_send_slist (stream,tag,base,s," HEADER References ", pgm->references,limit)))) return reply; /* all other headers */ if (hdr = pgm->header) do { *s = imap_send_spgm_trim (base,*s," HEADER "); if (reply = imap_send_astring (stream,tag,s,&hdr->line,NIL,limit)) return reply; *(*s)++ = ' '; if (reply = imap_send_astring (stream,tag,s,&hdr->text,NIL,limit)) return reply; } while (hdr = hdr->next); for (pgo = pgm->or; pgo; pgo = pgo->next) { *s = imap_send_spgm_trim (base,*s," OR ("); if (reply = imap_send_spgm (stream,tag,base,s,pgo->first,limit)) return reply; for (t = ") ("; *t; *(*s)++ = *t++); if (reply = imap_send_spgm (stream,tag,base,s,pgo->second,limit)) return reply; *(*s)++ = ')'; } for (pgl = pgm->not; pgl; pgl = pgl->next) { *s = imap_send_spgm_trim (base,*s," NOT ("); if (reply = imap_send_spgm (stream,tag,base,s,pgl->pgm,limit)) return reply; *(*s)++ = ')'; } /* trim if needed */ *s = imap_send_spgm_trim (base,*s,NIL); return NIL; /* search program written OK */ } /* Write new text and trim extraneous "ALL" from searchpgm * Accepts: pointer to start of searchpgm or NIL * current end pointer * new text to write or NIL * Returns: new end pointer, trimmed if needed */ char *imap_send_spgm_trim (char *base,char *s,char *text) { char *t; /* write new text */ if (text) for (t = text; *t; *s++ = *t++); /* need to trim? */ if (base && (s > (t = (base + 4))) && (*base == 'A') && (base[1] == 'L') && (base[2] == 'L') && (base[3] == ' ')) { memmove (base,t,s - t); /* yes, blat down remaining text */ s -= 4; /* and reduce current pointer */ } return s; /* return new end pointer */ } /* IMAP send search set * Accepts: MAIL stream * current command tag * base pointer if trimming needed * pointer to current position pointer of output bigbuf * search set to output * message prefix * maximum output pointer * Returns: NIL if success, error reply if error */ IMAPPARSEDREPLY *imap_send_sset (MAILSTREAM *stream,char *tag,char *base, char **s,SEARCHSET *set,char *prefix, char *limit) { IMAPPARSEDREPLY *reply; STRING st; char c,*t; char *start = *s; /* trim and write prefix */ *s = imap_send_spgm_trim (base,*s,prefix); /* run down search list */ for (c = NIL; set && (*s < limit); set = set->next, c = ',') { if (c) *(*s)++ = c; /* write delimiter and first value */ if (set->first == 0xffffffff) *(*s)++ = '*'; else { sprintf (*s,"%lu",set->first); *s += strlen (*s); } /* have a second value? */ if (set->last && (set->first != set->last)) { *(*s)++ = ':'; /* write delimiter and second value */ if (set->last == 0xffffffff) *(*s)++ = '*'; else { sprintf (*s,"%lu",set->last); *s += strlen (*s); } } } if (set) { /* insert "OR" in front of incomplete set */ memmove (start + 3,start,*s - start); memcpy (start," OR",3); *s += 3; /* point to end of buffer */ /* write glue that is equivalent to ALL */ for (t =" ((OR BCC FOO NOT BCC "; *t; *(*s)++ = *t++); /* but broken by a literal */ INIT (&st,mail_string,(void *) "FOO",3); if (reply = imap_send_literal (stream,tag,s,&st)) return reply; *(*s)++ = ')'; /* close glue */ if (reply = imap_send_sset (stream,tag,NIL,s,set,prefix,limit)) return reply; *(*s)++ = ')'; /* close second OR argument */ } return NIL; } /* IMAP send search list * Accepts: MAIL stream * reply tag * base pointer if trimming needed * pointer to current position pointer of output bigbuf * name of search list * search list to output * maximum output pointer * Returns: NIL if success, error reply if error */ IMAPPARSEDREPLY *imap_send_slist (MAILSTREAM *stream,char *tag,char *base, char **s,char *name,STRINGLIST *list, char *limit) { IMAPPARSEDREPLY *reply; do { *s = imap_send_spgm_trim (base,*s,name); base = NIL; /* no longer need trimming */ reply = imap_send_astring (stream,tag,s,&list->text,NIL,limit); } while (!reply && (list = list->next)); return reply; } /* IMAP send search date * Accepts: pointer to current position pointer of output bigbuf * field name * search date to output */ void imap_send_sdate (char **s,char *name,unsigned short date) { sprintf (*s," %s %d-%s-%d",name,date & 0x1f, months[((date >> 5) & 0xf) - 1],BASEYEAR + (date >> 9)); *s += strlen (*s); } /* IMAP send buffered command to sender * Accepts: MAIL stream * reply tag * string * pointer to string tail pointer * Returns: reply */ IMAPPARSEDREPLY *imap_sout (MAILSTREAM *stream,char *tag,char *base,char **s) { IMAPPARSEDREPLY *reply; if (stream->debug) { /* output debugging telemetry */ **s = '\0'; mail_dlog (base,LOCAL->sensitive); } *(*s)++ = '\015'; /* append CRLF */ *(*s)++ = '\012'; **s = '\0'; reply = net_sout (LOCAL->netstream,base,*s - base) ? imap_reply (stream,tag) : imap_fake (stream,tag,"[CLOSED] IMAP connection broken (command)"); *s = base; /* restart buffer */ return reply; } /* IMAP send null-terminated string to sender * Accepts: MAIL stream * string * Returns: T if success, else NIL */ long imap_soutr (MAILSTREAM *stream,char *string) { long ret; unsigned long i; char *s; if (stream->debug) mm_dlog (string); sprintf (s = (char *) fs_get ((i = strlen (string) + 2) + 1), "%s\015\012",string); ret = net_sout (LOCAL->netstream,s,i); fs_give ((void **) &s); return ret; } /* IMAP get reply * Accepts: MAIL stream * tag to search or NIL if want a greeting * Returns: parsed reply, never NIL */ IMAPPARSEDREPLY *imap_reply (MAILSTREAM *stream,char *tag) { IMAPPARSEDREPLY *reply; while (LOCAL->netstream) { /* parse reply from server */ if (reply = imap_parse_reply (stream,net_getline (LOCAL->netstream))) { /* continuation ready? */ if (!strcmp (reply->tag,"+")) return reply; /* untagged data? */ else if (!strcmp (reply->tag,"*")) { imap_parse_unsolicited (stream,reply); if (!tag) return reply; /* return if just wanted greeting */ } else { /* tagged data */ if (tag && !compare_cstring (tag,reply->tag)) return reply; /* report bogon */ sprintf (LOCAL->tmp,"Unexpected tagged response: %.80s %.80s %.80s", (char *) reply->tag,(char *) reply->key,(char *) reply->text); mm_notify (stream,LOCAL->tmp,WARN); stream->unhealthy = T; } } } return imap_fake (stream,tag, "[CLOSED] IMAP connection broken (server response)"); } /* IMAP parse reply * Accepts: MAIL stream * text of reply * Returns: parsed reply, or NIL if can't parse at least a tag and key */ IMAPPARSEDREPLY *imap_parse_reply (MAILSTREAM *stream,char *text) { char *r; if (LOCAL->reply.line) fs_give ((void **) &LOCAL->reply.line); /* init fields in case error */ LOCAL->reply.key = LOCAL->reply.text = LOCAL->reply.tag = NIL; if (!(LOCAL->reply.line = text)) { /* NIL text means the stream died */ if (LOCAL->netstream) net_close (LOCAL->netstream); LOCAL->netstream = NIL; return NIL; } if (stream->debug) mm_dlog (LOCAL->reply.line); if (!(LOCAL->reply.tag = strtok_r (LOCAL->reply.line," ",&r))) { mm_notify (stream,"IMAP server sent a blank line",WARN); stream->unhealthy = T; return NIL; } /* non-continuation replies */ if (strcmp (LOCAL->reply.tag,"+")) { /* parse key */ if (!(LOCAL->reply.key = strtok_r (NIL," ",&r))) { /* determine what is missing */ sprintf (LOCAL->tmp,"Missing IMAP reply key: %.80s", (char *) LOCAL->reply.tag); mm_notify (stream,LOCAL->tmp,WARN); stream->unhealthy = T; return NIL; /* can't parse this text */ } ucase (LOCAL->reply.key); /* canonicalize key to upper */ /* get text as well, allow empty text */ if (!(LOCAL->reply.text = strtok_r (NIL,"\n",&r))) LOCAL->reply.text = LOCAL->reply.key + strlen (LOCAL->reply.key); } else { /* special handling of continuation */ LOCAL->reply.key = "BAD"; /* so it barfs if not expecting continuation */ if (!(LOCAL->reply.text = strtok_r (NIL,"\n",&r))) LOCAL->reply.text = ""; } return &LOCAL->reply; /* return parsed reply */ } /* IMAP fake reply when stream determined to be dead * Accepts: MAIL stream * tag * text of fake reply (must start with "[CLOSED]") * Returns: parsed reply */ IMAPPARSEDREPLY *imap_fake (MAILSTREAM *stream,char *tag,char *text) { mm_notify (stream,text,BYE); /* send bye alert */ if (LOCAL->netstream) net_close (LOCAL->netstream); LOCAL->netstream = NIL; /* farewell, dear NET stream... */ /* flush previous reply */ if (LOCAL->reply.line) fs_give ((void **) &LOCAL->reply.line); /* build new fake reply */ LOCAL->reply.tag = LOCAL->reply.line = cpystr (tag ? tag : "*"); LOCAL->reply.key = "NO"; LOCAL->reply.text = text; return &LOCAL->reply; /* return parsed reply */ } /* IMAP check for OK response in tagged reply * Accepts: MAIL stream * parsed reply * Returns: T if OK else NIL */ long imap_OK (MAILSTREAM *stream,IMAPPARSEDREPLY *reply) { long ret = NIL; /* OK - operation succeeded */ if (!strcmp (reply->key,"OK")) { imap_parse_response (stream,reply->text,NIL,NIL); ret = T; } /* NO - operation failed */ else if (!strcmp (reply->key,"NO")) imap_parse_response (stream,reply->text,WARN,NIL); else { /* BAD - operation rejected */ if (!strcmp (reply->key,"BAD")) { imap_parse_response (stream,reply->text,ERROR,NIL); sprintf (LOCAL->tmp,"IMAP protocol error: %.80s",(char *) reply->text); } /* bad protocol received */ else sprintf (LOCAL->tmp,"Unexpected IMAP response: %.80s %.80s", (char *) reply->key,(char *) reply->text); mm_log (LOCAL->tmp,ERROR); /* either way, this is not good */ } return ret; } /* IMAP parse and act upon unsolicited reply * Accepts: MAIL stream * parsed reply */ void imap_parse_unsolicited (MAILSTREAM *stream,IMAPPARSEDREPLY *reply) { unsigned long i = 0; unsigned long j,msgno; unsigned char *s,*t; char *r; /* see if key is a number */ if (isdigit (*reply->key)) { msgno = strtoul (reply->key,(char **) &s,10); if (*s) { /* better be nothing after number */ sprintf (LOCAL->tmp,"Unexpected untagged message: %.80s", (char *) reply->key); mm_notify (stream,LOCAL->tmp,WARN); stream->unhealthy = T; return; } if (!reply->text) { /* better be some data */ mm_notify (stream,"Missing message data",WARN); stream->unhealthy = T; return; } /* get message data type, canonicalize upper */ s = ucase (strtok_r (reply->text," ",&r)); /* and locate the text after it */ t = strtok_r (NIL,"\n",&r); /* now take the action */ /* change in size of mailbox */ if (!strcmp (s,"EXISTS") && (msgno >= stream->nmsgs)) mail_exists (stream,msgno); else if (!strcmp (s,"RECENT") && (msgno <= stream->nmsgs)) mail_recent (stream,msgno); else if (!strcmp (s,"EXPUNGE") && msgno && (msgno <= stream->nmsgs)) { mailcache_t mc = (mailcache_t) mail_parameters (NIL,GET_CACHE,NIL); MESSAGECACHE *elt = (MESSAGECACHE *) (*mc) (stream,msgno,CH_ELT); if (elt) imap_gc_body (elt->private.msg.body); /* notify upper level */ mail_expunged (stream,msgno); } else if ((!strcmp (s,"FETCH") || !strcmp (s,"STORE")) && msgno && (msgno <= stream->nmsgs)) { char *prop; GETS_DATA md; ENVELOPE **e; MESSAGECACHE *elt = mail_elt (stream,msgno); ENVELOPE *env = NIL; imapenvelope_t ie = (imapenvelope_t) mail_parameters (stream,GET_IMAPENVELOPE,NIL); ++t; /* skip past open parenthesis */ /* parse Lisp-form property list */ while (prop = (strtok_r (t," )",&r))) { t = strtok_r (NIL,"\n",&r); INIT_GETS (md,stream,elt->msgno,NIL,0,0); e = NIL; /* not pointing at any envelope yet */ /* canonicalize property, parse it */ if (!strcmp (ucase (prop),"FLAGS")) imap_parse_flags (stream,elt,&t); else if (!strcmp (prop,"INTERNALDATE") && (s = imap_parse_string (stream,&t,reply,NIL,NIL,LONGT))) { if (!mail_parse_date (elt,s)) { sprintf (LOCAL->tmp,"Bogus date: %.80s",(char *) s); mm_notify (stream,LOCAL->tmp,WARN); stream->unhealthy = T; /* slam in default so we don't try again */ mail_parse_date (elt,"01-Jan-1970 00:00:00 +0000"); } fs_give ((void **) &s); } /* unique identifier */ else if (!strcmp (prop,"UID")) { LOCAL->lastuid.uid = elt->private.uid = strtoul (t,(char **) &t,10); LOCAL->lastuid.msgno = elt->msgno; } else if (!strcmp (prop,"ENVELOPE")) { if (stream->scache) { /* short cache, flush old stuff */ mail_free_body (&stream->body); stream->msgno = elt->msgno; e = &stream->env; /* get pointer to envelope */ } else e = &elt->private.msg.env; imap_parse_envelope (stream,e,&t,reply); } else if (!strncmp (prop,"BODY",4)) { if (!prop[4] || !strcmp (prop+4,"STRUCTURE")) { BODY **body; if (stream->scache){/* short cache, flush old stuff */ if (stream->msgno != msgno) { mail_free_envelope (&stream->env); sprintf (LOCAL->tmp,"Body received for %lu but current is %lu", msgno,stream->msgno); stream->msgno = msgno; } /* get pointer to body */ body = &stream->body; } else body = &elt->private.msg.body; /* flush any prior body */ mail_free_body (body); /* instantiate and parse a new body */ imap_parse_body_structure (stream,*body = mail_newbody(),&t,reply); } else if (prop[4] == '[') { STRINGLIST *stl = NIL; SIZEDTEXT text; /* will want to return envelope data */ if (!strcmp (md.what = cpystr (prop + 5),"HEADER]") || !strcmp (md.what,"0]")) e = stream->scache ? &stream->env : &elt->private.msg.env; LOCAL->tmp[0] ='\0';/* no errors yet */ /* found end of section? */ if (!(s = strchr (md.what,']'))) { /* skip leading nesting */ for (s = md.what; *s && (isdigit (*s) || (*s == '.')); s++); /* better be one of these */ if (strncmp (s,"HEADER.FIELDS",13) && (!s[13] || strcmp (s+13,".NOT"))) sprintf (LOCAL->tmp,"Unterminated section: %.80s",md.what); /* get list of headers */ else if (!(stl = imap_parse_stringlist (stream,&t,reply))) sprintf (LOCAL->tmp,"Bogus header field list: %.80s", (char *) t); else if (*t != ']') sprintf (LOCAL->tmp,"Unterminated header section: %.80s", (char *) t); /* point after the text */ else if (t = strchr (s = t,' ')) *t++ = '\0'; } if (s && !LOCAL->tmp[0]) { *s++ = '\0'; /* tie off section specifier */ if (*s == '<') { /* partial specifier? */ md.first = strtoul (s+1,(char **) &s,10) + 1; if (*s++ != '>') /* make sure properly terminated */ sprintf (LOCAL->tmp,"Unterminated partial data: %.80s", (char *) s-1); } if (!LOCAL->tmp[0] && *s) sprintf (LOCAL->tmp,"Junk after section: %.80s",(char *) s); } if (LOCAL->tmp[0]) { /* got any errors? */ mm_notify (stream,LOCAL->tmp,WARN); stream->unhealthy = T; mail_free_stringlist (&stl); } else { /* parse text from server */ text.data = (unsigned char *) imap_parse_string (stream,&t,reply, ((md.what[0] && (md.what[0] != 'H')) || md.first || md.last) ? &md : NIL, &text.size,NIL); /* all done if partial */ if (md.first || md.last) mail_free_stringlist (&stl); /* otherwise register it in the cache */ else imap_cache (stream,msgno,md.what,stl,&text); } fs_give ((void **) &md.what); } else { sprintf (LOCAL->tmp,"Unknown body message property: %.80s",prop); mm_notify (stream,LOCAL->tmp,WARN); stream->unhealthy = T; } } /* one of the RFC822 props? */ else if (!strncmp (prop,"RFC822",6) && (!prop[6] || (prop[6] == '.'))){ SIZEDTEXT text; if (!prop[6]) { /* cache full message */ md.what = ""; text.data = (unsigned char *) imap_parse_string (stream,&t,reply,&md,&text.size,NIL); imap_cache (stream,msgno,md.what,NIL,&text); } else if (!strcmp (prop+7,"SIZE")) elt->rfc822_size = strtoul (t,(char **) &t,10); /* legacy properties */ else if (!strcmp (prop+7,"HEADER")) { text.data = (unsigned char *) imap_parse_string (stream,&t,reply,NIL,&text.size,NIL); imap_cache (stream,msgno,"HEADER",NIL,&text); e = stream->scache ? &stream->env : &elt->private.msg.env; } else if (!strcmp (prop+7,"TEXT")) { md.what = "TEXT"; text.data = (unsigned char *) imap_parse_string (stream,&t,reply,&md,&text.size,NIL); imap_cache (stream,msgno,md.what,NIL,&text); } else { sprintf (LOCAL->tmp,"Unknown RFC822 message property: %.80s",prop); mm_notify (stream,LOCAL->tmp,WARN); stream->unhealthy = T; } } else { sprintf (LOCAL->tmp,"Unknown message property: %.80s",prop); mm_notify (stream,LOCAL->tmp,WARN); stream->unhealthy = T; } if (e && *e) env = *e; /* note envelope if we got one */ } /* do callback if requested */ if (ie && env) (*ie) (stream,msgno,env); } /* obsolete response to COPY */ else if (strcmp (s,"COPY")) { sprintf (LOCAL->tmp,"Unknown message data: %lu %.80s",msgno,(char *) s); mm_notify (stream,LOCAL->tmp,WARN); stream->unhealthy = T; } } else if (!strcmp (reply->key,"FLAGS") && reply->text && (*reply->text == '(') && (s = strtok_r (reply->text+1," )",&r))) do if (*s != '\\') { for (i = 0; (i < NUSERFLAGS) && stream->user_flags[i] && compare_cstring (s,stream->user_flags[i]); i++); if (i > NUSERFLAGS) { sprintf (LOCAL->tmp,"Too many server flags, discarding: %.80s", (char *) s); mm_notify (stream,LOCAL->tmp,WARN); } else if (!stream->user_flags[i]) stream->user_flags[i++] = cpystr (s); } while (s = strtok_r (NIL," )",&r)); else if (!strcmp (reply->key,"SEARCH")) { /* only do something if have text */ if (reply->text && (t = strtok_r (reply->text," ",&r))) do if (i = strtoul (t,NIL,10)) { /* UIDs always passed to main program */ if (LOCAL->uidsearch) mm_searched (stream,i); /* should be a msgno then */ else if ((i <= stream->nmsgs) && (!LOCAL->filter || mail_elt (stream,i)->private.filter)) { mail_elt (stream,i)->searched = T; if (!stream->silent) mm_searched (stream,i); } } while (t = strtok_r (NIL," ",&r)); } else if (!strcmp (reply->key,"SORT")) { sortresults_t sr = (sortresults_t) mail_parameters (NIL,GET_SORTRESULTS,NIL); LOCAL->sortsize = 0; /* initialize sort data */ if (LOCAL->sortdata) fs_give ((void **) &LOCAL->sortdata); LOCAL->sortdata = (unsigned long *) fs_get ((stream->nmsgs + 1) * sizeof (unsigned long)); /* only do something if have text */ if (reply->text && (t = strtok_r (reply->text," ",&r))) { do if ((i = atol (t)) && (LOCAL->filter ? mail_elt (stream,i)->searched : T)) LOCAL->sortdata[LOCAL->sortsize++] = i; while ((t = strtok_r (NIL," ",&r)) && (LOCAL->sortsize < stream->nmsgs)); } LOCAL->sortdata[LOCAL->sortsize] = 0; /* also return via callback if requested */ if (sr) (*sr) (stream,LOCAL->sortdata,LOCAL->sortsize); } else if (!strcmp (reply->key,"THREAD")) { threadresults_t tr = (threadresults_t) mail_parameters (NIL,GET_THREADRESULTS,NIL); if (LOCAL->threaddata) mail_free_threadnode (&LOCAL->threaddata); if (s = reply->text) { LOCAL->threaddata = imap_parse_thread (stream,&s); if (tr) (*tr) (stream,LOCAL->threaddata); if (s && *s) { sprintf (LOCAL->tmp,"Junk at end of thread: %.80s",(char *) s); mm_notify (stream,LOCAL->tmp,WARN); stream->unhealthy = T; } } } else if (!strcmp (reply->key,"STATUS") && reply->text) { MAILSTATUS status; unsigned char *txt = reply->text; if ((t = imap_parse_astring (stream,&txt,reply,&j)) && txt && (*txt++ == ' ') && (*txt++ == '(') && (s = strchr (txt,')')) && (s - txt) && !s[1]) { *s = '\0'; /* tie off status data */ /* initialize data block */ status.flags = status.messages = status.recent = status.unseen = status.uidnext = status.uidvalidity = 0; while (*txt && (s = strchr (txt,' '))) { *s++ = '\0'; /* tie off status attribute name */ /* get attribute value */ i = strtoul (s,(char **) &s,10); if (!compare_cstring (txt,"MESSAGES")) { status.flags |= SA_MESSAGES; status.messages = i; } else if (!compare_cstring (txt,"RECENT")) { status.flags |= SA_RECENT; status.recent = i; } else if (!compare_cstring (txt,"UNSEEN")) { status.flags |= SA_UNSEEN; status.unseen = i; } else if (!compare_cstring (txt,"UIDNEXT")) { status.flags |= SA_UIDNEXT; status.uidnext = i; } else if (!compare_cstring (txt,"UIDVALIDITY")) { status.flags |= SA_UIDVALIDITY; status.uidvalidity = i; } /* next attribute */ txt = (*s == ' ') ? s + 1 : s; } if (((i = 1 + strchr (stream->mailbox,'}') - stream->mailbox) + j) < IMAPTMPLEN) { strcpy (strncpy (LOCAL->tmp,stream->mailbox,i) + i,t); /* pass status to main program */ mm_status (stream,LOCAL->tmp,&status); } } if (t) fs_give ((void **) &t); } else if ((!strcmp (reply->key,"LIST") || !strcmp (reply->key,"LSUB")) && reply->text && (*reply->text == '(') && (s = strchr (reply->text,')')) && (s[1] == ' ')) { char delimiter = '\0'; *s++ = '\0'; /* tie off attribute list */ /* parse attribute list */ if (t = strtok_r (reply->text+1," ",&r)) do { if (!compare_cstring (t,"\\NoInferiors")) i |= LATT_NOINFERIORS; else if (!compare_cstring (t,"\\NoSelect")) i |= LATT_NOSELECT; else if (!compare_cstring (t,"\\Marked")) i |= LATT_MARKED; else if (!compare_cstring (t,"\\Unmarked")) i |= LATT_UNMARKED; else if (!compare_cstring (t,"\\HasChildren")) i |= LATT_HASCHILDREN; else if (!compare_cstring (t,"\\HasNoChildren")) i |= LATT_HASNOCHILDREN; /* ignore extension flags */ } while (t = strtok_r (NIL," ",&r)); switch (*++s) { /* process delimiter */ case 'N': /* NIL */ case 'n': s += 4; /* skip over NIL */ break; case '"': /* have a delimiter */ delimiter = (*++s == '\\') ? *++s : *s; s += 3; /* skip over */ } /* parse the mailbox name */ if (t = imap_parse_astring (stream,&s,reply,&j)) { /* prepend prefix if requested */ if (LOCAL->prefix && ((strlen (LOCAL->prefix) + j) < IMAPTMPLEN)) sprintf (s = LOCAL->tmp,"%s%s",LOCAL->prefix,(char *) t); else s = t; /* otherwise just mailbox name */ /* pass data to main program */ if (reply->key[1] == 'S') mm_lsub (stream,delimiter,s,i); else mm_list (stream,delimiter,s,i); fs_give ((void **) &t); /* flush mailbox name */ } } else if (!strcmp (reply->key,"NAMESPACE")) { if (LOCAL->namespace) { mail_free_namespace (&LOCAL->namespace[0]); mail_free_namespace (&LOCAL->namespace[1]); mail_free_namespace (&LOCAL->namespace[2]); } else LOCAL->namespace = (NAMESPACE **) fs_get (3 * sizeof (NAMESPACE *)); if (s = reply->text) { /* parse namespace results */ LOCAL->namespace[0] = imap_parse_namespace (stream,&s,reply); LOCAL->namespace[1] = imap_parse_namespace (stream,&s,reply); LOCAL->namespace[2] = imap_parse_namespace (stream,&s,reply); if (s && *s) { sprintf (LOCAL->tmp,"Junk after namespace list: %.80s",(char *) s); mm_notify (stream,LOCAL->tmp,WARN); stream->unhealthy = T; } } else { mm_notify (stream,"Missing namespace list",WARN); stream->unhealthy = T; } } else if (!strcmp (reply->key,"ACL") && (s = reply->text) && (t = imap_parse_astring (stream,&s,reply,NIL))) { getacl_t ar = (getacl_t) mail_parameters (NIL,GET_ACL,NIL); if (s && (*s++ == ' ')) { ACLLIST *al = mail_newacllist (); ACLLIST *ac = al; do if ((ac->identifier = imap_parse_astring (stream,&s,reply,NIL)) && s && (*s++ == ' ')) ac->rights = imap_parse_astring (stream,&s,reply,NIL); while (ac->rights && s && (*s == ' ') && s++ && (ac = ac->next = mail_newacllist ())); if (!ac->rights || (s && *s)) { sprintf (LOCAL->tmp,"Invalid ACL identifer/rights for %.80s", (char *) t); mm_notify (stream,LOCAL->tmp,WARN); stream->unhealthy = T; } else if (ar) (*ar) (stream,t,al); mail_free_acllist (&al); /* clean up */ } /* no optional rights */ else if (ar) (*ar) (stream,t,NIL); fs_give ((void **) &t); /* free mailbox name */ } else if (!strcmp (reply->key,"LISTRIGHTS") && (s = reply->text) && (t = imap_parse_astring (stream,&s,reply,NIL))) { listrights_t lr = (listrights_t) mail_parameters (NIL,GET_LISTRIGHTS,NIL); char *id,*r; if (s && (*s++ == ' ') && (id = imap_parse_astring (stream,&s,reply,NIL))){ if (s && (*s++ == ' ') && (r = imap_parse_astring (stream,&s,reply,NIL))) { if (s && (*s++ == ' ')) { STRINGLIST *rl = mail_newstringlist (); STRINGLIST *rc = rl; do rc->text.data = (unsigned char *) imap_parse_astring (stream,&s,reply,&rc->text.size); while (rc->text.data && s && (*s == ' ') && s++ && (rc = rc->next = mail_newstringlist ())); if (!rc->text.data || (s && *s)) { sprintf (LOCAL->tmp,"Invalid optional LISTRIGHTS for %.80s", (char *) t); mm_notify (stream,LOCAL->tmp,WARN); stream->unhealthy = T; } else if (lr) (*lr) (stream,t,id,r,rl); /* clean up */ mail_free_stringlist (&rl); } /* no optional rights */ else if (lr) (*lr) (stream,t,id,r,NIL); fs_give ((void **) &r); /* free rights */ } else { sprintf (LOCAL->tmp,"Missing LISTRIGHTS rights for %.80s",(char *) t); mm_notify (stream,LOCAL->tmp,WARN); stream->unhealthy = T; } fs_give ((void **) &id); /* free identifier */ } else { sprintf (LOCAL->tmp,"Missing LISTRIGHTS identifer for %.80s",(char *) t); mm_notify (stream,LOCAL->tmp,WARN); stream->unhealthy = T; } fs_give ((void **) &t); /* free mailbox name */ } else if (!strcmp (reply->key,"MYRIGHTS") && (s = reply->text) && (t = imap_parse_astring (stream,&s,reply,NIL))) { myrights_t mr = (myrights_t) mail_parameters (NIL,GET_MYRIGHTS,NIL); char *r; if (s && (*s++ == ' ') && (r = imap_parse_astring (stream,&s,reply,NIL))) { if (s && *s) { sprintf (LOCAL->tmp,"Junk after MYRIGHTS for %.80s",(char *) t); mm_notify (stream,LOCAL->tmp,WARN); stream->unhealthy = T; } else if (mr) (*mr) (stream,t,r); fs_give ((void **) &r); /* free rights */ } else { sprintf (LOCAL->tmp,"Missing MYRIGHTS for %.80s",(char *) t); mm_notify (stream,LOCAL->tmp,WARN); stream->unhealthy = T; } fs_give ((void **) &t); /* free mailbox name */ } /* this response has a bizarre syntax! */ else if (!strcmp (reply->key,"QUOTA") && (s = reply->text) && (t = imap_parse_astring (stream,&s,reply,NIL))) { /* in case error */ sprintf (LOCAL->tmp,"Bad quota resource list for %.80s",(char *) t); if (s && (*s++ == ' ') && (*s++ == '(') && *s && ((*s != ')') || !s[1])) { quota_t qt = (quota_t) mail_parameters (NIL,GET_QUOTA,NIL); QUOTALIST *ql = NIL; QUOTALIST *qc; /* parse non-empty quota resource list */ if (*s != ')') for (ql = qc = mail_newquotalist (); T; qc = qc->next = mail_newquotalist ()) { if ((qc->name = imap_parse_astring (stream,&s,reply,NIL)) && s && (*s++ == ' ') && (isdigit (*s) || (LOCAL->loser && (*s == '-')))) { if (isdigit (*s)) qc->usage = strtoul (s,(char **) &s,10); else if (t = strchr (s,' ')) t = s; if ((*s++ == ' ') && (isdigit (*s) || (LOCAL->loser &&(*s == '-')))){ if (isdigit (*s)) qc->limit = strtoul (s,(char **) &s,10); else if (t = strpbrk (s," )")) t = s; /* another resource follows? */ if (*s == ' ') continue; /* end of resource list? */ if ((*s == ')') && !s[1]) { if (qt) (*qt) (stream,t,ql); break; /* all done */ } } } /* something bad happened */ mm_notify (stream,LOCAL->tmp,WARN); stream->unhealthy = T; break; /* parse failed */ } /* all done with quota resource list now */ if (ql) mail_free_quotalist (&ql); } else { mm_notify (stream,LOCAL->tmp,WARN); stream->unhealthy = T; } fs_give ((void **) &t); /* free root name */ } else if (!strcmp (reply->key,"QUOTAROOT") && (s = reply->text) && (t = imap_parse_astring (stream,&s,reply,NIL))) { sprintf (LOCAL->tmp,"Bad quota root list for %.80s",(char *) t); if (s && (*s++ == ' ')) { quotaroot_t qr = (quotaroot_t) mail_parameters (NIL,GET_QUOTAROOT,NIL); STRINGLIST *rl = mail_newstringlist (); STRINGLIST *rc = rl; do rc->text.data = (unsigned char *) imap_parse_astring (stream,&s,reply,&rc->text.size); while (rc->text.data && *s && (*s++ == ' ') && (rc = rc->next = mail_newstringlist ())); if (!rc->text.data || (s && *s)) { mm_notify (stream,LOCAL->tmp,WARN); stream->unhealthy = T; } else if (qr) (*qr) (stream,t,rl); /* clean up */ mail_free_stringlist (&rl); } else { mm_notify (stream,LOCAL->tmp,WARN); stream->unhealthy = T; } fs_give ((void **) &t); } else if (!strcmp (reply->key,"OK") || !strcmp (reply->key,"PREAUTH")) imap_parse_response (stream,reply->text,NIL,T); else if (!strcmp (reply->key,"NO")) imap_parse_response (stream,reply->text,WARN,T); else if (!strcmp (reply->key,"BAD")) imap_parse_response (stream,reply->text,ERROR,T); else if (!strcmp (reply->key,"BYE")) { LOCAL->byeseen = T; /* note that a BYE seen */ imap_parse_response (stream,reply->text,BYE,T); } else if (!strcmp (reply->key,"CAPABILITY") && reply->text) imap_parse_capabilities (stream,reply->text); else if (!strcmp (reply->key,"MAILBOX") && reply->text) { if (LOCAL->prefix && ((strlen (LOCAL->prefix) + strlen (reply->text)) < IMAPTMPLEN)) sprintf (t = LOCAL->tmp,"%s%s",LOCAL->prefix,(char *) reply->text); else t = reply->text; mm_list (stream,NIL,t,NIL); } else { sprintf (LOCAL->tmp,"Unexpected untagged message: %.80s", (char *) reply->key); mm_notify (stream,LOCAL->tmp,WARN); stream->unhealthy = T; } } /* Parse human-readable response text * Accepts: mail stream * text * error level for mm_notify() * non-NIL if want mm_notify() event even if no response code */ void imap_parse_response (MAILSTREAM *stream,char *text,long errflg,long ntfy) { char *s,*t,*r; size_t i; unsigned long j; MESSAGECACHE *elt; copyuid_t cu; appenduid_t au; SEARCHSET *source = NIL; SEARCHSET *dest = NIL; if (text && (*text == '[') && (t = strchr (s = text + 1,']')) && ((i = t - s) < IMAPTMPLEN)) { LOCAL->tmp[i] = '\0'; /* make mungable copy of text code */ if (s = strchr (strncpy (t = LOCAL->tmp,s,i),' ')) *s++ = '\0'; if (s) { /* have argument? */ ntfy = NIL; /* suppress mm_notify if normal SELECT data */ if (!compare_cstring (t,"UIDVALIDITY") && ((j = strtoul (s,NIL,10)) != stream->uid_validity)) { mailcache_t mc = (mailcache_t) mail_parameters (NIL,GET_CACHE,NIL); stream->uid_validity = j; /* purge any UIDs in cache */ for (j = 1; j <= stream->nmsgs; j++) if (elt = (MESSAGECACHE *) (*mc) (stream,j,CH_ELT)) elt->private.uid = 0; } else if (!compare_cstring (t,"UIDNEXT")) stream->uid_last = strtoul (s,NIL,10) - 1; else if (!compare_cstring (t,"PERMANENTFLAGS") && (*s == '(') && (t[i-1] == ')')) { t[i-1] = '\0'; /* tie off flags */ stream->perm_seen = stream->perm_deleted = stream->perm_answered = stream->perm_draft = stream->kwd_create = NIL; stream->perm_user_flags = NIL; if (s = strtok_r (s+1," ",&r)) do { if (*s == '\\') { /* system flags */ if (!compare_cstring (s,"\\Seen")) stream->perm_seen = T; else if (!compare_cstring (s,"\\Deleted")) stream->perm_deleted = T; else if (!compare_cstring (s,"\\Flagged")) stream->perm_flagged = T; else if (!compare_cstring (s,"\\Answered")) stream->perm_answered = T; else if (!compare_cstring (s,"\\Draft")) stream->perm_draft = T; else if (!strcmp (s,"\\*")) stream->kwd_create = T; } else stream->perm_user_flags |= imap_parse_user_flag (stream,s); } while (s = strtok_r (NIL," ",&r)); } else if (!compare_cstring (t,"CAPABILITY")) imap_parse_capabilities (stream,s); else if ((j = LEVELUIDPLUS (stream) && LOCAL->appendmailbox) && !compare_cstring (t,"COPYUID") && (cu = (copyuid_t) mail_parameters (NIL,GET_COPYUID,NIL)) && isdigit (*s) && (j = strtoul (s,&s,10)) && (*s++ == ' ') && (source = mail_parse_set (s,&s)) && (*s++ == ' ') && (dest = mail_parse_set (s,&s)) && !*s) (*cu) (stream,LOCAL->appendmailbox,j,source,dest); else if (j && !compare_cstring (t,"APPENDUID") && (au = (appenduid_t) mail_parameters (NIL,GET_APPENDUID,NIL)) && isdigit (*s) && (j = strtoul (s,&s,10)) && (*s++ == ' ') && (dest = mail_parse_set (s,&s)) && !*s) (*au) (LOCAL->appendmailbox,j,dest); else { /* all other response code events */ ntfy = T; /* must mm_notify() */ if (!compare_cstring (t,"REFERRAL")) LOCAL->referral = cpystr (t + 9); } mail_free_searchset (&source); mail_free_searchset (&dest); } else { /* no arguments */ if (!compare_cstring (t,"UIDNOTSTICKY")) { ntfy = NIL; stream->uid_nosticky = T; } else if (!compare_cstring (t,"READ-ONLY")) stream->rdonly = T; else if (!compare_cstring (t,"READ-WRITE")) stream->rdonly = NIL; else if (!compare_cstring (t,"PARSE") && !errflg) errflg = PARSE; } } /* give event to main program */ if (ntfy && !stream->silent) mm_notify (stream,text ? text : "",errflg); } /* Parse a namespace * Accepts: mail stream * current text pointer * parsed reply * Returns: namespace list, text pointer updated */ NAMESPACE *imap_parse_namespace (MAILSTREAM *stream,unsigned char **txtptr, IMAPPARSEDREPLY *reply) { NAMESPACE *ret = NIL; NAMESPACE *nam = NIL; NAMESPACE *prev = NIL; PARAMETER *par = NIL; if (*txtptr) { /* only if argument given */ /* ignore leading space */ while (**txtptr == ' ') ++*txtptr; switch (**txtptr) { case 'N': /* if NIL */ case 'n': ++*txtptr; /* bump past "N" */ ++*txtptr; /* bump past "I" */ ++*txtptr; /* bump past "L" */ break; case '(': ++*txtptr; /* skip past open paren */ while (**txtptr == '(') { ++*txtptr; /* skip past open paren */ prev = nam; /* note previous if any */ nam = (NAMESPACE *) memset (fs_get (sizeof (NAMESPACE)),0, sizeof (NAMESPACE)); if (!ret) ret = nam; /* if first time note first namespace */ /* if previous link new block to it */ if (prev) prev->next = nam; nam->name = imap_parse_string (stream,txtptr,reply,NIL,NIL,NIL); /* ignore whitespace */ while (**txtptr == ' ') ++*txtptr; switch (**txtptr) { /* parse delimiter */ case 'N': case 'n': *txtptr += 3; /* bump past "NIL" */ break; case '"': if (*++*txtptr == '\\') nam->delimiter = *++*txtptr; else nam->delimiter = **txtptr; *txtptr += 2; /* bump past character and closing quote */ break; default: sprintf (LOCAL->tmp,"Missing delimiter in namespace: %.80s", (char *) *txtptr); mm_notify (stream,LOCAL->tmp,WARN); stream->unhealthy = T; *txtptr = NIL; /* stop parse */ return ret; } while (**txtptr == ' '){/* append new parameter to tail */ if (nam->param) par = par->next = mail_newbody_parameter (); else nam->param = par = mail_newbody_parameter (); if (!(par->attribute = imap_parse_string (stream,txtptr,reply,NIL, NIL,NIL))) { mm_notify (stream,"Missing namespace extension attribute",WARN); stream->unhealthy = T; par->attribute = cpystr ("UNKNOWN"); } /* skip space */ while (**txtptr == ' ') ++*txtptr; if (**txtptr == '(') {/* have value list? */ char *att = par->attribute; ++*txtptr; /* yes */ do { /* parse each value */ if (!(par->value = imap_parse_string (stream,txtptr,reply,NIL, NIL,LONGT))) { sprintf (LOCAL->tmp, "Missing value for namespace attribute %.80s",att); mm_notify (stream,LOCAL->tmp,WARN); stream->unhealthy = T; par->value = cpystr ("UNKNOWN"); } /* is there another value? */ if (**txtptr == ' ') par = par->next = mail_newbody_parameter (); } while (!par->value); } else { sprintf (LOCAL->tmp,"Missing values for namespace attribute %.80s", par->attribute); mm_notify (stream,LOCAL->tmp,WARN); stream->unhealthy = T; par->value = cpystr ("UNKNOWN"); } } if (**txtptr == ')') ++*txtptr; else { /* missing trailing paren */ sprintf (LOCAL->tmp,"Junk at end of namespace: %.80s", (char *) *txtptr); mm_notify (stream,LOCAL->tmp,WARN); stream->unhealthy = T; return ret; } } if (**txtptr == ')') { /* expected trailing paren? */ ++*txtptr; /* got it! */ break; } default: sprintf (LOCAL->tmp,"Not a namespace: %.80s",(char *) *txtptr); mm_notify (stream,LOCAL->tmp,WARN); stream->unhealthy = T; *txtptr = NIL; /* stop parse now */ break; } } return ret; } /* Parse a thread node list * Accepts: mail stream * current text pointer * Returns: thread node list, text pointer updated */ THREADNODE *imap_parse_thread (MAILSTREAM *stream,unsigned char **txtptr) { char *s; THREADNODE *ret = NIL; /* returned tree */ THREADNODE *last = NIL; /* last branch in this tree */ THREADNODE *parent = NIL; /* parent of current node */ THREADNODE *cur; /* current node */ while (**txtptr == '(') { /* see a thread? */ ++*txtptr; /* skip past open paren */ while (**txtptr != ')') { /* parse thread */ if (**txtptr == '(') { /* thread branch */ cur = imap_parse_thread (stream,txtptr); /* add to parent */ if (parent) parent = parent->next = cur; else { /* no parent, create dummy */ if (last) last = last->branch = mail_newthreadnode (NIL); /* new tree */ else ret = last = mail_newthreadnode (NIL); /* add to dummy parent */ last->next = parent = cur; } } /* threaded message number */ else if (isdigit (*(s = *txtptr)) && ((cur = mail_newthreadnode (NIL))->num = strtoul (*txtptr,(char **) txtptr,10))) { if (LOCAL->filter && !mail_elt (stream,cur->num)->searched) cur->num = NIL; /* make dummy if filtering and not searched */ /* add to parent */ if (parent) parent = parent->next = cur; /* no parent, start new thread */ else if (last) last = last->branch = parent = cur; /* create new tree */ else ret = last = parent = cur; } else { /* anything else is a bogon */ char tmp[MAILTMPLEN]; sprintf (tmp,"Bogus thread member: %.80s",s); mm_notify (stream,tmp,WARN); stream->unhealthy = T; return ret; } /* skip past any space */ if (**txtptr == ' ') ++*txtptr; } ++*txtptr; /* skip pase end of thread */ parent = NIL; /* close this thread */ } return ret; /* return parsed thread */ } /* Parse RFC822 message header * Accepts: MAIL stream * envelope to parse into * header as sized text * stringlist if partial header */ void imap_parse_header (MAILSTREAM *stream,ENVELOPE **env,SIZEDTEXT *hdr, STRINGLIST *stl) { ENVELOPE *nenv; /* parse what we can from this header */ rfc822_parse_msg (&nenv,NIL,(char *) hdr->data,hdr->size,NIL, net_host (LOCAL->netstream),stream->dtb->flags); if (*env) { /* need to merge this header into envelope? */ if (!(*env)->newsgroups) { /* need Newsgroups? */ (*env)->newsgroups = nenv->newsgroups; (*env)->ngpathexists = nenv->ngpathexists; nenv->newsgroups = NIL; } if (!(*env)->followup_to) { /* need Followup-To? */ (*env)->followup_to = nenv->followup_to; nenv->followup_to = NIL; } if (!(*env)->references) { /* need References? */ (*env)->references = nenv->references; nenv->references = NIL; } if (!(*env)->sparep) { /* need spare pointer? */ (*env)->sparep = nenv->sparep; nenv->sparep = NIL; } mail_free_envelope (&nenv); (*env)->imapenvonly = NIL; /* have complete envelope now */ } /* otherwise set it to this envelope */ else (*env = nenv)->incomplete = stl ? T : NIL; } /* IMAP parse envelope * Accepts: MAIL stream * pointer to envelope pointer * current text pointer * parsed reply * * Updates text pointer */ void imap_parse_envelope (MAILSTREAM *stream,ENVELOPE **env, unsigned char **txtptr,IMAPPARSEDREPLY *reply) { ENVELOPE *oenv = *env; char c = *((*txtptr)++); /* grab first character */ /* ignore leading spaces */ while (c == ' ') c = *((*txtptr)++); switch (c) { /* dispatch on first character */ case '(': /* if envelope S-expression */ *env = mail_newenvelope (); /* parse the new envelope */ (*env)->date = imap_parse_string (stream,txtptr,reply,NIL,NIL,LONGT); (*env)->subject = imap_parse_string (stream,txtptr,reply,NIL,NIL,LONGT); (*env)->from = imap_parse_adrlist (stream,txtptr,reply); (*env)->sender = imap_parse_adrlist (stream,txtptr,reply); (*env)->reply_to = imap_parse_adrlist (stream,txtptr,reply); (*env)->to = imap_parse_adrlist (stream,txtptr,reply); (*env)->cc = imap_parse_adrlist (stream,txtptr,reply); (*env)->bcc = imap_parse_adrlist (stream,txtptr,reply); (*env)->in_reply_to = imap_parse_string (stream,txtptr,reply,NIL,NIL, LONGT); (*env)->message_id = imap_parse_string (stream,txtptr,reply,NIL,NIL,LONGT); if (oenv) { /* need to merge old envelope? */ (*env)->newsgroups = oenv->newsgroups; oenv->newsgroups = NIL; (*env)->ngpathexists = oenv->ngpathexists; (*env)->followup_to = oenv->followup_to; oenv->followup_to = NIL; (*env)->references = oenv->references; oenv->references = NIL; mail_free_envelope(&oenv);/* free old envelope */ } /* have IMAP envelope components only */ else (*env)->imapenvonly = T; if (**txtptr != ')') { sprintf (LOCAL->tmp,"Junk at end of envelope: %.80s",(char *) *txtptr); mm_notify (stream,LOCAL->tmp,WARN); stream->unhealthy = T; } else ++*txtptr; /* skip past delimiter */ break; case 'N': /* if NIL */ case 'n': ++*txtptr; /* bump past "I" */ ++*txtptr; /* bump past "L" */ break; default: sprintf (LOCAL->tmp,"Not an envelope: %.80s",(char *) *txtptr); mm_notify (stream,LOCAL->tmp,WARN); stream->unhealthy = T; break; } } /* IMAP parse address list * Accepts: MAIL stream * current text pointer * parsed reply * Returns: address list, NIL on failure * * Updates text pointer */ ADDRESS *imap_parse_adrlist (MAILSTREAM *stream,unsigned char **txtptr, IMAPPARSEDREPLY *reply) { ADDRESS *adr = NIL; char c = **txtptr; /* sniff at first character */ /* ignore leading spaces */ while (c == ' ') c = *++*txtptr; ++*txtptr; /* skip past open paren */ switch (c) { case '(': /* if envelope S-expression */ adr = imap_parse_address (stream,txtptr,reply); if (**txtptr != ')') { sprintf (LOCAL->tmp,"Junk at end of address list: %.80s", (char *) *txtptr); mm_notify (stream,LOCAL->tmp,WARN); stream->unhealthy = T; } else ++*txtptr; /* skip past delimiter */ break; case 'N': /* if NIL */ case 'n': ++*txtptr; /* bump past "I" */ ++*txtptr; /* bump past "L" */ break; default: sprintf (LOCAL->tmp,"Not an address: %.80s",(char *) *txtptr); mm_notify (stream,LOCAL->tmp,WARN); stream->unhealthy = T; break; } return adr; } /* IMAP parse address * Accepts: MAIL stream * current text pointer * parsed reply * Returns: address, NIL on failure * * Updates text pointer */ ADDRESS *imap_parse_address (MAILSTREAM *stream,unsigned char **txtptr, IMAPPARSEDREPLY *reply) { long ingroup = 0; ADDRESS *adr = NIL; ADDRESS *ret = NIL; ADDRESS *prev = NIL; char c = **txtptr; /* sniff at first address character */ switch (c) { case '(': /* if envelope S-expression */ while (c == '(') { /* recursion dies on small stack machines */ ++*txtptr; /* skip past open paren */ if (adr) prev = adr; /* note previous if any */ adr = mail_newaddr (); /* instantiate address and parse its fields */ adr->personal = imap_parse_string (stream,txtptr,reply,NIL,NIL,LONGT); adr->adl = imap_parse_string (stream,txtptr,reply,NIL,NIL,LONGT); adr->mailbox = imap_parse_string (stream,txtptr,reply,NIL,NIL,LONGT); adr->host = imap_parse_string (stream,txtptr,reply,NIL,NIL,LONGT); if (**txtptr != ')') { /* handle trailing paren */ sprintf (LOCAL->tmp,"Junk at end of address: %.80s",(char *) *txtptr); mm_notify (stream,LOCAL->tmp,WARN); stream->unhealthy = T; } else ++*txtptr; /* skip past close paren */ c = **txtptr; /* set up for while test */ /* ignore leading spaces in front of next */ while (c == ' ') c = *++*txtptr; if (!adr->mailbox) { /* end of group? */ /* decrement group if all looks well */ if (ingroup && !(adr->personal || adr->adl || adr->host)) --ingroup; else { if (ingroup) { /* in a group? */ sprintf (LOCAL->tmp,/* yes, must be bad syntax */ "Junk in end of group: pn=%.80s al=%.80s dn=%.80s", adr->personal ? adr->personal : "", adr->adl ? adr->adl : "", adr->host ? adr->host : ""); mm_notify (stream,LOCAL->tmp,WARN); } else mm_notify (stream,"End of group encountered when not in group", WARN); stream->unhealthy = T; mail_free_address (&adr); adr = prev; prev = NIL; } } else if (!adr->host) { /* start of group? */ if (adr->personal || adr->adl) { sprintf (LOCAL->tmp,"Junk in start of group: pn=%.80s al=%.80s", adr->personal ? adr->personal : "", adr->adl ? adr->adl : ""); mm_notify (stream,LOCAL->tmp,WARN); stream->unhealthy = T; mail_free_address (&adr); adr = prev; prev = NIL; } else ++ingroup; /* in a group now */ } if (adr) { /* good address */ if (!ret) ret = adr; /* if first time note first adr */ /* if previous link new block to it */ if (prev) prev->next = adr; /* flush bogus personal name */ if (LOCAL->loser && adr->personal && strchr (adr->personal,'@')) fs_give ((void **) &adr->personal); } } break; case 'N': /* if NIL */ case 'n': *txtptr += 3; /* bump past NIL */ break; default: sprintf (LOCAL->tmp,"Not an address: %.80s",(char *) *txtptr); mm_notify (stream,LOCAL->tmp,WARN); stream->unhealthy = T; break; } return ret; } /* IMAP parse flags * Accepts: current message cache * current text pointer * * Updates text pointer */ void imap_parse_flags (MAILSTREAM *stream,MESSAGECACHE *elt, unsigned char **txtptr) { char *flag; char c = '\0'; struct { /* old flags */ unsigned int valid : 1; unsigned int seen : 1; unsigned int deleted : 1; unsigned int flagged : 1; unsigned int answered : 1; unsigned int draft : 1; unsigned long user_flags; } old; old.valid = elt->valid; old.seen = elt->seen; old.deleted = elt->deleted; old.flagged = elt->flagged; old.answered = elt->answered; old.draft = elt->draft; old.user_flags = elt->user_flags; elt->valid = T; /* mark have valid flags now */ elt->user_flags = NIL; /* zap old flag values */ elt->seen = elt->deleted = elt->flagged = elt->answered = elt->draft = elt->recent = NIL; while (c != ')') { /* parse list of flags */ /* point at a flag */ while (*(flag = ++*txtptr) == ' '); /* scan for end of flag */ while (**txtptr != ' ' && **txtptr != ')') ++*txtptr; c = **txtptr; /* save delimiter */ **txtptr = '\0'; /* tie off flag */ if (!*flag) break; /* null flag */ /* if starts with \ must be sys flag */ else if (*flag == '\\') { if (!compare_cstring (flag,"\\Seen")) elt->seen = T; else if (!compare_cstring (flag,"\\Deleted")) elt->deleted = T; else if (!compare_cstring (flag,"\\Flagged")) elt->flagged = T; else if (!compare_cstring (flag,"\\Answered")) elt->answered = T; else if (!compare_cstring (flag,"\\Recent")) elt->recent = T; else if (!compare_cstring (flag,"\\Draft")) elt->draft = T; } /* otherwise user flag */ else elt->user_flags |= imap_parse_user_flag (stream,flag); } ++*txtptr; /* bump past delimiter */ if (!old.valid || (old.seen != elt->seen) || (old.deleted != elt->deleted) || (old.flagged != elt->flagged) || (old.answered != elt->answered) || (old.draft != elt->draft) || (old.user_flags != elt->user_flags)) mm_flags (stream,elt->msgno); } /* IMAP parse user flag * Accepts: MAIL stream * flag name * Returns: flag bit position */ unsigned long imap_parse_user_flag (MAILSTREAM *stream,char *flag) { long i; /* sniff through all user flags */ for (i = 0; i < NUSERFLAGS; ++i) if (stream->user_flags[i]) if (!compare_cstring (flag,stream->user_flags[i])) return (1 << i); return (unsigned long) 0; /* not found */ } /* IMAP parse atom-string * Accepts: MAIL stream * current text pointer * parsed reply * returned string length * Returns: string * * Updates text pointer */ unsigned char *imap_parse_astring (MAILSTREAM *stream,unsigned char **txtptr, IMAPPARSEDREPLY *reply,unsigned long *len) { unsigned long i; unsigned char c,*s,*ret; /* ignore leading spaces */ for (c = **txtptr; c == ' '; c = *++*txtptr); switch (c) { case '"': /* quoted string? */ case '{': /* literal? */ ret = imap_parse_string (stream,txtptr,reply,NIL,len,NIL); break; default: /* must be atom */ for (c = *(s = *txtptr); /* find end of atom */ c && (c > ' ') && (c != '(') && (c != ')') && (c != '{') && (c != '%') && (c != '*') && (c != '"') && (c != '\\') && (c < 0x80); c = *++*txtptr); if (i = *txtptr - s) { /* atom ends at atom_special */ if (len) *len = i; /* return length of atom */ ret = strncpy ((char *) fs_get (i + 1),s,i); ret[i] = '\0'; /* tie off string */ } else { /* no atom found */ sprintf (LOCAL->tmp,"Not an atom: %.80s",(char *) *txtptr); mm_notify (stream,LOCAL->tmp,WARN); stream->unhealthy = T; if (len) *len = 0; ret = NIL; } break; } return ret; } /* IMAP parse string * Accepts: MAIL stream * current text pointer * parsed reply * mailgets data * returned string length * filter newline flag * Returns: string * * Updates text pointer */ unsigned char *imap_parse_string (MAILSTREAM *stream,unsigned char **txtptr, IMAPPARSEDREPLY *reply,GETS_DATA *md, unsigned long *len,long flags) { char *st; char *string = NIL; unsigned long i,j,k; int bogon = NIL; unsigned char c = **txtptr; /* sniff at first character */ mailgets_t mg = (mailgets_t) mail_parameters (NIL,GET_GETS,NIL); readprogress_t rp = (readprogress_t) mail_parameters (NIL,GET_READPROGRESS,NIL); /* ignore leading spaces */ while (c == ' ') c = *++*txtptr; st = ++*txtptr; /* remember start of string */ switch (c) { case '"': /* if quoted string */ i = 0; /* initial byte count */ /* search for end of string */ for (c = **txtptr; c != '"'; ++i,c = *++*txtptr) { /* backslash quotes next character */ if (c == '\\') c = *++*txtptr; /* CHAR8 not permitted in quoted string */ if (!bogon && (bogon = (c & 0x80))) { sprintf (LOCAL->tmp,"Invalid CHAR in quoted string: %x", (unsigned int) c); mm_notify (stream,LOCAL->tmp,WARN); stream->unhealthy = T; } else if (!c) { /* NUL not permitted either */ mm_notify (stream,"Unterminated quoted string",WARN); stream->unhealthy = T; if (len) *len = 0; /* punt, since may be at end of string */ return NIL; } } ++*txtptr; /* bump past delimiter */ string = (char *) fs_get ((size_t) i + 1); for (j = 0; j < i; j++) { /* copy the string */ if (*st == '\\') ++st; /* quoted character */ string[j] = *st++; } string[j] = '\0'; /* tie off string */ if (len) *len = i; /* set return value too */ if (md && mg) { /* have special routine to slurp string? */ STRING bs; if (md->first) { /* partial fetch? */ md->first--; /* restore origin octet */ md->last = i; /* number of octets that we got */ } INIT (&bs,mail_string,string,i); (*mg) (mail_read,&bs,i,md); } break; case 'N': /* if NIL */ case 'n': ++*txtptr; /* bump past "I" */ ++*txtptr; /* bump past "L" */ if (len) *len = 0; break; case '{': /* if literal string */ /* get size of string */ if ((i = strtoul (*txtptr,(char **) txtptr,10)) > MAXSERVERLIT) { sprintf (LOCAL->tmp,"Absurd server literal length %lu",i); mm_notify (stream,LOCAL->tmp,WARN); stream->unhealthy = T; /* read and discard */ do net_getbuffer (LOCAL->netstream,j = min (i,(long) IMAPTMPLEN - 1), LOCAL->tmp); while (i -= j); } if (len) *len = i; /* set return value */ if (md && mg) { /* have special routine to slurp string? */ if (md->first) { /* partial fetch? */ md->first--; /* restore origin octet */ md->last = i; /* number of octets that we got */ } else md->flags |= MG_COPY;/* otherwise flag need to copy */ string = (*mg) (net_getbuffer,LOCAL->netstream,i,md); } else { /* must slurp into free storage */ string = (char *) fs_get ((size_t) i + 1); *string = '\0'; /* init in case getbuffer fails */ /* get the literal */ if (rp) for (k = 0; j = min ((long) MAILTMPLEN,(long) i); i -= j) { net_getbuffer (LOCAL->netstream,j,string + k); (*rp) (md,k += j); } else net_getbuffer (LOCAL->netstream,i,string); } fs_give ((void **) &reply->line); if (flags && string) /* need to filter newlines? */ for (st = string; st = strpbrk (st,"\015\012\011"); *st++ = ' '); /* get new reply text line */ if (!(reply->line = net_getline (LOCAL->netstream))) reply->line = cpystr (""); if (stream->debug) mm_dlog (reply->line); *txtptr = reply->line; /* set text pointer to point at it */ break; default: sprintf (LOCAL->tmp,"Not a string: %c%.80s",c,(char *) *txtptr); mm_notify (stream,LOCAL->tmp,WARN); stream->unhealthy = T; if (len) *len = 0; break; } return (unsigned char *) string; } /* Register text in IMAP cache * Accepts: MAIL stream * message number * IMAP segment specifier * header string list (if a HEADER section specifier) * sized text to register * Returns: non-zero if cache non-empty */ long imap_cache (MAILSTREAM *stream,unsigned long msgno,char *seg, STRINGLIST *stl,SIZEDTEXT *text) { char *t,tmp[MAILTMPLEN]; unsigned long i; BODY *b; SIZEDTEXT *ret; STRINGLIST *stc; MESSAGECACHE *elt = mail_elt (stream,msgno); /* top-level header never does mailgets */ if (!strcmp (seg,"HEADER") || !strcmp (seg,"0") || !strcmp (seg,"HEADER.FIELDS") || !strcmp (seg,"HEADER.FIELDS.NOT")) { ret = &elt->private.msg.header.text; if (text) { /* don't do this if no text */ if (ret->data) fs_give ((void **) &ret->data); mail_free_stringlist (&elt->private.msg.lines); elt->private.msg.lines = stl; /* prevent cache reuse of .NOT */ if ((seg[0] == 'H') && (seg[6] == '.') && (seg[13] == '.')) for (stc = stl; stc; stc = stc->next) stc->text.size = 0; if (stream->scache) { /* short caching puts it in the stream */ if (stream->msgno != msgno) { /* flush old stuff */ mail_free_envelope (&stream->env); mail_free_body (&stream->body); stream->msgno = msgno; } imap_parse_header (stream,&stream->env,text,stl); } /* regular caching */ else imap_parse_header (stream,&elt->private.msg.env,text,stl); } } /* top level text */ else if (!strcmp (seg,"TEXT")) { ret = &elt->private.msg.text.text; if (text && ret->data) fs_give ((void **) &ret->data); } else if (!*seg) { /* full message */ ret = &elt->private.msg.full.text; if (text && ret->data) fs_give ((void **) &ret->data); } else { /* nested, find non-contents specifier */ for (t = seg; *t && !((*t == '.') && (isalpha(t[1]) || !atol (t+1))); t++); if (*t) *t++ = '\0'; /* tie off section from data specifier */ if (!(b = mail_body (stream,msgno,seg))) { sprintf (tmp,"Unknown section number: %.80s",seg); mm_notify (stream,tmp,WARN); stream->unhealthy = T; return NIL; } if (*t) { /* if a non-numberic subpart */ if ((i = (b->type == TYPEMESSAGE) && (!strcmp (b->subtype,"RFC822"))) && (!strcmp (t,"HEADER") || !strcmp (t,"0") || !strcmp (t,"HEADER.FIELDS") || !strcmp (t,"HEADER.FIELDS.NOT"))) { ret = &b->nested.msg->header.text; if (text) { if (ret->data) fs_give ((void **) &ret->data); mail_free_stringlist (&b->nested.msg->lines); b->nested.msg->lines = stl; /* prevent cache reuse of .NOT */ if ((t[0] == 'H') && (t[6] == '.') && (t[13] == '.')) for (stc = stl; stc; stc = stc->next) stc->text.size = 0; imap_parse_header (stream,&b->nested.msg->env,text,stl); } } else if (i && !strcmp (t,"TEXT")) { ret = &b->nested.msg->text.text; if (text && ret->data) fs_give ((void **) &ret->data); } /* otherwise it must be MIME */ else if (!strcmp (t,"MIME")) { ret = &b->mime.text; if (text && ret->data) fs_give ((void **) &ret->data); } else { sprintf (tmp,"Unknown section specifier: %.80s.%.80s",seg,t); mm_notify (stream,tmp,WARN); stream->unhealthy = T; return NIL; } } else { /* ordinary contents */ ret = &b->contents.text; if (text && ret->data) fs_give ((void **) &ret->data); } } if (text) { /* update cache if requested */ ret->data = text->data; ret->size = text->size; } return ret->data ? LONGT : NIL; } /* IMAP parse body structure * Accepts: MAIL stream * body structure to write into * current text pointer * parsed reply * * Updates text pointer */ void imap_parse_body_structure (MAILSTREAM *stream,BODY *body, unsigned char **txtptr,IMAPPARSEDREPLY *reply) { int i; char *s; PART *part = NIL; char c = *((*txtptr)++); /* grab first character */ /* ignore leading spaces */ while (c == ' ') c = *((*txtptr)++); switch (c) { /* dispatch on first character */ case '(': /* body structure list */ if (**txtptr == '(') { /* multipart body? */ body->type= TYPEMULTIPART;/* yes, set its type */ do { /* instantiate new body part */ if (part) part = part->next = mail_newbody_part (); else body->nested.part = part = mail_newbody_part (); /* parse it */ imap_parse_body_structure (stream,&part->body,txtptr,reply); } while (**txtptr == '(');/* for each body part */ if (body->subtype = imap_parse_string(stream,txtptr,reply,NIL,NIL,LONGT)) ucase (body->subtype); else { mm_notify (stream,"Missing multipart subtype",WARN); stream->unhealthy = T; body->subtype = cpystr (rfc822_default_subtype (body->type)); } if (**txtptr == ' ') /* multipart parameters */ body->parameter = imap_parse_body_parameter (stream,txtptr,reply); if (**txtptr == ' ') { /* disposition */ imap_parse_disposition (stream,body,txtptr,reply); if (LOCAL->cap.extlevel < BODYEXTDSP) LOCAL->cap.extlevel = BODYEXTDSP; } if (**txtptr == ' ') { /* language */ body->language = imap_parse_language (stream,txtptr,reply); if (LOCAL->cap.extlevel < BODYEXTLANG) LOCAL->cap.extlevel = BODYEXTLANG; } if (**txtptr == ' ') { /* location */ body->location = imap_parse_string (stream,txtptr,reply,NIL,NIL,LONGT); if (LOCAL->cap.extlevel < BODYEXTLOC) LOCAL->cap.extlevel = BODYEXTLOC; } while (**txtptr == ' ') imap_parse_extension (stream,txtptr,reply); if (**txtptr != ')') { /* validate ending */ sprintf (LOCAL->tmp,"Junk at end of multipart body: %.80s", (char *) *txtptr); mm_notify (stream,LOCAL->tmp,WARN); stream->unhealthy = T; } else ++*txtptr; /* skip past delimiter */ } else { /* not multipart, parse type name */ if (**txtptr == ')') { /* empty body? */ ++*txtptr; /* bump past it */ break; /* and punt */ } body->type = TYPEOTHER; /* assume unknown type */ body->encoding = ENCOTHER;/* and unknown encoding */ /* parse type */ if (s = imap_parse_string (stream,txtptr,reply,NIL,NIL,LONGT)) { ucase (s); /* application always gets uppercase form */ for (i = 0; /* look in existing table */ (i <= TYPEMAX) && body_types[i] && strcmp (s,body_types[i]); i++); if (i <= TYPEMAX) { /* only if found a slot */ body->type = i; /* set body type */ if (body_types[i]) fs_give ((void **) &s); else body_types[i]=s; /* assign empty slot */ } } if (body->subtype = imap_parse_string(stream,txtptr,reply,NIL,NIL,LONGT)) ucase (body->subtype); /* parse subtype */ else { mm_notify (stream,"Missing body subtype",WARN); stream->unhealthy = T; body->subtype = cpystr (rfc822_default_subtype (body->type)); } body->parameter = imap_parse_body_parameter (stream,txtptr,reply); body->id = imap_parse_string (stream,txtptr,reply,NIL,NIL,LONGT); body->description = imap_parse_string (stream,txtptr,reply,NIL,NIL, LONGT); if (s = imap_parse_string (stream,txtptr,reply,NIL,NIL,LONGT)) { ucase (s); /* application always gets uppercase form */ for (i = 0; /* search for body encoding */ (i <= ENCMAX) && body_encodings[i] && strcmp(s,body_encodings[i]); i++); if (i > ENCMAX) body->encoding = ENCOTHER; else { /* only if found a slot */ body->encoding = i; /* set body encoding */ if (body_encodings[i]) fs_give ((void **) &s); /* assign empty slot */ else body_encodings[i] = s; } } /* parse size of contents in bytes */ body->size.bytes = strtoul (*txtptr,(char **) txtptr,10); switch (body->type) { /* possible extra stuff */ case TYPEMESSAGE: /* message envelope and body */ /* non MESSAGE/RFC822 is basic type */ if (strcmp (body->subtype,"RFC822")) break; { /* make certain server sends an envelope */ ENVELOPE *env = NIL; imap_parse_envelope (stream,&env,txtptr,reply); if (!env) { mm_notify (stream,"Missing body message envelope",WARN); stream->unhealthy = T; body->subtype = cpystr ("RFC822_MISSING_ENVELOPE"); break; } (body->nested.msg = mail_newmsg ())->env = env; } body->nested.msg->body = mail_newbody (); imap_parse_body_structure (stream,body->nested.msg->body,txtptr,reply); /* drop into text case */ case TYPETEXT: /* size in lines */ body->size.lines = strtoul (*txtptr,(char **) txtptr,10); break; default: /* otherwise nothing special */ break; } if (**txtptr == ' ') { /* extension data - md5 */ body->md5 = imap_parse_string (stream,txtptr,reply,NIL,NIL,LONGT); if (LOCAL->cap.extlevel < BODYEXTMD5) LOCAL->cap.extlevel = BODYEXTMD5; } if (**txtptr == ' ') { /* disposition */ imap_parse_disposition (stream,body,txtptr,reply); if (LOCAL->cap.extlevel < BODYEXTDSP) LOCAL->cap.extlevel = BODYEXTDSP; } if (**txtptr == ' ') { /* language */ body->language = imap_parse_language (stream,txtptr,reply); if (LOCAL->cap.extlevel < BODYEXTLANG) LOCAL->cap.extlevel = BODYEXTLANG; } if (**txtptr == ' ') { /* location */ body->location = imap_parse_string (stream,txtptr,reply,NIL,NIL,LONGT); if (LOCAL->cap.extlevel < BODYEXTLOC) LOCAL->cap.extlevel = BODYEXTLOC; } while (**txtptr == ' ') imap_parse_extension (stream,txtptr,reply); if (**txtptr != ')') { /* validate ending */ sprintf (LOCAL->tmp,"Junk at end of body part: %.80s", (char *) *txtptr); mm_notify (stream,LOCAL->tmp,WARN); stream->unhealthy = T; } else ++*txtptr; /* skip past delimiter */ } break; case 'N': /* if NIL */ case 'n': ++*txtptr; /* bump past "I" */ ++*txtptr; /* bump past "L" */ break; default: /* otherwise quite bogus */ sprintf (LOCAL->tmp,"Bogus body structure: %.80s",(char *) *txtptr); mm_notify (stream,LOCAL->tmp,WARN); stream->unhealthy = T; break; } } /* IMAP parse body parameter * Accepts: MAIL stream * current text pointer * parsed reply * Returns: body parameter * Updates text pointer */ PARAMETER *imap_parse_body_parameter (MAILSTREAM *stream, unsigned char **txtptr, IMAPPARSEDREPLY *reply) { PARAMETER *ret = NIL; PARAMETER *par = NIL; char c,*s; /* ignore leading spaces */ while ((c = *(*txtptr)++) == ' '); /* parse parameter list */ if (c == '(') while (c != ')') { /* append new parameter to tail */ if (ret) par = par->next = mail_newbody_parameter (); else ret = par = mail_newbody_parameter (); if(!(par->attribute=imap_parse_string (stream,txtptr,reply,NIL,NIL, LONGT))) { mm_notify (stream,"Missing parameter attribute",WARN); stream->unhealthy = T; par->attribute = cpystr ("UNKNOWN"); } if (!(par->value = imap_parse_string (stream,txtptr,reply,NIL,NIL,LONGT))){ sprintf (LOCAL->tmp,"Missing value for parameter %.80s",par->attribute); mm_notify (stream,LOCAL->tmp,WARN); stream->unhealthy = T; par->value = cpystr ("UNKNOWN"); } switch (c = **txtptr) { /* see what comes after */ case ' ': /* flush whitespace */ while ((c = *++*txtptr) == ' '); break; case ')': /* end of attribute/value pairs */ ++*txtptr; /* skip past closing paren */ break; default: sprintf (LOCAL->tmp,"Junk at end of parameter: %.80s",(char *) *txtptr); mm_notify (stream,LOCAL->tmp,WARN); stream->unhealthy = T; break; } } /* empty parameter, must be NIL */ else if (((c == 'N') || (c == 'n')) && ((*(s = *txtptr) == 'I') || (*s == 'i')) && ((s[1] == 'L') || (s[1] == 'l'))) *txtptr += 2; else { sprintf (LOCAL->tmp,"Bogus body parameter: %c%.80s",c, (char *) (*txtptr) - 1); mm_notify (stream,LOCAL->tmp,WARN); stream->unhealthy = T; } return ret; } /* IMAP parse body disposition * Accepts: MAIL stream * body structure to write into * current text pointer * parsed reply */ void imap_parse_disposition (MAILSTREAM *stream,BODY *body, unsigned char **txtptr,IMAPPARSEDREPLY *reply) { switch (*++*txtptr) { case '(': ++*txtptr; /* skip open paren */ body->disposition.type = imap_parse_string (stream,txtptr,reply,NIL,NIL, LONGT); body->disposition.parameter = imap_parse_body_parameter (stream,txtptr,reply); if (**txtptr != ')') { /* validate ending */ sprintf (LOCAL->tmp,"Junk at end of disposition: %.80s", (char *) *txtptr); mm_notify (stream,LOCAL->tmp,WARN); stream->unhealthy = T; } else ++*txtptr; /* skip past delimiter */ break; case 'N': /* if NIL */ case 'n': ++*txtptr; /* bump past "N" */ ++*txtptr; /* bump past "I" */ ++*txtptr; /* bump past "L" */ break; default: sprintf (LOCAL->tmp,"Unknown body disposition: %.80s",(char *) *txtptr); mm_notify (stream,LOCAL->tmp,WARN); stream->unhealthy = T; /* try to skip to next space */ while ((*++*txtptr != ' ') && (**txtptr != ')') && **txtptr); break; } } /* IMAP parse body language * Accepts: MAIL stream * current text pointer * parsed reply * Returns: string list or NIL if empty or error */ STRINGLIST *imap_parse_language (MAILSTREAM *stream,unsigned char **txtptr, IMAPPARSEDREPLY *reply) { unsigned long i; char *s; STRINGLIST *ret = NIL; /* language is a list */ if (*++*txtptr == '(') ret = imap_parse_stringlist (stream,txtptr,reply); else if (s = imap_parse_string (stream,txtptr,reply,NIL,&i,LONGT)) { (ret = mail_newstringlist ())->text.data = (unsigned char *) s; ret->text.size = i; } return ret; } /* IMAP parse string list * Accepts: MAIL stream * current text pointer * parsed reply * Returns: string list or NIL if empty or error */ STRINGLIST *imap_parse_stringlist (MAILSTREAM *stream,unsigned char **txtptr, IMAPPARSEDREPLY *reply) { STRINGLIST *stl = NIL; STRINGLIST *stc = NIL; unsigned char *t = *txtptr; /* parse the list */ if (*t++ == '(') while (*t != ')') { if (stl) stc = stc->next = mail_newstringlist (); else stc = stl = mail_newstringlist (); /* parse astring */ if (!(stc->text.data = imap_parse_astring (stream,&t,reply,&stc->text.size))) { sprintf (LOCAL->tmp,"Bogus string list member: %.80s",(char *) t); mm_notify (stream,LOCAL->tmp,WARN); stream->unhealthy = T; mail_free_stringlist (&stl); break; } else if (*t == ' ') ++t; /* another token follows */ } if (stl) *txtptr = ++t; /* update return string */ return stl; } /* IMAP parse unknown body extension data * Accepts: MAIL stream * current text pointer * parsed reply * * Updates text pointer */ void imap_parse_extension (MAILSTREAM *stream,unsigned char **txtptr, IMAPPARSEDREPLY *reply) { unsigned long i,j; switch (*++*txtptr) { /* action depends upon first character */ case '(': while (**txtptr != ')') imap_parse_extension (stream,txtptr,reply); ++*txtptr; /* bump past closing parenthesis */ break; case '"': /* if quoted string */ while (*++*txtptr != '"') if (**txtptr == '\\') ++*txtptr; ++*txtptr; /* bump past closing quote */ break; case 'N': /* if NIL */ case 'n': ++*txtptr; /* bump past "N" */ ++*txtptr; /* bump past "I" */ ++*txtptr; /* bump past "L" */ break; case '{': /* get size of literal */ ++*txtptr; /* bump past open squiggle */ if (i = strtoul (*txtptr,(char **) txtptr,10)) do net_getbuffer (LOCAL->netstream,j = min (i,(long) IMAPTMPLEN - 1), LOCAL->tmp); while (i -= j); /* get new reply text line */ if (!(reply->line = net_getline (LOCAL->netstream))) reply->line = cpystr (""); if (stream->debug) mm_dlog (reply->line); *txtptr = reply->line; /* set text pointer to point at it */ break; case '0': case '1': case '2': case '3': case '4': case '5': case '6': case '7': case '8': case '9': strtoul (*txtptr,(char **) txtptr,10); break; default: sprintf (LOCAL->tmp,"Unknown extension token: %.80s",(char *) *txtptr); mm_notify (stream,LOCAL->tmp,WARN); stream->unhealthy = T; /* try to skip to next space */ while ((*++*txtptr != ' ') && (**txtptr != ')') && **txtptr); break; } } /* IMAP parse capabilities * Accepts: MAIL stream * capability list */ void imap_parse_capabilities (MAILSTREAM *stream,char *t) { char *s,*r; unsigned long i; THREADER *thr,*th; if (!LOCAL->gotcapability) { /* need to save previous capabilities? */ /* no, flush threaders */ if (thr = LOCAL->cap.threader) while (th = thr) { fs_give ((void **) &th->name); thr = th->next; fs_give ((void **) &th); } /* zap capabilities */ memset (&LOCAL->cap,0,sizeof (LOCAL->cap)); LOCAL->gotcapability = T; /* flag that capabilities arrived */ } for (t = strtok_r (t," ",&r); t; t = strtok_r (NIL," ",&r)) { if (!compare_cstring (t,"IMAP4")) LOCAL->cap.imap4 = LOCAL->cap.imap2bis = LOCAL->cap.rfc1176 = T; else if (!compare_cstring (t,"IMAP4rev1")) LOCAL->cap.imap4rev1 = LOCAL->cap.imap2bis = LOCAL->cap.rfc1176 = T; else if (!compare_cstring (t,"IMAP2")) LOCAL->cap.rfc1176 = T; else if (!compare_cstring (t,"IMAP2bis")) LOCAL->cap.imap2bis = LOCAL->cap.rfc1176 = T; else if (!compare_cstring (t,"ACL")) LOCAL->cap.acl = T; else if (!compare_cstring (t,"QUOTA")) LOCAL->cap.quota = T; else if (!compare_cstring (t,"LITERAL+")) LOCAL->cap.litplus = T; else if (!compare_cstring (t,"IDLE")) LOCAL->cap.idle = T; else if (!compare_cstring (t,"MAILBOX-REFERRALS")) LOCAL->cap.mbx_ref = T; else if (!compare_cstring (t,"LOGIN-REFERRALS")) LOCAL->cap.log_ref = T; else if (!compare_cstring (t,"NAMESPACE")) LOCAL->cap.namespace = T; else if (!compare_cstring (t,"UIDPLUS")) LOCAL->cap.uidplus = T; else if (!compare_cstring (t,"STARTTLS")) LOCAL->cap.starttls = T; else if (!compare_cstring (t,"LOGINDISABLED"))LOCAL->cap.logindisabled = T; else if (!compare_cstring (t,"ID")) LOCAL->cap.id = T; else if (!compare_cstring (t,"CHILDREN")) LOCAL->cap.children = T; else if (!compare_cstring (t,"MULTIAPPEND")) LOCAL->cap.multiappend = T; else if (!compare_cstring (t,"BINARY")) LOCAL->cap.binary = T; else if (!compare_cstring (t,"UNSELECT")) LOCAL->cap.unselect = T; else if (!compare_cstring (t,"SASL-IR")) LOCAL->cap.sasl_ir = T; else if (!compare_cstring (t,"SCAN")) LOCAL->cap.scan = T; else if (!compare_cstring (t,"URLAUTH")) LOCAL->cap.urlauth = T; else if (!compare_cstring (t,"CATENATE")) LOCAL->cap.catenate = T; else if (!compare_cstring (t,"CONDSTORE")) LOCAL->cap.condstore = T; else if (!compare_cstring (t,"ESEARCH")) LOCAL->cap.esearch = T; else if (((t[0] == 'S') || (t[0] == 's')) && ((t[1] == 'O') || (t[1] == 'o')) && ((t[2] == 'R') || (t[2] == 'r')) && ((t[3] == 'T') || (t[3] == 't'))) LOCAL->cap.sort = T; /* capability with value? */ else if (s = strchr (t,'=')) { *s++ = '\0'; /* separate token from value */ if (!compare_cstring (t,"THREAD") && !LOCAL->loser) { THREADER *thread = (THREADER *) fs_get (sizeof (THREADER)); thread->name = cpystr (s); thread->dispatch = NIL; thread->next = LOCAL->cap.threader; LOCAL->cap.threader = thread; } else if (!compare_cstring (t,"AUTH")) { if ((i = mail_lookup_auth_name (s,LOCAL->authflags)) && (--i < MAXAUTHENTICATORS)) LOCAL->cap.auth |= (1 << i); else if (!compare_cstring (s,"ANONYMOUS")) LOCAL->cap.authanon = T; } } /* ignore other capabilities */ } /* disable LOGIN if PLAIN also advertised */ if ((i = mail_lookup_auth_name ("PLAIN",NIL)) && (--i < MAXAUTHENTICATORS) && (LOCAL->cap.auth & (1 << i)) && (i = mail_lookup_auth_name ("LOGIN",NIL)) && (--i < MAXAUTHENTICATORS)) LOCAL->cap.auth &= ~(1 << i); } /* IMAP load cache * Accepts: MAIL stream * sequence * flags * Returns: parsed reply from fetch */ IMAPPARSEDREPLY *imap_fetch (MAILSTREAM *stream,char *sequence,long flags) { int i = 2; char *cmd = (LEVELIMAP4 (stream) && (flags & FT_UID)) ? "UID FETCH" : "FETCH"; IMAPARG *args[9],aseq,aarg,aenv,ahhr,axtr,ahtr,abdy,atrl; if (LOCAL->loser) sequence = imap_reform_sequence (stream,sequence, flags & FT_UID); args[0] = &aseq; aseq.type = SEQUENCE; aseq.text = (void *) sequence; args[1] = &aarg; aarg.type = ATOM; aenv.type = ATOM; aenv.text = (void *) "ENVELOPE"; ahhr.type = ATOM; ahhr.text = (void *) hdrheader[LOCAL->cap.extlevel]; axtr.type = ATOM; axtr.text = (void *) imap_extrahdrs; ahtr.type = ATOM; ahtr.text = (void *) hdrtrailer; abdy.type = ATOM; abdy.text = (void *) "BODYSTRUCTURE"; atrl.type = ATOM; atrl.text = (void *) "INTERNALDATE RFC822.SIZE FLAGS)"; if (LEVELIMAP4 (stream)) { /* include UID if IMAP4 or IMAP4rev1 */ aarg.text = (void *) "(UID"; if (flags & FT_NEEDENV) { /* if need envelopes */ args[i++] = &aenv; /* include envelope */ /* extra header poop if IMAP4rev1 */ if (!(flags & FT_NOHDRS) && LEVELIMAP4rev1 (stream)) { args[i++] = &ahhr; /* header header */ if (axtr.text) args[i++] = &axtr; args[i++] = &ahtr; /* header trailer */ } /* fetch body if requested */ if (flags & FT_NEEDBODY) args[i++] = &abdy; } args[i++] = &atrl; /* fetch trailer */ } /* easy if IMAP2 */ else aarg.text = (void *) (flags & FT_NEEDENV) ? ((flags & FT_NEEDBODY) ? "(RFC822.HEADER BODY INTERNALDATE RFC822.SIZE FLAGS)" : "(RFC822.HEADER INTERNALDATE RFC822.SIZE FLAGS)") : "FAST"; args[i] = NIL; /* tie off command */ return imap_send (stream,cmd,args); } /* Reform sequence for losing server that doesn't handle ranges right * Accepts: MAIL stream * sequence * non-zero if UID * Returns: sequence */ char *imap_reform_sequence (MAILSTREAM *stream,char *sequence,long flags) { unsigned long i,j,star; char *s,*t,*tl,*rs; /* can't win if empty */ if (!stream->nmsgs) return sequence; /* get highest possible range value */ star = flags ? mail_uid (stream,stream->nmsgs) : stream->nmsgs; /* flush old reformed sequence */ if (LOCAL->reform) fs_give ((void **) &LOCAL->reform); rs = LOCAL->reform = (char *) fs_get (1+ strlen (sequence)); for (s = sequence; t = strpbrk (s,",:"); ) switch (*t++) { case ',': /* single message */ strncpy (rs,s,i = t - s); /* copy string up to that point */ rs += i; /* advance destination pointer */ s += i; /* and source */ break; case ':': /* message range */ i = (*s == '*') ? star : strtoul (s,NIL,10); if (*t == '*') { /* range ends with star */ j = star; tl = t+1; } else { /* numeric range end */ j = strtoul (t,(char **) &tl,10); if (!tl) tl = t + strlen (t); } if (i <= j) { /* if first less than second */ if (*tl) tl++; /* skip past end of range if present */ strncpy (rs,s,i = tl - s);/* copy string up to that point */ rs += i; /* advance destination and source pointers */ s += i; } else { /* here's the workaround for losing servers */ strncpy (rs,t,i = tl - t);/* swap the order */ rs[i] = ':'; /* delimit */ strncpy (rs+i+1,s,j = (t-1) - s); rs += i + 1 + j; /* advance destination pointer */ if (*tl) *rs++ = *tl++; /* write trailing delimiter if present */ s = tl; /* advance source pointer */ } } if (*s) strcpy (rs,s); /* write remainder of sequence */ else *rs = '\0'; /* tie off string */ return LOCAL->reform; } /* IMAP return host name * Accepts: MAIL stream * Returns: host name */ char *imap_host (MAILSTREAM *stream) { if (stream->dtb != &imapdriver) fatal ("imap_host called on non-IMAP stream!"); /* return host name on stream if open */ return (LOCAL && LOCAL->netstream) ? net_host (LOCAL->netstream) : ".NO-IMAP-CONNECTION."; } /* IMAP return IMAP capability structure * Accepts: MAIL stream * Returns: IMAP capability structure */ IMAPCAP *imap_cap (MAILSTREAM *stream) { if (stream->dtb != &imapdriver) fatal ("imap_cap called on non-IMAP stream!"); return &LOCAL->cap; /* return capability structure */ } alpine-2.10+dfsg/imap/src/c-client/smtp.c0000600000175000017500000006452311512502124021710 0ustar paulproteuspaulproteus/* ======================================================================== * Copyright 1988-2008 University of Washington * * Licensed under the Apache License, Version 2.0 (the "License"); * you may not use this file except in compliance with the License. * You may obtain a copy of the License at * * http://www.apache.org/licenses/LICENSE-2.0 * * * ======================================================================== */ /* * Program: Simple Mail Transfer Protocol (SMTP) routines * * Author: Mark Crispin * Networks and Distributed Computing * Computing & Communications * University of Washington * Administration Building, AG-44 * Seattle, WA 98195 * Internet: MRC@CAC.Washington.EDU * * Date: 27 July 1988 * Last Edited: 28 January 2008 * * This original version of this file is * Copyright 1988 Stanford University * and was developed in the Symbolic Systems Resources Group of the Knowledge * Systems Laboratory at Stanford University in 1987-88, and was funded by the * Biomedical Research Technology Program of the National Institutes of Health * under grant number RR-00785. */ #include #include #include "c-client.h" /* Constants */ #define SMTPSSLPORT (long) 465 /* former assigned SSL TCP contact port */ #define SMTPGREET (long) 220 /* SMTP successful greeting */ #define SMTPAUTHED (long) 235 /* SMTP successful authentication */ #define SMTPOK (long) 250 /* SMTP OK code */ #define SMTPAUTHREADY (long) 334/* SMTP ready for authentication */ #define SMTPREADY (long) 354 /* SMTP ready for data */ #define SMTPSOFTFATAL (long) 421/* SMTP soft fatal code */ #define SMTPWANTAUTH (long) 505 /* SMTP authentication needed */ #define SMTPWANTAUTH2 (long) 530/* SMTP authentication needed */ #define SMTPUNAVAIL (long) 550 /* SMTP mailbox unavailable */ #define SMTPHARDERROR (long) 554/* SMTP miscellaneous hard failure */ /* Convenient access to protocol-specific data */ #define ESMTP stream->protocol.esmtp /* Function prototypes */ void *smtp_challenge (void *s,unsigned long *len); long smtp_response (void *s,char *response,unsigned long size); long smtp_auth (SENDSTREAM *stream,NETMBX *mb,char *tmp); long smtp_rcpt (SENDSTREAM *stream,ADDRESS *adr,long *error); long smtp_send (SENDSTREAM *stream,char *command,char *args); long smtp_reply (SENDSTREAM *stream); long smtp_ehlo (SENDSTREAM *stream,char *host,NETMBX *mb); long smtp_fake (SENDSTREAM *stream,char *text); static long smtp_seterror (SENDSTREAM *stream,long code,char *text); long smtp_soutr (void *stream,char *s); /* Mailer parameters */ static unsigned long smtp_maxlogintrials = MAXLOGINTRIALS; static long smtp_port = 0; /* default port override */ static long smtp_sslport = 0; #ifndef RFC2821 #define RFC2821 /* RFC 2821 compliance */ #endif /* SMTP limits, current as of RFC 2821 */ #define SMTPMAXLOCALPART 64 #define SMTPMAXDOMAIN 255 #define SMTPMAXPATH 256 /* I have seen local parts of more than 64 octets, in spite of the SMTP * limits. So, we'll have a more generous limit that's still guaranteed * not to pop the buffer, and let the server worry about it. As of this * writing, it comes out to 240. Anyone with a mailbox name larger than * that is in serious need of a life or at least a new ISP! 23 June 1998 */ #define MAXLOCALPART ((MAILTMPLEN - (SMTPMAXDOMAIN + SMTPMAXPATH + 32)) / 2) /* Mail Transfer Protocol manipulate driver parameters * Accepts: function code * function-dependent value * Returns: function-dependent return value */ void *smtp_parameters (long function,void *value) { switch ((int) function) { case SET_MAXLOGINTRIALS: smtp_maxlogintrials = (unsigned long) value; break; case GET_MAXLOGINTRIALS: value = (void *) smtp_maxlogintrials; break; case SET_SMTPPORT: smtp_port = (long) value; break; case GET_SMTPPORT: value = (void *) smtp_port; break; case SET_SSLSMTPPORT: smtp_sslport = (long) value; break; case GET_SSLSMTPPORT: value = (void *) smtp_sslport; break; default: value = NIL; /* error case */ break; } return value; } /* Mail Transfer Protocol open connection * Accepts: network driver * service host list * port number * service name * SMTP open options * Returns: SEND stream on success, NIL on failure */ SENDSTREAM *smtp_open_full (NETDRIVER *dv,char **hostlist,char *service, unsigned long port,long options) { SENDSTREAM *stream = NIL; long reply; char *s,tmp[MAILTMPLEN]; NETSTREAM *netstream; NETMBX mb; if (!(hostlist && *hostlist)) mm_log ("Missing SMTP service host",ERROR); /* maximum domain name is 64 characters */ else do if (strlen (*hostlist) < SMTPMAXDOMAIN) { sprintf (tmp,"{%.1000s}",*hostlist); if (!mail_valid_net_parse_work (tmp,&mb,service ? service : "smtp") || mb.anoflag || mb.readonlyflag) { sprintf (tmp,"Invalid host specifier: %.80s",*hostlist); mm_log (tmp,ERROR); } else { /* light tryssl flag if requested */ mb.trysslflag = (options & SOP_TRYSSL) ? T : NIL; /* explicit port overrides all */ if (mb.port) port = mb.port; /* else /submit overrides port argument */ else if (!compare_cstring (mb.service,"submit")) { port = SUBMITTCPPORT; /* override port, use IANA name */ strcpy (mb.service,"submission"); } /* else port argument overrides SMTP port */ else if (!port) port = smtp_port ? smtp_port : SMTPTCPPORT; if (netstream = /* try to open ordinary connection */ net_open (&mb,dv,port, (NETDRIVER *) mail_parameters (NIL,GET_SSLDRIVER,NIL), "*smtps",smtp_sslport ? smtp_sslport : SMTPSSLPORT)) { stream = (SENDSTREAM *) memset (fs_get (sizeof (SENDSTREAM)),0, sizeof (SENDSTREAM)); stream->netstream = netstream; stream->host = cpystr ((long) mail_parameters (NIL,GET_TRUSTDNS,NIL) ? net_host (netstream) : mb.host); stream->debug = (mb.dbgflag || (options & OP_DEBUG)) ? T : NIL; if (options & SOP_SECURE) mb.secflag = T; /* get name of local host to use */ s = compare_cstring ("localhost",mb.host) ? net_localhost (netstream) : "localhost"; do reply = smtp_reply (stream); while ((reply < 100) || (stream->reply[3] == '-')); if (reply != SMTPGREET){/* get SMTP greeting */ sprintf (tmp,"SMTP greeting failure: %.80s",stream->reply); mm_log (tmp,ERROR); stream = smtp_close (stream); } /* try EHLO first, then HELO */ else if (((reply = smtp_ehlo (stream,s,&mb)) != SMTPOK) && ((reply = smtp_send (stream,"HELO",s)) != SMTPOK)) { sprintf (tmp,"SMTP hello failure: %.80s",stream->reply); mm_log (tmp,ERROR); stream = smtp_close (stream); } else { NETDRIVER *ssld =(NETDRIVER *)mail_parameters(NIL,GET_SSLDRIVER,NIL); sslstart_t stls = (sslstart_t) mail_parameters(NIL,GET_SSLSTART,NIL); ESMTP.ok = T; /* ESMTP server, start TLS if present */ if (!dv && stls && ESMTP.service.starttls && !mb.sslflag && !mb.notlsflag && (smtp_send (stream,"STARTTLS",NIL) == SMTPGREET)) { mb.tlsflag = T; /* TLS OK, get into TLS at this end */ stream->netstream->dtb = ssld; /* TLS started, negotiate it */ if (!(stream->netstream->stream = (*stls) (stream->netstream->stream,mb.host, (mb.tlssslv23 ? NIL : NET_TLSCLIENT) | (mb.novalidate ? NET_NOVALIDATECERT:NIL)))){ /* TLS negotiation failed after STARTTLS */ sprintf (tmp,"Unable to negotiate TLS with this server: %.80s", mb.host); mm_log (tmp,ERROR); /* close without doing QUIT */ if (stream->netstream) net_close (stream->netstream); stream->netstream = NIL; stream = smtp_close (stream); } /* TLS OK, re-negotiate EHLO */ else if ((reply = smtp_ehlo (stream,s,&mb)) != SMTPOK) { sprintf (tmp,"SMTP EHLO failure after STARTTLS: %.80s", stream->reply); mm_log (tmp,ERROR); stream = smtp_close (stream); } else ESMTP.ok = T; /* TLS OK and EHLO successful */ } else if (mb.tlsflag) {/* user specified /tls but can't do it */ sprintf (tmp,"TLS unavailable with this server: %.80s",mb.host); mm_log (tmp,ERROR); stream = smtp_close (stream); } /* remote name for authentication */ if (stream && ((mb.secflag || mb.user[0]))) { if (ESMTP.auth) { /* use authenticator? */ if ((long) mail_parameters (NIL,GET_TRUSTDNS,NIL)) { /* remote name for authentication */ strncpy (mb.host, (long) mail_parameters (NIL,GET_SASLUSESPTRNAME,NIL) ? net_remotehost (netstream) : net_host (netstream), NETMAXHOST-1); mb.host[NETMAXHOST-1] = '\0'; } if (!smtp_auth (stream,&mb,tmp)) stream = smtp_close (stream); } else { /* no available authenticators? */ sprintf (tmp,"%sSMTP authentication not available: %.80s", mb.secflag ? "Secure " : "",mb.host); mm_log (tmp,ERROR); stream = smtp_close (stream); } } } } } } while (!stream && *++hostlist); if (stream) { /* set stream options if have a stream */ if (options &(SOP_DSN | SOP_DSN_NOTIFY_FAILURE | SOP_DSN_NOTIFY_DELAY | SOP_DSN_NOTIFY_SUCCESS | SOP_DSN_RETURN_FULL)) { ESMTP.dsn.want = T; if (options & SOP_DSN_NOTIFY_FAILURE) ESMTP.dsn.notify.failure = T; if (options & SOP_DSN_NOTIFY_DELAY) ESMTP.dsn.notify.delay = T; if (options & SOP_DSN_NOTIFY_SUCCESS) ESMTP.dsn.notify.success = T; if (options & SOP_DSN_RETURN_FULL) ESMTP.dsn.full = T; } if (options & SOP_8BITMIME) ESMTP.eightbit.want = T; } return stream; } /* SMTP authenticate * Accepts: stream to login * parsed network mailbox structure * scratch buffer * place to return user name * Returns: T on success, NIL on failure */ long smtp_auth (SENDSTREAM *stream,NETMBX *mb,char *tmp) { unsigned long trial,auths; char *lsterr = NIL; char usr[MAILTMPLEN]; AUTHENTICATOR *at; long ret = NIL; for (auths = ESMTP.auth, stream->saslcancel = NIL; !ret && stream->netstream && auths && (at = mail_lookup_auth (find_rightmost_bit (&auths) + 1)); ) { if (lsterr) { /* previous authenticator failed? */ sprintf (tmp,"Retrying using %s authentication after %.80s", at->name,lsterr); mm_log (tmp,NIL); fs_give ((void **) &lsterr); } trial = 0; /* initial trial count */ tmp[0] = '\0'; /* empty buffer */ if (stream->netstream) do { if (lsterr) { sprintf (tmp,"Retrying %s authentication after %.80s",at->name,lsterr); mm_log (tmp,WARN); fs_give ((void **) &lsterr); } stream->saslcancel = NIL; if (smtp_send (stream,"AUTH",at->name) == SMTPAUTHREADY) { /* hide client authentication responses */ if (!(at->flags & AU_SECURE)) stream->sensitive = T; if ((*at->client) (smtp_challenge,smtp_response,"smtp",mb,stream, &trial,usr)) { if (stream->replycode == SMTPAUTHED) { ESMTP.auth = NIL; /* disable authenticators */ ret = LONGT; } /* if main program requested cancellation */ else if (!trial) mm_log ("SMTP Authentication cancelled",ERROR); } stream->sensitive = NIL;/* unhide */ } /* remember response if error and no cancel */ if (!ret && trial) lsterr = cpystr (stream->reply); } while (!ret && stream->netstream && trial && (trial < smtp_maxlogintrials)); } if (lsterr) { /* previous authenticator failed? */ if (!stream->saslcancel) { /* don't do this if a cancel */ sprintf (tmp,"Can not authenticate to SMTP server: %.80s",lsterr); mm_log (tmp,ERROR); } fs_give ((void **) &lsterr); } return ret; /* authentication failed */ } /* Get challenge to authenticator in binary * Accepts: stream * pointer to returned size * Returns: challenge or NIL if not challenge */ void *smtp_challenge (void *s,unsigned long *len) { char tmp[MAILTMPLEN]; void *ret = NIL; SENDSTREAM *stream = (SENDSTREAM *) s; if ((stream->replycode == SMTPAUTHREADY) && !(ret = rfc822_base64 ((unsigned char *) stream->reply + 4, strlen (stream->reply + 4),len))) { sprintf (tmp,"SMTP SERVER BUG (invalid challenge): %.80s",stream->reply+4); mm_log (tmp,ERROR); } return ret; } /* Send authenticator response in BASE64 * Accepts: MAIL stream * string to send * length of string * Returns: T, always */ long smtp_response (void *s,char *response,unsigned long size) { SENDSTREAM *stream = (SENDSTREAM *) s; unsigned long i,j; char *t,*u; if (response) { /* make CRLFless BASE64 string */ if (size) { for (t = (char *) rfc822_binary ((void *) response,size,&i),u = t,j = 0; j < i; j++) if (t[j] > ' ') *u++ = t[j]; *u = '\0'; /* tie off string */ i = smtp_send (stream,t,NIL); fs_give ((void **) &t); } else i = smtp_send (stream,"",NIL); } else { /* abort requested */ i = smtp_send (stream,"*",NIL); stream->saslcancel = T; /* mark protocol-requested SASL cancel */ } return LONGT; } /* Mail Transfer Protocol close connection * Accepts: SEND stream * Returns: NIL always */ SENDSTREAM *smtp_close (SENDSTREAM *stream) { if (stream) { /* send "QUIT" */ if (stream->netstream) { /* do close actions if have netstream */ smtp_send (stream,"QUIT",NIL); if (stream->netstream) /* could have been closed during "QUIT" */ net_close (stream->netstream); } /* clean up */ if (stream->host) fs_give ((void **) &stream->host); if (stream->reply) fs_give ((void **) &stream->reply); if (ESMTP.dsn.envid) fs_give ((void **) &ESMTP.dsn.envid); if (ESMTP.atrn.domains) fs_give ((void **) &ESMTP.atrn.domains); fs_give ((void **) &stream);/* flush the stream */ } return NIL; } /* Mail Transfer Protocol deliver mail * Accepts: SEND stream * delivery option (MAIL, SEND, SAML, SOML) * message envelope * message body * Returns: T on success, NIL on failure */ long smtp_mail (SENDSTREAM *stream,char *type,ENVELOPE *env,BODY *body) { RFC822BUFFER buf; char tmp[SENDBUFLEN+1]; long error = NIL; long retry = NIL; buf.f = smtp_soutr; /* initialize buffer */ buf.s = stream->netstream; buf.end = (buf.beg = buf.cur = tmp) + SENDBUFLEN; tmp[SENDBUFLEN] = '\0'; /* must have additional null guard byte */ if (!(env->to || env->cc || env->bcc)) { /* no recipients in request */ smtp_seterror (stream,SMTPHARDERROR,"No recipients specified"); return NIL; } do { /* make sure stream is in good shape */ smtp_send (stream,"RSET",NIL); if (retry) { /* need to retry with authentication? */ NETMBX mb; /* yes, build remote name for authentication */ sprintf (tmp,"{%.200s/smtp%s}", (long) mail_parameters (NIL,GET_TRUSTDNS,NIL) ? ((long) mail_parameters (NIL,GET_SASLUSESPTRNAME,NIL) ? net_remotehost (stream->netstream) : net_host (stream->netstream)) : stream->host, (stream->netstream->dtb == (NETDRIVER *) mail_parameters (NIL,GET_SSLDRIVER,NIL)) ? "/ssl" : ""); mail_valid_net_parse (tmp,&mb); if (!smtp_auth (stream,&mb,tmp)) return NIL; retry = NIL; /* no retry at this point */ } strcpy (tmp,"FROM:<"); /* compose "MAIL FROM:" */ #ifdef RFC2821 if (env->return_path && env->return_path->host && !((strlen (env->return_path->mailbox) > SMTPMAXLOCALPART) || (strlen (env->return_path->host) > SMTPMAXDOMAIN))) { rfc822_cat (tmp,env->return_path->mailbox,NIL); sprintf (tmp + strlen (tmp),"@%s",env->return_path->host); } #else /* old code with A-D-L support */ if (env->return_path && env->return_path->host && !((env->return_path->adl && (strlen (env->return_path->adl) > SMTPMAXPATH)) || (strlen (env->return_path->mailbox) > SMTPMAXLOCALPART) || (strlen (env->return_path->host) > SMTPMAXDOMAIN))) rfc822_address (tmp,env->return_path); #endif strcat (tmp,">"); if (ESMTP.ok) { if (ESMTP.eightbit.ok && ESMTP.eightbit.want) strcat (tmp," BODY=8BITMIME"); if (ESMTP.dsn.ok && ESMTP.dsn.want) { strcat (tmp,ESMTP.dsn.full ? " RET=FULL" : " RET=HDRS"); if (ESMTP.dsn.envid) sprintf (tmp + strlen (tmp)," ENVID=%.100s",ESMTP.dsn.envid); } } /* send "MAIL FROM" command */ switch (smtp_send (stream,type,tmp)) { case SMTPUNAVAIL: /* mailbox unavailable? */ case SMTPWANTAUTH: /* wants authentication? */ case SMTPWANTAUTH2: if (ESMTP.auth) retry = T;/* yes, retry with authentication */ case SMTPOK: /* looks good */ break; default: /* other failure */ return NIL; } /* negotiate the recipients */ if (!retry && env->to) retry = smtp_rcpt (stream,env->to,&error); if (!retry && env->cc) retry = smtp_rcpt (stream,env->cc,&error); if (!retry && env->bcc) retry = smtp_rcpt (stream,env->bcc,&error); if (!retry && error) { /* any recipients failed? */ smtp_send (stream,"RSET",NIL); smtp_seterror (stream,SMTPHARDERROR,"One or more recipients failed"); return NIL; } } while (retry); /* negotiate data command */ if (!(smtp_send (stream,"DATA",NIL) == SMTPREADY)) return NIL; /* send message data */ if (!rfc822_output_full (&buf,env,body, ESMTP.eightbit.ok && ESMTP.eightbit.want)) { smtp_fake (stream,"SMTP connection broken (message data)"); return NIL; /* can't do much else here */ } /* send trailing dot */ return (smtp_send (stream,".",NIL) == SMTPOK) ? LONGT : NIL; } /* Simple Mail Transfer Protocol send VERBose * Accepts: SMTP stream * Returns: T if successful, else NIL * * Descriptive text formerly in [al]pine sources: * At worst, this command may cause the SMTP connection to get nuked. Modern * sendmail's recognize it, and possibly other SMTP implementations (the "ON" * arg is for PMDF). What's more, if it works, the reply code and accompanying * text may vary from server to server. */ long smtp_verbose (SENDSTREAM *stream) { /* accept any 2xx reply code */ return ((smtp_send (stream,"VERB","ON") / (long) 100) == 2) ? LONGT : NIL; } /* Internal routines */ /* Simple Mail Transfer Protocol send recipient * Accepts: SMTP stream * address list * pointer to error flag * Returns: T if should retry, else NIL */ long smtp_rcpt (SENDSTREAM *stream,ADDRESS *adr,long *error) { char *s,tmp[2*MAILTMPLEN],orcpt[MAILTMPLEN]; while (adr) { /* for each address on the list */ /* clear any former error */ if (adr->error) fs_give ((void **) &adr->error); if (adr->host) { /* ignore group syntax */ /* enforce SMTP limits to protect the buffer */ if (strlen (adr->mailbox) > MAXLOCALPART) { adr->error = cpystr ("501 Recipient name too long"); *error = T; } else if ((strlen (adr->host) > SMTPMAXDOMAIN)) { adr->error = cpystr ("501 Recipient domain too long"); *error = T; } #ifndef RFC2821 /* old code with A-D-L support */ else if (adr->adl && (strlen (adr->adl) > SMTPMAXPATH)) { adr->error = cpystr ("501 Path too long"); *error = T; } #endif else { strcpy (tmp,"TO:<"); /* compose "RCPT TO:" */ #ifdef RFC2821 rfc822_cat (tmp,adr->mailbox,NIL); sprintf (tmp + strlen (tmp),"@%s>",adr->host); #else /* old code with A-D-L support */ rfc822_address (tmp,adr); strcat (tmp,">"); #endif /* want notifications */ if (ESMTP.ok && ESMTP.dsn.ok && ESMTP.dsn.want) { /* yes, start with prefix */ strcat (tmp," NOTIFY="); s = tmp + strlen (tmp); if (ESMTP.dsn.notify.failure) strcat (s,"FAILURE,"); if (ESMTP.dsn.notify.delay) strcat (s,"DELAY,"); if (ESMTP.dsn.notify.success) strcat (s,"SUCCESS,"); /* tie off last comma */ if (*s) s[strlen (s) - 1] = '\0'; else strcat (tmp,"NEVER"); if (adr->orcpt.addr) { sprintf (orcpt,"%.498s;%.498s", adr->orcpt.type ? adr->orcpt.type : "rfc822", adr->orcpt.addr); sprintf (tmp + strlen (tmp)," ORCPT=%.500s",orcpt); } } switch (smtp_send (stream,"RCPT",tmp)) { case SMTPOK: /* looks good */ break; case SMTPUNAVAIL: /* mailbox unavailable? */ case SMTPWANTAUTH: /* wants authentication? */ case SMTPWANTAUTH2: if (ESMTP.auth) return T; default: /* other failure */ *error = T; /* note that an error occurred */ adr->error = cpystr (stream->reply); } } } adr = adr->next; /* do any subsequent recipients */ } return NIL; /* no retry called for */ } /* Simple Mail Transfer Protocol send command * Accepts: SEND stream * text * Returns: reply code */ long smtp_send (SENDSTREAM *stream,char *command,char *args) { long ret; char *s = (char *) fs_get (strlen (command) + (args ? strlen (args) + 1 : 0) + 3); /* build the complete command */ if (args) sprintf (s,"%s %s",command,args); else strcpy (s,command); if (stream->debug) mail_dlog (s,stream->sensitive); strcat (s,"\015\012"); /* send the command */ if (stream->netstream && net_soutr (stream->netstream,s)) { do stream->replycode = smtp_reply (stream); while ((stream->replycode < 100) || (stream->reply[3] == '-')); ret = stream->replycode; } else ret = smtp_fake (stream,"SMTP connection broken (command)"); fs_give ((void **) &s); return ret; } /* Simple Mail Transfer Protocol get reply * Accepts: SMTP stream * Returns: reply code */ long smtp_reply (SENDSTREAM *stream) { smtpverbose_t pv = (smtpverbose_t) mail_parameters (NIL,GET_SMTPVERBOSE,NIL); long reply; /* flush old reply */ if (stream->reply) fs_give ((void **) &stream->reply); /* get reply */ if (stream->netstream && (stream->reply = net_getline (stream->netstream))) { if (stream->debug) mm_dlog (stream->reply); /* return response code */ reply = atol (stream->reply); if (pv && (reply < 100)) (*pv) (stream->reply); } else reply = smtp_fake (stream,"SMTP connection broken (reply)"); return reply; } /* Simple Mail Transfer Protocol send EHLO * Accepts: SMTP stream * host name to use in EHLO * NETMBX structure * Returns: reply code */ long smtp_ehlo (SENDSTREAM *stream,char *host,NETMBX *mb) { unsigned long i,j; long flags = (mb->secflag ? AU_SECURE : NIL) | (mb->authuser[0] ? AU_AUTHUSER : NIL); char *s,*t,*r,tmp[MAILTMPLEN]; /* clear ESMTP data */ memset (&ESMTP,0,sizeof (ESMTP)); if (mb->loser) return 500; /* never do EHLO if a loser */ sprintf (tmp,"EHLO %s",host); /* build the complete command */ if (stream->debug) mm_dlog (tmp); strcat (tmp,"\015\012"); /* send the command */ if (!net_soutr (stream->netstream,tmp)) return smtp_fake (stream,"SMTP connection broken (EHLO)"); /* got an OK reply? */ do if ((i = smtp_reply (stream)) == SMTPOK) { /* hack for AUTH= */ if (stream->reply[4] && stream->reply[5] && stream->reply[6] && stream->reply[7] && (stream->reply[8] == '=')) stream->reply[8] = ' '; /* get option code */ if (!(s = strtok_r (stream->reply+4," ",&r))); /* have option, does it have a value */ else if ((t = strtok_r (NIL," ",&r)) && *t) { /* EHLO options which take arguments */ if (!compare_cstring (s,"SIZE")) { if (isdigit (*t)) ESMTP.size.limit = strtoul (t,&t,10); ESMTP.size.ok = T; } else if (!compare_cstring (s,"DELIVERBY")) { if (isdigit (*t)) ESMTP.deliverby.minby = strtoul (t,&t,10); ESMTP.deliverby.ok = T; } else if (!compare_cstring (s,"ATRN")) { ESMTP.atrn.domains = cpystr (t); ESMTP.atrn.ok = T; } else if (!compare_cstring (s,"AUTH")) do if ((j = mail_lookup_auth_name (t,flags)) && (--j < MAXAUTHENTICATORS)) ESMTP.auth |= (1 << j); while ((t = strtok_r (NIL," ",&r)) && *t); } /* EHLO options which do not take arguments */ else if (!compare_cstring (s,"SIZE")) ESMTP.size.ok = T; else if (!compare_cstring (s,"8BITMIME")) ESMTP.eightbit.ok = T; else if (!compare_cstring (s,"DSN")) ESMTP.dsn.ok = T; else if (!compare_cstring (s,"ATRN")) ESMTP.atrn.ok = T; else if (!compare_cstring (s,"SEND")) ESMTP.service.send = T; else if (!compare_cstring (s,"SOML")) ESMTP.service.soml = T; else if (!compare_cstring (s,"SAML")) ESMTP.service.saml = T; else if (!compare_cstring (s,"EXPN")) ESMTP.service.expn = T; else if (!compare_cstring (s,"HELP")) ESMTP.service.help = T; else if (!compare_cstring (s,"TURN")) ESMTP.service.turn = T; else if (!compare_cstring (s,"ETRN")) ESMTP.service.etrn = T; else if (!compare_cstring (s,"STARTTLS")) ESMTP.service.starttls = T; else if (!compare_cstring (s,"RELAY")) ESMTP.service.relay = T; else if (!compare_cstring (s,"PIPELINING")) ESMTP.service.pipe = T; else if (!compare_cstring (s,"ENHANCEDSTATUSCODES")) ESMTP.service.ensc = T; else if (!compare_cstring (s,"BINARYMIME")) ESMTP.service.bmime = T; else if (!compare_cstring (s,"CHUNKING")) ESMTP.service.chunk = T; } while ((i < 100) || (stream->reply[3] == '-')); /* disable LOGIN if PLAIN also advertised */ if ((j = mail_lookup_auth_name ("PLAIN",NIL)) && (--j < MAXAUTHENTICATORS) && (ESMTP.auth & (1 << j)) && (j = mail_lookup_auth_name ("LOGIN",NIL)) && (--j < MAXAUTHENTICATORS)) ESMTP.auth &= ~(1 << j); return i; /* return the response code */ } /* Simple Mail Transfer Protocol set fake error and abort * Accepts: SMTP stream * error text * Returns: SMTPSOFTFATAL, always */ long smtp_fake (SENDSTREAM *stream,char *text) { if (stream->netstream) { /* close net connection if still open */ net_close (stream->netstream); stream->netstream = NIL; } /* set last error */ return smtp_seterror (stream,SMTPSOFTFATAL,text); } /* Simple Mail Transfer Protocol set error * Accepts: SMTP stream * SMTP error code * error text * Returns: error code */ static long smtp_seterror (SENDSTREAM *stream,long code,char *text) { /* flush any old reply */ if (stream->reply ) fs_give ((void **) &stream->reply); /* set up pseudo-reply string */ stream->reply = (char *) fs_get (20+strlen (text)); sprintf (stream->reply,"%ld %s",code,text); return code; /* return error code */ } /* Simple Mail Transfer Protocol filter mail * Accepts: stream * string * Returns: T on success, NIL on failure */ long smtp_soutr (void *stream,char *s) { char c,*t; /* "." on first line */ if (s[0] == '.') net_sout (stream,".",1); /* find lines beginning with a "." */ while (t = strstr (s,"\015\012.")) { c = *(t += 3); /* remember next character after "." */ *t = '\0'; /* tie off string */ /* output prefix */ if (!net_sout (stream,s,t-s)) return NIL; *t = c; /* restore delimiter */ s = t - 1; /* push pointer up to the "." */ } /* output remainder of text */ return *s ? net_soutr (stream,s) : T; } alpine-2.10+dfsg/imap/src/c-client/mail.c0000600000175000017500000062437712074110156021664 0ustar paulproteuspaulproteus/* ======================================================================== * Copyright 1988-2008 University of Washington * * Licensed under the Apache License, Version 2.0 (the "License"); * you may not use this file except in compliance with the License. * You may obtain a copy of the License at * * http://www.apache.org/licenses/LICENSE-2.0 * * * ======================================================================== */ /* * Program: Mailbox Access routines * * Author: Mark Crispin * UW Technology * University of Washington * Seattle, WA 98195 * Internet: MRC@Washington.EDU * * Date: 22 November 1989 * Last Edited: 15 April 2008 */ #include #include #include #include "c-client.h" char *UW_copyright = "Copyright 1988-2007 University of Washington\n\nLicensed under the Apache License, Version 2.0 (the \"License\");\nyou may not use this file except in compliance with the License.\nYou may obtain a copy of the License at\n\n http://www.apache.org/licenses/LICENSE-2.0\n"; /* c-client global data */ /* version of this library */ static char *mailcclientversion = CCLIENTVERSION; /* list of mail drivers */ static DRIVER *maildrivers = NIL; /* list of authenticators */ static AUTHENTICATOR *mailauthenticators = NIL; /* SSL driver pointer */ static NETDRIVER *mailssldriver = NIL; /* pointer to alternate gets function */ static mailgets_t mailgets = NIL; /* pointer to read progress function */ static readprogress_t mailreadprogress = NIL; /* mail cache manipulation function */ static mailcache_t mailcache = mm_cache; /* RFC-822 output generator */ static rfc822out_t mail822out = NIL; /* RFC-822 output generator (new style) */ static rfc822outfull_t mail822outfull = NIL; /* SMTP verbose callback */ static smtpverbose_t mailsmtpverbose = mm_dlog; /* proxy copy routine */ static mailproxycopy_t mailproxycopy = NIL; /* RFC-822 external line parse */ static parseline_t mailparseline = NIL; /* RFC-822 external phrase parser */ static parsephrase_t mailparsephrase = NIL; static kinit_t mailkinit = NIL; /* application kinit callback */ /* note network sent command */ static sendcommand_t mailsendcommand = NIL; /* newsrc file name decision function */ static newsrcquery_t mailnewsrcquery = NIL; /* ACL results callback */ static getacl_t mailaclresults = NIL; /* list rights results callback */ static listrights_t maillistrightsresults = NIL; /* my rights results callback */ static myrights_t mailmyrightsresults = NIL; /* quota results callback */ static quota_t mailquotaresults = NIL; /* quota root results callback */ static quotaroot_t mailquotarootresults = NIL; /* sorted results callback */ static sortresults_t mailsortresults = NIL; /* threaded results callback */ static threadresults_t mailthreadresults = NIL; /* COPY UID results */ static copyuid_t mailcopyuid = NIL; /* APPEND UID results */ static appenduid_t mailappenduid = NIL; /* free elt extra stuff callback */ static freeeltsparep_t mailfreeeltsparep = NIL; /* free envelope extra stuff callback */ static freeenvelopesparep_t mailfreeenvelopesparep = NIL; /* free body extra stuff callback */ static freebodysparep_t mailfreebodysparep = NIL; /* free stream extra stuff callback */ static freestreamsparep_t mailfreestreamsparep = NIL; /* SSL start routine */ static sslstart_t mailsslstart = NIL; /* SSL certificate query */ static sslcertificatequery_t mailsslcertificatequery = NIL; /* SSL client certificate */ static sslclientcert_t mailsslclientcert = NIL; /* SSL client private key */ static sslclientkey_t mailsslclientkey = NIL; /* SSL failure notify */ static sslfailure_t mailsslfailure = NIL; /* snarf interval */ static long mailsnarfinterval = 60; /* snarf preservation */ static long mailsnarfpreserve = NIL; /* newsrc name uses canonical host */ static long mailnewsrccanon = LONGT; /* supported threaders */ static THREADER mailthreadordsub = { "ORDEREDSUBJECT",mail_thread_orderedsubject,NIL }; static THREADER mailthreadlist = { "REFERENCES",mail_thread_references,&mailthreadordsub }; /* server name */ static char *servicename = "unknown"; /* server externally-set authentication ID */ static char *externalauthid = NIL; static int expungeatping = T; /* mail_ping() may call mm_expunged() */ static int trysslfirst = NIL; /* always try SSL first */ static int notimezones = NIL; /* write timezones in "From " header */ static int trustdns = T; /* do DNS canonicalization */ static int saslusesptrname = T; /* SASL uses name from DNS PTR lookup */ /* trustdns also must be set */ static int debugsensitive = NIL;/* debug telemetry includes sensitive data */ /* Default mail cache handler * Accepts: pointer to cache handle * message number * caching function * Returns: cache data */ void *mm_cache (MAILSTREAM *stream,unsigned long msgno,long op) { size_t n; void *ret = NIL; unsigned long i; switch ((int) op) { /* what function? */ case CH_INIT: /* initialize cache */ if (stream->cache) { /* flush old cache contents */ while (stream->cachesize) { mm_cache (stream,stream->cachesize,CH_FREE); mm_cache (stream,stream->cachesize--,CH_FREESORTCACHE); } fs_give ((void **) &stream->cache); fs_give ((void **) &stream->sc); stream->nmsgs = 0; /* can't have any messages now */ } break; case CH_SIZE: /* (re-)size the cache */ if (!stream->cache) { /* have a cache already? */ /* no, create new cache */ n = (stream->cachesize = msgno + CACHEINCREMENT) * sizeof (void *); stream->cache = (MESSAGECACHE **) memset (fs_get (n),0,n); stream->sc = (SORTCACHE **) memset (fs_get (n),0,n); } /* is existing cache size large neough */ else if (msgno > stream->cachesize) { i = stream->cachesize; /* remember old size */ n = (stream->cachesize = msgno + CACHEINCREMENT) * sizeof (void *); fs_resize ((void **) &stream->cache,n); fs_resize ((void **) &stream->sc,n); while (i < stream->cachesize) { stream->cache[i] = NIL; stream->sc[i++] = NIL; } } break; case CH_MAKEELT: /* return elt, make if necessary */ if (!stream->cache[msgno - 1]) stream->cache[msgno - 1] = mail_new_cache_elt (msgno); /* falls through */ case CH_ELT: /* return elt */ ret = (void *) stream->cache[msgno - 1]; break; case CH_SORTCACHE: /* return sortcache entry, make if needed */ if (!stream->sc[msgno - 1]) stream->sc[msgno - 1] = (SORTCACHE *) memset (fs_get (sizeof (SORTCACHE)),0,sizeof (SORTCACHE)); ret = (void *) stream->sc[msgno - 1]; break; case CH_FREE: /* free elt */ mail_free_elt (&stream->cache[msgno - 1]); break; case CH_FREESORTCACHE: if (stream->sc[msgno - 1]) { if (stream->sc[msgno - 1]->from) fs_give ((void **) &stream->sc[msgno - 1]->from); if (stream->sc[msgno - 1]->to) fs_give ((void **) &stream->sc[msgno - 1]->to); if (stream->sc[msgno - 1]->cc) fs_give ((void **) &stream->sc[msgno - 1]->cc); if (stream->sc[msgno - 1]->subject) fs_give ((void **) &stream->sc[msgno - 1]->subject); if (stream->sc[msgno - 1]->unique && (stream->sc[msgno - 1]->unique != stream->sc[msgno - 1]->message_id)) fs_give ((void **) &stream->sc[msgno - 1]->unique); if (stream->sc[msgno - 1]->message_id) fs_give ((void **) &stream->sc[msgno - 1]->message_id); if (stream->sc[msgno - 1]->references) mail_free_stringlist (&stream->sc[msgno - 1]->references); fs_give ((void **) &stream->sc[msgno - 1]); } break; case CH_EXPUNGE: /* expunge cache slot */ for (i = msgno - 1; msgno < stream->nmsgs; i++,msgno++) { if (stream->cache[i] = stream->cache[msgno]) stream->cache[i]->msgno = msgno; stream->sc[i] = stream->sc[msgno]; } stream->cache[i] = NIL; /* top of cache goes away */ stream->sc[i] = NIL; break; default: fatal ("Bad mm_cache op"); break; } return ret; } /* Dummy string driver for complete in-memory strings */ static void mail_string_init (STRING *s,void *data,unsigned long size); static char mail_string_next (STRING *s); static void mail_string_setpos (STRING *s,unsigned long i); STRINGDRIVER mail_string = { mail_string_init, /* initialize string structure */ mail_string_next, /* get next byte in string structure */ mail_string_setpos /* set position in string structure */ }; /* Initialize mail string structure for in-memory string * Accepts: string structure * pointer to string * size of string */ static void mail_string_init (STRING *s,void *data,unsigned long size) { /* set initial string pointers */ s->chunk = s->curpos = (char *) (s->data = data); /* and sizes */ s->size = s->chunksize = s->cursize = size; s->data1 = s->offset = 0; /* never any offset */ } /* Get next character from string * Accepts: string structure * Returns: character, string structure chunk refreshed */ static char mail_string_next (STRING *s) { return *s->curpos++; /* return the last byte */ } /* Set string pointer position * Accepts: string structure * new position */ static void mail_string_setpos (STRING *s,unsigned long i) { s->curpos = s->chunk + i; /* set new position */ s->cursize = s->chunksize - i;/* and new size */ } /* Mail routines * * mail_xxx routines are the interface between this module and the outside * world. Only these routines should be referenced by external callers. * * Note that there is an important difference between a "sequence" and a * "message #" (msgno). A sequence is a string representing a sequence in * {"n", "n:m", or combination separated by commas} format, whereas a msgno * is a single integer. * */ /* Mail version check * Accepts: version */ void mail_versioncheck (char *version) { /* attempt to protect again wrong .h */ if (strcmp (version,mailcclientversion)) { char tmp[MAILTMPLEN]; sprintf (tmp,"c-client library version skew, app=%.100s library=%.100s", version,mailcclientversion); fatal (tmp); } } /* Mail link driver * Accepts: driver to add to list */ void mail_link (DRIVER *driver) { DRIVER **d = &maildrivers; while (*d) d = &(*d)->next; /* find end of list of drivers */ *d = driver; /* put driver at the end */ driver->next = NIL; /* this driver is the end of the list */ } /* Mail manipulate driver parameters * Accepts: mail stream * function code * function-dependent value * Returns: function-dependent return value */ void *mail_parameters (MAILSTREAM *stream,long function,void *value) { void *r,*ret = NIL; DRIVER *d; AUTHENTICATOR *a; switch ((int) function) { case SET_INBOXPATH: fatal ("SET_INBOXPATH not permitted"); case GET_INBOXPATH: if ((stream || (stream = mail_open (NIL,"INBOX",OP_PROTOTYPE))) && stream->dtb) ret = (*stream->dtb->parameters) (function,value); break; case SET_THREADERS: fatal ("SET_THREADERS not permitted"); case GET_THREADERS: /* use stream dtb instead of global */ ret = (stream && stream->dtb) ? /* KLUDGE ALERT: note stream passed as value */ (*stream->dtb->parameters) (function,stream) : (void *) &mailthreadlist; break; case SET_NAMESPACE: fatal ("SET_NAMESPACE not permitted"); break; case SET_NEWSRC: /* too late on open stream */ if (stream && stream->dtb && (stream != ((*stream->dtb->open) (NIL)))) fatal ("SET_NEWSRC not permitted"); else ret = env_parameters (function,value); break; case GET_NAMESPACE: case GET_NEWSRC: /* use stream dtb instead of environment */ ret = (stream && stream->dtb) ? /* KLUDGE ALERT: note stream passed as value */ (*stream->dtb->parameters) (function,stream) : env_parameters (function,value); break; case ENABLE_DEBUG: fatal ("ENABLE_DEBUG not permitted"); case DISABLE_DEBUG: fatal ("DISABLE_DEBUG not permitted"); case SET_DIRFMTTEST: fatal ("SET_DIRFMTTEST not permitted"); case GET_DIRFMTTEST: if (!(stream && stream->dtb && (ret = (*stream->dtb->parameters) (function,NIL)))) fatal ("GET_DIRFMTTEST not permitted"); break; case SET_DRIVERS: fatal ("SET_DRIVERS not permitted"); case GET_DRIVERS: /* always return global */ ret = (void *) maildrivers; break; case SET_DRIVER: fatal ("SET_DRIVER not permitted"); case GET_DRIVER: for (d = maildrivers; d && compare_cstring (d->name,(char *) value); d = d->next); ret = (void *) d; break; case ENABLE_DRIVER: for (d = maildrivers; d && compare_cstring (d->name,(char *) value); d = d->next); if (ret = (void *) d) d->flags &= ~DR_DISABLE; break; case DISABLE_DRIVER: for (d = maildrivers; d && compare_cstring (d->name,(char *) value); d = d->next); if (ret = (void *) d) d->flags |= DR_DISABLE; break; case ENABLE_AUTHENTICATOR: for (a = mailauthenticators;/* scan authenticators */ a && compare_cstring (a->name,(char *) value); a = a->next); if (ret = (void *) a) a->flags &= ~AU_DISABLE; break; case DISABLE_AUTHENTICATOR: for (a = mailauthenticators;/* scan authenticators */ a && compare_cstring (a->name,(char *) value); a = a->next); if (ret = (void *) a) a->flags |= AU_DISABLE; break; case UNHIDE_AUTHENTICATOR: for (a = mailauthenticators;/* scan authenticators */ a && compare_cstring (a->name,(char *) value); a = a->next); if (ret = (void *) a) a->flags &= ~AU_HIDE; break; case HIDE_AUTHENTICATOR: for (a = mailauthenticators;/* scan authenticators */ a && compare_cstring (a->name,(char *) value); a = a->next); if (ret = (void *) a) a->flags |= AU_HIDE; break; case SET_EXTERNALAUTHID: if (value) { /* setting external authentication ID */ externalauthid = cpystr ((char *) value); mail_parameters (NIL,UNHIDE_AUTHENTICATOR,"EXTERNAL"); } else { /* clearing external authentication ID */ if (externalauthid) fs_give ((void **) &externalauthid); mail_parameters (NIL,HIDE_AUTHENTICATOR,"EXTERNAL"); } case GET_EXTERNALAUTHID: ret = (void *) externalauthid; break; case SET_GETS: mailgets = (mailgets_t) value; case GET_GETS: ret = (void *) mailgets; break; case SET_READPROGRESS: mailreadprogress = (readprogress_t) value; case GET_READPROGRESS: ret = (void *) mailreadprogress; break; case SET_CACHE: mailcache = (mailcache_t) value; case GET_CACHE: ret = (void *) mailcache; break; case SET_RFC822OUTPUT: mail822out = (rfc822out_t) value; case GET_RFC822OUTPUT: ret = (void *) mail822out; break; case SET_RFC822OUTPUTFULL: mail822outfull = (rfc822outfull_t) value; case GET_RFC822OUTPUTFULL: ret = (void *) mail822outfull; break; case SET_SMTPVERBOSE: mailsmtpverbose = (smtpverbose_t) value; case GET_SMTPVERBOSE: ret = (void *) mailsmtpverbose; break; case SET_MAILPROXYCOPY: mailproxycopy = (mailproxycopy_t) value; case GET_MAILPROXYCOPY: ret = (void *) mailproxycopy; break; case SET_PARSELINE: mailparseline = (parseline_t) value; case GET_PARSELINE: ret = (void *) mailparseline; break; case SET_PARSEPHRASE: mailparsephrase = (parsephrase_t) value; case GET_PARSEPHRASE: ret = (void *) mailparsephrase; break; case SET_NEWSRCQUERY: mailnewsrcquery = (newsrcquery_t) value; case GET_NEWSRCQUERY: ret = (void *) mailnewsrcquery; break; case SET_NEWSRCCANONHOST: mailnewsrccanon = (long) value; case GET_NEWSRCCANONHOST: ret = (void *) mailnewsrccanon; break; case SET_COPYUID: mailcopyuid = (copyuid_t) value; case GET_COPYUID: ret = (void *) mailcopyuid; break; case SET_APPENDUID: mailappenduid = (appenduid_t) value; case GET_APPENDUID: ret = (void *) mailappenduid; break; case SET_FREEENVELOPESPAREP: mailfreeenvelopesparep = (freeenvelopesparep_t) value; case GET_FREEENVELOPESPAREP: ret = (void *) mailfreeenvelopesparep; break; case SET_FREEELTSPAREP: mailfreeeltsparep = (freeeltsparep_t) value; case GET_FREEELTSPAREP: ret = (void *) mailfreeeltsparep; break; case SET_FREESTREAMSPAREP: mailfreestreamsparep = (freestreamsparep_t) value; case GET_FREESTREAMSPAREP: ret = (void *) mailfreestreamsparep; break; case SET_FREEBODYSPAREP: mailfreebodysparep = (freebodysparep_t) value; case GET_FREEBODYSPAREP: ret = (void *) mailfreebodysparep; break; case SET_SSLSTART: mailsslstart = (sslstart_t) value; case GET_SSLSTART: ret = (void *) mailsslstart; break; case SET_SSLCERTIFICATEQUERY: mailsslcertificatequery = (sslcertificatequery_t) value; case GET_SSLCERTIFICATEQUERY: ret = (void *) mailsslcertificatequery; break; case SET_SSLCLIENTCERT: mailsslclientcert = (sslclientcert_t) value; case GET_SSLCLIENTCERT: ret = (void *) mailsslclientcert; break; case SET_SSLCLIENTKEY: mailsslclientkey = (sslclientkey_t) value; case GET_SSLCLIENTKEY: ret = (void *) mailsslclientkey; break; case SET_SSLFAILURE: mailsslfailure = (sslfailure_t) value; case GET_SSLFAILURE: ret = (void *) mailsslfailure; break; case SET_KINIT: mailkinit = (kinit_t) value; case GET_KINIT: ret = (void *) mailkinit; break; case SET_SENDCOMMAND: mailsendcommand = (sendcommand_t) value; case GET_SENDCOMMAND: ret = (void *) mailsendcommand; break; case SET_SERVICENAME: servicename = (char *) value; case GET_SERVICENAME: ret = (void *) servicename; break; case SET_EXPUNGEATPING: expungeatping = (value ? T : NIL); case GET_EXPUNGEATPING: ret = (void *) (expungeatping ? VOIDT : NIL); break; case SET_SORTRESULTS: mailsortresults = (sortresults_t) value; case GET_SORTRESULTS: ret = (void *) mailsortresults; break; case SET_THREADRESULTS: mailthreadresults = (threadresults_t) value; case GET_THREADRESULTS: ret = (void *) mailthreadresults; break; case SET_SSLDRIVER: mailssldriver = (NETDRIVER *) value; case GET_SSLDRIVER: ret = (void *) mailssldriver; break; case SET_TRYSSLFIRST: trysslfirst = (value ? T : NIL); case GET_TRYSSLFIRST: ret = (void *) (trysslfirst ? VOIDT : NIL); break; case SET_NOTIMEZONES: notimezones = (value ? T : NIL); case GET_NOTIMEZONES: ret = (void *) (notimezones ? VOIDT : NIL); break; case SET_TRUSTDNS: trustdns = (value ? T : NIL); case GET_TRUSTDNS: ret = (void *) (trustdns ? VOIDT : NIL); break; case SET_SASLUSESPTRNAME: saslusesptrname = (value ? T : NIL); case GET_SASLUSESPTRNAME: ret = (void *) (saslusesptrname ? VOIDT : NIL); break; case SET_DEBUGSENSITIVE: debugsensitive = (value ? T : NIL); case GET_DEBUGSENSITIVE: ret = (void *) (debugsensitive ? VOIDT : NIL); break; case SET_ACL: mailaclresults = (getacl_t) value; case GET_ACL: ret = (void *) mailaclresults; break; case SET_LISTRIGHTS: maillistrightsresults = (listrights_t) value; case GET_LISTRIGHTS: ret = (void *) maillistrightsresults; break; case SET_MYRIGHTS: mailmyrightsresults = (myrights_t) value; case GET_MYRIGHTS: ret = (void *) mailmyrightsresults; break; case SET_QUOTA: mailquotaresults = (quota_t) value; case GET_QUOTA: ret = (void *) mailquotaresults; break; case SET_QUOTAROOT: mailquotarootresults = (quotaroot_t) value; case GET_QUOTAROOT: ret = (void *) mailquotarootresults; break; case SET_SNARFINTERVAL: mailsnarfinterval = (long) value; case GET_SNARFINTERVAL: ret = (void *) mailsnarfinterval; break; case SET_SNARFPRESERVE: mailsnarfpreserve = (long) value; case GET_SNARFPRESERVE: ret = (void *) mailsnarfpreserve; break; case SET_SNARFMAILBOXNAME: if (stream) { /* have a stream? */ if (stream->snarf.name) fs_give ((void **) &stream->snarf.name); stream->snarf.name = cpystr ((char *) value); } else fatal ("SET_SNARFMAILBOXNAME with no stream"); case GET_SNARFMAILBOXNAME: if (stream) ret = (void *) stream->snarf.name; break; default: if (r = smtp_parameters (function,value)) ret = r; if (r = env_parameters (function,value)) ret = r; if (r = tcp_parameters (function,value)) ret = r; if (stream && stream->dtb) {/* if have stream, do for its driver only */ if (r = (*stream->dtb->parameters) (function,value)) ret = r; } /* else do all drivers */ else for (d = maildrivers; d; d = d->next) if (r = (d->parameters) (function,value)) ret = r; break; } return ret; } /* Mail validate mailbox name * Accepts: MAIL stream * mailbox name * purpose string for error message * Return: driver factory on success, NIL on failure */ DRIVER *mail_valid (MAILSTREAM *stream,char *mailbox,char *purpose) { char tmp[MAILTMPLEN]; DRIVER *factory = NIL; /* never allow names with newlines */ if (strpbrk (mailbox,"\015\012")) { if (purpose) { /* if want an error message */ sprintf (tmp,"Can't %s with such a name",purpose); MM_LOG (tmp,ERROR); } return NIL; } /* validate name, find driver factory */ if (strlen (mailbox) < (NETMAXHOST+(NETMAXUSER*2)+NETMAXMBX+NETMAXSRV+50)) for (factory = maildrivers; factory && ((factory->flags & DR_DISABLE) || ((factory->flags & DR_LOCAL) && (*mailbox == '{')) || !(*factory->valid) (mailbox)); factory = factory->next); /* validate factory against non-dummy stream */ if (factory && stream && stream->dtb && (stream->dtb != factory) && strcmp (stream->dtb->name,"dummy")) /* factory invalid; if dummy, use stream */ factory = strcmp (factory->name,"dummy") ? NIL : stream->dtb; if (!factory && purpose) { /* if want an error message */ sprintf (tmp,"Can't %s %.80s: %s",purpose,mailbox,(*mailbox == '{') ? "invalid remote specification" : "no such mailbox"); MM_LOG (tmp,ERROR); } return factory; /* return driver factory */ } /* Mail validate network mailbox name * Accepts: mailbox name * mailbox driver to validate against * pointer to where to return host name if non-NIL * pointer to where to return mailbox name if non-NIL * Returns: driver on success, NIL on failure */ DRIVER *mail_valid_net (char *name,DRIVER *drv,char *host,char *mailbox) { NETMBX mb; if (!mail_valid_net_parse (name,&mb) || strcmp (mb.service,drv->name)) return NIL; if (host) strcpy (host,mb.host); if (mailbox) strcpy (mailbox,mb.mailbox); return drv; } /* Mail validate network mailbox name * Accepts: mailbox name * NETMBX structure to return values * Returns: T on success, NIL on failure */ long mail_valid_net_parse (char *name,NETMBX *mb) { return mail_valid_net_parse_work (name,mb,"imap"); } /* Mail validate network mailbox name worker routine * Accepts: mailbox name * NETMBX structure to return values * default service * Returns: T on success, NIL on failure */ long mail_valid_net_parse_work (char *name,NETMBX *mb,char *service) { int i,j; char c,*s,*t,*v,tmp[MAILTMPLEN],arg[MAILTMPLEN]; /* initialize structure */ memset (mb,'\0',sizeof (NETMBX)); /* must have host specification */ if (*name++ != '{') return NIL; if (*name == '[') { /* if domain literal, find its ending */ if (!((v = strpbrk (name,"]}")) && (*v++ == ']'))) return NIL; } /* find end of host name */ else if (!(v = strpbrk (name,"/:}"))) return NIL; /* validate length, find mailbox part */ if (!((i = v - name) && (i < NETMAXHOST) && (t = strchr (v,'}')) && ((j = t - v) < MAILTMPLEN) && (strlen (t+1) < (size_t) NETMAXMBX))) return NIL; /* invalid mailbox */ strncpy (mb->host,name,i); /* set host name */ strncpy (mb->orighost,name,i); mb->host[i] = mb->orighost[i] = '\0'; strcpy (mb->mailbox,t+1); /* set mailbox name */ if (t - v) { /* any switches or port specification? */ strncpy (t = tmp,v,j); /* copy it */ tmp[j] = '\0'; /* tie it off */ c = *t++; /* get first delimiter */ do switch (c) { /* act based upon the character */ case ':': /* port specification */ if (mb->port || !(mb->port = strtoul (t,&t,10))) return NIL; c = t ? *t++ : '\0'; /* get delimiter, advance pointer */ break; case '/': /* switch */ /* find delimiter */ if (t = strpbrk (s = t,"/:=")) { c = *t; /* remember delimiter for later */ *t++ = '\0'; /* tie off switch name */ } else c = '\0'; /* no delimiter */ if (c == '=') { /* parse switches which take arguments */ if (*t == '"') { /* quoted string? */ for (v = arg,i = 0,++t; (c = *t++) != '"';) { if (!c) return NIL; /* unterminated string */ /* quote next character */ if (c == '\\') c = *t++; if (!c) return NIL; /* can't quote NUL either */ arg[i++] = c; } c = *t++; /* remember delimiter for later */ arg[i] = '\0'; /* tie off argument */ } else { /* non-quoted argument */ if (t = strpbrk (v = t,"/:")) { c = *t; /* remember delimiter for later */ *t++ = '\0'; /* tie off switch name */ } else c = '\0'; /* no delimiter */ i = strlen (v); /* length of argument */ } if (!compare_cstring (s,"service") && (i < NETMAXSRV) && !*mb->service) lcase (strcpy (mb->service,v)); else if (!compare_cstring (s,"user") && (i < NETMAXUSER) && !*mb->user) strcpy (mb->user,v); else if (!compare_cstring (s,"authuser") && (i < NETMAXUSER) && !*mb->authuser) strcpy (mb->authuser,v); else return NIL; } else { /* non-argument switch */ if (!compare_cstring (s,"anonymous")) mb->anoflag = T; else if (!compare_cstring (s,"debug")) mb->dbgflag = T; else if (!compare_cstring (s,"readonly")) mb->readonlyflag = T; else if (!compare_cstring (s,"secure")) mb->secflag = T; else if (!compare_cstring (s,"norsh")) mb->norsh = T; else if (!compare_cstring (s,"loser")) mb->loser = T; else if (!compare_cstring (s,"tls") && !mb->notlsflag) mb->tlsflag = T; else if (!compare_cstring (s,"tls-sslv23") && !mb->notlsflag) mb->tlssslv23 = mb->tlsflag = T; else if (!compare_cstring (s,"notls") && !mb->tlsflag) mb->notlsflag = T; else if (!compare_cstring (s,"tryssl")) mb->trysslflag = mailssldriver? T : NIL; else if (mailssldriver && !compare_cstring (s,"ssl") && !mb->tlsflag) mb->sslflag = mb->notlsflag = T; else if (mailssldriver && !compare_cstring (s,"novalidate-cert")) mb->novalidate = T; /* hack for compatibility with the past */ else if (mailssldriver && !compare_cstring (s,"validate-cert")); /* service switches below here */ else if (*mb->service) return NIL; else if (!compare_cstring (s,"imap") || !compare_cstring (s,"nntp") || !compare_cstring (s,"pop3") || !compare_cstring (s,"smtp") || !compare_cstring (s,"submit")) lcase (strcpy (mb->service,s)); else if (!compare_cstring (s,"imap2") || !compare_cstring (s,"imap2bis") || !compare_cstring (s,"imap4") || !compare_cstring (s,"imap4rev1")) strcpy (mb->service,"imap"); else if (!compare_cstring (s,"pop")) strcpy (mb->service,"pop3"); else return NIL; /* invalid non-argument switch */ } break; default: /* anything else is bogus */ return NIL; } while (c); /* see if anything more to parse */ } /* default mailbox name */ if (!*mb->mailbox) strcpy (mb->mailbox,"INBOX"); /* default service name */ if (!*mb->service) strcpy (mb->service,service); /* /norsh only valid if imap */ if (mb->norsh && strcmp (mb->service,"imap")) return NIL; return T; } /* Mail scan mailboxes for string * Accepts: mail stream * reference * pattern to search * contents to search */ void mail_scan (MAILSTREAM *stream,char *ref,char *pat,char *contents) { int remote = ((*pat == '{') || (ref && *ref == '{')); DRIVER *d; if (ref && (strlen (ref) > NETMAXMBX)) { char tmp[MAILTMPLEN]; sprintf (tmp,"Invalid LIST reference specification: %.80s",ref); MM_LOG (tmp,ERROR); return; } if (strlen (pat) > NETMAXMBX) { char tmp[MAILTMPLEN]; sprintf (tmp,"Invalid LIST pattern specification: %.80s",pat); MM_LOG (tmp,ERROR); return; } if (*pat == '{') ref = NIL; /* ignore reference if pattern is remote */ if (stream) { /* if have a stream, do it for that stream */ if ((d = stream->dtb) && d->scan && !(((d->flags & DR_LOCAL) && remote))) (*d->scan) (stream,ref,pat,contents); } /* otherwise do for all DTB's */ else for (d = maildrivers; d; d = d->next) if (d->scan && !((d->flags & DR_DISABLE) || ((d->flags & DR_LOCAL) && remote))) (d->scan) (NIL,ref,pat,contents); } /* Mail list mailboxes * Accepts: mail stream * reference * pattern to search */ void mail_list (MAILSTREAM *stream,char *ref,char *pat) { int remote = ((*pat == '{') || (ref && *ref == '{')); DRIVER *d = maildrivers; if (ref && (strlen (ref) > NETMAXMBX)) { char tmp[MAILTMPLEN]; sprintf (tmp,"Invalid LIST reference specification: %.80s",ref); MM_LOG (tmp,ERROR); return; } if (strlen (pat) > NETMAXMBX) { char tmp[MAILTMPLEN]; sprintf (tmp,"Invalid LIST pattern specification: %.80s",pat); MM_LOG (tmp,ERROR); return; } if (*pat == '{') ref = NIL; /* ignore reference if pattern is remote */ if (stream && stream->dtb) { /* if have a stream, do it for that stream */ if (!(((d = stream->dtb)->flags & DR_LOCAL) && remote)) (*d->list) (stream,ref,pat); } /* otherwise do for all DTB's */ else do if (!((d->flags & DR_DISABLE) || ((d->flags & DR_LOCAL) && remote))) (d->list) (NIL,ref,pat); while (d = d->next); /* until at the end */ } /* Mail list subscribed mailboxes * Accepts: mail stream * pattern to search */ void mail_lsub (MAILSTREAM *stream,char *ref,char *pat) { int remote = ((*pat == '{') || (ref && *ref == '{')); DRIVER *d = maildrivers; if (ref && (strlen (ref) > NETMAXMBX)) { char tmp[MAILTMPLEN]; sprintf (tmp,"Invalid LSUB reference specification: %.80s",ref); MM_LOG (tmp,ERROR); return; } if (strlen (pat) > NETMAXMBX) { char tmp[MAILTMPLEN]; sprintf (tmp,"Invalid LSUB pattern specification: %.80s",pat); MM_LOG (tmp,ERROR); return; } if (*pat == '{') ref = NIL; /* ignore reference if pattern is remote */ if (stream && stream->dtb) { /* if have a stream, do it for that stream */ if (!(((d = stream->dtb)->flags & DR_LOCAL) && remote)) (*d->lsub) (stream,ref,pat); } /* otherwise do for all DTB's */ else do if (!((d->flags & DR_DISABLE) || ((d->flags & DR_LOCAL) && remote))) (d->lsub) (NIL,ref,pat); while (d = d->next); /* until at the end */ } /* Mail subscribe to mailbox * Accepts: mail stream * mailbox to add to subscription list * Returns: T on success, NIL on failure */ long mail_subscribe (MAILSTREAM *stream,char *mailbox) { DRIVER *factory = mail_valid (stream,mailbox,"subscribe to mailbox"); return factory ? (factory->subscribe ? (*factory->subscribe) (stream,mailbox) : sm_subscribe (mailbox)) : NIL; } /* Mail unsubscribe to mailbox * Accepts: mail stream * mailbox to delete from subscription list * Returns: T on success, NIL on failure */ long mail_unsubscribe (MAILSTREAM *stream,char *mailbox) { DRIVER *factory = mail_valid (stream,mailbox,NIL); return (factory && factory->unsubscribe) ? (*factory->unsubscribe) (stream,mailbox) : sm_unsubscribe (mailbox); } /* Mail create mailbox * Accepts: mail stream * mailbox name to create * Returns: T on success, NIL on failure */ long mail_create (MAILSTREAM *stream,char *mailbox) { MAILSTREAM *ts; char *s,*t,tmp[MAILTMPLEN]; size_t i; DRIVER *d; /* never allow names with newlines */ if (s = strpbrk (mailbox,"\015\012")) { MM_LOG ("Can't create mailbox with such a name",ERROR); return NIL; } if (strlen (mailbox) >= (NETMAXHOST+(NETMAXUSER*2)+NETMAXMBX+NETMAXSRV+50)) { sprintf (tmp,"Can't create %.80s: %s",mailbox,(*mailbox == '{') ? "invalid remote specification" : "no such mailbox"); MM_LOG (tmp,ERROR); return NIL; } /* create of INBOX invalid */ if (!compare_cstring (mailbox,"INBOX")) { MM_LOG ("Can't create INBOX",ERROR); return NIL; } /* validate name */ if (s = mail_utf7_valid (mailbox)) { sprintf (tmp,"Can't create %s: %.80s",s,mailbox); MM_LOG (tmp,ERROR); return NIL; } /* see if special driver hack */ if ((mailbox[0] == '#') && ((mailbox[1] == 'd') || (mailbox[1] == 'D')) && ((mailbox[2] == 'r') || (mailbox[2] == 'R')) && ((mailbox[3] == 'i') || (mailbox[3] == 'I')) && ((mailbox[4] == 'v') || (mailbox[4] == 'V')) && ((mailbox[5] == 'e') || (mailbox[5] == 'E')) && ((mailbox[6] == 'r') || (mailbox[6] == 'R')) && (mailbox[7] == '.')) { /* copy driver until likely delimiter */ if ((s = strpbrk (t = mailbox+8,"/\\:")) && (i = s - t)) { strncpy (tmp,t,i); tmp[i] = '\0'; } else { sprintf (tmp,"Can't create mailbox %.80s: bad driver syntax",mailbox); MM_LOG (tmp,ERROR); return NIL; } for (d = maildrivers; d && strcmp (d->name,tmp); d = d->next); if (d) mailbox = ++s; /* skip past driver specification */ else { sprintf (tmp,"Can't create mailbox %.80s: unknown driver",mailbox); MM_LOG (tmp,ERROR); return NIL; } } /* use stream if one given or deterministic */ else if ((stream && stream->dtb) || (((*mailbox == '{') || (*mailbox == '#')) && (stream = mail_open (NIL,mailbox,OP_PROTOTYPE | OP_SILENT)))) d = stream->dtb; else if ((*mailbox != '{') && (ts = default_proto (NIL))) d = ts->dtb; else { /* failed utterly */ sprintf (tmp,"Can't create mailbox %.80s: indeterminate format",mailbox); MM_LOG (tmp,ERROR); return NIL; } return (*d->create) (stream,mailbox); } /* Mail delete mailbox * Accepts: mail stream * mailbox name to delete * Returns: T on success, NIL on failure */ long mail_delete (MAILSTREAM *stream,char *mailbox) { DRIVER *dtb = mail_valid (stream,mailbox,"delete mailbox"); if (!dtb) return NIL; if (((mailbox[0] == 'I') || (mailbox[0] == 'i')) && ((mailbox[1] == 'N') || (mailbox[1] == 'n')) && ((mailbox[2] == 'B') || (mailbox[2] == 'b')) && ((mailbox[3] == 'O') || (mailbox[3] == 'o')) && ((mailbox[4] == 'X') || (mailbox[4] == 'x')) && !mailbox[5]) { MM_LOG ("Can't delete INBOX",ERROR); return NIL; } return SAFE_DELETE (dtb,stream,mailbox); } /* Mail rename mailbox * Accepts: mail stream * old mailbox name * new mailbox name * Returns: T on success, NIL on failure */ long mail_rename (MAILSTREAM *stream,char *old,char *newname) { char *s,tmp[MAILTMPLEN]; DRIVER *dtb = mail_valid (stream,old,"rename mailbox"); if (!dtb) return NIL; /* validate name */ if (s = mail_utf7_valid (newname)) { sprintf (tmp,"Can't rename to %s: %.80s",s,newname); MM_LOG (tmp,ERROR); return NIL; } if ((*old != '{') && (*old != '#') && mail_valid (NIL,newname,NIL)) { sprintf (tmp,"Can't rename %.80s: mailbox %.80s already exists", old,newname); MM_LOG (tmp,ERROR); return NIL; } return SAFE_RENAME (dtb,stream,old,newname); } /* Validate mailbox as Modified UTF-7 * Accepts: candidate mailbox name * Returns: error string if error, NIL if valid */ char *mail_utf7_valid (char *mailbox) { char *s; for (s = mailbox; *s; s++) { /* make sure valid name */ /* reserved for future use with UTF-8 */ if (*s & 0x80) return "mailbox name with 8-bit octet"; /* validate modified UTF-7 */ else if (*s == '&') while (*++s != '-') switch (*s) { case '\0': return "unterminated modified UTF-7 name"; case '+': /* valid modified BASE64 */ case ',': break; /* all OK so far */ default: /* must be alphanumeric */ if (!isalnum (*s)) return "invalid modified UTF-7 name"; break; } } return NIL; /* all OK */ } /* Mail status of mailbox * Accepts: mail stream if open on this mailbox * mailbox name * status flags * Returns: T on success, NIL on failure */ long mail_status (MAILSTREAM *stream,char *mbx,long flags) { DRIVER *dtb = mail_valid (stream,mbx,"get status of mailbox"); if (!dtb) return NIL; /* only if valid */ if (stream && ((dtb != stream->dtb) || ((dtb->flags & DR_LOCAL) && strcmp (mbx,stream->mailbox) && strcmp (mbx,stream->original_mailbox)))) stream = NIL; /* stream not suitable */ return SAFE_STATUS (dtb,stream,mbx,flags); } /* Mail status of mailbox default handler * Accepts: mail stream * mailbox name * status flags * Returns: T on success, NIL on failure */ long mail_status_default (MAILSTREAM *stream,char *mbx,long flags) { MAILSTATUS status; unsigned long i; MAILSTREAM *tstream = NIL; /* make temporary stream (unless this mbx) */ if (!stream && !(stream = tstream = mail_open (NIL,mbx,OP_READONLY|OP_SILENT))) return NIL; status.flags = flags; /* return status values */ status.messages = stream->nmsgs; status.recent = stream->recent; if (flags & SA_UNSEEN) /* must search to get unseen messages */ for (i = 1,status.unseen = 0; i <= stream->nmsgs; i++) if (!mail_elt (stream,i)->seen) status.unseen++; status.uidnext = stream->uid_last + 1; status.uidvalidity = stream->uid_validity; MM_STATUS(stream,mbx,&status);/* pass status to main program */ if (tstream) mail_close (tstream); return T; /* success */ } /* Mail open * Accepts: candidate stream for recycling * mailbox name * open options * Returns: stream to use on success, NIL on failure */ MAILSTREAM *mail_open (MAILSTREAM *stream,char *name,long options) { int i; char c,*s,tmp[MAILTMPLEN]; NETMBX mb; DRIVER *d; switch (name[0]) { /* see if special handling */ case '#': /* possible special hacks */ if (((name[1] == 'M') || (name[1] == 'm')) && ((name[2] == 'O') || (name[2] == 'o')) && ((name[3] == 'V') || (name[3] == 'v')) && ((name[4] == 'E') || (name[4] == 'e')) && (c = name[5]) && (s = strchr (name+6,c)) && (i = s - (name + 6)) && (i < MAILTMPLEN)) { if (stream = mail_open (stream,s+1,options)) { strncpy (tmp,name+6,i); /* copy snarf mailbox name */ tmp[i] = '\0'; /* tie off name */ mail_parameters (stream,SET_SNARFMAILBOXNAME,(void *) tmp); stream->snarf.options = options; mail_ping (stream); /* do initial snarf */ /* punt if can't do initial snarf */ if (!stream->snarf.time) stream = mail_close (stream); } return stream; } /* special POP hack */ else if (((name[1] == 'P') || (name[1] == 'p')) && ((name[2] == 'O') || (name[2] == 'o')) && ((name[3] == 'P') || (name[3] == 'p')) && mail_valid_net_parse_work (name+4,&mb,"pop3") && !strcmp (mb.service,"pop3") && !mb.anoflag && !mb.readonlyflag) { if (stream = mail_open (stream,mb.mailbox,options)) { sprintf (tmp,"{%.255s",mb.host); if (mb.port) sprintf (tmp + strlen (tmp),":%lu",mb.port); if (mb.user[0]) sprintf (tmp + strlen (tmp),"/user=%.64s",mb.user); if (mb.dbgflag) strcat (tmp,"/debug"); if (mb.secflag) strcat (tmp,"/secure"); if (mb.tlsflag) strcat (tmp,"/tls"); if (mb.notlsflag) strcat (tmp,"/notls"); if (mb.sslflag) strcat (tmp,"/ssl"); if (mb.trysslflag) strcat (tmp,"/tryssl"); if (mb.novalidate) strcat (tmp,"/novalidate-cert"); strcat (tmp,"/pop3/loser}"); mail_parameters (stream,SET_SNARFMAILBOXNAME,(void *) tmp); mail_ping (stream); /* do initial snarf */ } return stream; /* return local mailbox stream */ } else if ((options & OP_PROTOTYPE) && ((name[1] == 'D') || (name[1] == 'd')) && ((name[2] == 'R') || (name[2] == 'r')) && ((name[3] == 'I') || (name[3] == 'i')) && ((name[4] == 'V') || (name[4] == 'v')) && ((name[5] == 'E') || (name[5] == 'e')) && ((name[6] == 'R') || (name[6] == 'r')) && (name[7] == '.')) { sprintf (tmp,"%.80s",name+8); /* tie off name at likely delimiter */ if (s = strpbrk (tmp,"/\\:")) *s++ = '\0'; else { sprintf (tmp,"Can't resolve mailbox %.80s: bad driver syntax",name); MM_LOG (tmp,ERROR); return mail_close (stream); } for (d = maildrivers; d && compare_cstring (d->name,tmp); d = d->next); if (d) return (*d->open) (NIL); sprintf (tmp,"Can't resolve mailbox %.80s: unknown driver",name); MM_LOG (tmp,ERROR); return mail_close (stream); } /* fall through to default case */ default: /* not special hack (but could be # name */ d = mail_valid (NIL,name,(options & OP_SILENT) ? (char *) NIL : "open mailbox"); } return d ? mail_open_work (d,stream,name,options) : stream; } /* Mail open worker routine * Accepts: factory * candidate stream for recycling * mailbox name * open options * Returns: stream to use on success, NIL on failure */ MAILSTREAM *mail_open_work (DRIVER *d,MAILSTREAM *stream,char *name, long options) { int i; char tmp[MAILTMPLEN]; NETMBX mb; if (options & OP_PROTOTYPE) return (*d->open) (NIL); /* name is copied here in case the caller does a re-open using * stream->mailbox or stream->original_mailbox as the argument. */ name = cpystr (name); /* make copy of name */ if (stream) { /* recycling requested? */ if ((stream->dtb == d) && (d->flags & DR_RECYCLE) && ((d->flags & DR_HALFOPEN) || !(options & OP_HALFOPEN)) && mail_usable_network_stream (stream,name)) { /* yes, checkpoint if needed */ if (d->flags & DR_XPOINT) mail_check (stream); mail_free_cache (stream); /* clean up stream */ if (stream->mailbox) fs_give ((void **) &stream->mailbox); if (stream->original_mailbox) fs_give ((void **) &stream->original_mailbox); /* flush user flags */ for (i = 0; i < NUSERFLAGS; i++) if (stream->user_flags[i]) fs_give ((void **) &stream->user_flags[i]); } else { /* stream not recycleable, babble if net */ if (!stream->silent && stream->dtb && !(stream->dtb->flags&DR_LOCAL) && mail_valid_net_parse (stream->mailbox,&mb)) { sprintf (tmp,"Closing connection to %.80s",mb.host); MM_LOG (tmp,(long) NIL); } /* flush the old stream */ stream = mail_close (stream); } } /* check if driver does not support halfopen */ else if ((options & OP_HALFOPEN) && !(d->flags & DR_HALFOPEN)) { fs_give ((void **) &name); return NIL; } /* instantiate new stream if not recycling */ if (!stream) (*mailcache) (stream = (MAILSTREAM *) memset (fs_get (sizeof (MAILSTREAM)),0, sizeof (MAILSTREAM)),(long) 0,CH_INIT); stream->dtb = d; /* set dispatch */ /* set mailbox name */ stream->mailbox = cpystr (stream->original_mailbox = name); /* initialize stream flags */ stream->inbox = stream->lock = NIL; stream->debug = (options & OP_DEBUG) ? T : NIL; stream->rdonly = (options & OP_READONLY) ? T : NIL; stream->anonymous = (options & OP_ANONYMOUS) ? T : NIL; stream->scache = (options & OP_SHORTCACHE) ? T : NIL; stream->silent = (options & OP_SILENT) ? T : NIL; stream->halfopen = (options & OP_HALFOPEN) ? T : NIL; stream->secure = (options & OP_SECURE) ? T : NIL; stream->tryssl = (options & OP_TRYSSL) ? T : NIL; stream->mulnewsrc = (options & OP_MULNEWSRC) ? T : NIL; stream->nokod = (options & OP_NOKOD) ? T : NIL; stream->sniff = (options & OP_SNIFF) ? T : NIL; stream->perm_seen = stream->perm_deleted = stream->perm_flagged = stream->perm_answered = stream->perm_draft = stream->kwd_create = NIL; stream->uid_nosticky = (d->flags & DR_NOSTICKY) ? T : NIL; stream->uid_last = 0; /* default UID validity */ stream->uid_validity = (unsigned long) time (0); /* have driver open, flush if failed */ return ((*d->open) (stream)) ? stream : mail_close (stream); } /* Mail close * Accepts: mail stream * close options * Returns: NIL, always */ MAILSTREAM *mail_close_full (MAILSTREAM *stream,long options) { int i; if (stream) { /* make sure argument given */ /* do the driver's close action */ if (stream->dtb) (*stream->dtb->close) (stream,options); stream->dtb = NIL; /* resign driver */ if (stream->mailbox) fs_give ((void **) &stream->mailbox); if (stream->original_mailbox) fs_give ((void **) &stream->original_mailbox); if (stream->snarf.name) fs_give ((void **) &stream->snarf.name); stream->sequence++; /* invalidate sequence */ /* flush user flags */ for (i = 0; i < NUSERFLAGS; i++) if (stream->user_flags[i]) fs_give ((void **) &stream->user_flags[i]); mail_free_cache (stream); /* finally free the stream's storage */ if (mailfreestreamsparep && stream->sparep) (*mailfreestreamsparep) (&stream->sparep); if (!stream->use) fs_give ((void **) &stream); } return NIL; } /* Mail make handle * Accepts: mail stream * Returns: handle * * Handles provide a way to have multiple pointers to a stream yet allow the * stream's owner to nuke it or recycle it. */ MAILHANDLE *mail_makehandle (MAILSTREAM *stream) { MAILHANDLE *handle = (MAILHANDLE *) fs_get (sizeof (MAILHANDLE)); handle->stream = stream; /* copy stream */ /* and its sequence */ handle->sequence = stream->sequence; stream->use++; /* let stream know another handle exists */ return handle; } /* Mail release handle * Accepts: Mail handle */ void mail_free_handle (MAILHANDLE **handle) { MAILSTREAM *s; if (*handle) { /* only free if exists */ /* resign stream, flush unreferenced zombies */ if ((!--(s = (*handle)->stream)->use) && !s->dtb) fs_give ((void **) &s); fs_give ((void **) handle); /* now flush the handle */ } } /* Mail get stream handle * Accepts: Mail handle * Returns: mail stream or NIL if stream gone */ MAILSTREAM *mail_stream (MAILHANDLE *handle) { MAILSTREAM *s = handle->stream; return (s->dtb && (handle->sequence == s->sequence)) ? s : NIL; } /* Mail fetch cache element * Accepts: mail stream * message # to fetch * Returns: cache element of this message * Can also be used to create cache elements for new messages. */ MESSAGECACHE *mail_elt (MAILSTREAM *stream,unsigned long msgno) { if (msgno < 1 || msgno > stream->nmsgs) { char tmp[MAILTMPLEN]; sprintf (tmp,"Bad msgno %lu in mail_elt, nmsgs = %lu, mbx=%.80s", msgno,stream->nmsgs,stream->mailbox ? stream->mailbox : "???"); fatal (tmp); } return (MESSAGECACHE *) (*mailcache) (stream,msgno,CH_MAKEELT); } /* Mail fetch fast information * Accepts: mail stream * sequence * option flags * * Generally, mail_fetch_structure is preferred */ void mail_fetch_fast (MAILSTREAM *stream,char *sequence,long flags) { /* do the driver's action */ if (stream->dtb && stream->dtb->fast) (*stream->dtb->fast) (stream,sequence,flags); } /* Mail fetch flags * Accepts: mail stream * sequence * option flags */ void mail_fetch_flags (MAILSTREAM *stream,char *sequence,long flags) { /* do the driver's action */ if (stream->dtb && stream->dtb->msgflags) (*stream->dtb->msgflags) (stream,sequence,flags); } /* Mail fetch message overview * Accepts: mail stream * UID sequence to fetch * pointer to overview return function */ void mail_fetch_overview (MAILSTREAM *stream,char *sequence,overview_t ofn) { if (stream->dtb && mail_uid_sequence (stream,sequence) && !(stream->dtb->overview && (*stream->dtb->overview) (stream,ofn)) && mail_ping (stream)) mail_fetch_overview_default (stream,ofn); } /* Mail fetch message overview using sequence numbers instead of UIDs * Accepts: mail stream * sequence to fetch * pointer to overview return function */ void mail_fetch_overview_sequence (MAILSTREAM *stream,char *sequence, overview_t ofn) { if (stream->dtb && mail_sequence (stream,sequence) && !(stream->dtb->overview && (*stream->dtb->overview) (stream,ofn)) && mail_ping (stream)) mail_fetch_overview_default (stream,ofn); } /* Mail fetch message overview default handler * Accepts: mail stream with sequence bits lit * pointer to overview return function */ void mail_fetch_overview_default (MAILSTREAM *stream,overview_t ofn) { MESSAGECACHE *elt; ENVELOPE *env; OVERVIEW ov; unsigned long i; ov.optional.lines = 0; ov.optional.xref = NIL; for (i = 1; i <= stream->nmsgs; i++) if (((elt = mail_elt (stream,i))->sequence) && (env = mail_fetch_structure (stream,i,NIL,NIL)) && ofn) { ov.subject = env->subject; ov.from = env->from; ov.date = env->date; ov.message_id = env->message_id; ov.references = env->references; ov.optional.octets = elt->rfc822_size; (*ofn) (stream,mail_uid (stream,i),&ov,i); } } /* Mail fetch message structure * Accepts: mail stream * message # to fetch * pointer to return body * option flags * Returns: envelope of this message, body returned in body value * * Fetches the "fast" information as well */ ENVELOPE *mail_fetch_structure (MAILSTREAM *stream,unsigned long msgno, BODY **body,long flags) { ENVELOPE **env; BODY **b; MESSAGECACHE *elt; char c,*s,*hdr; unsigned long hdrsize; STRING bs; /* do the driver's action if specified */ if (stream->dtb && stream->dtb->structure) return (*stream->dtb->structure) (stream,msgno,body,flags); if (flags & FT_UID) { /* UID form of call */ if (msgno = mail_msgno (stream,msgno)) flags &= ~FT_UID; else return NIL; /* must get UID/msgno map first */ } elt = mail_elt (stream,msgno);/* get elt for real message number */ if (stream->scache) { /* short caching */ if (msgno != stream->msgno){/* garbage collect if not same message */ mail_gc (stream,GC_ENV | GC_TEXTS); stream->msgno = msgno; /* this is the current message now */ } env = &stream->env; /* get pointers to envelope and body */ b = &stream->body; } else { /* get pointers to elt envelope and body */ env = &elt->private.msg.env; b = &elt->private.msg.body; } if (stream->dtb && ((body && !*b) || !*env || (*env)->incomplete)) { mail_free_envelope (env); /* flush old envelope and body */ mail_free_body (b); /* see if need to fetch the whole thing */ if (body || !elt->rfc822_size) { s = (*stream->dtb->header) (stream,msgno,&hdrsize,flags & ~FT_INTERNAL); /* make copy in case body fetch smashes it */ hdr = (char *) memcpy (fs_get ((size_t) hdrsize+1),s,(size_t) hdrsize); hdr[hdrsize] = '\0'; /* tie off header */ (*stream->dtb->text) (stream,msgno,&bs,(flags & ~FT_INTERNAL) | FT_PEEK); if (!elt->rfc822_size) elt->rfc822_size = hdrsize + SIZE (&bs); if (body) /* only parse body if requested */ rfc822_parse_msg (env,b,hdr,hdrsize,&bs,BADHOST,stream->dtb->flags); else rfc822_parse_msg (env,NIL,hdr,hdrsize,NIL,BADHOST,stream->dtb->flags); fs_give ((void **) &hdr); /* flush header */ } else { /* can save memory doing it this way */ hdr = (*stream->dtb->header) (stream,msgno,&hdrsize,flags | FT_INTERNAL); if (hdrsize) { /* in case null header */ c = hdr[hdrsize]; /* preserve what's there */ hdr[hdrsize] = '\0'; /* tie off header */ rfc822_parse_msg (env,NIL,hdr,hdrsize,NIL,BADHOST,stream->dtb->flags); hdr[hdrsize] = c; /* restore in case cached data */ } else *env = mail_newenvelope (); } } /* if need date, have date in envelope? */ if (!elt->day && *env && (*env)->date) mail_parse_date (elt,(*env)->date); /* sigh, fill in bogus default */ if (!elt->day) elt->day = elt->month = 1; if (body) *body = *b; /* return the body */ return *env; /* return the envelope */ } /* Mail mark single message (internal use only) * Accepts: mail stream * elt to mark * fetch flags */ static void markseen (MAILSTREAM *stream,MESSAGECACHE *elt,long flags) { unsigned long i; char sequence[20]; MESSAGECACHE *e; /* non-peeking and needs to set \Seen? */ if (!(flags & FT_PEEK) && !elt->seen) { if (stream->dtb->flagmsg){ /* driver wants per-message call? */ elt->valid = NIL; /* do pre-alteration driver call */ (*stream->dtb->flagmsg) (stream,elt); /* set seen, do post-alteration driver call */ elt->seen = elt->valid = T; (*stream->dtb->flagmsg) (stream,elt); } if (stream->dtb->flag) { /* driver wants one-time call? */ /* better safe than sorry, save seq bits */ for (i = 1; i <= stream->nmsgs; i++) { e = mail_elt (stream,i); e->private.sequence = e->sequence; } /* call driver to set the message */ sprintf (sequence,"%lu",elt->msgno); (*stream->dtb->flag) (stream,sequence,"\\Seen",ST_SET); /* restore sequence bits */ for (i = 1; i <= stream->nmsgs; i++) { e = mail_elt (stream,i); e->sequence = e->private.sequence; } } /* notify mail program of flag change */ MM_FLAGS (stream,elt->msgno); } } /* Mail fetch message * Accepts: mail stream * message # to fetch * pointer to returned length * flags * Returns: message text */ char *mail_fetch_message (MAILSTREAM *stream,unsigned long msgno, unsigned long *len,long flags) { GETS_DATA md; SIZEDTEXT *t; STRING bs; MESSAGECACHE *elt; char *s,*u; unsigned long i,j; if (len) *len = 0; /* default return size */ if (flags & FT_UID) { /* UID form of call */ if (msgno = mail_msgno (stream,msgno)) flags &= ~FT_UID; else return ""; /* must get UID/msgno map first */ } /* initialize message data identifier */ INIT_GETS (md,stream,msgno,"",0,0); /* is data already cached? */ if ((t = &(elt = mail_elt (stream,msgno))->private.msg.full.text)->data) { markseen (stream,elt,flags);/* mark message seen */ return mail_fetch_text_return (&md,t,len); } if (!stream->dtb) return ""; /* not in cache, must have live driver */ if (stream->dtb->msgdata) return ((*stream->dtb->msgdata) (stream,msgno,"",0,0,NIL,flags) && t->data) ? mail_fetch_text_return (&md,t,len) : ""; /* ugh, have to do this the crufty way */ u = mail_fetch_header (stream,msgno,NIL,NIL,&i,flags); /* copy in case text method stomps on it */ s = (char *) memcpy (fs_get ((size_t) i),u,(size_t) i); if ((*stream->dtb->text) (stream,msgno,&bs,flags)) { t = &stream->text; /* build combined copy */ if (t->data) fs_give ((void **) &t->data); t->data = (unsigned char *) fs_get ((t->size = i + SIZE (&bs)) + 1); if (!elt->rfc822_size) elt->rfc822_size = t->size; else if (elt->rfc822_size != t->size) { char tmp[MAILTMPLEN]; sprintf (tmp,"Calculated RFC822.SIZE (%lu) != reported size (%lu)", t->size,elt->rfc822_size); mm_log (tmp,WARN); /* bug trap */ } memcpy (t->data,s,(size_t) i); for (u = (char *) t->data + i, j = SIZE (&bs); j;) { memcpy (u,bs.curpos,bs.cursize); u += bs.cursize; /* update text */ j -= bs.cursize; bs.curpos += (bs.cursize -1); bs.cursize = 0; (*bs.dtb->next) (&bs); /* advance to next buffer's worth */ } *u = '\0'; /* tie off data */ u = mail_fetch_text_return (&md,t,len); } else u = ""; fs_give ((void **) &s); /* finished with copy of header */ return u; } /* Mail fetch message header * Accepts: mail stream * message # to fetch * MIME section specifier (#.#.#...#) * list of lines to fetch * pointer to returned length * flags * Returns: message header in RFC822 format * * Note: never calls a mailgets routine */ char *mail_fetch_header (MAILSTREAM *stream,unsigned long msgno,char *section, STRINGLIST *lines,unsigned long *len,long flags) { STRING bs; BODY *b = NIL; SIZEDTEXT *t = NIL,rt; MESSAGE *m = NIL; MESSAGECACHE *elt; char tmp[MAILTMPLEN]; if (len) *len = 0; /* default return size */ if (section && (strlen (section) > (MAILTMPLEN - 20))) return ""; if (flags & FT_UID) { /* UID form of call */ if (msgno = mail_msgno (stream,msgno)) flags &= ~FT_UID; else return ""; /* must get UID/msgno map first */ } elt = mail_elt (stream,msgno);/* get cache data */ if (section && *section) { /* nested body header wanted? */ if (!((b = mail_body (stream,msgno,section)) && (b->type == TYPEMESSAGE) && !strcmp (b->subtype,"RFC822"))) return ""; /* lose if no body or not MESSAGE/RFC822 */ m = b->nested.msg; /* point to nested message */ } /* else top-level message header wanted */ else m = &elt->private.msg; if (m->header.text.data && mail_match_lines (lines,m->lines,flags)) { if (lines) textcpy (t = &stream->text,&m->header.text); else t = &m->header.text; /* in cache, and cache is valid */ markseen (stream,elt,flags);/* mark message seen */ } else if (stream->dtb) { /* not in cache, has live driver? */ if (stream->dtb->msgdata) { /* has driver section fetch? */ /* build driver section specifier */ if (section && *section) sprintf (tmp,"%s.HEADER",section); else strcpy (tmp,"HEADER"); if ((*stream->dtb->msgdata) (stream,msgno,tmp,0,0,lines,flags)) { t = &m->header.text; /* fetch data */ /* don't need to postprocess lines */ if (m->lines) lines = NIL; else if (lines) textcpy (t = &stream->text,&m->header.text); } } else if (b) { /* nested body wanted? */ if (stream->private.search.text) { rt.data = (unsigned char *) stream->private.search.text + b->nested.msg->header.offset; rt.size = b->nested.msg->header.text.size; t = &rt; } else if ((*stream->dtb->text) (stream,msgno,&bs,flags & ~FT_INTERNAL)) { if ((bs.dtb->next == mail_string_next) && !lines) { rt.data = (unsigned char *) bs.curpos + b->nested.msg->header.offset; rt.size = b->nested.msg->header.text.size; if (stream->private.search.string) stream->private.search.text = bs.curpos; t = &rt; /* special hack to avoid extra copy */ } else textcpyoffstring (t = &stream->text,&bs, b->nested.msg->header.offset, b->nested.msg->header.text.size); } } else { /* top-level header fetch */ /* mark message seen */ markseen (stream,elt,flags); if (rt.data = (unsigned char *) (*stream->dtb->header) (stream,msgno,&rt.size,flags)) { /* make a safe copy if need to filter */ if (lines) textcpy (t = &stream->text,&rt); else t = &rt; /* top level header */ } } } if (!t || !t->data) return "";/* error if no string */ /* filter headers if requested */ if (lines) t->size = mail_filter ((char *) t->data,t->size,lines,flags); if (len) *len = t->size; /* return size if requested */ return (char *) t->data; /* and text */ } /* Mail fetch message text * Accepts: mail stream * message # to fetch * MIME section specifier (#.#.#...#) * pointer to returned length * flags * Returns: message text */ char *mail_fetch_text (MAILSTREAM *stream,unsigned long msgno,char *section, unsigned long *len,long flags) { GETS_DATA md; PARTTEXT *p; STRING bs; MESSAGECACHE *elt; BODY *b = NIL; char tmp[MAILTMPLEN]; unsigned long i; if (len) *len = 0; /* default return size */ memset (&stream->private.string,NIL,sizeof (STRING)); if (section && (strlen (section) > (MAILTMPLEN - 20))) return ""; if (flags & FT_UID) { /* UID form of call */ if (msgno = mail_msgno (stream,msgno)) flags &= ~FT_UID; else return ""; /* must get UID/msgno map first */ } elt = mail_elt (stream,msgno);/* get cache data */ if (section && *section) { /* nested body text wanted? */ if (!((b = mail_body (stream,msgno,section)) && (b->type == TYPEMESSAGE) && !strcmp (b->subtype,"RFC822"))) return ""; /* lose if no body or not MESSAGE/RFC822 */ p = &b->nested.msg->text; /* point at nested message */ /* build IMAP-format section specifier */ sprintf (tmp,"%s.TEXT",section); flags &= ~FT_INTERNAL; /* can't win with this set */ } else { /* top-level message text wanted */ p = &elt->private.msg.text; strcpy (tmp,"TEXT"); } /* initialize message data identifier */ INIT_GETS (md,stream,msgno,section,0,0); if (p->text.data) { /* is data already cached? */ markseen (stream,elt,flags);/* mark message seen */ return mail_fetch_text_return (&md,&p->text,len); } if (!stream->dtb) return ""; /* not in cache, must have live driver */ if (stream->dtb->msgdata) return ((*stream->dtb->msgdata) (stream,msgno,tmp,0,0,NIL,flags) && p->text.data)? mail_fetch_text_return (&md,&p->text,len) : ""; if (!(*stream->dtb->text) (stream,msgno,&bs,flags)) return ""; if (section && *section) { /* nested is more complex */ SETPOS (&bs,p->offset); i = p->text.size; /* just want this much */ } else i = SIZE (&bs); /* want entire text */ return mail_fetch_string_return (&md,&bs,i,len,flags); } /* Mail fetch message body part MIME headers * Accepts: mail stream * message # to fetch * MIME section specifier (#.#.#...#) * pointer to returned length * flags * Returns: message text */ char *mail_fetch_mime (MAILSTREAM *stream,unsigned long msgno,char *section, unsigned long *len,long flags) { PARTTEXT *p; STRING bs; BODY *b; char tmp[MAILTMPLEN]; if (len) *len = 0; /* default return size */ if (section && (strlen (section) > (MAILTMPLEN - 20))) return ""; if (flags & FT_UID) { /* UID form of call */ if (msgno = mail_msgno (stream,msgno)) flags &= ~FT_UID; else return ""; /* must get UID/msgno map first */ } flags &= ~FT_INTERNAL; /* can't win with this set */ if (!(section && *section && (b = mail_body (stream,msgno,section)))) return ""; /* not valid section */ /* in cache? */ if ((p = &b->mime)->text.data) { /* mark message seen */ markseen (stream,mail_elt (stream,msgno),flags); if (len) *len = p->text.size; return (char *) p->text.data; } if (!stream->dtb) return ""; /* not in cache, must have live driver */ if (stream->dtb->msgdata) { /* has driver fetch? */ /* build driver section specifier */ sprintf (tmp,"%s.MIME",section); if ((*stream->dtb->msgdata) (stream,msgno,tmp,0,0,NIL,flags) && p->text.data) { if (len) *len = p->text.size; return (char *) p->text.data; } else return ""; } if (len) *len = b->mime.text.size; if (!b->mime.text.size) { /* empty MIME header -- mark seen anyway */ markseen (stream,mail_elt (stream,msgno),flags); return ""; } /* have to get it from offset */ if (stream->private.search.text) return stream->private.search.text + b->mime.offset; if (!(*stream->dtb->text) (stream,msgno,&bs,flags)) { if (len) *len = 0; return ""; } if (bs.dtb->next == mail_string_next) { if (stream->private.search.string) stream->private.search.text = bs.curpos; return bs.curpos + b->mime.offset; } return textcpyoffstring (&stream->text,&bs,b->mime.offset,b->mime.text.size); } /* Mail fetch message body part * Accepts: mail stream * message # to fetch * MIME section specifier (#.#.#...#) * pointer to returned length * flags * Returns: message body */ char *mail_fetch_body (MAILSTREAM *stream,unsigned long msgno,char *section, unsigned long *len,long flags) { GETS_DATA md; PARTTEXT *p; STRING bs; BODY *b; SIZEDTEXT *t; char *s,tmp[MAILTMPLEN]; memset (&stream->private.string,NIL,sizeof (STRING)); if (!(section && *section)) /* top-level text wanted? */ return mail_fetch_message (stream,msgno,len,flags); else if (strlen (section) > (MAILTMPLEN - 20)) return ""; flags &= ~FT_INTERNAL; /* can't win with this set */ /* initialize message data identifier */ INIT_GETS (md,stream,msgno,section,0,0); /* kludge for old section 0 header */ if (!strcmp (s = strcpy (tmp,section),"0") || ((s = strstr (tmp,".0")) && !s[2])) { SIZEDTEXT ht; *s = '\0'; /* tie off section */ /* this silly way so it does mailgets */ ht.data = (unsigned char *) mail_fetch_header (stream,msgno, tmp[0] ? tmp : NIL,NIL, &ht.size,flags); /* may have UIDs here */ md.flags = (flags & FT_UID) ? MG_UID : NIL; return mail_fetch_text_return (&md,&ht,len); } if (len) *len = 0; /* default return size */ if (flags & FT_UID) { /* UID form of call */ if (msgno = mail_msgno (stream,msgno)) flags &= ~FT_UID; else return ""; /* must get UID/msgno map first */ } /* must have body */ if (!(b = mail_body (stream,msgno,section))) return ""; /* have cached text? */ if ((t = &(p = &b->contents)->text)->data) { /* mark message seen */ markseen (stream,mail_elt (stream,msgno),flags); return mail_fetch_text_return (&md,t,len); } if (!stream->dtb) return ""; /* not in cache, must have live driver */ if (stream->dtb->msgdata) return ((*stream->dtb->msgdata)(stream,msgno,section,0,0,NIL,flags) && t->data) ? mail_fetch_text_return (&md,t,len) : ""; if (len) *len = t->size; if (!t->size) { /* empty body part -- mark seen anyway */ markseen (stream,mail_elt (stream,msgno),flags); return ""; } /* copy body from stringstruct offset */ if (stream->private.search.text) return stream->private.search.text + p->offset; if (!(*stream->dtb->text) (stream,msgno,&bs,flags)) { if (len) *len = 0; return ""; } if (bs.dtb->next == mail_string_next) { if (stream->private.search.string) stream->private.search.text = bs.curpos; return bs.curpos + p->offset; } SETPOS (&bs,p->offset); return mail_fetch_string_return (&md,&bs,t->size,len,flags); } /* Mail fetch partial message text * Accepts: mail stream * message # to fetch * MIME section specifier (#.#.#...#) * offset of first designed byte or 0 to start at beginning * maximum number of bytes or 0 for all bytes * flags * Returns: T if successful, else NIL */ long mail_partial_text (MAILSTREAM *stream,unsigned long msgno,char *section, unsigned long first,unsigned long last,long flags) { GETS_DATA md; PARTTEXT *p = NIL; MESSAGECACHE *elt; STRING bs; BODY *b; char tmp[MAILTMPLEN]; unsigned long i; if (!mailgets) fatal ("mail_partial_text() called without a mailgets!"); if (section && (strlen (section) > (MAILTMPLEN - 20))) return NIL; if (flags & FT_UID) { /* UID form of call */ if (msgno = mail_msgno (stream,msgno)) flags &= ~FT_UID; else return NIL; /* must get UID/msgno map first */ } elt = mail_elt (stream,msgno);/* get cache data */ flags &= ~FT_INTERNAL; /* bogus if this is set */ if (section && *section) { /* nested body text wanted? */ if (!((b = mail_body (stream,msgno,section)) && (b->type == TYPEMESSAGE) && !strcmp (b->subtype,"RFC822"))) return NIL; /* lose if no body or not MESSAGE/RFC822 */ p = &b->nested.msg->text; /* point at nested message */ /* build IMAP-format section specifier */ sprintf (tmp,"%s.TEXT",section); } else { /* else top-level message text wanted */ p = &elt->private.msg.text; strcpy (tmp,"TEXT"); } /* initialize message data identifier */ INIT_GETS (md,stream,msgno,tmp,first,last); if (p->text.data) { /* is data already cached? */ INIT (&bs,mail_string,p->text.data,i = p->text.size); markseen (stream,elt,flags);/* mark message seen */ } else { /* else get data from driver */ if (!stream->dtb) return NIL; if (stream->dtb->msgdata) /* driver will handle this */ return (*stream->dtb->msgdata) (stream,msgno,tmp,first,last,NIL,flags); if (!(*stream->dtb->text) (stream,msgno,&bs,flags)) return NIL; if (section && *section) { /* nexted if more complex */ SETPOS (&bs,p->offset); /* offset stringstruct to data */ i = p->text.size; /* maximum size of data */ } else i = SIZE (&bs); /* just want this much */ } if (i <= first) i = first = 0;/* first byte is beyond end of text */ /* truncate as needed */ else { /* offset and truncate */ SETPOS (&bs,first + GETPOS (&bs)); i -= first; /* reduced size */ if (last && (i > last)) i = last; } /* do the mailgets thing */ (*mailgets) (mail_read,&bs,i,&md); return T; /* success */ } /* Mail fetch partial message body part * Accepts: mail stream * message # to fetch * MIME section specifier (#.#.#...#) * offset of first designed byte or 0 to start at beginning * maximum number of bytes or 0 for all bytes * flags * Returns: T if successful, else NIL */ long mail_partial_body (MAILSTREAM *stream,unsigned long msgno,char *section, unsigned long first,unsigned long last,long flags) { GETS_DATA md; PARTTEXT *p; STRING bs; BODY *b; SIZEDTEXT *t; unsigned long i; if (!(section && *section)) /* top-level text wanted? */ return mail_partial_text (stream,msgno,NIL,first,last,flags); if (!mailgets) fatal ("mail_partial_body() called without a mailgets!"); if (flags & FT_UID) { /* UID form of call */ if (msgno = mail_msgno (stream,msgno)) flags &= ~FT_UID; else return NIL; /* must get UID/msgno map first */ } /* must have body */ if (!(b = mail_body (stream,msgno,section))) return NIL; flags &= ~FT_INTERNAL; /* bogus if this is set */ /* initialize message data identifier */ INIT_GETS (md,stream,msgno,section,first,last); /* have cached text? */ if ((t = &(p = &b->contents)->text)->data) { /* mark message seen */ markseen (stream,mail_elt (stream,msgno),flags); INIT (&bs,mail_string,t->data,i = t->size); } else { /* else get data from driver */ if (!stream->dtb) return NIL; if (stream->dtb->msgdata) /* driver will handle this */ return (*stream->dtb->msgdata) (stream,msgno,section,first,last,NIL, flags); if (!(*stream->dtb->text) (stream,msgno,&bs,flags)) return NIL; if (section && *section) { /* nexted if more complex */ SETPOS (&bs,p->offset); /* offset stringstruct to data */ i = t->size; /* maximum size of data */ } else i = SIZE (&bs); /* just want this much */ } if (i <= first) i = first = 0;/* first byte is beyond end of text */ else { /* offset and truncate */ SETPOS (&bs,first + GETPOS (&bs)); i -= first; /* reduced size */ if (last && (i > last)) i = last; } /* do the mailgets thing */ (*mailgets) (mail_read,&bs,i,&md); return T; /* success */ } /* Mail return message text * Accepts: identifier data * sized text * pointer to returned length * Returns: text */ char *mail_fetch_text_return (GETS_DATA *md,SIZEDTEXT *t,unsigned long *len) { STRING bs; if (len) *len = t->size; /* return size */ if (t->size && mailgets) { /* have to do the mailgets thing? */ /* silly but do it anyway for consistency */ INIT (&bs,mail_string,t->data,t->size); return (*mailgets) (mail_read,&bs,t->size,md); } return t->size ? (char *) t->data : ""; } /* Mail return message string * Accepts: identifier data * stringstruct * text length * pointer to returned length * flags * Returns: text, or NIL if stringstruct returned */ char *mail_fetch_string_return (GETS_DATA *md,STRING *bs,unsigned long i, unsigned long *len,long flags) { char *ret = NIL; if (len) *len = i; /* return size */ /* return stringstruct hack */ if (flags & FT_RETURNSTRINGSTRUCT) { memcpy (&md->stream->private.string,bs,sizeof (STRING)); SETPOS (&md->stream->private.string,GETPOS (&md->stream->private.string)); } /* have to do the mailgets thing? */ else if (mailgets) ret = (*mailgets) (mail_read,bs,i,md); /* special hack to avoid extra copy */ else if (bs->dtb->next == mail_string_next) ret = bs->curpos; /* make string copy in memory */ else ret = textcpyoffstring (&md->stream->text,bs,GETPOS (bs),i); return ret; } /* Read data from stringstruct * Accepts: stringstruct * size of data to read * buffer to read into * Returns: T, always, stringstruct updated */ long mail_read (void *stream,unsigned long size,char *buffer) { unsigned long i; STRING *s = (STRING *) stream; while (size) { /* until satisfied */ memcpy (buffer,s->curpos,i = min (s->cursize,size)); buffer += i; /* update buffer */ size -= i; /* note that we read this much */ s->curpos += --i; /* advance that many spaces minus 1 */ s->cursize -= i; SNX (s); /* now use SNX to advance the last byte */ } return T; } /* Mail fetch UID * Accepts: mail stream * message number * Returns: UID or zero if dead stream */ unsigned long mail_uid (MAILSTREAM *stream,unsigned long msgno) { unsigned long uid = mail_elt (stream,msgno)->private.uid; return uid ? uid : (stream->dtb && stream->dtb->uid) ? (*stream->dtb->uid) (stream,msgno) : 0; } /* Mail fetch msgno from UID * Accepts: mail stream * UID * Returns: msgno or zero if failed */ unsigned long mail_msgno (MAILSTREAM *stream,unsigned long uid) { unsigned long msgno,delta,first,firstuid,last,lastuid,middle,miduid; if (stream->dtb) { /* active stream? */ if (stream->dtb->msgno) /* direct way */ return (*stream->dtb->msgno) (stream,uid); else if (stream->dtb->uid) {/* indirect way */ /* Placeholder for now, since currently there are no drivers which * have a uid method but not a msgno method */ for (msgno = 1; msgno <= stream->nmsgs; msgno++) if ((*stream->dtb->uid) (stream,msgno) == uid) return msgno; } /* binary search since have full map */ else for (first = 1,last = stream->nmsgs, delta = (first <= last) ? 1 : 0; delta && (uid >= (firstuid = mail_elt (stream,first)->private.uid)) && (uid <= (lastuid = mail_elt (stream,last)->private.uid));) { /* done if match at an endpoint */ if (uid == firstuid) return first; if (uid == lastuid) return last; /* have anything between endpoints? */ if (delta = ((last - first) / 2)) { if ((miduid = mail_elt (stream,middle = first + delta)->private.uid) == uid) return middle; /* found match in middle */ else if (uid < miduid) last = middle - 1; else first = middle + 1; } } } else { /* dead stream, do linear search for UID */ for (msgno = 1; msgno <= stream->nmsgs; msgno++) if (mail_elt (stream,msgno)->private.uid == uid) return msgno; } return 0; /* didn't find the UID anywhere */ } /* Mail fetch From string for menu * Accepts: destination string * mail stream * message # to fetch * desired string length * Returns: string of requested length */ void mail_fetchfrom (char *s,MAILSTREAM *stream,unsigned long msgno, long length) { char *t; char tmp[MAILTMPLEN]; ENVELOPE *env = mail_fetchenvelope (stream,msgno); ADDRESS *adr = env ? env->from : NIL; memset (s,' ',(size_t)length);/* fill it with spaces */ s[length] = '\0'; /* tie off with null */ /* get first from address from envelope */ while (adr && !adr->host) adr = adr->next; if (adr) { /* if a personal name exists use it */ if (!(t = adr->personal)) sprintf (t = tmp,"%.256s@%.256s",adr->mailbox,adr->host); memcpy (s,t,(size_t) min (length,(long) strlen (t))); } } /* Mail fetch Subject string for menu * Accepts: destination string * mail stream * message # to fetch * desired string length * Returns: string of no more than requested length */ void mail_fetchsubject (char *s,MAILSTREAM *stream,unsigned long msgno, long length) { ENVELOPE *env = mail_fetchenvelope (stream,msgno); memset (s,'\0',(size_t) length+1); /* copy subject from envelope */ if (env && env->subject) strncpy (s,env->subject,(size_t) length); else *s = ' '; /* if no subject then just a space */ } /* Mail modify flags * Accepts: mail stream * sequence * flag(s) * option flags */ void mail_flag (MAILSTREAM *stream,char *sequence,char *flag,long flags) { MESSAGECACHE *elt; unsigned long i,uf; long f; short nf; if (!stream->dtb) return; /* no-op if no stream */ if ((stream->dtb->flagmsg || !stream->dtb->flag) && ((flags & ST_UID) ? mail_uid_sequence (stream,sequence) : mail_sequence (stream,sequence)) && ((f = mail_parse_flags (stream,flag,&uf)) || uf)) for (i = 1,nf = (flags & ST_SET) ? T : NIL; i <= stream->nmsgs; i++) if ((elt = mail_elt (stream,i))->sequence) { struct { /* old flags */ unsigned int valid : 1; unsigned int seen : 1; unsigned int deleted : 1; unsigned int flagged : 1; unsigned int answered : 1; unsigned int draft : 1; unsigned long user_flags; } old; old.valid = elt->valid; old.seen = elt->seen; old.deleted = elt->deleted; old.flagged = elt->flagged; old.answered = elt->answered; old.draft = elt->draft; old.user_flags = elt->user_flags; elt->valid = NIL; /* prepare for flag alteration */ if (stream->dtb->flagmsg) (*stream->dtb->flagmsg) (stream,elt); if (f&fSEEN) elt->seen = nf; if (f&fDELETED) elt->deleted = nf; if (f&fFLAGGED) elt->flagged = nf; if (f&fANSWERED) elt->answered = nf; if (f&fDRAFT) elt->draft = nf; /* user flags */ if (flags & ST_SET) elt->user_flags |= uf; else elt->user_flags &= ~uf; elt->valid = T; /* flags now altered */ if ((old.valid != elt->valid) || (old.seen != elt->seen) || (old.deleted != elt->deleted) || (old.flagged != elt->flagged) || (old.answered != elt->answered) || (old.draft != elt->draft) || (old.user_flags != elt->user_flags)) MM_FLAGS (stream,elt->msgno); if (stream->dtb->flagmsg) (*stream->dtb->flagmsg) (stream,elt); } /* call driver once */ if (stream->dtb->flag) (*stream->dtb->flag) (stream,sequence,flag,flags); } /* Mail search for messages * Accepts: mail stream * character set * search program * option flags * Returns: T if successful, NIL if dead stream, NIL searchpgm or bad charset */ long mail_search_full (MAILSTREAM *stream,char *charset,SEARCHPGM *pgm, long flags) { unsigned long i; long ret = NIL; if (!(flags & SE_RETAIN)) /* clear search vector unless retaining */ for (i = 1; i <= stream->nmsgs; ++i) mail_elt (stream,i)->searched = NIL; if (pgm && stream->dtb) /* must have a search program and driver */ ret = (*(stream->dtb->search ? stream->dtb->search : mail_search_default)) (stream,charset,pgm,flags); /* flush search program if requested */ if (flags & SE_FREE) mail_free_searchpgm (&pgm); return ret; } /* Mail search for messages default handler * Accepts: mail stream * character set * search program * option flags * Returns: T if successful, NIL if bad charset */ long mail_search_default (MAILSTREAM *stream,char *charset,SEARCHPGM *pgm, long flags) { unsigned long i; char *msg; /* make sure that charset is good */ if (msg = utf8_badcharset (charset)) { MM_LOG (msg,ERROR); /* output error */ fs_give ((void **) &msg); return NIL; } utf8_searchpgm (pgm,charset); for (i = 1; i <= stream->nmsgs; ++i) if (mail_search_msg (stream,i,NIL,pgm)) { if (flags & SE_UID) mm_searched (stream,mail_uid (stream,i)); else { /* mark as searched, notify mail program */ mail_elt (stream,i)->searched = T; if (!stream->silent) mm_searched (stream,i); } } return LONGT; /* search completed */ } /* Mail ping mailbox * Accepts: mail stream * Returns: stream if still open else NIL */ long mail_ping (MAILSTREAM *stream) { unsigned long i,n,uf,len; char *s,*f,tmp[MAILTMPLEN],flags[MAILTMPLEN]; MAILSTREAM *snarf; MESSAGECACHE *elt; STRING bs; long ret; /* do driver action */ if ((ret = ((stream && stream->dtb) ? (stream->dtb->ping) (stream) : NIL)) && stream->snarf.name && /* time to snarf? */ /* prohibit faster than once/min */ (time (0) > (time_t) (stream->snarf.time + min(60,mailsnarfinterval))) && (snarf = mail_open (NIL,stream->snarf.name, stream->snarf.options | OP_SILENT))) { if ((n = snarf->nmsgs) && /* yes, have messages to snarf? */ mail_search_full (snarf,NIL,mail_criteria ("UNDELETED"),SE_FREE)) { for (i = 1; ret && (i <= n); i++) /* for each message */ if ((elt = mail_elt (snarf,i))->searched && (s = mail_fetch_message (snarf,i,&len,FT_PEEK)) && len) { INIT (&bs,mail_string,s,len); if (mailsnarfpreserve) { /* yes, make sure have fast data */ if (!elt->valid || !elt->day) { sprintf (tmp,"%lu",n); mail_fetch_fast (snarf,tmp,NIL); } /* initialize flag string */ memset (flags,0,MAILTMPLEN); /* output system flags except \Deleted */ if (elt->seen) strcat (flags," \\Seen"); if (elt->flagged) strcat (flags," \\Flagged"); if (elt->answered) strcat (flags," \\Answered"); if (elt->draft) strcat (flags," \\Draft"); /* any user flags? */ for (uf = elt->user_flags,s = flags + strlen (flags); uf && (f = stream->user_flags[find_rightmost_bit (&uf)]) && ((MAILTMPLEN - (s - tmp)) > (long) (2 + strlen (f))); s += strlen (s)) sprintf (s," %s",f); ret = mail_append_full (stream,stream->mailbox,flags + 1, mail_date (tmp,elt),&bs); } else ret = mail_append (stream,stream->mailbox,&bs); if (ret) { /* did snarf succeed? */ /* driver has per-message (or no) flag call */ if (snarf->dtb->flagmsg || !snarf->dtb->flag) { elt->valid = NIL; /* prepare for flag alteration */ if (snarf->dtb->flagmsg) (*snarf->dtb->flagmsg) (snarf,elt); /* flags now altered */ elt->deleted = elt->seen = elt->valid = T; if (snarf->dtb->flagmsg) (*snarf->dtb->flagmsg) (snarf,elt); } /* driver has one-time flag call */ if (snarf->dtb->flag) { sprintf (tmp,"%lu",i); (*snarf->dtb->flag) (snarf,tmp,"\\Deleted \\Seen",ST_SET); } } else { /* copy failed */ sprintf (tmp,"Unable to move message %lu from %s mailbox", i,snarf->dtb->name); mm_log (tmp,WARN); } } } /* expunge the messages */ mail_close_full (snarf,n ? CL_EXPUNGE : NIL); stream->snarf.time = (unsigned long) time (0); /* Even if the snarf failed, we don't want to return NIL if the stream * is still alive. Or at least that's what we currently think. */ /* redo the driver's action */ ret = stream->dtb ? (*stream->dtb->ping) (stream) : NIL; } return ret; } /* Mail check mailbox * Accepts: mail stream */ void mail_check (MAILSTREAM *stream) { /* do the driver's action */ if (stream->dtb) (*stream->dtb->check) (stream); } /* Mail expunge mailbox * Accepts: mail stream * sequence to expunge if non-NIL * expunge options * Returns: T on success, NIL on failure */ long mail_expunge_full (MAILSTREAM *stream,char *sequence,long options) { /* do the driver's action */ return stream->dtb ? (*stream->dtb->expunge) (stream,sequence,options) : NIL; } /* Mail copy message(s) * Accepts: mail stream * sequence * destination mailbox * flags */ long mail_copy_full (MAILSTREAM *stream,char *sequence,char *mailbox, long options) { return stream->dtb ? SAFE_COPY (stream->dtb,stream,sequence,mailbox,options) : NIL; } /* Append data package to use for old single-message mail_append() interface */ typedef struct mail_append_package { char *flags; /* initial flags */ char *date; /* message internal date */ STRING *message; /* stringstruct of message */ } APPENDPACKAGE; /* Single append message string * Accepts: mail stream * package pointer (cast as a void *) * pointer to return initial flags * pointer to return message internal date * pointer to return stringstruct of message to append * Returns: T, always */ static long mail_append_single (MAILSTREAM *stream,void *data,char **flags, char **date,STRING **message) { APPENDPACKAGE *ap = (APPENDPACKAGE *) data; *flags = ap->flags; /* get desired data from the package */ *date = ap->date; *message = ap->message; ap->message = NIL; /* so next callback puts a stop to it */ return LONGT; /* always return success */ } /* Mail append message string * Accepts: mail stream * destination mailbox * initial flags * message internal date * stringstruct of message to append * Returns: T on success, NIL on failure */ long mail_append_full (MAILSTREAM *stream,char *mailbox,char *flags,char *date, STRING *message) { APPENDPACKAGE ap; ap.flags = flags; /* load append package */ ap.date = date; ap.message = message; return mail_append_multiple (stream,mailbox,mail_append_single,(void *) &ap); } /* Mail append message(s) * Accepts: mail stream * destination mailbox * append data callback * arbitrary data for callback use * Returns: T on success, NIL on failure */ long mail_append_multiple (MAILSTREAM *stream,char *mailbox,append_t af, void *data) { char *s,tmp[MAILTMPLEN]; DRIVER *d = NIL; long ret = NIL; /* never allow names with newlines */ if (strpbrk (mailbox,"\015\012")) MM_LOG ("Can't append to mailbox with such a name",ERROR); else if (strlen (mailbox) >= (NETMAXHOST+(NETMAXUSER*2)+NETMAXMBX+NETMAXSRV+50)) { sprintf (tmp,"Can't append %.80s: %s",mailbox,(*mailbox == '{') ? "invalid remote specification" : "no such mailbox"); MM_LOG (tmp,ERROR); } /* special driver hack? */ else if (!strncmp (lcase (strcpy (tmp,mailbox)),"#driver.",8)) { /* yes, tie off name at likely delimiter */ if (!(s = strpbrk (tmp+8,"/\\:"))) { sprintf (tmp,"Can't append to mailbox %.80s: bad driver syntax",mailbox); MM_LOG (tmp,ERROR); return NIL; } *s++ = '\0'; /* tie off at delimiter */ if (!(d = (DRIVER *) mail_parameters (NIL,GET_DRIVER,tmp+8))) { sprintf (tmp,"Can't append to mailbox %.80s: unknown driver",mailbox); MM_LOG (tmp,ERROR); } else ret = SAFE_APPEND (d,stream,mailbox + (s - tmp),af,data); } else if (d = mail_valid (stream,mailbox,NIL)) ret = SAFE_APPEND (d,stream,mailbox,af,data); /* No driver, try for TRYCREATE if no stream. Note that we use the * createProto here, not the appendProto, since the dummy driver already * took care of the appendProto case. Otherwise, if appendProto is set to * NIL, we won't get a TRYCREATE. */ else if (!stream && (stream = default_proto (NIL)) && stream->dtb && SAFE_APPEND (stream->dtb,stream,mailbox,af,data)) /* timing race? */ MM_NOTIFY (stream,"Append validity confusion",WARN); /* generate error message */ else mail_valid (stream,mailbox,"append to mailbox"); return ret; } /* Mail garbage collect stream * Accepts: mail stream * garbage collection flags */ void mail_gc (MAILSTREAM *stream,long gcflags) { MESSAGECACHE *elt; unsigned long i; /* do the driver's action first */ if (stream->dtb && stream->dtb->gc) (*stream->dtb->gc) (stream,gcflags); stream->msgno = 0; /* nothing cached now */ if (gcflags & GC_ENV) { /* garbage collect envelopes? */ if (stream->env) mail_free_envelope (&stream->env); if (stream->body) mail_free_body (&stream->body); } if (gcflags & GC_TEXTS) { /* free texts */ if (stream->text.data) fs_give ((void **) &stream->text.data); stream->text.size = 0; } /* garbage collect per-message stuff */ for (i = 1; i <= stream->nmsgs; i++) if (elt = (MESSAGECACHE *) (*mailcache) (stream,i,CH_ELT)) mail_gc_msg (&elt->private.msg,gcflags); } /* Mail garbage collect message * Accepts: message structure * garbage collection flags */ void mail_gc_msg (MESSAGE *msg,long gcflags) { if (gcflags & GC_ENV) { /* garbage collect envelopes? */ mail_free_envelope (&msg->env); mail_free_body (&msg->body); } if (gcflags & GC_TEXTS) { /* garbage collect texts */ if (msg->full.text.data) fs_give ((void **) &msg->full.text.data); if (msg->header.text.data) { mail_free_stringlist (&msg->lines); fs_give ((void **) &msg->header.text.data); } if (msg->text.text.data) fs_give ((void **) &msg->text.text.data); /* now GC all body components */ if (msg->body) mail_gc_body (msg->body); } } /* Mail garbage collect texts in BODY structure * Accepts: BODY structure */ void mail_gc_body (BODY *body) { PART *part; switch (body->type) { /* free contents */ case TYPEMULTIPART: /* multiple part */ for (part = body->nested.part; part; part = part->next) mail_gc_body (&part->body); break; case TYPEMESSAGE: /* encapsulated message */ if (body->subtype && !strcmp (body->subtype,"RFC822")) { mail_free_stringlist (&body->nested.msg->lines); mail_gc_msg (body->nested.msg,GC_TEXTS); } break; default: break; } if (body->mime.text.data) fs_give ((void **) &body->mime.text.data); if (body->contents.text.data) fs_give ((void **) &body->contents.text.data); } /* Mail get body part * Accepts: mail stream * message number * section specifier * Returns: pointer to body */ BODY *mail_body (MAILSTREAM *stream,unsigned long msgno,unsigned char *section) { BODY *b = NIL; PART *pt; unsigned long i; /* make sure have a body */ if (section && *section && mail_fetchstructure (stream,msgno,&b) && b) while (*section) { /* find desired section */ if (isdigit (*section)) { /* get section specifier */ /* make sure what follows is valid */ if (!(i = strtoul (section,(char **) §ion,10)) || (*section && ((*section++ != '.') || !*section))) return NIL; /* multipart content? */ if (b->type == TYPEMULTIPART) { /* yes, find desired part */ if (pt = b->nested.part) while (--i && (pt = pt->next)); if (!pt) return NIL; /* bad specifier */ b = &pt->body; /* note new body */ } /* otherwise must be section 1 */ else if (i != 1) return NIL; /* need to go down further? */ if (*section) switch (b->type) { case TYPEMULTIPART: /* multipart */ break; case TYPEMESSAGE: /* embedded message */ if (!strcmp (b->subtype,"RFC822")) { b = b->nested.msg->body; break; } default: /* bogus subpart specification */ return NIL; } } else return NIL; /* unknown section specifier */ } return b; } /* Mail output date from elt fields * Accepts: character string to write into * elt to get data data from * Returns: the character string */ const char *days[] = {"Sun", "Mon", "Tue", "Wed", "Thu", "Fri", "Sat"}; const char *months[] = {"Jan", "Feb", "Mar", "Apr", "May", "Jun", "Jul", "Aug", "Sep", "Oct", "Nov", "Dec"}; char *mail_date (char *string,MESSAGECACHE *elt) { sprintf (string,"%2d-%s-%d %02d:%02d:%02d %c%02d%02d", elt->day ? elt->day : 1, months[elt->month ? (elt->month - 1) : 0], elt->year + BASEYEAR,elt->hours,elt->minutes,elt->seconds, elt->zoccident ? '-' : '+',elt->zhours,elt->zminutes); return string; } /* Mail output extended-ctime format date from elt fields * Accepts: character string to write into * elt to get data data from * Returns: the character string */ char *mail_cdate (char *string,MESSAGECACHE *elt) { char *fmt = "%s %s %2d %02d:%02d:%02d %4d %s%02d%02d\n"; int d = elt->day ? elt->day : 1; int m = elt->month ? (elt->month - 1) : 0; int y = elt->year + BASEYEAR; const char *s = months[m]; if (m < 2) { /* if before March, */ m += 10; /* January = month 10 of previous year */ y--; } else m -= 2; /* March is month 0 */ sprintf (string,fmt,days[(int) (d + 2 + ((7 + 31 * m) / 12) #ifndef USEJULIANCALENDAR #ifndef USEORTHODOXCALENDAR /* Gregorian calendar */ + (y / 400) #ifdef Y4KBUGFIX - (y / 4000) #endif #else /* Orthodox calendar */ + (2 * (y / 900)) + ((y % 900) >= 200) + ((y % 900) >= 600) #endif - (y / 100) #endif + y + (y / 4)) % 7], s,d,elt->hours,elt->minutes,elt->seconds,elt->year + BASEYEAR, elt->zoccident ? "-" : "+",elt->zhours,elt->zminutes); return string; } /* Mail parse date into elt fields * Accepts: elt to write into * date string to parse * Returns: T if parse successful, else NIL * This routine parses dates as follows: * . leading three alphas followed by comma and space are ignored * . date accepted in format: mm/dd/yy, mm/dd/yyyy, dd-mmm-yy, dd-mmm-yyyy, * dd mmm yy, dd mmm yyyy, yyyy-mm-dd, yyyymmdd * . two and three digit years interpreted according to RFC 2822 rules * . mandatory end of string if yyyy-mm-dd or yyyymmdd; otherwise optional * space followed by time: * . time accepted in format hh:mm:ss or hh:mm * . end of string accepted * . timezone accepted: hyphen followed by symbolic timezone, or space * followed by signed numeric timezone or symbolic timezone * Examples of normal input: * . IMAP date-only (SEARCH): * dd-mmm-yyyy * . IMAP date-time (INTERNALDATE): * dd-mmm-yyyy hh:mm:ss +zzzz * . RFC-822: * www, dd mmm yy hh:mm:ss zzz * . RFC-2822: * www, dd mmm yyyy hh:mm:ss +zzzz */ long mail_parse_date (MESSAGECACHE *elt,unsigned char *s) { unsigned long d,m,y; int mi,ms; struct tm *t; time_t tn; char tmp[MAILTMPLEN]; static unsigned long maxyear = 0; if (!maxyear) { /* know the end of time yet? */ MESSAGECACHE tmpelt; memset (&tmpelt,0xff,sizeof (MESSAGECACHE)); maxyear = BASEYEAR + tmpelt.year; } /* clear elt */ elt->zoccident = elt->zhours = elt->zminutes = elt->hours = elt->minutes = elt->seconds = elt->day = elt->month = elt->year = 0; /* make a writeable uppercase copy */ if (s && *s && (strlen (s) < (size_t)MAILTMPLEN)) s = ucase (strcpy (tmp,s)); else return NIL; /* skip over possible day of week */ if (isalpha (*s) && isalpha (s[1]) && isalpha (s[2]) && (s[3] == ',') && (s[4] == ' ')) s += 5; while (*s == ' ') s++; /* parse first number (probable month) */ if (!(m = strtoul (s,(char **) &s,10))) return NIL; switch (*s) { /* different parse based on delimiter */ case '/': /* mm/dd/yy format */ if (isdigit (*++s) && (d = strtoul (s,(char **) &s,10)) && (*s == '/') && isdigit (*++s)) { y = strtoul (s,(char **) &s,10); if (*s == '\0') break; /* must end here */ } return NIL; /* bogon */ case ' ': /* dd mmm yy format */ while (s[1] == ' ') s++; /* slurp extra whitespace */ case '-': if (isdigit (s[1])) { /* possible ISO 8601 date format? */ y = m; /* yes, first number is year */ /* get month and day */ if ((m = strtoul (s+1,(char **) &s,10)) && (*s++ == '-') && (d = strtoul (s,(char **) &s,10)) && !*s) break; return NIL; /* syntax error or time present */ } d = m; /* dd-mmm-yy[yy], so first number is a day */ /* make sure string long enough! */ if (strlen (s) < (size_t) 5) return NIL; /* Some compilers don't allow `<<' and/or longs in case statements. */ /* slurp up the month string */ ms = ((s[1] - 'A') * 1024) + ((s[2] - 'A') * 32) + (s[3] - 'A'); switch (ms) { /* determine the month */ case (('J'-'A') * 1024) + (('A'-'A') * 32) + ('N'-'A'): m = 1; break; case (('F'-'A') * 1024) + (('E'-'A') * 32) + ('B'-'A'): m = 2; break; case (('M'-'A') * 1024) + (('A'-'A') * 32) + ('R'-'A'): m = 3; break; case (('A'-'A') * 1024) + (('P'-'A') * 32) + ('R'-'A'): m = 4; break; case (('M'-'A') * 1024) + (('A'-'A') * 32) + ('Y'-'A'): m = 5; break; case (('J'-'A') * 1024) + (('U'-'A') * 32) + ('N'-'A'): m = 6; break; case (('J'-'A') * 1024) + (('U'-'A') * 32) + ('L'-'A'): m = 7; break; case (('A'-'A') * 1024) + (('U'-'A') * 32) + ('G'-'A'): m = 8; break; case (('S'-'A') * 1024) + (('E'-'A') * 32) + ('P'-'A'): m = 9; break; case (('O'-'A') * 1024) + (('C'-'A') * 32) + ('T'-'A'): m = 10; break; case (('N'-'A') * 1024) + (('O'-'A') * 32) + ('V'-'A'): m = 11; break; case (('D'-'A') * 1024) + (('E'-'A') * 32) + ('C'-'A'): m = 12; break; default: return NIL; /* unknown month */ } if (s[4] == *s) s += 5; /* advance to year */ else { /* first three were OK, possibly full name */ mi = *s; /* note delimiter, skip alphas */ for (s += 4; isalpha (*s); s++); /* error if delimiter not here */ if (mi != *s++) return NIL; } while (*s == ' ') s++; /* parse year */ if (isdigit (*s)) { /* must be a digit here */ y = strtoul (s,(char **) &s,10); if (*s == '\0' || *s == ' ') break; } case '\0': /* ISO 8601 compact date */ if (m < (BASEYEAR * 10000)) return NIL; y = m / 10000; /* get year */ d = (m %= 10000) % 100; /* get day */ m /= 100; /* and month */ break; default: return NIL; /* unknown date format */ } /* minimal validity check of date */ if ((d > 31) || (m > 12)) return NIL; if (y < 49) y += 2000; /* RFC 2282 rules for two digit years 00-49 */ else if (y < 999) y += 1900; /* 2-digit years 50-99 and 3-digit years */ /* reject prehistoric and far future years */ if ((y < BASEYEAR) || (y > maxyear)) return NIL; /* set values in elt */ elt->day = d; elt->month = m; elt->year = y - BASEYEAR; ms = '\0'; /* initially no time zone string */ if (*s) { /* time specification present? */ /* parse time */ d = strtoul (s+1,(char **) &s,10); if (*s != ':') return NIL; m = strtoul (++s,(char **) &s,10); y = (*s == ':') ? strtoul (++s,(char **) &s,10) : 0; /* validity check time */ if ((d > 23) || (m > 59) || (y > 60)) return NIL; /* set values in elt */ elt->hours = d; elt->minutes = m; elt->seconds = y; switch (*s) { /* time zone specifier? */ case ' ': /* numeric time zone */ while (s[1] == ' ') s++; /* slurp extra whitespace */ if (!isalpha (s[1])) { /* treat as '-' case if alphabetic */ /* test for sign character */ if ((elt->zoccident = (*++s == '-')) || (*s == '+')) s++; /* validate proper timezone */ if (isdigit(*s) && isdigit(s[1]) && isdigit(s[2]) && (s[2] < '6') && isdigit(s[3])) { elt->zhours = (*s - '0') * 10 + (s[1] - '0'); elt->zminutes = (s[2] - '0') * 10 + (s[3] - '0'); } return T; /* all done! */ } /* falls through */ case '-': /* symbolic time zone */ if (!(ms = *++s)) ms = 'Z'; else if (*++s) { /* multi-character? */ ms -= 'A'; ms *= 1024; /* yes, make compressed three-byte form */ ms += ((*s++ - 'A') * 32); if (*s) ms += *s++ - 'A'; if (*s) ms = '\0'; /* more than three characters */ } default: /* ignore anything else */ break; } } /* This is not intended to be a comprehensive list of all possible * timezone strings. Such a list would be impractical. Rather, this * listing is intended to incorporate all military, North American, and * a few special cases such as Japan and the major European zone names, * such as what might be expected to be found in a Tenex format mailbox * and spewed from an IMAP server. The trend is to migrate to numeric * timezones which lack the flavor but also the ambiguity of the names. * * RFC-822 only recognizes UT, GMT, 1-letter military timezones, and the * 4 CONUS timezones and their summer time variants. [Sorry, Canadian * Atlantic Provinces, Alaska, and Hawaii.] */ switch (ms) { /* determine the timezone */ /* Universal */ case (('U'-'A')*1024)+(('T'-'A')*32): #ifndef STRICT_RFC822_TIMEZONES case (('U'-'A')*1024)+(('T'-'A')*32)+'C'-'A': #endif /* Greenwich */ case (('G'-'A')*1024)+(('M'-'A')*32)+'T'-'A': case 'Z': elt->zhours = 0; break; /* oriental (from Greenwich) timezones */ #ifndef STRICT_RFC822_TIMEZONES /* Middle Europe */ case (('M'-'A')*1024)+(('E'-'A')*32)+'T'-'A': #endif #ifdef BRITISH_SUMMER_TIME /* British Summer */ case (('B'-'A')*1024)+(('S'-'A')*32)+'T'-'A': #endif case 'A': elt->zhours = 1; break; #ifndef STRICT_RFC822_TIMEZONES /* Eastern Europe */ case (('E'-'A')*1024)+(('E'-'A')*32)+'T'-'A': #endif case 'B': elt->zhours = 2; break; case 'C': elt->zhours = 3; break; case 'D': elt->zhours = 4; break; case 'E': elt->zhours = 5; break; case 'F': elt->zhours = 6; break; case 'G': elt->zhours = 7; break; case 'H': elt->zhours = 8; break; #ifndef STRICT_RFC822_TIMEZONES /* Japan */ case (('J'-'A')*1024)+(('S'-'A')*32)+'T'-'A': #endif case 'I': elt->zhours = 9; break; case 'K': elt->zhours = 10; break; case 'L': elt->zhours = 11; break; case 'M': elt->zhours = 12; break; /* occidental (from Greenwich) timezones */ case 'N': elt->zoccident = 1; elt->zhours = 1; break; case 'O': elt->zoccident = 1; elt->zhours = 2; break; #ifndef STRICT_RFC822_TIMEZONES case (('A'-'A')*1024)+(('D'-'A')*32)+'T'-'A': #endif case 'P': elt->zoccident = 1; elt->zhours = 3; break; #ifdef NEWFOUNDLAND_STANDARD_TIME /* Newfoundland */ case (('N'-'A')*1024)+(('S'-'A')*32)+'T'-'A': elt->zoccident = 1; elt->zhours = 3; elt->zminutes = 30; break; #endif #ifndef STRICT_RFC822_TIMEZONES /* Atlantic */ case (('A'-'A')*1024)+(('S'-'A')*32)+'T'-'A': #endif /* CONUS */ case (('E'-'A')*1024)+(('D'-'A')*32)+'T'-'A': case 'Q': elt->zoccident = 1; elt->zhours = 4; break; /* Eastern */ case (('E'-'A')*1024)+(('S'-'A')*32)+'T'-'A': case (('C'-'A')*1024)+(('D'-'A')*32)+'T'-'A': case 'R': elt->zoccident = 1; elt->zhours = 5; break; /* Central */ case (('C'-'A')*1024)+(('S'-'A')*32)+'T'-'A': case (('M'-'A')*1024)+(('D'-'A')*32)+'T'-'A': case 'S': elt->zoccident = 1; elt->zhours = 6; break; /* Mountain */ case (('M'-'A')*1024)+(('S'-'A')*32)+'T'-'A': case (('P'-'A')*1024)+(('D'-'A')*32)+'T'-'A': case 'T': elt->zoccident = 1; elt->zhours = 7; break; /* Pacific */ case (('P'-'A')*1024)+(('S'-'A')*32)+'T'-'A': #ifndef STRICT_RFC822_TIMEZONES case (('Y'-'A')*1024)+(('D'-'A')*32)+'T'-'A': #endif case 'U': elt->zoccident = 1; elt->zhours = 8; break; #ifndef STRICT_RFC822_TIMEZONES /* Yukon */ case (('Y'-'A')*1024)+(('S'-'A')*32)+'T'-'A': #endif case 'V': elt->zoccident = 1; elt->zhours = 9; break; #ifndef STRICT_RFC822_TIMEZONES /* Hawaii */ case (('H'-'A')*1024)+(('S'-'A')*32)+'T'-'A': #endif case 'W': elt->zoccident = 1; elt->zhours = 10; break; /* Nome/Bering/Samoa */ #ifdef NOME_STANDARD_TIME case (('N'-'A')*1024)+(('S'-'A')*32)+'T'-'A': #endif #ifdef BERING_STANDARD_TIME case (('B'-'A')*1024)+(('S'-'A')*32)+'T'-'A': #endif #ifdef SAMOA_STANDARD_TIME case (('S'-'A')*1024)+(('S'-'A')*32)+'T'-'A': #endif case 'X': elt->zoccident = 1; elt->zhours = 11; break; case 'Y': elt->zoccident = 1; elt->zhours = 12; break; default: /* unknown time zones treated as local */ tn = time (0); /* time now... */ t = localtime (&tn); /* get local minutes since midnight */ mi = t->tm_hour * 60 + t->tm_min; ms = t->tm_yday; /* note Julian day */ if (t = gmtime (&tn)) { /* minus UTC minutes since midnight */ mi -= t->tm_hour * 60 + t->tm_min; /* ms can be one of: * 36x local time is December 31, UTC is January 1, offset -24 hours * 1 local time is 1 day ahead of UTC, offset +24 hours * 0 local time is same day as UTC, no offset * -1 local time is 1 day behind UTC, offset -24 hours * -36x local time is January 1, UTC is December 31, offset +24 hours */ if (ms -= t->tm_yday) /* correct offset if different Julian day */ mi += ((ms < 0) == (abs (ms) == 1)) ? -24*60 : 24*60; if (mi < 0) { /* occidental? */ mi = abs (mi); /* yup, make positive number */ elt->zoccident = 1; /* and note west of UTC */ } elt->zhours = mi / 60; /* now break into hours and minutes */ elt->zminutes = mi % 60; } break; } return T; } /* Mail n messages exist * Accepts: mail stream * number of messages */ void mail_exists (MAILSTREAM *stream,unsigned long nmsgs) { char tmp[MAILTMPLEN]; if (nmsgs > MAXMESSAGES) { sprintf (tmp,"Mailbox has more messages (%lu) exist than maximum (%lu)", nmsgs,MAXMESSAGES); mm_log (tmp,ERROR); nmsgs = MAXMESSAGES; /* cap to maximum */ /* probably will crash in mail_elt() soon enough... */ } /* make sure cache is large enough */ (*mailcache) (stream,nmsgs,CH_SIZE); stream->nmsgs = nmsgs; /* update stream status */ /* notify main program of change */ if (!stream->silent) MM_EXISTS (stream,nmsgs); } /* Mail n messages are recent * Accepts: mail stream * number of recent messages */ void mail_recent (MAILSTREAM *stream,unsigned long recent) { char tmp[MAILTMPLEN]; if (recent <= stream->nmsgs) stream->recent = recent; else { sprintf (tmp,"Non-existent recent message(s) %lu, nmsgs=%lu", recent,stream->nmsgs); mm_log (tmp,ERROR); } } /* Mail message n is expunged * Accepts: mail stream * message # */ void mail_expunged (MAILSTREAM *stream,unsigned long msgno) { char tmp[MAILTMPLEN]; MESSAGECACHE *elt; if (msgno > stream->nmsgs) { sprintf (tmp,"Expunge of non-existent message %lu, nmsgs=%lu", msgno,stream->nmsgs); mm_log (tmp,ERROR); } else { elt = (MESSAGECACHE *) (*mailcache) (stream,msgno,CH_ELT); /* notify main program of change */ if (!stream->silent) MM_EXPUNGED (stream,msgno); if (elt) { /* if an element is there */ elt->msgno = 0; /* invalidate its message number and free */ (*mailcache) (stream,msgno,CH_FREE); (*mailcache) (stream,msgno,CH_FREESORTCACHE); } /* expunge the slot */ (*mailcache) (stream,msgno,CH_EXPUNGE); --stream->nmsgs; /* update stream status */ if (stream->msgno) { /* have stream pointers? */ /* make sure the short cache is nuked */ if (stream->scache) mail_gc (stream,GC_ENV | GC_TEXTS); else stream->msgno = 0; /* make sure invalidated in any case */ } } } /* Mail stream status routines */ /* Mail lock stream * Accepts: mail stream */ void mail_lock (MAILSTREAM *stream) { if (stream->lock) { char tmp[MAILTMPLEN]; sprintf (tmp,"Lock when already locked, mbx=%.80s", stream->mailbox ? stream->mailbox : "???"); fatal (tmp); } else stream->lock = T; /* lock stream */ } /* Mail unlock stream * Accepts: mail stream */ void mail_unlock (MAILSTREAM *stream) { if (!stream->lock) fatal ("Unlock when not locked"); else stream->lock = NIL; /* unlock stream */ } /* Mail turn on debugging telemetry * Accepts: mail stream */ void mail_debug (MAILSTREAM *stream) { stream->debug = T; /* turn on debugging telemetry */ if (stream->dtb) (*stream->dtb->parameters) (ENABLE_DEBUG,stream); } /* Mail turn off debugging telemetry * Accepts: mail stream */ void mail_nodebug (MAILSTREAM *stream) { stream->debug = NIL; /* turn off debugging telemetry */ if (stream->dtb) (*stream->dtb->parameters) (DISABLE_DEBUG,stream); } /* Mail log to debugging telemetry * Accepts: message * flag that data is "sensitive" */ void mail_dlog (char *string,long flag) { mm_dlog ((debugsensitive || !flag) ? string : ""); } /* Mail parse UID sequence * Accepts: mail stream * sequence to parse * Returns: T if parse successful, else NIL */ long mail_uid_sequence (MAILSTREAM *stream,unsigned char *sequence) { unsigned long i,j,k,x,y; for (i = 1; i <= stream->nmsgs; i++) mail_elt (stream,i)->sequence = NIL; while (sequence && *sequence){/* while there is something to parse */ if (*sequence == '*') { /* maximum message */ i = stream->nmsgs ? mail_uid (stream,stream->nmsgs) : stream->uid_last; sequence++; /* skip past * */ } /* parse and validate message number */ /* parse and validate message number */ else if (!isdigit (*sequence)) { MM_LOG ("Syntax error in sequence",ERROR); return NIL; } else if (!(i = strtoul (sequence,(char **) &sequence,10))) { MM_LOG ("UID may not be zero",ERROR); return NIL; } switch (*sequence) { /* see what the delimiter is */ case ':': /* sequence range */ if (*++sequence == '*') { /* maximum message */ j = stream->nmsgs ? mail_uid (stream,stream->nmsgs) : stream->uid_last; sequence++; /* skip past * */ } /* parse end of range */ else if (!(j = strtoul (sequence,(char **) &sequence,10))) { MM_LOG ("UID sequence range invalid",ERROR); return NIL; } if (*sequence && *sequence++ != ',') { MM_LOG ("UID sequence range syntax error",ERROR); return NIL; } if (i > j) { /* swap the range if backwards */ x = i; i = j; j = x; } x = mail_msgno (stream,i);/* get msgnos */ y = mail_msgno (stream,j);/* for both UIDS (don't && it) */ /* easy if both UIDs valid */ if (x && y) while (x <= y) mail_elt (stream,x++)->sequence = T; /* start UID valid, end is not */ else if (x) while ((x <= stream->nmsgs) && (mail_uid (stream,x) <= j)) mail_elt (stream,x++)->sequence = T; /* end UID valid, start is not */ else if (y) for (x = 1; x <= y; x++) { if (mail_uid (stream,x) >= i) mail_elt (stream,x)->sequence = T; } /* neither is valid, ugh */ else for (x = 1; x <= stream->nmsgs; x++) if (((k = mail_uid (stream,x)) >= i) && (k <= j)) mail_elt (stream,x)->sequence = T; break; case ',': /* single message */ ++sequence; /* skip the delimiter, fall into end case */ case '\0': /* end of sequence, mark this message */ if (x = mail_msgno (stream,i)) mail_elt (stream,x)->sequence = T; break; default: /* anything else is a syntax error! */ MM_LOG ("UID sequence syntax error",ERROR); return NIL; } } return T; /* successfully parsed sequence */ } /* Mail see if line list matches that in cache * Accepts: candidate line list * cached line list * matching flags * Returns: T if match, NIL if no match */ long mail_match_lines (STRINGLIST *lines,STRINGLIST *msglines,long flags) { unsigned long i; unsigned char *s,*t; STRINGLIST *m; if (!msglines) return T; /* full header is in cache */ /* need full header but filtered in cache */ if ((flags & FT_NOT) || !lines) return NIL; do { /* make sure all present & accounted for */ for (m = msglines; m; m = m->next) if (lines->text.size == m->text.size) { for (s = lines->text.data,t = m->text.data,i = lines->text.size; i && !compare_uchar (*s,*t); s++,t++,i--); if (!i) break; /* this line matches */ } if (!m) return NIL; /* didn't find in the list */ } while (lines = lines->next); return T; /* all lines found */ } /* Mail filter text by header lines * Accepts: text to filter, with trailing null * length of text * list of lines * fetch flags * Returns: new text size, text overwritten */ unsigned long mail_filter (char *text,unsigned long len,STRINGLIST *lines, long flags) { STRINGLIST *hdrs; int notfound; unsigned long i; char c,*s,*e,*t,tmp[MAILTMPLEN]; char *src = text; char *dst = src; char *end = text + len; text[len] = '\012'; /* guard against running off buffer */ while (src < end) { /* process header */ /* slurp header line name */ for (s = src,e = s + MAILTMPLEN - 1,e = (e < end ? e : end),t = tmp; (s < e) && ((c = (*s ? *s : (*s = ' '))) != ':') && ((c > ' ') || ((c != ' ') && (c != '\t') && (c != '\015') && (c != '\012'))); *t++ = *s++); *t = '\0'; /* tie off */ notfound = T; /* not found yet */ if (i = t - tmp) /* see if found in header */ for (hdrs = lines; hdrs && notfound; hdrs = hdrs->next) if ((hdrs->text.size == i) && !compare_csizedtext (tmp,&hdrs->text)) notfound = NIL; /* skip header line if not wanted */ if (i && ((flags & FT_NOT) ? !notfound : notfound)) while (((*src++ != '\012') && (*src++ != '\012') && (*src++ != '\012') && (*src++ != '\012') && (*src++ != '\012') && (*src++ != '\012') && (*src++ != '\012') && (*src++ != '\012') && (*src++ != '\012') && (*src++ != '\012')) || ((*src == ' ') || (*src == '\t'))); else if (src == dst) { /* copy to self */ while (((*src++ != '\012') && (*src++ != '\012') && (*src++ != '\012') && (*src++ != '\012') && (*src++ != '\012') && (*src++ != '\012') && (*src++ != '\012') && (*src++ != '\012') && (*src++ != '\012') && (*src++ != '\012')) || ((*src == ' ') || (*src == '\t'))); dst = src; /* update destination */ } else { /* copy line and any continuation line */ while ((((*dst++ = *src++) != '\012') && ((*dst++ = *src++) != '\012') && ((*dst++ = *src++) != '\012') && ((*dst++ = *src++) != '\012') && ((*dst++ = *src++) != '\012') && ((*dst++ = *src++) != '\012') && ((*dst++ = *src++) != '\012') && ((*dst++ = *src++) != '\012') && ((*dst++ = *src++) != '\012') && ((*dst++ = *src++) != '\012'))|| ((*src == ' ') || (*src == '\t'))); /* in case hit the guard LF */ if (src > end) dst -= (src - end); } } *dst = '\0'; /* tie off destination */ return dst - text; } /* Local mail search message * Accepts: MAIL stream * message number * optional section specification * search program * Returns: T if found, NIL otherwise */ long mail_search_msg (MAILSTREAM *stream,unsigned long msgno,char *section, SEARCHPGM *pgm) { unsigned short d; char tmp[MAILTMPLEN]; MESSAGECACHE *elt = mail_elt (stream,msgno); SEARCHHEADER *hdr; SEARCHOR *or; SEARCHPGMLIST *not; unsigned long now = (unsigned long) time (0); if (pgm->msgno || pgm->uid) { /* message set searches */ SEARCHSET *set; /* message sequences */ if (pgm->msgno) { /* inside this message sequence set */ for (set = pgm->msgno; set; set = set->next) if (set->last ? ((set->first <= set->last) ? ((msgno >= set->first) && (msgno <= set->last)) : ((msgno >= set->last) && (msgno <= set->first))) : msgno == set->first) break; if (!set) return NIL; /* not found within sequence */ } if (pgm->uid) { /* inside this unique identifier set */ unsigned long uid = mail_uid (stream,msgno); for (set = pgm->uid; set; set = set->next) if (set->last ? ((set->first <= set->last) ? ((uid >= set->first) && (uid <= set->last)) : ((uid >= set->last) && (uid <= set->first))) : uid == set->first) break; if (!set) return NIL; /* not found within sequence */ } } /* Fast data searches */ /* need to fetch fast data? */ if ((!elt->rfc822_size && (pgm->larger || pgm->smaller)) || (!elt->year && (pgm->before || pgm->on || pgm->since || pgm->older || pgm->younger)) || (!elt->valid && (pgm->answered || pgm->unanswered || pgm->deleted || pgm->undeleted || pgm->draft || pgm->undraft || pgm->flagged || pgm->unflagged || pgm->recent || pgm->old || pgm->seen || pgm->unseen || pgm->keyword || pgm->unkeyword))) { unsigned long i; MESSAGECACHE *ielt; for (i = elt->msgno; /* find last unloaded message in range */ (i < stream->nmsgs) && (ielt = mail_elt (stream,i+1)) && ((!ielt->rfc822_size && (pgm->larger || pgm->smaller)) || (!ielt->year && (pgm->before || pgm->on || pgm->since || pgm->older || pgm->younger)) || (!ielt->valid && (pgm->answered || pgm->unanswered || pgm->deleted || pgm->undeleted || pgm->draft || pgm->undraft || pgm->flagged || pgm->unflagged || pgm->recent || pgm->old || pgm->seen || pgm->unseen || pgm->keyword || pgm->unkeyword))); ++i); if (i == elt->msgno) sprintf (tmp,"%lu",elt->msgno); else sprintf (tmp,"%lu:%lu",elt->msgno,i); mail_fetch_fast (stream,tmp,NIL); } /* size ranges */ if ((pgm->larger && (elt->rfc822_size <= pgm->larger)) || (pgm->smaller && (elt->rfc822_size >= pgm->smaller))) return NIL; /* message flags */ if ((pgm->answered && !elt->answered) || (pgm->unanswered && elt->answered) || (pgm->deleted && !elt->deleted) || (pgm->undeleted && elt->deleted) || (pgm->draft && !elt->draft) || (pgm->undraft && elt->draft) || (pgm->flagged && !elt->flagged) || (pgm->unflagged && elt->flagged) || (pgm->recent && !elt->recent) || (pgm->old && elt->recent) || (pgm->seen && !elt->seen) || (pgm->unseen && elt->seen)) return NIL; /* keywords */ if ((pgm->keyword && !mail_search_keyword (stream,elt,pgm->keyword,LONGT)) || (pgm->unkeyword && !mail_search_keyword (stream,elt,pgm->unkeyword,NIL))) return NIL; /* internal date ranges */ if (pgm->before || pgm->on || pgm->since) { d = mail_shortdate (elt->year,elt->month,elt->day); if (pgm->before && (d >= pgm->before)) return NIL; if (pgm->on && (d != pgm->on)) return NIL; if (pgm->since && (d < pgm->since)) return NIL; } if (pgm->older || pgm->younger) { unsigned long msgd = mail_longdate (elt); if (pgm->older && msgd > (now - pgm->older)) return NIL; if (pgm->younger && msgd < (now - pgm->younger)) return NIL; } /* envelope searches */ if (pgm->sentbefore || pgm->senton || pgm->sentsince || pgm->bcc || pgm->cc || pgm->from || pgm->to || pgm->subject || pgm->return_path || pgm->sender || pgm->reply_to || pgm->in_reply_to || pgm->message_id || pgm->newsgroups || pgm->followup_to || pgm->references) { ENVELOPE *env; MESSAGECACHE delt; if (section) { /* use body part envelope */ BODY *body = mail_body (stream,msgno,section); env = (body && (body->type == TYPEMESSAGE) && body->subtype && !strcmp (body->subtype,"RFC822")) ? body->nested.msg->env : NIL; } else { /* use top level envelope if no section */ if (pgm->header && !stream->scache && !(stream->dtb->flags & DR_LOCAL)) mail_fetch_header(stream,msgno,NIL,NIL,NIL,FT_PEEK|FT_SEARCHLOOKAHEAD); env = mail_fetchenvelope (stream,msgno); } if (!env) return NIL; /* no envelope obtained */ /* sent date ranges */ if ((pgm->sentbefore || pgm->senton || pgm->sentsince) && (!mail_parse_date (&delt,env->date) || !(d = mail_shortdate (delt.year,delt.month,delt.day)) || (pgm->sentbefore && (d >= pgm->sentbefore)) || (pgm->senton && (d != pgm->senton)) || (pgm->sentsince && (d < pgm->sentsince)))) return NIL; /* search headers */ if ((pgm->bcc && !mail_search_addr (env->bcc,pgm->bcc)) || (pgm->cc && !mail_search_addr (env->cc,pgm->cc)) || (pgm->from && !mail_search_addr (env->from,pgm->from)) || (pgm->to && !mail_search_addr (env->to,pgm->to)) || (pgm->subject && !mail_search_header_text (env->subject,pgm->subject))) return NIL; /* These criteria are not supported by IMAP and have to be emulated */ if ((pgm->return_path && !mail_search_addr (env->return_path,pgm->return_path)) || (pgm->sender && !mail_search_addr (env->sender,pgm->sender)) || (pgm->reply_to && !mail_search_addr (env->reply_to,pgm->reply_to)) || (pgm->in_reply_to && !mail_search_header_text (env->in_reply_to,pgm->in_reply_to)) || (pgm->message_id && !mail_search_header_text (env->message_id,pgm->message_id)) || (pgm->newsgroups && !mail_search_header_text (env->newsgroups,pgm->newsgroups)) || (pgm->followup_to && !mail_search_header_text (env->followup_to,pgm->followup_to)) || (pgm->references && !mail_search_header_text (env->references,pgm->references))) return NIL; } /* search header lines */ for (hdr = pgm->header; hdr; hdr = hdr->next) { char *t,*e,*v; SIZEDTEXT s; STRINGLIST sth,stc; sth.next = stc.next = NIL; /* only one at a time */ sth.text.data = hdr->line.data; sth.text.size = hdr->line.size; /* get the header text */ if ((t = mail_fetch_header (stream,msgno,NIL,&sth,&s.size, FT_INTERNAL | FT_PEEK | (section ? NIL : FT_SEARCHLOOKAHEAD))) && strchr (t,':')) { if (hdr->text.size) { /* anything matches empty search string */ /* non-empty, copy field data */ s.data = (unsigned char *) fs_get (s.size + 1); /* for each line */ for (v = (char *) s.data, e = t + s.size; t < e;) switch (*t) { default: /* non-continuation, skip leading field name */ while ((t < e) && (*t++ != ':')); if ((t < e) && (*t == ':')) t++; case '\t': case ' ': /* copy field data */ while ((t < e) && (*t != '\015') && (*t != '\012')) *v++ = *t++; *v++ = '\n'; /* tie off line */ while (((*t == '\015') || (*t == '\012')) && (t < e)) t++; } /* calculate true size */ s.size = v - (char *) s.data; *v = '\0'; /* tie off results */ stc.text.data = hdr->text.data; stc.text.size = hdr->text.size; /* search header */ if (mail_search_header (&s,&stc)) fs_give ((void **) &s.data); else { /* search failed */ fs_give ((void **) &s.data); return NIL; } } } else return NIL; /* no matching header text */ } /* search strings */ if ((pgm->text && !mail_search_text (stream,msgno,section,pgm->text,LONGT))|| (pgm->body && !mail_search_text (stream,msgno,section,pgm->body,NIL))) return NIL; /* logical conditions */ for (or = pgm->or; or; or = or->next) if (!(mail_search_msg (stream,msgno,section,or->first) || mail_search_msg (stream,msgno,section,or->second))) return NIL; for (not = pgm->not; not; not = not->next) if (mail_search_msg (stream,msgno,section,not->pgm)) return NIL; return T; } /* Mail search message header null-terminated text * Accepts: header text * strings to search * Returns: T if search found a match */ long mail_search_header_text (char *s,STRINGLIST *st) { SIZEDTEXT h; /* have any text? */ if (h.data = (unsigned char *) s) { h.size = strlen (s); /* yes, get its size */ return mail_search_header (&h,st); } return NIL; } /* Mail search message header * Accepts: header as sized text * strings to search * Returns: T if search found a match */ long mail_search_header (SIZEDTEXT *hdr,STRINGLIST *st) { SIZEDTEXT h; long ret = LONGT; /* make UTF-8 version of header */ utf8_mime2text (hdr,&h,U8T_CANONICAL); while (h.size && ((h.data[h.size-1]=='\015') || (h.data[h.size-1]=='\012'))) --h.size; /* slice off trailing newlines */ do if (h.size ? /* search non-empty string */ !ssearch (h.data,h.size,st->text.data,st->text.size) : st->text.size) ret = NIL; while (ret && (st = st->next)); if (h.data != hdr->data) fs_give ((void **) &h.data); return ret; } /* Mail search message body * Accepts: MAIL stream * message number * optional section specification * string list * flags * Returns: T if search found a match */ long mail_search_text (MAILSTREAM *stream,unsigned long msgno,char *section, STRINGLIST *st,long flags) { BODY *body; long ret = NIL; STRINGLIST *s = mail_newstringlist (); mailgets_t omg = mailgets; if (stream->dtb->flags & DR_LOWMEM) mailgets = mail_search_gets; /* strings to search */ for (stream->private.search.string = s; st;) { s->text.data = st->text.data; s->text.size = st->text.size; if (st = st->next) s = s->next = mail_newstringlist (); } stream->private.search.text = NIL; if (flags) { /* want header? */ SIZEDTEXT s,t; s.data = (unsigned char *) mail_fetch_header (stream,msgno,section,NIL,&s.size,FT_INTERNAL|FT_PEEK); utf8_mime2text (&s,&t,U8T_CANONICAL); ret = mail_search_string_work (&t,&stream->private.search.string); if (t.data != s.data) fs_give ((void **) &t.data); } if (!ret) { /* still looking for match? */ /* no section, get top-level body */ if (!section) mail_fetchstructure (stream,msgno,&body); /* get body of nested message */ else if ((body = mail_body (stream,msgno,section)) && (body->type == TYPEMULTIPART) && body->subtype && !strcmp (body->subtype,"RFC822")) body = body->nested.msg->body; if (body) ret = mail_search_body (stream,msgno,body,NIL,1,flags); } mailgets = omg; /* restore former gets routine */ /* clear searching */ for (s = stream->private.search.string; s; s = s->next) s->text.data = NIL; mail_free_stringlist (&stream->private.search.string); stream->private.search.text = NIL; return ret; } /* Mail search message body text parts * Accepts: MAIL stream * message number * current body pointer * hierarchical level prefix * position at current hierarchical level * string list * flags * Returns: T if search found a match */ long mail_search_body (MAILSTREAM *stream,unsigned long msgno,BODY *body, char *prefix,unsigned long section,long flags) { long ret = NIL; unsigned long i; char *s,*t,sect[MAILTMPLEN]; SIZEDTEXT st,h; PART *part; PARAMETER *param; if (prefix && (strlen (prefix) > (MAILTMPLEN - 20))) return NIL; sprintf (sect,"%s%lu",prefix ? prefix : "",section++); if (flags && prefix) { /* want to search MIME header too? */ st.data = (unsigned char *) mail_fetch_mime (stream,msgno,sect,&st.size, FT_INTERNAL | FT_PEEK); if (stream->dtb->flags & DR_LOWMEM) ret = stream->private.search.result; else { /* make UTF-8 version of header */ utf8_mime2text (&st,&h,U8T_CANONICAL); ret = mail_search_string_work (&h,&stream->private.search.string); if (h.data != st.data) fs_give ((void **) &h.data); } } if (!ret) switch (body->type) { case TYPEMULTIPART: /* extend prefix if not first time */ s = prefix ? strcat (sect,".") : ""; for (i = 1,part = body->nested.part; part && !ret; i++,part = part->next) ret = mail_search_body (stream,msgno,&part->body,s,i,flags); break; case TYPEMESSAGE: if (!strcmp (body->subtype,"RFC822")) { if (flags) { /* want to search nested message header? */ st.data = (unsigned char *) mail_fetch_header (stream,msgno,sect,NIL,&st.size, FT_INTERNAL | FT_PEEK); if (stream->dtb->flags & DR_LOWMEM) ret =stream->private.search.result; else { /* make UTF-8 version of header */ utf8_mime2text (&st,&h,U8T_CANONICAL); ret = mail_search_string_work (&h,&stream->private.search.string); if (h.data != st.data) fs_give ((void **) &h.data); } } if (body = body->nested.msg->body) ret = (body->type == TYPEMULTIPART) ? mail_search_body (stream,msgno,body,(prefix ? prefix : ""), section - 1,flags) : mail_search_body (stream,msgno,body,strcat (sect,"."),1,flags); break; } /* non-MESSAGE/RFC822 falls into text case */ case TYPETEXT: s = mail_fetch_body (stream,msgno,sect,&i,FT_INTERNAL | FT_PEEK); if (stream->dtb->flags & DR_LOWMEM) ret = stream->private.search.result; else { for (t = NIL,param = body->parameter; param && !t; param = param->next) if (!strcmp (param->attribute,"CHARSET")) t = param->value; switch (body->encoding) { /* what encoding? */ case ENCBASE64: if (st.data = (unsigned char *) rfc822_base64 ((unsigned char *) s,i,&st.size)) { ret = mail_search_string (&st,t,&stream->private.search.string); fs_give ((void **) &st.data); } break; case ENCQUOTEDPRINTABLE: if (st.data = rfc822_qprint ((unsigned char *) s,i,&st.size)) { ret = mail_search_string (&st,t,&stream->private.search.string); fs_give ((void **) &st.data); } break; default: st.data = (unsigned char *) s; st.size = i; ret = mail_search_string (&st,t,&stream->private.search.string); break; } } break; } return ret; } /* Mail search text * Accepts: sized text to search * character set of sized text * string list of search keys * Returns: T if search found a match */ long mail_search_string (SIZEDTEXT *s,char *charset,STRINGLIST **st) { SIZEDTEXT u; long ret; STRINGLIST **sc = st; /* convert to UTF-8 as best we can */ if (!utf8_text (s,charset,&u,U8T_CANONICAL)) utf8_text (s,NIL,&u,U8T_CANONICAL); ret = mail_search_string_work (&u,st); if (u.data != s->data) fs_give ((void **) &u.data); return ret; } /* Mail search text worker routine * Accepts: sized text to search * string list of search keys * Returns: T if search found a match */ long mail_search_string_work (SIZEDTEXT *s,STRINGLIST **st) { void *t; STRINGLIST **sc = st; while (*sc) { /* run down criteria list */ if (ssearch (s->data,s->size,(*sc)->text.data,(*sc)->text.size)) { t = (void *) (*sc); /* found one, need to flush this */ *sc = (*sc)->next; /* remove it from the list */ fs_give (&t); /* flush the buffer */ } else sc = &(*sc)->next; /* move to next in list */ } return *st ? NIL : LONGT; } /* Mail search keyword * Accepts: MAIL stream * elt to get flags from * keyword list * T for keyword search, NIL for unkeyword search * Returns: T if search found a match */ long mail_search_keyword (MAILSTREAM *stream,MESSAGECACHE *elt,STRINGLIST *st, long flag) { int i,j; unsigned long f = 0; unsigned long tf; do { for (i = 0; (j = (i < NUSERFLAGS) && stream->user_flags[i]); ++i) if (!compare_csizedtext (stream->user_flags[i],&st->text)) { f |= (1 << i); break; } if (flag && !j) return NIL; } while (st = st->next); tf = elt->user_flags & f; /* get set flags which match */ return flag ? (f == tf) : !tf; } /* Mail search an address list * Accepts: address list * string list * Returns: T if search found a match */ #define SEARCHBUFLEN (size_t) 2000 #define SEARCHBUFSLOP (size_t) 5 long mail_search_addr (ADDRESS *adr,STRINGLIST *st) { ADDRESS *a,tadr; SIZEDTEXT txt; char tmp[SENDBUFLEN + 1]; size_t i = SEARCHBUFLEN; size_t k; long ret = NIL; if (adr) { txt.data = (unsigned char *) fs_get (i + SEARCHBUFSLOP); /* never an error or next */ tadr.error = NIL,tadr.next = NIL; /* write address list */ for (txt.size = 0,a = adr; a; a = a->next) { k = (tadr.mailbox = a->mailbox) ? 4 + 2*strlen (a->mailbox) : 3; if (tadr.personal = a->personal) k += 3 + 2*strlen (a->personal); if (tadr.adl = a->adl) k += 3 + 2*strlen (a->adl); if (tadr.host = a->host) k += 3 + 2*strlen (a->host); if (tadr.personal || tadr.adl) k += 2; if (k < (SENDBUFLEN-10)) {/* ignore ridiculous addresses */ tmp[0] = '\0'; rfc822_write_address (tmp,&tadr); /* resize buffer if necessary */ if (((k = strlen (tmp)) + txt.size) > i) fs_resize ((void **) &txt.data,SEARCHBUFSLOP + (i += SEARCHBUFLEN)); /* add new address */ memcpy (txt.data + txt.size,tmp,k); txt.size += k; /* another address follows */ if (a->next) txt.data[txt.size++] = ','; } } txt.data[txt.size] = '\0'; /* tie off string */ ret = mail_search_header (&txt,st); fs_give ((void **) &txt.data); } return ret; } /* Get string for low-memory searching * Accepts: readin function pointer * stream to use * number of bytes * gets data packet * mail stream * message number * descriptor string * option flags * Returns: NIL, always */ #define SEARCHSLOP 128 char *mail_search_gets (readfn_t f,void *stream,unsigned long size, GETS_DATA *md) { unsigned long i; char tmp[MAILTMPLEN+SEARCHSLOP+1]; SIZEDTEXT st; /* better not be called unless searching */ if (!md->stream->private.search.string) { sprintf (tmp,"Search botch, mbx = %.80s, %s = %lu[%.80s]", md->stream->mailbox, (md->flags & FT_UID) ? "UID" : "msg",md->msgno,md->what); fatal (tmp); } /* initially no match for search */ md->stream->private.search.result = NIL; /* make sure buffer clear */ memset (st.data = (unsigned char *) tmp,'\0', (size_t) MAILTMPLEN+SEARCHSLOP+1); /* read first buffer */ (*f) (stream,st.size = i = min (size,(long) MAILTMPLEN),tmp); /* search for text */ if (mail_search_string (&st,NIL,&md->stream->private.search.string)) md->stream->private.search.result = T; else if (size -= i) { /* more to do, blat slop down */ memmove (tmp,tmp+MAILTMPLEN-SEARCHSLOP,(size_t) SEARCHSLOP); do { /* read subsequent buffers one at a time */ (*f) (stream,i = min (size,(long) MAILTMPLEN),tmp+SEARCHSLOP); st.size = i + SEARCHSLOP; if (mail_search_string (&st,NIL,&md->stream->private.search.string)) md->stream->private.search.result = T; else memmove (tmp,tmp+MAILTMPLEN,(size_t) SEARCHSLOP); } while ((size -= i) && !md->stream->private.search.result); } if (size) { /* toss out everything after that */ do (*f) (stream,i = min (size,(long) MAILTMPLEN),tmp); while (size -= i); } return NIL; } /* Mail parse search criteria * Accepts: criteria * Returns: search program if parse successful, else NIL */ SEARCHPGM *mail_criteria (char *criteria) { SEARCHPGM *pgm = NIL; char *criterion,*r,tmp[MAILTMPLEN]; int f; if (criteria) { /* only if criteria defined */ /* make writeable copy of criteria */ criteria = cpystr (criteria); /* for each criterion */ for (pgm = mail_newsearchpgm (), criterion = strtok_r (criteria," ",&r); criterion; (criterion = strtok_r (NIL," ",&r))) { f = NIL; /* init then scan the criterion */ switch (*ucase (criterion)) { case 'A': /* possible ALL, ANSWERED */ if (!strcmp (criterion+1,"LL")) f = T; else if (!strcmp (criterion+1,"NSWERED")) f = pgm->answered = T; break; case 'B': /* possible BCC, BEFORE, BODY */ if (!strcmp (criterion+1,"CC")) f = mail_criteria_string (&pgm->bcc,&r); else if (!strcmp (criterion+1,"EFORE")) f = mail_criteria_date (&pgm->before,&r); else if (!strcmp (criterion+1,"ODY")) f = mail_criteria_string (&pgm->body,&r); break; case 'C': /* possible CC */ if (!strcmp (criterion+1,"C")) f = mail_criteria_string (&pgm->cc,&r); break; case 'D': /* possible DELETED */ if (!strcmp (criterion+1,"ELETED")) f = pgm->deleted = T; break; case 'F': /* possible FLAGGED, FROM */ if (!strcmp (criterion+1,"LAGGED")) f = pgm->flagged = T; else if (!strcmp (criterion+1,"ROM")) f = mail_criteria_string (&pgm->from,&r); break; case 'K': /* possible KEYWORD */ if (!strcmp (criterion+1,"EYWORD")) f = mail_criteria_string (&pgm->keyword,&r); break; case 'N': /* possible NEW */ if (!strcmp (criterion+1,"EW")) f = pgm->recent = pgm->unseen = T; break; case 'O': /* possible OLD, ON */ if (!strcmp (criterion+1,"LD")) f = pgm->old = T; else if (!strcmp (criterion+1,"N")) f = mail_criteria_date (&pgm->on,&r); break; case 'R': /* possible RECENT */ if (!strcmp (criterion+1,"ECENT")) f = pgm->recent = T; break; case 'S': /* possible SEEN, SINCE, SUBJECT */ if (!strcmp (criterion+1,"EEN")) f = pgm->seen = T; else if (!strcmp (criterion+1,"INCE")) f = mail_criteria_date (&pgm->since,&r); else if (!strcmp (criterion+1,"UBJECT")) f = mail_criteria_string (&pgm->subject,&r); break; case 'T': /* possible TEXT, TO */ if (!strcmp (criterion+1,"EXT")) f = mail_criteria_string (&pgm->text,&r); else if (!strcmp (criterion+1,"O")) f = mail_criteria_string (&pgm->to,&r); break; case 'U': /* possible UN* */ if (criterion[1] == 'N') { if (!strcmp (criterion+2,"ANSWERED")) f = pgm->unanswered = T; else if (!strcmp (criterion+2,"DELETED")) f = pgm->undeleted = T; else if (!strcmp (criterion+2,"FLAGGED")) f = pgm->unflagged = T; else if (!strcmp (criterion+2,"KEYWORD")) f = mail_criteria_string (&pgm->unkeyword,&r); else if (!strcmp (criterion+2,"SEEN")) f = pgm->unseen = T; } break; default: /* we will barf below */ break; } if (!f) { /* if can't identify criterion */ sprintf (tmp,"Unknown search criterion: %.30s",criterion); MM_LOG (tmp,ERROR); mail_free_searchpgm (&pgm); break; } } /* no longer need copy of criteria */ fs_give ((void **) &criteria); } return pgm; } /* Parse a date * Accepts: pointer to date integer to return * pointer to strtok state * Returns: T if successful, else NIL */ int mail_criteria_date (unsigned short *date,char **r) { STRINGLIST *s = NIL; MESSAGECACHE elt; /* parse the date and return fn if OK */ int ret = (mail_criteria_string (&s,r) && mail_parse_date (&elt,(char *) s->text.data) && (*date = mail_shortdate (elt.year,elt.month,elt.day))) ? T : NIL; if (s) mail_free_stringlist (&s); return ret; } /* Calculate shortdate from elt values * Accepts: year (0 = BASEYEAR) * month (1 = January) * day * Returns: shortdate */ unsigned short mail_shortdate (unsigned int year,unsigned int month, unsigned int day) { return (year << 9) + (month << 5) + day; } /* Parse a string * Accepts: pointer to stringlist * pointer to strtok state * Returns: T if successful, else NIL */ int mail_criteria_string (STRINGLIST **s,char **r) { unsigned long n; char e,*d,*end = " ",*c = strtok_r (NIL,"",r); if (!c) return NIL; /* missing argument */ switch (*c) { /* see what the argument is */ case '{': /* literal string */ n = strtoul (c+1,&d,10); /* get its length */ if ((*d++ == '}') && (*d++ == '\015') && (*d++ == '\012') && (!(*(c = d + n)) || (*c == ' '))) { e = *--c; /* store old delimiter */ *c = '\377'; /* make sure not a space */ strtok_r (c," ",r); /* reset the strtok mechanism */ *c = e; /* put character back */ break; } case '\0': /* catch bogons */ case ' ': return NIL; case '"': /* quoted string */ if (strchr (c+1,'"')) end = "\""; else return NIL; /* falls through */ default: /* atomic string */ if (d = strtok_r (c,end,r)) n = strlen (d); else return NIL; break; } while (*s) s = &(*s)->next; /* find tail of list */ *s = mail_newstringlist (); /* make new entry */ /* return the data */ (*s)->text.data = (unsigned char *) cpystr (d); (*s)->text.size = n; return T; } /* Mail parse set from string * Accepts: string to parse * pointer to updated string pointer for return * Returns: set with pointer updated, or NIL if error */ SEARCHSET *mail_parse_set (char *s,char **ret) { SEARCHSET *cur; SEARCHSET *set = NIL; while (isdigit (*s)) { if (!set) cur = set = mail_newsearchset (); else cur = cur->next = mail_newsearchset (); /* parse value */ if (!(cur->first = strtoul (s,&s,10)) || ((*s == ':') && !(isdigit (*++s) && (cur->last = strtoul (s,&s,10))))) break; /* bad value or range */ if (*s == ',') ++s; /* point to next value if more */ else { /* end of set */ *ret = s; /* set return pointer */ return set; /* return set */ } } mail_free_searchset (&set); /* failure, punt partial set */ return NIL; } /* Mail append to set * Accepts: head of search set or NIL to do nothing * message to add * Returns: tail of search set or NIL if did nothing */ SEARCHSET *mail_append_set (SEARCHSET *set,unsigned long msgno) { if (set) { /* find tail */ while (set->next) set = set->next; /* start of set if no first member */ if (!set->first) set->first = msgno; else if (msgno == (set->last ? set->last : set->first) + 1) set->last = msgno; /* extend range if 1 past current */ else (set = set->next = mail_newsearchset ())->first = msgno; } return set; } /* Mail sort messages * Accepts: mail stream * character set * search program * sort program * option flags * Returns: vector of sorted message sequences or NIL if error */ unsigned long *mail_sort (MAILSTREAM *stream,char *charset,SEARCHPGM *spg, SORTPGM *pgm,long flags) { unsigned long *ret = NIL; if (stream->dtb) /* do the driver's action */ ret = (*(stream->dtb->sort ? stream->dtb->sort : mail_sort_msgs)) (stream,charset,spg,pgm,flags); /* flush search/sort programs if requested */ if (spg && (flags & SE_FREE)) mail_free_searchpgm (&spg); if (flags & SO_FREE) mail_free_sortpgm (&pgm); return ret; } /* Mail sort messages work routine * Accepts: mail stream * character set * search program * sort program * option flags * Returns: vector of sorted message sequences or NIL if error */ unsigned long *mail_sort_msgs (MAILSTREAM *stream,char *charset,SEARCHPGM *spg, SORTPGM *pgm,long flags) { unsigned long i; SORTCACHE **sc; unsigned long *ret = NIL; if (spg) { /* only if a search needs to be done */ int silent = stream->silent; stream->silent = T; /* don't pass up mm_searched() events */ /* search for messages */ mail_search_full (stream,charset,spg,NIL); stream->silent = silent; /* restore silence state */ } /* initialize progress counters */ pgm->nmsgs = pgm->progress.cached = 0; /* pass 1: count messages to sort */ for (i = 1; i <= stream->nmsgs; ++i) if (mail_elt (stream,i)->searched) pgm->nmsgs++; if (pgm->nmsgs) { /* pass 2: sort cache */ sc = mail_sort_loadcache (stream,pgm); /* pass 3: sort messages */ if (!pgm->abort) ret = mail_sort_cache (stream,pgm,sc,flags); fs_give ((void **) &sc); /* don't need sort vector any more */ } /* empty sort results */ else ret = (unsigned long *) memset (fs_get (sizeof (unsigned long)),0, sizeof (unsigned long)); /* also return via callback if requested */ if (mailsortresults) (*mailsortresults) (stream,ret,pgm->nmsgs); return ret; /* return sort results */ } /* Mail sort sortcache vector * Accepts: mail stream * sort program * sortcache vector * option flags * Returns: vector of sorted message sequences or NIL if error */ unsigned long *mail_sort_cache (MAILSTREAM *stream,SORTPGM *pgm,SORTCACHE **sc, long flags) { unsigned long i,*ret; /* pass 3: sort messages */ qsort ((void *) sc,pgm->nmsgs,sizeof (SORTCACHE *),mail_sort_compare); /* optional post sorting */ if (pgm->postsort) (*pgm->postsort) ((void *) sc); /* pass 4: return results */ ret = (unsigned long *) fs_get ((pgm->nmsgs+1) * sizeof (unsigned long)); if (flags & SE_UID) /* UID or msgno? */ for (i = 0; i < pgm->nmsgs; i++) ret[i] = mail_uid (stream,sc[i]->num); else for (i = 0; i < pgm->nmsgs; i++) ret[i] = sc[i]->num; ret[pgm->nmsgs] = 0; /* tie off message list */ return ret; } /* Mail load sortcache * Accepts: mail stream, already searched * sort program * Returns: vector of sortcache pointers matching search */ static STRINGLIST maildateline = {{(unsigned char *) "date",4},NIL}; static STRINGLIST mailrnfromline = {{(unsigned char *) ">from",5},NIL}; static STRINGLIST mailfromline = {{(unsigned char *) "from",4}, &mailrnfromline}; static STRINGLIST mailtonline = {{(unsigned char *) "to",2},NIL}; static STRINGLIST mailccline = {{(unsigned char *) "cc",2},NIL}; static STRINGLIST mailsubline = {{(unsigned char *) "subject",7},NIL}; SORTCACHE **mail_sort_loadcache (MAILSTREAM *stream,SORTPGM *pgm) { char *t,*v,*x,tmp[MAILTMPLEN]; SORTPGM *pg; SORTCACHE *s,**sc; MESSAGECACHE *elt,telt; ENVELOPE *env; ADDRESS *adr = NIL; unsigned long i = (pgm->nmsgs) * sizeof (SORTCACHE *); sc = (SORTCACHE **) memset (fs_get ((size_t) i),0,(size_t) i); /* see what needs to be loaded */ for (i = 1; !pgm->abort && (i <= stream->nmsgs); i++) if ((elt = mail_elt (stream,i))->searched) { sc[pgm->progress.cached++] = s = (SORTCACHE *) (*mailcache) (stream,i,CH_SORTCACHE); s->pgm = pgm; /* note sort program */ s->num = i; /* get envelope if cached */ if (stream->scache) env = (i == stream->msgno) ? stream->env : NIL; else env = elt->private.msg.env; for (pg = pgm; pg; pg = pg->next) switch (pg->function) { case SORTARRIVAL: /* sort by arrival date */ if (!s->arrival) { /* internal date unknown but can get? */ if (!elt->day && !(stream->dtb->flags & DR_NOINTDATE)) { sprintf (tmp,"%lu",i); mail_fetch_fast (stream,tmp,NIL); } /* wrong thing before 3-Jan-1970 */ s->arrival = elt->day ? mail_longdate (elt) : 1; s->dirty = T; } break; case SORTSIZE: /* sort by message size */ if (!s->size) { if (!elt->rfc822_size) { sprintf (tmp,"%lu",i); mail_fetch_fast (stream,tmp,NIL); } s->size = elt->rfc822_size ? elt->rfc822_size : 1; s->dirty = T; } break; case SORTDATE: /* sort by date */ if (!s->date) { if (env) t = env->date; else if ((t = mail_fetch_header (stream,i,NIL,&maildateline,NIL, FT_INTERNAL | FT_PEEK)) && (t = strchr (t,':'))) for (x = ++t; x = strpbrk (x,"\012\015"); x++) switch (*(v = ((*x == '\015') && (x[1] == '\012')) ? x+2 : x+1)){ case ' ': /* erase continuation newlines */ case '\t': memmove (x,v,strlen (v)); break; default: /* tie off extraneous text */ *x = x[1] = '\0'; } /* skip leading whitespace */ if (t) while ((*t == ' ') || (*t == '\t')) t++; /* parse date from Date: header */ if (!(t && mail_parse_date (&telt,t) && (s->date = mail_longdate (&telt)))) { /* failed, use internal date */ if (!(s->date = s->arrival)) { /* internal date unknown but can get? */ if (!elt->day && !(stream->dtb->flags & DR_NOINTDATE)) { sprintf (tmp,"%lu",i); mail_fetch_fast (stream,tmp,NIL); } /* wrong thing before 3-Jan-1970 */ s->date = (s->arrival = elt->day ? mail_longdate (elt) : 1); } } s->dirty = T; } break; case SORTFROM: /* sort by first from */ if (!s->from) { if (env) s->from = env->from && env->from->mailbox ? cpystr (env->from->mailbox) : NIL; else if ((t = mail_fetch_header (stream,i,NIL,&mailfromline,NIL, FT_INTERNAL | FT_PEEK)) && (t = strchr (t,':'))) { for (x = ++t; x = strpbrk (x,"\012\015"); x++) switch (*(v = ((*x == '\015') && (x[1] == '\012')) ? x+2 : x+1)){ case ' ': /* erase continuation newlines */ case '\t': memmove (x,v,strlen (v)); break; case 'f': /* continuation but with extra "From:" */ case 'F': if (v = strchr (v,':')) { memmove (x,v+1,strlen (v+1)); break; } default: /* tie off extraneous text */ *x = x[1] = '\0'; } if (adr = rfc822_parse_address (&adr,adr,&t,BADHOST,0)) { s->from = adr->mailbox; adr->mailbox = NIL; mail_free_address (&adr); } } if (!s->from) s->from = cpystr (""); s->dirty = T; } break; case SORTTO: /* sort by first to */ if (!s->to) { if (env) s->to = env->to && env->to->mailbox ? cpystr (env->to->mailbox) : NIL; else if ((t = mail_fetch_header (stream,i,NIL,&mailtonline,NIL, FT_INTERNAL | FT_PEEK)) && (t = strchr (t,':'))) { for (x = ++t; x = strpbrk (x,"\012\015"); x++) switch (*(v = ((*x == '\015') && (x[1] == '\012')) ? x+2 : x+1)){ case ' ': /* erase continuation newlines */ case '\t': memmove (x,v,strlen (v)); break; case 't': /* continuation but with extra "To:" */ case 'T': if (v = strchr (v,':')) { memmove (x,v+1,strlen (v+1)); break; } default: /* tie off extraneous text */ *x = x[1] = '\0'; } if (adr = rfc822_parse_address (&adr,adr,&t,BADHOST,0)) { s->to = adr->mailbox; adr->mailbox = NIL; mail_free_address (&adr); } } if (!s->to) s->to = cpystr (""); s->dirty = T; } break; case SORTCC: /* sort by first cc */ if (!s->cc) { if (env) s->cc = env->cc && env->cc->mailbox ? cpystr (env->cc->mailbox) : NIL; else if ((t = mail_fetch_header (stream,i,NIL,&mailccline,NIL, FT_INTERNAL | FT_PEEK)) && (t = strchr (t,':'))) { for (x = ++t; x = strpbrk (x,"\012\015"); x++) switch (*(v = ((*x == '\015') && (x[1] == '\012')) ? x+2 : x+1)){ case ' ': /* erase continuation newlines */ case '\t': memmove (x,v,strlen (v)); break; case 't': /* continuation but with extra "To:" */ case 'T': if (v = strchr (v,':')) { memmove (x,v+1,strlen (v+1)); break; } default: /* tie off extraneous text */ *x = x[1] = '\0'; } if (adr = rfc822_parse_address (&adr,adr,&t,BADHOST,0)) { s->cc = adr->mailbox; adr->mailbox = NIL; mail_free_address (&adr); } } if (!s->cc) s->cc = cpystr (""); s->dirty = T; } break; case SORTSUBJECT: /* sort by subject */ if (!s->subject) { /* get subject from envelope if have one */ if (env) t = env->subject ? env->subject : ""; /* otherwise snarf from header text */ else if ((t = mail_fetch_header (stream,i,NIL,&mailsubline, NIL,FT_INTERNAL | FT_PEEK)) && (t = strchr (t,':'))) for (x = ++t; x = strpbrk (x,"\012\015"); x++) switch (*(v = ((*x == '\015') && (x[1] == '\012')) ? x+2 : x+1)){ case ' ': /* erase continuation newlines */ case '\t': memmove (x,v,strlen (v)); break; default: /* tie off extraneous text */ *x = x[1] = '\0'; } else t = ""; /* empty subject */ /* strip and cache subject */ s->refwd = mail_strip_subject (t,&s->subject); s->dirty = T; } break; default: fatal ("Unknown sort function"); } } return sc; } /* Strip subjects of extra spaces and leading and trailing cruft for sorting * Accepts: unstripped subject * pointer to return stripped subject, in cpystr form * Returns: T if subject had a re/fwd, NIL otherwise */ unsigned int mail_strip_subject (char *t,char **ret) { SIZEDTEXT src,dst; unsigned long i,slen; char c,*s,*x; unsigned int refwd = NIL; if (src.size = strlen (t)) { /* have non-empty subject? */ src.data = (unsigned char *) t; /* Step 1 */ /* make copy, convert MIME2 if needed */ *ret = s = (utf8_mime2text (&src,&dst,U8T_CANONICAL) && (src.data != dst.data)) ? (char *) dst.data : cpystr (t); /* convert spaces to tab, strip extra spaces */ for (x = t = s, c = 'x'; *t; t++) { if (c != ' ') c = *x++ = ((*t == '\t') ? ' ' : *t); else if ((*t != '\t') && (*t != ' ')) c = *x++ = *t; } *x = '\0'; /* tie off string */ /* Step 2 */ for (slen = dst.size; s; slen = strlen (s)) { for (t = s + slen; t > s; ) switch (t[-1]) { case ' ': case '\t': /* WSP */ *--t = '\0'; /* just remove it */ break; case ')': /* possible "(fwd)" */ if ((t >= (s + 5)) && (t[-5] == '(') && ((t[-4] == 'F') || (t[-4] == 'f')) && ((t[-3] == 'W') || (t[-3] == 'w')) && ((t[-2] == 'D') || (t[-2] == 'd'))) { *(t -= 5) = '\0'; /* remove "(fwd)" */ refwd = T; /* note a re/fwd */ break; } default: /* not a subj-trailer */ t = s; break; } /* Steps 3-5 */ for (t = s; t; ) switch (*s) { case ' ': case '\t': /* WSP */ s = t = mail_strip_subject_wsp (s + 1); break; case 'r': case 'R': /* possible "re" */ if (((s[1] == 'E') || (s[1] == 'e')) && (t = mail_strip_subject_wsp (s + 2)) && (t = mail_strip_subject_blob (t)) && (*t == ':')) { s = ++t; /* found "re" */ refwd = T; /* definitely a re/fwd at this point */ } else t = NIL; /* found subj-middle */ break; case 'f': case 'F': /* possible "fw" or "fwd" */ if (((s[1] == 'w') || (s[1] == 'W')) && (((s[2] == 'd') || (s[2] == 'D')) ? (t = mail_strip_subject_wsp (s + 3)) : (t = mail_strip_subject_wsp (s + 2))) && (t = mail_strip_subject_blob (t)) && (*t == ':')) { s = ++t; /* found "fwd" */ refwd = T; /* definitely a re/fwd at this point */ } else t = NIL; /* found subj-middle */ break; case '[': /* possible subj-blob */ if ((t = mail_strip_subject_blob (s)) && *t) s = t; else t = NIL; /* found subj-middle */ break; default: t = NIL; /* found subj-middle */ break; } /* Step 6 */ /* Netscape-style "[Fwd: ...]"? */ if ((*s == '[') && ((s[1] == 'F') || (s[1] == 'f')) && ((s[2] == 'W') || (s[2] == 'w')) && ((s[3] == 'D') || (s[3] == 'd')) && (s[4] == ':') && (s[i = strlen (s) - 1] == ']')) { s[i] = '\0'; /* flush closing "]" */ s += 5; /* and leading "[Fwd:" */ refwd = T; /* definitely a re/fwd at this point */ } else break; /* don't need to loop back to step 2 */ } if (s != (t = *ret)) { /* removed leading text? */ s = *ret = cpystr (s); /* yes, make a fresh return copy */ fs_give ((void **) &t); /* flush old copy */ } } else *ret = cpystr (""); /* empty subject */ return refwd; /* return re/fwd state */ } /* Strip subject wsp helper routine * Accepts: text * Returns: pointer to text after blob */ char *mail_strip_subject_wsp (char *s) { while ((*s == ' ') || (*s == '\t')) s++; return s; } /* Strip subject blob helper routine * Accepts: text * Returns: pointer to text after any blob, NIL if blob-like but not blob */ char *mail_strip_subject_blob (char *s) { if (*s != '[') return s; /* not a blob, ignore */ /* search for end of blob */ while (*++s != ']') if ((*s == '[') || !*s) return NIL; return mail_strip_subject_wsp (s + 1); } /* Sort compare messages * Accept: first message sort cache element * second message sort cache element * Returns: -1 if a1 < a2, 0 if a1 == a2, 1 if a1 > a2 */ int mail_sort_compare (const void *a1,const void *a2) { int i = 0; SORTCACHE *s1 = *(SORTCACHE **) a1; SORTCACHE *s2 = *(SORTCACHE **) a2; SORTPGM *pgm = s1->pgm; if (!s1->sorted) { /* this one sorted yet? */ s1->sorted = T; pgm->progress.sorted++; /* another sorted message */ } if (!s2->sorted) { /* this one sorted yet? */ s2->sorted = T; pgm->progress.sorted++; /* another sorted message */ } do { switch (pgm->function) { /* execute search program */ case SORTDATE: /* sort by date */ i = compare_ulong (s1->date,s2->date); break; case SORTARRIVAL: /* sort by arrival date */ i = compare_ulong (s1->arrival,s2->arrival); break; case SORTSIZE: /* sort by message size */ i = compare_ulong (s1->size,s2->size); break; case SORTFROM: /* sort by first from */ i = compare_cstring (s1->from,s2->from); break; case SORTTO: /* sort by first to */ i = compare_cstring (s1->to,s2->to); break; case SORTCC: /* sort by first cc */ i = compare_cstring (s1->cc,s2->cc); break; case SORTSUBJECT: /* sort by subject */ i = compare_cstring (s1->subject,s2->subject); break; } if (pgm->reverse) i = -i; /* flip results if necessary */ } while (pgm = i ? NIL : pgm->next); /* return result, avoid 0 if at all possible */ return i ? i : compare_ulong (s1->num,s2->num); } /* Return message date as an unsigned long seconds since time began * Accepts: message cache pointer * Returns: unsigned long of date * * This routine, like most UNIX systems, is clueless about leap seconds. * Thus, it treats 23:59:60 as equivalent to 00:00:00 the next day. * * This routine forces any early hours on 1-Jan-1970 in oriental timezones * to be 1-Jan-1970 00:00:00 UTC, so as to avoid negative longdates. */ unsigned long mail_longdate (MESSAGECACHE *elt) { unsigned long m = elt->month ? elt->month : 1; unsigned long yr = elt->year + BASEYEAR; /* number of days since time began */ unsigned long ret = (elt->day ? (elt->day - 1) : 0) + 30 * (m - 1) + ((m + (m > 8)) / 2) #ifndef USEJULIANCALENDAR #ifndef USEORTHODOXCALENDAR /* Gregorian calendar */ + ((yr / 400) - (BASEYEAR / 400)) - ((yr / 100) - (BASEYEAR / 100)) #ifdef Y4KBUGFIX - ((yr / 4000) - (BASEYEAR / 4000)) #endif - ((m < 3) ? !(yr % 4) && ((yr % 100) || (!(yr % 400) #ifdef Y4KBUGFIX && (yr % 4000) #endif )) : 2) #else /* Orthodox calendar */ + ((2*(yr / 900)) - (2*(BASEYEAR / 900))) + (((yr % 900) >= 200) - ((BASEYEAR % 900) >= 200)) + (((yr % 900) >= 600) - ((BASEYEAR % 900) >= 600)) - ((yr / 100) - (BASEYEAR / 100)) - ((m < 3) ? !(yr % 4) && ((yr % 100) || ((yr % 900) == 200) || ((yr % 900) == 600)) : 2) #endif #endif + elt->year * 365 + (((unsigned long) (elt->year + (BASEYEAR % 4))) / 4); ret *= 24; ret += elt->hours; /* date value in hours */ ret *= 60; ret +=elt->minutes;/* date value in minutes */ yr = (elt->zhours * 60) + elt->zminutes; if (elt->zoccident) ret += yr;/* occidental timezone, make UTC */ else if (ret < yr) return 0; /* still 31-Dec-1969 in UTC */ else ret -= yr; /* oriental timezone, make UTC */ ret *= 60; ret += elt->seconds; return ret; } /* Mail thread messages * Accepts: mail stream * thread type * character set * search program * option flags * Returns: thread node tree or NIL if error */ THREADNODE *mail_thread (MAILSTREAM *stream,char *type,char *charset, SEARCHPGM *spg,long flags) { THREADNODE *ret = NIL; if (stream->dtb) /* must have a live driver */ ret = stream->dtb->thread ? /* do driver's action if available */ (*stream->dtb->thread) (stream,type,charset,spg,flags) : mail_thread_msgs (stream,type,charset,spg,flags,mail_sort_msgs); /* flush search/sort programs if requested */ if (spg && (flags & SE_FREE)) mail_free_searchpgm (&spg); return ret; } /* Mail thread messages * Accepts: mail stream * thread type * character set * search program * option flags * sorter routine * Returns: thread node tree or NIL if error */ THREADNODE *mail_thread_msgs (MAILSTREAM *stream,char *type,char *charset, SEARCHPGM *spg,long flags,sorter_t sorter) { THREADER *t; for (t = &mailthreadlist; t; t = t->next) if (!compare_cstring (type,t->name)) { THREADNODE *ret = (*t->dispatch) (stream,charset,spg,flags,sorter); if (mailthreadresults) (*mailthreadresults) (stream,ret); return ret; } MM_LOG ("No such thread type",ERROR); return NIL; } /* Mail thread ordered subject * Accepts: mail stream * character set * search program * option flags * sorter routine * Returns: thread node tree */ THREADNODE *mail_thread_orderedsubject (MAILSTREAM *stream,char *charset, SEARCHPGM *spg,long flags, sorter_t sorter) { THREADNODE *thr = NIL; THREADNODE *cur,*top,**tc; SORTPGM pgm,pgm2; SORTCACHE *s; unsigned long i,j,*lst,*ls; /* sort by subject+date */ memset (&pgm,0,sizeof (SORTPGM)); memset (&pgm2,0,sizeof (SORTPGM)); pgm.function = SORTSUBJECT; pgm.next = &pgm2; pgm2.function = SORTDATE; if (lst = (*sorter) (stream,charset,spg,&pgm,flags & ~(SE_FREE | SE_UID))){ if (*(ls = lst)) { /* create thread */ /* note first subject */ cur = top = thr = mail_newthreadnode ((SORTCACHE *) (*mailcache) (stream,*ls++,CH_SORTCACHE)); /* note its number */ cur->num = (flags & SE_UID) ? mail_uid (stream,*lst) : *lst; i = 1; /* number of threads */ while (*ls) { /* build tree */ /* subjects match? */ s = (SORTCACHE *) (*mailcache) (stream,*ls++,CH_SORTCACHE); if (compare_cstring (top->sc->subject,s->subject)) { i++; /* have a new thread */ top = top->branch = cur = mail_newthreadnode (s); } /* start a child of the top */ else if (cur == top) cur = cur->next = mail_newthreadnode (s); /* sibling of child */ else cur = cur->branch = mail_newthreadnode (s); /* set to msgno or UID as needed */ cur->num = (flags & SE_UID) ? mail_uid (stream,s->num) : s->num; } /* make threadnode cache */ tc = (THREADNODE **) fs_get (i * sizeof (THREADNODE *)); /* load threadnode cache */ for (j = 0, cur = thr; cur; cur = cur->branch) tc[j++] = cur; if (i != j) fatal ("Threadnode cache confusion"); qsort ((void *) tc,i,sizeof (THREADNODE *),mail_thread_compare_date); for (j = 0, --i; j < i; j++) tc[j]->branch = tc[j+1]; tc[j]->branch = NIL; /* end of root */ thr = tc[0]; /* head of data */ fs_give ((void **) &tc); } fs_give ((void **) &lst); } return thr; } /* Mail thread references * Accepts: mail stream * character set * search program * option flags * sorter routine * Returns: thread node tree */ #define REFHASHSIZE 1009 /* arbitrary prime for hash table size */ /* Reference threading container, as described in Jamie Zawinski's web page * (http://www.jwz.org/doc/threading.html) for this algorithm. These are * stored as extended data in the hash table (called "id_table" in JWZ's * document) and are maintained by the hash table routines. The hash table * routines implement extended data as additional void* words at the end of * each bucket, hence these strange macros instead of a struct which would * have been more straightforward. */ #define THREADLINKS 3 /* number of thread links */ #define CACHE(data) ((SORTCACHE *) (data)[0]) #define PARENT(data) ((container_t) (data)[1]) #define SETPARENT(data,value) ((container_t) (data[1] = value)) #define SIBLING(data) ((container_t) (data)[2]) #define SETSIBLING(data,value) ((container_t) (data[2] = value)) #define CHILD(data) ((container_t) (data)[3]) #define SETCHILD(data,value) ((container_t) (data[3] = value)) THREADNODE *mail_thread_references (MAILSTREAM *stream,char *charset, SEARCHPGM *spg,long flags,sorter_t sorter) { MESSAGECACHE *elt,telt; ENVELOPE *env; SORTCACHE *s; STRINGLIST *st; HASHENT *he; THREADNODE **tc,*cur,*lst,*nxt,*sis,*msg; container_t con,nxc,prc,sib; void **sub; char *t,tmp[MAILTMPLEN]; unsigned long j,nmsgs; unsigned long i = stream->nmsgs * sizeof (SORTCACHE *); SORTCACHE **sc = (SORTCACHE **) memset (fs_get ((size_t) i),0,(size_t) i); HASHTAB *ht = hash_create (REFHASHSIZE); THREADNODE *root = NIL; if (spg) { /* only if a search needs to be done */ int silent = stream->silent; stream->silent = T; /* don't pass up mm_searched() events */ /* search for messages */ mail_search_full (stream,charset,spg,NIL); stream->silent = silent; /* restore silence state */ } /* create SORTCACHE vector of requested msgs */ for (i = 1, nmsgs = 0; i <= stream->nmsgs; ++i) if (mail_elt (stream,i)->searched) (sc[nmsgs++] = (SORTCACHE *)(*mailcache)(stream,i,CH_SORTCACHE))->num =i; /* separate pass so can do overview fetch lookahead */ for (i = 0; i < nmsgs; ++i) { /* for each requested message */ /* is anything missing in its SORTCACHE? */ if (!((s = sc[i])->date && s->subject && s->message_id && s->references)) { /* driver has an overview mechanism? */ if (stream->dtb && stream->dtb->overview) { /* yes, find following unloaded entries */ for (j = i + 1; (j < nmsgs) && !sc[j]->references; ++j); sprintf (tmp,"%lu",mail_uid (stream,s->num)); if (i != --j) /* end of range different? */ sprintf (tmp + strlen (tmp),":%lu",mail_uid (stream,sc[j]->num)); /* load via overview mechanism */ mail_fetch_overview (stream,tmp,mail_thread_loadcache); } /* still missing data? */ if (!s->date || !s->subject || !s->message_id || !s->references) { /* try to load data from envelope */ if (env = mail_fetch_structure (stream,s->num,NIL,NIL)) { if (!s->date && env->date && mail_parse_date (&telt,env->date)) s->date = mail_longdate (&telt); if (!s->subject && env->subject) s->refwd = mail_strip_subject (env->subject,&s->subject); if (!s->message_id && env->message_id && *env->message_id) s->message_id = mail_thread_parse_msgid (env->message_id,NIL); if (!s->references && /* use References: or In-Reply-To: */ !(s->references = mail_thread_parse_references (env->references,T))) s->references = mail_thread_parse_references(env->in_reply_to,NIL); } /* last resort */ if (!s->date && !(s->date = s->arrival)) { /* internal date unknown but can get? */ if (!(elt = mail_elt (stream,s->num))->day && !(stream->dtb->flags & DR_NOINTDATE)) { sprintf (tmp,"%lu",s->num); mail_fetch_fast (stream,tmp,NIL); } /* wrong thing before 3-Jan-1970 */ s->date = (s->arrival = elt->day ? mail_longdate (elt) : 1); } if (!s->subject) s->subject = cpystr (""); if (!s->references) s->references = mail_newstringlist (); s->dirty = T; } } /* Step 1 (preliminary) */ /* generate unique string */ sprintf (tmp,"%s.%lx.%lx@%s",stream->mailbox,stream->uid_validity, mail_uid (stream,s->num),mylocalhost ()); /* flush old unique string if not message-id */ if (s->unique && (s->unique != s->message_id)) fs_give ((void **) &s->unique); s->unique = s->message_id ? /* don't permit Message ID duplicates */ (hash_lookup (ht,s->message_id) ? cpystr (tmp) : s->message_id) : (s->message_id = cpystr (tmp)); /* add unique string to hash table */ hash_add (ht,s->unique,s,THREADLINKS); } /* Step 1 */ for (i = 0; i < nmsgs; ++i) { /* for each message in sortcache */ /* Step 1A */ if ((st = (s = sc[i])->references) && st->text.data) for (con = hash_lookup_and_add (ht,(char *) st->text.data,NIL, THREADLINKS); st = st->next; con = nxc) { nxc = hash_lookup_and_add (ht,(char *) st->text.data,NIL,THREADLINKS); /* only if no parent & won't introduce loop */ if (!PARENT (nxc) && !mail_thread_check_child (con,nxc)) { SETPARENT (nxc,con); /* establish parent/child link */ /* other children become sibling of this one */ SETSIBLING (nxc,CHILD (con)); SETCHILD (con,nxc); /* set as child of parent */ } } else con = NIL; /* else message has no ancestors */ /* Step 1B */ if ((prc = PARENT ((nxc = hash_lookup (ht,s->unique)))) && (prc != con)) { /* break links if have a different parent */ SETPARENT (nxc,NIL); /* easy if direct child */ if (nxc == CHILD (prc)) SETCHILD (prc,SIBLING (nxc)); else { /* otherwise hunt through sisters */ for (sib = CHILD (prc); nxc != SIBLING (sib); sib = SIBLING (sib)); SETSIBLING (sib,SIBLING (nxc)); } SETSIBLING (nxc,NIL); /* no more little sisters either */ prc = NIL; /* no more parent set */ } /* need to set parent, and parent is good? */ if (!prc && !mail_thread_check_child (con,nxc)) { SETPARENT (nxc,con); /* establish parent/child link */ if (con) { /* if non-root parent, set parent's child */ if (CHILD (con)) { /* have a child already */ /* find youngest daughter */ for (con = CHILD (con); SIBLING (con); con = SIBLING (con)); SETSIBLING (con,nxc); /* add new baby sister */ } else SETCHILD (con,nxc);/* set as only child */ } } } fs_give ((void **) &sc); /* finished with sortcache vector */ /* Step 2 */ /* search hash table for parentless messages */ for (i = 0, prc = con = NIL; i < ht->size; i++) for (he = ht->table[i]; he; he = he->next) if (!PARENT ((nxc = he->data))) { /* sibling of previous parentless message */ if (con) con = SETSIBLING (con,nxc); else prc = con = nxc; /* first parentless message */ } /* Once the dummy containers are pruned, we no longer need the parent * information, so we can convert the containers to THREADNODEs. Since * we don't need the id_table any more either, we can reset the hash table * and reuse it as a subject_table. Resetting the hash table will also * destroy the containers. */ /* Step 3 */ /* prune dummies, convert to threadnode */ root = mail_thread_c2node (stream,mail_thread_prune_dummy (prc,NIL),flags); /* Step 4 */ /* make buffer for sorting */ tc = (THREADNODE **) fs_get (nmsgs * sizeof (THREADNODE *)); /* load threadcache and count nodes to sort */ for (i = 0, cur = root; cur ; cur = cur->branch) tc[i++] = cur; if (i > 1) { /* only if need to sort */ qsort ((void *) tc,i,sizeof (THREADNODE *),mail_thread_compare_date); /* relink siblings */ for (j = 0, --i; j < i; j++) tc[j]->branch = tc[j+1]; tc[j]->branch = NIL; /* end of root */ root = tc[0]; /* establish new root */ } /* Step 5A */ hash_reset (ht); /* discard containers, reset ht */ /* Step 5B */ for (cur = root; cur; cur = cur->branch) if ((t = (nxt = (cur->sc ? cur : cur->next))->sc->subject) && *t) { /* add new subject to hash table */ if (!(sub = hash_lookup (ht,t))) hash_add (ht,t,cur,0); /* if one in table not dummy and */ else if ((s = (lst = (THREADNODE *) sub[0])->sc) && /* current dummy, or not re/fwd and table is */ (!cur->sc || (!nxt->sc->refwd && s->refwd))) sub[0] = (void *) cur; /* replace with this message */ } /* Step 5C */ for (cur = root, sis = NIL; cur; cur = msg) { /* do nothing if current message or no sub */ if (!(t = (cur->sc ? cur : cur->next)->sc->subject) || !*t || ((lst = (THREADNODE *) (sub = hash_lookup (ht,t))[0]) == cur)) msg = (sis = cur)->branch; else if (!lst->sc) { /* is message in the table a dummy? */ /* find youngest daughter of msg in table */ for (msg = lst->next; msg->branch; msg = msg->branch); if (!cur->sc) { /* current message a dummy? */ msg->branch = cur->next;/* current's daughter now dummy's youngest */ msg = cur->branch; /* continue scan at younger sister */ /* now delete this node */ cur->branch = cur->next = NIL; mail_free_threadnode (&cur); } else { /* current message not a dummy */ msg->branch = cur; /* append as youngest daughter */ msg = cur->branch; /* continue scan at younger sister */ cur->branch = NIL; /* lose our younger sisters */ } } else { /* no dummies, is current re/fwd, table not? */ if (cur->sc->refwd && !lst->sc->refwd) { if (lst->next) { /* find youngest daughter of msg in table */ for (msg = lst->next; msg->branch; msg = msg->branch); msg->branch = cur; /* append as youngest daughter */ } else lst->next = cur; /* no children, so make the eldest daughter */ } else { /* no re/fwd, create a new dummy */ msg = mail_newthreadnode (NIL); if (lst == root) { /* msg in table is root? */ root = lst->branch; /* younger sister becomes new root */ /* no longer older sister either */ if (lst == sis) sis = NIL; } else { /* find older sister of msg in table */ for (nxt = root; lst != nxt->branch; nxt = nxt->branch); /* remove from older sister */ nxt->branch = lst->branch; } msg->next = lst; /* msg in table becomes child */ lst->branch = cur; /* current now little sister of msg in table */ if (sis) { /* have an elder sister? */ if (sis == lst) /* rescan if lost her */ for (sis = root; cur != sis->branch; sis = sis->branch); sis->branch = msg; /* make dummy younger sister of big sister */ } else root = msg; /* otherwise this is the new root */ sub[0] = sis = msg; /* set new msg in table and new big sister */ } msg = cur->branch; /* continue scan at younger sister */ cur->branch = NIL; /* lose our younger sisters */ } if (sis) sis->branch = msg; /* older sister gets this as younger sister */ else root = msg; /* otherwise this is the new root */ } hash_destroy (&ht); /* finished with hash table */ /* Step 6 */ /* sort threads */ root = mail_thread_sort (root,tc); fs_give ((void **) &tc); /* finished with sort buffer */ return root; /* return sorted list */ } /* Fetch overview callback to load sortcache for threading * Accepts: MAIL stream * UID of this message * overview of this message * msgno of this message */ void mail_thread_loadcache (MAILSTREAM *stream,unsigned long uid,OVERVIEW *ov, unsigned long msgno) { if (msgno && ov) { /* just in case */ MESSAGECACHE telt, *elt; ENVELOPE *env; SORTCACHE *s = (SORTCACHE *) (*mailcache) (stream,msgno,CH_SORTCACHE); if (!s->subject && ov->subject) { s->refwd = mail_strip_subject (ov->subject,&s->subject); s->dirty = T; } if (!s->from && ov->from && ov->from->mailbox) { s->from = cpystr (ov->from->mailbox); s->dirty = T; } if (!s->date && ov->date && mail_parse_date (&telt,ov->date)) { s->date = mail_longdate (&telt); s->dirty = T; } if (!s->message_id && ov->message_id) { s->message_id = mail_thread_parse_msgid (ov->message_id,NIL); s->dirty = T; } if (!s->references && !(s->references = mail_thread_parse_references (ov->references,T)) && stream->dtb && !strcmp(stream->dtb->name, "imap") && (elt = mail_elt (stream, msgno)) != NULL && (env = elt->private.msg.env) != NULL && env->in_reply_to && !(s->references = mail_thread_parse_references(env->in_reply_to, NIL))) { /* don't do In-Reply-To with NNTP mailboxes */ s->references = mail_newstringlist (); s->dirty = T; } if (!s->size && ov->optional.octets) { s->size = ov->optional.octets; s->dirty = T; } } } /* Thread parse Message ID * Accepts: pointer to purported Message ID * pointer to return pointer * Returns: Message ID or NIL, return pointer updated */ char *mail_thread_parse_msgid (char *s,char **ss) { char *ret = NIL; char *t = NIL; ADDRESS *adr; if (s) { /* only for non-NIL strings */ rfc822_skipws (&s); /* skip whitespace */ /* ignore phrases */ if (((*s == '<') || (s = rfc822_parse_phrase (s))) && (adr = rfc822_parse_routeaddr (s,&t,BADHOST))) { /* make return msgid */ if (adr->mailbox && adr->host) sprintf (ret = (char *) fs_get (strlen (adr->mailbox) + strlen (adr->host) + 2),"%s@%s", adr->mailbox,adr->host); mail_free_address (&adr); /* don't need temporary address */ } } if (ss) *ss = t; /* update return pointer */ return ret; } /* Thread parse references * Accepts: pointer to purported references * parse multiple references flag * Returns: references or NIL */ STRINGLIST *mail_thread_parse_references (char *s,long flag) { char *t; STRINGLIST *ret = NIL; STRINGLIST *cur; /* found first reference? */ if (t = mail_thread_parse_msgid (s,&s)) { (ret = mail_newstringlist ())->text.data = (unsigned char *) t; ret->text.size = strlen (t); if (flag) /* parse subsequent references */ for (cur = ret; t = mail_thread_parse_msgid (s,&s); cur = cur->next) { (cur->next = mail_newstringlist ())->text.data = (unsigned char *) t; cur->next->text.size = strlen (t); } } return ret; } /* Prune dummy messages * Accepts: candidate container to prune * older sibling of container, if any * Returns: container in this position, possibly pruned * All children and younger siblings are also pruned */ container_t mail_thread_prune_dummy (container_t msg,container_t ane) { /* prune container and children */ container_t ret = msg ? mail_thread_prune_dummy_work (msg,ane) : NIL; /* prune all younger sisters */ if (ret) for (ane = ret; ane && (msg = SIBLING (ane)); ane = msg) msg = mail_thread_prune_dummy_work (msg,ane); return ret; } /* Prune dummy messages worker routine * Accepts: candidate container to prune * older sibling of container, if any * Returns: container in this position, possibly pruned * All children are also pruned */ container_t mail_thread_prune_dummy_work (container_t msg,container_t ane) { container_t cur; /* get children, if any */ container_t nxt = mail_thread_prune_dummy (CHILD (msg),NIL); /* just update children if container has msg */ if (CACHE (msg)) SETCHILD (msg,nxt); else if (!nxt) { /* delete dummy with no children */ nxt = SIBLING (msg); /* get younger sister */ if (ane) SETSIBLING (ane,nxt); /* prune younger sister if exists */ msg = nxt ? mail_thread_prune_dummy_work (nxt,ane) : NIL; } /* not if parent root & multiple children */ else if ((cur = PARENT (msg)) || !SIBLING (nxt)) { /* OK to promote, try younger sister of aunt */ if (ane) SETSIBLING (ane,nxt); /* otherwise promote to child of grandmother */ else if (cur) SETCHILD (cur,nxt); SETPARENT (nxt,cur); /* set parent as well */ /* look for end of siblings in new container */ for (cur = nxt; SIBLING (cur); cur = SIBLING (cur)); /* reattach deleted container's siblings */ SETSIBLING (cur,SIBLING (msg)); /* prune and return new container */ msg = mail_thread_prune_dummy_work (nxt,ane); } else SETCHILD (msg,nxt); /* in case child pruned */ return msg; /* return this message */ } /* Test that purported mother is not a child of purported daughter * Accepts: mother * purported daugher * Returns: T if circular parentage exists, else NIL */ long mail_thread_check_child (container_t mother,container_t daughter) { if (mother) { /* only if mother non-NIL */ if (mother == daughter) return T; for (daughter = CHILD (daughter); daughter; daughter = SIBLING (daughter)) if (mail_thread_check_child (mother,daughter)) return T; } return NIL; } /* Generate threadnodes from containers * Accepts: Mail stream * container * flags * Return: threadnode list */ THREADNODE *mail_thread_c2node (MAILSTREAM *stream,container_t con,long flags) { THREADNODE *ret,*cur; SORTCACHE *s; container_t nxt; /* for each container */ for (ret = cur = NIL; con; con = SIBLING (con)) { s = CACHE (con); /* yes, get its sortcache */ /* create node for it */ if (ret) cur = cur->branch = mail_newthreadnode (s); else ret = cur = mail_newthreadnode (s); /* attach sequence or UID for non-dummy */ if (s) cur->num = (flags & SE_UID) ? mail_uid (stream,s->num) : s->num; /* attach the children */ if (nxt = CHILD (con)) cur->next = mail_thread_c2node (stream,nxt,flags); } return ret; } /* Sort thread tree by date * Accepts: thread tree to sort * qsort vector to sort * Returns: sorted thread tree */ THREADNODE *mail_thread_sort (THREADNODE *thr,THREADNODE **tc) { unsigned long i,j; THREADNODE *cur; /* sort children of each thread */ for (cur = thr; cur; cur = cur->branch) if (cur->next) cur->next = mail_thread_sort (cur->next,tc); /* Must do this in a separate pass since recursive call will clobber tc */ /* load threadcache and count nodes to sort */ for (i = 0, cur = thr; cur; cur = cur->branch) tc[i++] = cur; if (i > 1) { /* only if need to sort */ qsort ((void *) tc,i,sizeof (THREADNODE *),mail_thread_compare_date); /* relink root siblings */ for (j = 0, --i; j < i; j++) tc[j]->branch = tc[j+1]; tc[j]->branch = NIL; /* end of root */ } return i ? tc[0] : NIL; /* return new head of list */ } /* Thread compare date * Accept: first message sort cache element * second message sort cache element * Returns: -1 if a1 < a2, 1 if a1 > a2 * * This assumes that a sort cache element is either a message (with a * sortcache entry) or a dummy with a message (with sortcache entry) child. * This is true of both the ORDEREDSUBJECT (no dummies) and REFERENCES * (dummies only at top-level, and with non-dummy children). * * If a new algorithm allows a dummy parent to have a dummy child, this * routine must be changed if it is to be used by that algorithm. * * Messages with bogus dates are always sorted at the top. */ int mail_thread_compare_date (const void *a1,const void *a2) { THREADNODE *t1 = *(THREADNODE **) a1; THREADNODE *t2 = *(THREADNODE **) a2; SORTCACHE *s1 = t1->sc ? t1->sc : t1->next->sc; SORTCACHE *s2 = t2->sc ? t2->sc : t2->next->sc; int ret = compare_ulong (s1->date,s2->date); /* use number as final tie-breaker */ return ret ? ret : compare_ulong (s1->num,s2->num); } /* Mail parse sequence * Accepts: mail stream * sequence to parse * Returns: T if parse successful, else NIL */ long mail_sequence (MAILSTREAM *stream,unsigned char *sequence) { unsigned long i,j,x; for (i = 1; i <= stream->nmsgs; i++) mail_elt (stream,i)->sequence = NIL; while (sequence && *sequence){/* while there is something to parse */ if (*sequence == '*') { /* maximum message */ if (stream->nmsgs) i = stream->nmsgs; else { MM_LOG ("No messages, so no maximum message number",ERROR); return NIL; } sequence++; /* skip past * */ } /* parse and validate message number */ else if (!isdigit (*sequence)) { MM_LOG ("Syntax error in sequence",ERROR); return NIL; } else if (!(i = strtoul (sequence,(char **) &sequence,10)) || (i > stream->nmsgs)) { MM_LOG ("Sequence out of range",ERROR); return NIL; } switch (*sequence) { /* see what the delimiter is */ case ':': /* sequence range */ if (*++sequence == '*') { /* maximum message */ if (stream->nmsgs) j = stream->nmsgs; else { MM_LOG ("No messages, so no maximum message number",ERROR); return NIL; } sequence++; /* skip past * */ } /* parse end of range */ else if (!(j = strtoul (sequence,(char **) &sequence,10)) || (j > stream->nmsgs)) { MM_LOG ("Sequence range invalid",ERROR); return NIL; } if (*sequence && *sequence++ != ',') { MM_LOG ("Sequence range syntax error",ERROR); return NIL; } if (i > j) { /* swap the range if backwards */ x = i; i = j; j = x; } /* mark each item in the sequence */ while (i <= j) mail_elt (stream,j--)->sequence = T; break; case ',': /* single message */ ++sequence; /* skip the delimiter, fall into end case */ case '\0': /* end of sequence, mark this message */ mail_elt (stream,i)->sequence = T; break; default: /* anything else is a syntax error! */ MM_LOG ("Sequence syntax error",ERROR); return NIL; } } return T; /* successfully parsed sequence */ } /* Parse flag list * Accepts: MAIL stream * flag list as a character string * pointer to user flags to return * Returns: system flags */ long mail_parse_flags (MAILSTREAM *stream,char *flag,unsigned long *uf) { char *t,*n,*s,tmp[MAILTMPLEN],msg[MAILTMPLEN]; short f = 0; long i,j; *uf = 0; /* initially no user flags */ if (flag && *flag) { /* no-op if no flag string */ /* check if a list and make sure valid */ if (((i = (*flag == '(')) ^ (flag[strlen (flag)-1] == ')')) || (strlen (flag) >= MAILTMPLEN)) { MM_LOG ("Bad flag list",ERROR); return NIL; } /* copy the flag string w/o list construct */ strncpy (n = tmp,flag+i,(j = strlen (flag) - (2*i))); tmp[j] = '\0'; while ((t = n) && *t) { /* parse the flags */ /* find end of flag */ if (n = strchr (t,' ')) *n++ = '\0'; if (*t == '\\') { /* system flag? */ if (!compare_cstring (t+1,"SEEN")) f |= fSEEN; else if (!compare_cstring (t+1,"DELETED")) f |= fDELETED; else if (!compare_cstring (t+1,"FLAGGED")) f |= fFLAGGED; else if (!compare_cstring (t+1,"ANSWERED")) f |= fANSWERED; else if (!compare_cstring (t+1,"DRAFT")) f |= fDRAFT; else { sprintf (msg,"Unsupported system flag: %.80s",t); MM_LOG (msg,WARN); } } else { /* keyword flag */ for (i = j = 0; /* user flag, search through table */ !i && (j < NUSERFLAGS) && (s = stream->user_flags[j]); ++j) if (!compare_cstring (t,s)) *uf |= i = 1 << j; if (!i) { /* flag not found, can it be created? */ if (stream->kwd_create && (j < NUSERFLAGS) && *t && (strlen (t) <= MAXUSERFLAG)) { for (s = t; t && *s; s++) switch (*s) { default: /* all other characters */ /* SPACE, CTL, or not CHAR */ if ((*s > ' ') && (*s < 0x7f)) break; case '*': case '%': /* list_wildcards */ case '"': case '\\':/* quoted-specials */ /* atom_specials */ case '(': case ')': case '{': case ']': /* resp-specials */ sprintf (msg,"Invalid flag: %.80s",t); MM_LOG (msg,WARN); t = NIL; } if (t) { /* only if valid */ *uf |= 1 << j; /* set the bit */ stream->user_flags[j] = cpystr (t); /* if out of user flags */ if (j == NUSERFLAGS - 1) stream->kwd_create = NIL; } } else { if (*t) sprintf (msg,"Unknown flag: %.80s",t); else strcpy (msg,"Empty flag invalid"); MM_LOG (msg,WARN); } } } } } return f; } /* Mail check network stream for usability with new name * Accepts: MAIL stream * candidate new name * Returns: T if stream can be used, NIL otherwise */ long mail_usable_network_stream (MAILSTREAM *stream,char *name) { NETMBX smb,nmb,omb; return (stream && stream->dtb && !(stream->dtb->flags & DR_LOCAL) && mail_valid_net_parse (name,&nmb) && mail_valid_net_parse (stream->mailbox,&smb) && mail_valid_net_parse (stream->original_mailbox,&omb) && ((!compare_cstring (smb.host, trustdns ? tcp_canonical (nmb.host) : nmb.host)&& !strcmp (smb.service,nmb.service) && (!nmb.port || (smb.port == nmb.port)) && (nmb.anoflag == stream->anonymous) && (!nmb.user[0] || !strcmp (smb.user,nmb.user))) || (!compare_cstring (omb.host,nmb.host) && !strcmp (omb.service,nmb.service) && (!nmb.port || (omb.port == nmb.port)) && (nmb.anoflag == stream->anonymous) && (!nmb.user[0] || !strcmp (omb.user,nmb.user))))) ? LONGT : NIL; } /* Mail data structure instantiation routines */ /* Mail instantiate cache elt * Accepts: initial message number * Returns: new cache elt */ MESSAGECACHE *mail_new_cache_elt (unsigned long msgno) { MESSAGECACHE *elt = (MESSAGECACHE *) memset (fs_get (sizeof (MESSAGECACHE)), 0,sizeof (MESSAGECACHE)); elt->lockcount = 1; /* initially only cache references it */ elt->msgno = msgno; /* message number */ return elt; } /* Mail instantiate envelope * Returns: new envelope */ ENVELOPE *mail_newenvelope (void) { return (ENVELOPE *) memset (fs_get (sizeof (ENVELOPE)),0,sizeof (ENVELOPE)); } /* Mail instantiate address * Returns: new address */ ADDRESS *mail_newaddr (void) { return (ADDRESS *) memset (fs_get (sizeof (ADDRESS)),0,sizeof (ADDRESS)); } /* Mail instantiate body * Returns: new body */ BODY *mail_newbody (void) { return mail_initbody ((BODY *) fs_get (sizeof (BODY))); } /* Mail initialize body * Accepts: body * Returns: body */ BODY *mail_initbody (BODY *body) { memset ((void *) body,0,sizeof (BODY)); body->type = TYPETEXT; /* content type */ body->encoding = ENC7BIT; /* content encoding */ return body; } /* Mail instantiate body parameter * Returns: new body part */ PARAMETER *mail_newbody_parameter (void) { return (PARAMETER *) memset (fs_get (sizeof(PARAMETER)),0,sizeof(PARAMETER)); } /* Mail instantiate body part * Returns: new body part */ PART *mail_newbody_part (void) { PART *part = (PART *) memset (fs_get (sizeof (PART)),0,sizeof (PART)); mail_initbody (&part->body); /* initialize the body */ return part; } /* Mail instantiate body message part * Returns: new body message part */ MESSAGE *mail_newmsg (void) { return (MESSAGE *) memset (fs_get (sizeof (MESSAGE)),0,sizeof (MESSAGE)); } /* Mail instantiate string list * Returns: new string list */ STRINGLIST *mail_newstringlist (void) { return (STRINGLIST *) memset (fs_get (sizeof (STRINGLIST)),0, sizeof (STRINGLIST)); } /* Mail instantiate new search program * Returns: new search program */ SEARCHPGM *mail_newsearchpgm (void) { return (SEARCHPGM *) memset (fs_get (sizeof(SEARCHPGM)),0,sizeof(SEARCHPGM)); } /* Mail instantiate new search program * Accepts: header line name * Returns: new search program */ SEARCHHEADER *mail_newsearchheader (char *line,char *text) { SEARCHHEADER *hdr = (SEARCHHEADER *) memset (fs_get (sizeof (SEARCHHEADER)), 0,sizeof (SEARCHHEADER)); hdr->line.size = strlen ((char *) (hdr->line.data = (unsigned char *) cpystr (line))); hdr->text.size = strlen ((char *) (hdr->text.data = (unsigned char *) cpystr (text))); return hdr; } /* Mail instantiate new search set * Returns: new search set */ SEARCHSET *mail_newsearchset (void) { return (SEARCHSET *) memset (fs_get (sizeof(SEARCHSET)),0,sizeof(SEARCHSET)); } /* Mail instantiate new search or * Returns: new search or */ SEARCHOR *mail_newsearchor (void) { SEARCHOR *or = (SEARCHOR *) memset (fs_get (sizeof (SEARCHOR)),0, sizeof (SEARCHOR)); or->first = mail_newsearchpgm (); or->second = mail_newsearchpgm (); return or; } /* Mail instantiate new searchpgmlist * Returns: new searchpgmlist */ SEARCHPGMLIST *mail_newsearchpgmlist (void) { SEARCHPGMLIST *pgl = (SEARCHPGMLIST *) memset (fs_get (sizeof (SEARCHPGMLIST)),0,sizeof (SEARCHPGMLIST)); pgl->pgm = mail_newsearchpgm (); return pgl; } /* Mail instantiate new sortpgm * Returns: new sortpgm */ SORTPGM *mail_newsortpgm (void) { return (SORTPGM *) memset (fs_get (sizeof (SORTPGM)),0,sizeof (SORTPGM)); } /* Mail instantiate new threadnode * Accepts: sort cache for thread node * Returns: new threadnode */ THREADNODE *mail_newthreadnode (SORTCACHE *sc) { THREADNODE *thr = (THREADNODE *) memset (fs_get (sizeof (THREADNODE)),0, sizeof (THREADNODE)); if (sc) thr->sc = sc; /* initialize sortcache */ return thr; } /* Mail instantiate new acllist * Returns: new acllist */ ACLLIST *mail_newacllist (void) { return (ACLLIST *) memset (fs_get (sizeof (ACLLIST)),0,sizeof (ACLLIST)); } /* Mail instantiate new quotalist * Returns: new quotalist */ QUOTALIST *mail_newquotalist (void) { return (QUOTALIST *) memset (fs_get (sizeof (QUOTALIST)),0, sizeof (QUOTALIST)); } /* Mail garbage collection routines */ /* Mail garbage collect body * Accepts: pointer to body pointer */ void mail_free_body (BODY **body) { if (*body) { /* only free if exists */ mail_free_body_data (*body);/* free its data */ fs_give ((void **) body); /* return body to free storage */ } } /* Mail garbage collect body data * Accepts: body pointer */ void mail_free_body_data (BODY *body) { switch (body->type) { /* free contents */ case TYPEMULTIPART: /* multiple part */ mail_free_body_part (&body->nested.part); break; case TYPEMESSAGE: /* encapsulated message */ if (body->subtype && !strcmp (body->subtype,"RFC822")) { mail_free_stringlist (&body->nested.msg->lines); mail_gc_msg (body->nested.msg,GC_ENV | GC_TEXTS); } if (body->nested.msg) fs_give ((void **) &body->nested.msg); break; default: break; } if (body->subtype) fs_give ((void **) &body->subtype); mail_free_body_parameter (&body->parameter); if (body->id) fs_give ((void **) &body->id); if (body->description) fs_give ((void **) &body->description); if (body->disposition.type) fs_give ((void **) &body->disposition.type); if (body->disposition.parameter) mail_free_body_parameter (&body->disposition.parameter); if (body->language) mail_free_stringlist (&body->language); if (body->location) fs_give ((void **) &body->location); if (body->mime.text.data) fs_give ((void **) &body->mime.text.data); if (body->contents.text.data) fs_give ((void **) &body->contents.text.data); if (body->md5) fs_give ((void **) &body->md5); if (mailfreebodysparep && body->sparep) (*mailfreebodysparep) (&body->sparep); } /* Mail garbage collect body parameter * Accepts: pointer to body parameter pointer */ void mail_free_body_parameter (PARAMETER **parameter) { if (*parameter) { /* only free if exists */ if ((*parameter)->attribute) fs_give ((void **) &(*parameter)->attribute); if ((*parameter)->value) fs_give ((void **) &(*parameter)->value); /* run down the list as necessary */ mail_free_body_parameter (&(*parameter)->next); /* return body part to free storage */ fs_give ((void **) parameter); } } /* Mail garbage collect body part * Accepts: pointer to body part pointer */ void mail_free_body_part (PART **part) { if (*part) { /* only free if exists */ mail_free_body_data (&(*part)->body); /* run down the list as necessary */ mail_free_body_part (&(*part)->next); fs_give ((void **) part); /* return body part to free storage */ } } /* Mail garbage collect message cache * Accepts: mail stream * * The message cache is set to NIL when this function finishes. */ void mail_free_cache (MAILSTREAM *stream) { /* do driver specific stuff first */ mail_gc (stream,GC_ELT | GC_ENV | GC_TEXTS); /* flush the cache */ (*mailcache) (stream,(long) 0,CH_INIT); } /* Mail garbage collect cache element * Accepts: pointer to cache element pointer */ void mail_free_elt (MESSAGECACHE **elt) { /* only free if exists and no sharers */ if (*elt && !--(*elt)->lockcount) { mail_gc_msg (&(*elt)->private.msg,GC_ENV | GC_TEXTS); if (mailfreeeltsparep && (*elt)->sparep) (*mailfreeeltsparep) (&(*elt)->sparep); fs_give ((void **) elt); } else *elt = NIL; /* else simply drop pointer */ } /* Mail garbage collect envelope * Accepts: pointer to envelope pointer */ void mail_free_envelope (ENVELOPE **env) { if (*env) { /* only free if exists */ if ((*env)->remail) fs_give ((void **) &(*env)->remail); mail_free_address (&(*env)->return_path); if ((*env)->date) fs_give ((void **) &(*env)->date); mail_free_address (&(*env)->from); mail_free_address (&(*env)->sender); mail_free_address (&(*env)->reply_to); if ((*env)->subject) fs_give ((void **) &(*env)->subject); mail_free_address (&(*env)->to); mail_free_address (&(*env)->cc); mail_free_address (&(*env)->bcc); if ((*env)->in_reply_to) fs_give ((void **) &(*env)->in_reply_to); if ((*env)->message_id) fs_give ((void **) &(*env)->message_id); if ((*env)->newsgroups) fs_give ((void **) &(*env)->newsgroups); if ((*env)->followup_to) fs_give ((void **) &(*env)->followup_to); if ((*env)->references) fs_give ((void **) &(*env)->references); if (mailfreeenvelopesparep && (*env)->sparep) (*mailfreeenvelopesparep) (&(*env)->sparep); fs_give ((void **) env); /* return envelope to free storage */ } } /* Mail garbage collect address * Accepts: pointer to address pointer */ void mail_free_address (ADDRESS **address) { if (*address) { /* only free if exists */ if ((*address)->personal) fs_give ((void **) &(*address)->personal); if ((*address)->adl) fs_give ((void **) &(*address)->adl); if ((*address)->mailbox) fs_give ((void **) &(*address)->mailbox); if ((*address)->host) fs_give ((void **) &(*address)->host); if ((*address)->error) fs_give ((void **) &(*address)->error); if ((*address)->orcpt.type) fs_give ((void **) &(*address)->orcpt.type); if ((*address)->orcpt.addr) fs_give ((void **) &(*address)->orcpt.addr); mail_free_address (&(*address)->next); fs_give ((void **) address);/* return address to free storage */ } } /* Mail garbage collect stringlist * Accepts: pointer to stringlist pointer */ void mail_free_stringlist (STRINGLIST **string) { if (*string) { /* only free if exists */ if ((*string)->text.data) fs_give ((void **) &(*string)->text.data); mail_free_stringlist (&(*string)->next); fs_give ((void **) string); /* return string to free storage */ } } /* Mail garbage collect searchpgm * Accepts: pointer to searchpgm pointer */ void mail_free_searchpgm (SEARCHPGM **pgm) { if (*pgm) { /* only free if exists */ mail_free_searchset (&(*pgm)->msgno); mail_free_searchset (&(*pgm)->uid); mail_free_searchor (&(*pgm)->or); mail_free_searchpgmlist (&(*pgm)->not); mail_free_searchheader (&(*pgm)->header); mail_free_stringlist (&(*pgm)->bcc); mail_free_stringlist (&(*pgm)->body); mail_free_stringlist (&(*pgm)->cc); mail_free_stringlist (&(*pgm)->from); mail_free_stringlist (&(*pgm)->keyword); mail_free_stringlist (&(*pgm)->subject); mail_free_stringlist (&(*pgm)->text); mail_free_stringlist (&(*pgm)->to); fs_give ((void **) pgm); /* return program to free storage */ } } /* Mail garbage collect searchheader * Accepts: pointer to searchheader pointer */ void mail_free_searchheader (SEARCHHEADER **hdr) { if (*hdr) { /* only free if exists */ if ((*hdr)->line.data) fs_give ((void **) &(*hdr)->line.data); if ((*hdr)->text.data) fs_give ((void **) &(*hdr)->text.data); mail_free_searchheader (&(*hdr)->next); fs_give ((void **) hdr); /* return header to free storage */ } } /* Mail garbage collect searchset * Accepts: pointer to searchset pointer */ void mail_free_searchset (SEARCHSET **set) { if (*set) { /* only free if exists */ mail_free_searchset (&(*set)->next); fs_give ((void **) set); /* return set to free storage */ } } /* Mail garbage collect searchor * Accepts: pointer to searchor pointer */ void mail_free_searchor (SEARCHOR **orl) { if (*orl) { /* only free if exists */ mail_free_searchpgm (&(*orl)->first); mail_free_searchpgm (&(*orl)->second); mail_free_searchor (&(*orl)->next); fs_give ((void **) orl); /* return searchor to free storage */ } } /* Mail garbage collect search program list * Accepts: pointer to searchpgmlist pointer */ void mail_free_searchpgmlist (SEARCHPGMLIST **pgl) { if (*pgl) { /* only free if exists */ mail_free_searchpgm (&(*pgl)->pgm); mail_free_searchpgmlist (&(*pgl)->next); fs_give ((void **) pgl); /* return searchpgmlist to free storage */ } } /* Mail garbage collect namespace * Accepts: poiner to namespace */ void mail_free_namespace (NAMESPACE **n) { if (*n) { fs_give ((void **) &(*n)->name); mail_free_namespace (&(*n)->next); mail_free_body_parameter (&(*n)->param); fs_give ((void **) n); /* return namespace to free storage */ } } /* Mail garbage collect sort program * Accepts: pointer to sortpgm pointer */ void mail_free_sortpgm (SORTPGM **pgm) { if (*pgm) { /* only free if exists */ mail_free_sortpgm (&(*pgm)->next); fs_give ((void **) pgm); /* return sortpgm to free storage */ } } /* Mail garbage collect thread node * Accepts: pointer to threadnode pointer */ void mail_free_threadnode (THREADNODE **thr) { if (*thr) { /* only free if exists */ mail_free_threadnode (&(*thr)->branch); mail_free_threadnode (&(*thr)->next); fs_give ((void **) thr); /* return threadnode to free storage */ } } /* Mail garbage collect acllist * Accepts: pointer to acllist pointer */ void mail_free_acllist (ACLLIST **al) { if (*al) { /* only free if exists */ if ((*al)->identifier) fs_give ((void **) &(*al)->identifier); if ((*al)->rights) fs_give ((void **) &(*al)->rights); mail_free_acllist (&(*al)->next); fs_give ((void **) al); /* return acllist to free storage */ } } /* Mail garbage collect quotalist * Accepts: pointer to quotalist pointer */ void mail_free_quotalist (QUOTALIST **ql) { if (*ql) { /* only free if exists */ if ((*ql)->name) fs_give ((void **) &(*ql)->name); mail_free_quotalist (&(*ql)->next); fs_give ((void **) ql); /* return quotalist to free storage */ } } /* Link authenicator * Accepts: authenticator to add to list */ void auth_link (AUTHENTICATOR *auth) { if (!auth->valid || (*auth->valid) ()) { AUTHENTICATOR **a = &mailauthenticators; while (*a) a = &(*a)->next; /* find end of list of authenticators */ *a = auth; /* put authenticator at the end */ auth->next = NIL; /* this authenticator is the end of the list */ } } /* Authenticate access * Accepts: mechanism name * responder function * argument count * argument vector * Returns: authenticated user name or NIL */ char *mail_auth (char *mechanism,authresponse_t resp,int argc,char *argv[]) { AUTHENTICATOR *auth; for (auth = mailauthenticators; auth; auth = auth->next) if (auth->server && !compare_cstring (auth->name,mechanism)) return (!(auth->flags & AU_DISABLE) && ((auth->flags & AU_SECURE) || !mail_parameters (NIL,GET_DISABLEPLAINTEXT,NIL))) ? (*auth->server) (resp,argc,argv) : NIL; return NIL; /* no authenticator found */ } /* Lookup authenticator index * Accepts: authenticator index * Returns: authenticator, or 0 if not found */ AUTHENTICATOR *mail_lookup_auth (unsigned long i) { AUTHENTICATOR *auth = mailauthenticators; while (auth && --i) auth = auth->next; return auth; } /* Lookup authenticator name * Accepts: authenticator name * required authenticator flags * Returns: index in authenticator chain, or 0 if not found */ unsigned int mail_lookup_auth_name (char *mechanism,long flags) { int i; AUTHENTICATOR *auth; for (i = 1, auth = mailauthenticators; auth; i++, auth = auth->next) if (auth->client && !(flags & ~auth->flags) && !(auth->flags & AU_DISABLE) && !compare_cstring (auth->name,mechanism)) return i; return 0; } /* Standard TCP/IP network driver */ static NETDRIVER tcpdriver = { tcp_open, /* open connection */ tcp_aopen, /* open preauthenticated connection */ tcp_getline, /* get a line */ tcp_getbuffer, /* get a buffer */ tcp_soutr, /* output pushed data */ tcp_sout, /* output string */ tcp_close, /* close connection */ tcp_host, /* return host name */ tcp_remotehost, /* return remote host name */ tcp_port, /* return port number */ tcp_localhost /* return local host name */ }; /* Network open * Accepts: NETMBX specifier to open * default network driver * default port * SSL driver * SSL service name * SSL driver port * Returns: Network stream if success, else NIL */ NETSTREAM *net_open (NETMBX *mb,NETDRIVER *dv,unsigned long port, NETDRIVER *ssld,char *ssls,unsigned long sslp) { NETSTREAM *stream = NIL; char tmp[MAILTMPLEN]; unsigned long flags = mb->novalidate ? NET_NOVALIDATECERT : 0; if (strlen (mb->host) >= NETMAXHOST) { sprintf (tmp,"Invalid host name: %.80s",mb->host); MM_LOG (tmp,ERROR); } /* use designated driver if given */ else if (dv) stream = net_open_work (dv,mb->host,mb->service,port,mb->port, flags); else if (mb->sslflag && ssld) /* use ssl if sslflag lit */ stream = net_open_work (ssld,mb->host,ssls,sslp,mb->port,flags); /* if trysslfirst and can open ssl... */ else if ((mb->trysslflag || trysslfirst) && ssld && (stream = net_open_work (ssld,mb->host,ssls,sslp,mb->port, flags | NET_SILENT | NET_TRYSSL))) { if (net_sout (stream,"",0)) mb->sslflag = T; else { net_close (stream); /* flush fake SSL stream */ stream = NIL; } } /* default to TCP driver */ else stream = net_open_work (&tcpdriver,mb->host,mb->service,port,mb->port, flags); return stream; } /* Network open worker routine * Accepts: network driver * host name * service name to look up port * port number if service name not found * port number to override service name * flags (passed on top of port) * Returns: Network stream if success, else NIL */ NETSTREAM *net_open_work (NETDRIVER *dv,char *host,char *service, unsigned long port,unsigned long portoverride, unsigned long flags) { NETSTREAM *stream = NIL; void *tstream; if (service && (*service == '*')) { flags |= NET_NOOPENTIMEOUT; /* mark that no timeout is desired */ ++service; /* no longer need the no timeout indicator */ } if (portoverride) { /* explicit port number? */ service = NIL; /* yes, override service name */ port = portoverride; /* use that instead of default port */ } if (tstream = (*dv->open) (host,service,port | flags)) { stream = (NETSTREAM *) fs_get (sizeof (NETSTREAM)); stream->stream = tstream; stream->dtb = dv; } return stream; } /* Network authenticated open * Accepts: network driver * NETMBX specifier * service specifier * return user name buffer * Returns: Network stream if success else NIL */ NETSTREAM *net_aopen (NETDRIVER *dv,NETMBX *mb,char *service,char *user) { NETSTREAM *stream = NIL; void *tstream; if (!dv) dv = &tcpdriver; /* default to TCP driver */ if (tstream = (*dv->aopen) (mb,service,user)) { stream = (NETSTREAM *) fs_get (sizeof (NETSTREAM)); stream->stream = tstream; stream->dtb = dv; } return stream; } /* Network receive line * Accepts: Network stream * Returns: text line string or NIL if failure */ char *net_getline (NETSTREAM *stream) { return (*stream->dtb->getline) (stream->stream); } /* Network receive buffer * Accepts: Network stream (must be void * for use as readfn_t) * size in bytes * buffer to read into * Returns: T if success, NIL otherwise */ long net_getbuffer (void *st,unsigned long size,char *buffer) { NETSTREAM *stream = (NETSTREAM *) st; return (*stream->dtb->getbuffer) (stream->stream,size,buffer); } /* Network send null-terminated string * Accepts: Network stream * string pointer * Returns: T if success else NIL */ long net_soutr (NETSTREAM *stream,char *string) { return (*stream->dtb->soutr) (stream->stream,string); } /* Network send string * Accepts: Network stream * string pointer * byte count * Returns: T if success else NIL */ long net_sout (NETSTREAM *stream,char *string,unsigned long size) { return (*stream->dtb->sout) (stream->stream,string,size); } /* Network close * Accepts: Network stream */ void net_close (NETSTREAM *stream) { if (stream->stream) (*stream->dtb->close) (stream->stream); fs_give ((void **) &stream); } /* Network get host name * Accepts: Network stream * Returns: host name for this stream */ char *net_host (NETSTREAM *stream) { return (*stream->dtb->host) (stream->stream); } /* Network get remote host name * Accepts: Network stream * Returns: host name for this stream */ char *net_remotehost (NETSTREAM *stream) { return (*stream->dtb->remotehost) (stream->stream); } /* Network return port for this stream * Accepts: Network stream * Returns: port number for this stream */ unsigned long net_port (NETSTREAM *stream) { return (*stream->dtb->port) (stream->stream); } /* Network get local host name * Accepts: Network stream * Returns: local host name */ char *net_localhost (NETSTREAM *stream) { return (*stream->dtb->localhost) (stream->stream); } alpine-2.10+dfsg/imap/src/c-client/c-client.h0000600000175000017500000000322711512502124022422 0ustar paulproteuspaulproteus/* ======================================================================== * Copyright 1988-2006 University of Washington * * Licensed under the Apache License, Version 2.0 (the "License"); * you may not use this file except in compliance with the License. * You may obtain a copy of the License at * * http://www.apache.org/licenses/LICENSE-2.0 * * * ======================================================================== */ /* * Program: c-client master include for application programs * * Author: Mark Crispin * Networks and Distributed Computing * Computing & Communications * University of Washington * Administration Building, AG-44 * Seattle, WA 98195 * Internet: MRC@CAC.Washington.EDU * * Date: 19 May 2000 * Last Edited: 6 December 2006 */ #ifndef __CCLIENT_H /* nobody should include this twice... */ #define __CCLIENT_H #ifdef __cplusplus /* help out people who use C++ compilers */ extern "C" { /* If you use gcc, you may also have to use -fno-operator-names */ #define private cclientPrivate /* private to c-client */ #define and cclientAnd /* C99 doesn't realize that ISO 646 is dead */ #define or cclientOr #define not cclientNot #endif #include "mail.h" /* primary interfaces */ #include "osdep.h" /* OS-dependent routines */ #include "rfc822.h" /* RFC822 and MIME routines */ #include "smtp.h" /* SMTP sending routines */ #include "nntp.h" /* NNTP sending routines */ #include "utf8.h" /* Unicode and charset routines */ #include "utf8aux.h" /* Unicode auxillary routines */ #include "misc.h" /* miscellaneous utility routines */ #ifdef __cplusplus /* undo the C++ mischief */ #undef private } #endif #endif alpine-2.10+dfsg/imap/src/c-client/auth_pla.c0000600000175000017500000001051311512502124022510 0ustar paulproteuspaulproteus/* ======================================================================== * Copyright 1988-2006 University of Washington * * Licensed under the Apache License, Version 2.0 (the "License"); * you may not use this file except in compliance with the License. * You may obtain a copy of the License at * * http://www.apache.org/licenses/LICENSE-2.0 * * * ======================================================================== */ /* * Program: Plain authenticator * * Author: Mark Crispin * Networks and Distributed Computing * Computing & Communications * University of Washington * Administration Building, AG-44 * Seattle, WA 98195 * Internet: MRC@CAC.Washington.EDU * * Date: 22 September 1998 * Last Edited: 30 August 2006 */ long auth_plain_client (authchallenge_t challenger,authrespond_t responder, char *service,NETMBX *mb,void *stream, unsigned long *trial,char *user); char *auth_plain_server (authresponse_t responder,int argc,char *argv[]); AUTHENTICATOR auth_pla = { AU_AUTHUSER | AU_HIDE, /* allow authuser, hidden */ "PLAIN", /* authenticator name */ NIL, /* always valid */ auth_plain_client, /* client method */ auth_plain_server, /* server method */ NIL /* next authenticator */ }; /* Client authenticator * Accepts: challenger function * responder function * SASL service name * parsed network mailbox structure * stream argument for functions * pointer to current trial count * returned user name * Returns: T if success, NIL otherwise, number of trials incremented if retry */ long auth_plain_client (authchallenge_t challenger,authrespond_t responder, char *service,NETMBX *mb,void *stream, unsigned long *trial,char *user) { char *u,pwd[MAILTMPLEN]; void *challenge; unsigned long clen; long ret = NIL; /* snarl if not SSL/TLS session */ if (!mb->sslflag && !mb->tlsflag) mm_log ("SECURITY PROBLEM: insecure server advertised AUTH=PLAIN",WARN); /* get initial (empty) challenge */ if (challenge = (*challenger) (stream,&clen)) { fs_give ((void **) &challenge); if (clen) { /* abort if challenge non-empty */ mm_log ("Server bug: non-empty initial PLAIN challenge",WARN); (*responder) (stream,NIL,0); ret = LONGT; /* will get a BAD response back */ } pwd[0] = NIL; /* prompt user if empty challenge */ mm_login (mb,user,pwd,*trial); if (!pwd[0]) { /* empty challenge or user requested abort */ (*responder) (stream,NIL,0); *trial = 0; /* cancel subsequent attempts */ ret = LONGT; /* will get a BAD response back */ } else { unsigned long rlen = strlen (mb->authuser) + strlen (user) + strlen (pwd) + 2; char *response = (char *) fs_get (rlen); char *t = response; /* copy authorization id */ if (mb->authuser[0]) for (u = user; *u; *t++ = *u++); *t++ = '\0'; /* delimiting NUL */ /* copy authentication id */ for (u = mb->authuser[0] ? mb->authuser : user; *u; *t++ = *u++); *t++ = '\0'; /* delimiting NUL */ /* copy password */ for (u = pwd; *u; *t++ = *u++); /* send credentials */ if ((*responder) (stream,response,rlen)) { if (challenge = (*challenger) (stream,&clen)) fs_give ((void **) &challenge); else { ++*trial; /* can try again if necessary */ ret = LONGT; /* check the authentication */ } } memset (response,0,rlen); /* erase credentials */ fs_give ((void **) &response); } } memset (pwd,0,MAILTMPLEN); /* erase password */ if (!ret) *trial = 65535; /* don't retry if bad protocol */ return ret; } /* Server authenticator * Accepts: responder function * argument count * argument vector * Returns: authenticated user name or NIL */ char *auth_plain_server (authresponse_t responder,int argc,char *argv[]) { char *ret = NIL; char *user,*aid,*pass; unsigned long len; /* get user name */ if (aid = (*responder) ("",0,&len)) { /* note: responders null-terminate */ if ((((unsigned long) ((user = aid + strlen (aid) + 1) - aid)) < len) && (((unsigned long) ((pass = user + strlen (user) + 1) - aid)) < len) && (((unsigned long) ((pass + strlen (pass)) - aid)) == len) && (*aid ? server_login (aid,pass,user,argc,argv) : server_login (user,pass,NIL,argc,argv))) ret = myusername (); fs_give ((void **) &aid); } return ret; } alpine-2.10+dfsg/imap/src/c-client/auth_gss.c0000600000175000017500000003437511512502124022544 0ustar paulproteuspaulproteus/* ======================================================================== * Copyright 1988-2006 University of Washington * * Licensed under the Apache License, Version 2.0 (the "License"); * you may not use this file except in compliance with the License. * You may obtain a copy of the License at * * http://www.apache.org/licenses/LICENSE-2.0 * * * ======================================================================== */ /* * Program: GSSAPI authenticator * * Author: Mark Crispin * Networks and Distributed Computing * Computing & Communications * University of Washington * Administration Building, AG-44 * Seattle, WA 98195 * Internet: MRC@CAC.Washington.EDU * * Date: 12 January 1998 * Last Edited: 30 August 2006 */ long auth_gssapi_valid (void); long auth_gssapi_client (authchallenge_t challenger,authrespond_t responder, char *service,NETMBX *mb,void *stream, unsigned long *trial,char *user); long auth_gssapi_client_work (authchallenge_t challenger,gss_buffer_desc chal, authrespond_t responder,char *service,NETMBX *mb, void *stream,char *user,kinit_t ki); char *auth_gssapi_server (authresponse_t responder,int argc,char *argv[]); AUTHENTICATOR auth_gss = { AU_SECURE | AU_AUTHUSER, /* secure authenticator */ "GSSAPI", /* authenticator name */ auth_gssapi_valid, /* check if valid */ auth_gssapi_client, /* client method */ auth_gssapi_server, /* server method */ NIL /* next authenticator */ }; #define AUTH_GSSAPI_P_NONE 1 #define AUTH_GSSAPI_P_INTEGRITY 2 #define AUTH_GSSAPI_P_PRIVACY 4 #define AUTH_GSSAPI_C_MAXSIZE 8192 #define SERVER_LOG(x,y) syslog (LOG_ALERT,x,y) /* Check if GSSAPI valid on this system * Returns: T if valid, NIL otherwise */ long auth_gssapi_valid (void) { char tmp[MAILTMPLEN]; OM_uint32 smn; gss_buffer_desc buf; gss_name_t name; /* make service name */ sprintf (tmp,"%s@%s",(char *) mail_parameters (NIL,GET_SERVICENAME,NIL), mylocalhost ()); buf.length = strlen (buf.value = tmp); /* see if can build a name */ if (gss_import_name (&smn,&buf,GSS_C_NT_HOSTBASED_SERVICE,&name) != GSS_S_COMPLETE) return NIL; /* remove server method if no keytab */ if (!kerberos_server_valid ()) auth_gss.server = NIL; gss_release_name (&smn,&name);/* finished with name */ return LONGT; } /* Client authenticator * Accepts: challenger function * responder function * SASL service name * parsed network mailbox structure * stream argument for functions * pointer to current trial count * returned user name * Returns: T if success, NIL otherwise, number of trials incremented if retry */ long auth_gssapi_client (authchallenge_t challenger,authrespond_t responder, char *service,NETMBX *mb,void *stream, unsigned long *trial,char *user) { gss_buffer_desc chal; kinit_t ki = (kinit_t) mail_parameters (NIL,GET_KINIT,NIL); long ret = NIL; *trial = 65535; /* never retry */ /* get initial (empty) challenge */ if (chal.value = (*challenger) (stream,(unsigned long *) &chal.length)) { if (chal.length) { /* abort if challenge non-empty */ mm_log ("Server bug: non-empty initial GSSAPI challenge",WARN); (*responder) (stream,NIL,0); ret = LONGT; /* will get a BAD response back */ } else if (mb->authuser[0] && strcmp (mb->authuser,myusername ())) { mm_log ("Can't use Kerberos: invalid /authuser",WARN); (*responder) (stream,NIL,0); ret = LONGT; /* will get a BAD response back */ } else ret = auth_gssapi_client_work (challenger,chal,responder,service,mb, stream,user,ki); } return ret; } /* Client authenticator worker function * Accepts: challenger function * responder function * SASL service name * parsed network mailbox structure * stream argument for functions * returned user name * kinit function pointer if should retry with kinit * Returns: T if success, NIL otherwise */ long auth_gssapi_client_work (authchallenge_t challenger,gss_buffer_desc chal, authrespond_t responder,char *service,NETMBX *mb, void *stream,char *user,kinit_t ki) { char tmp[MAILTMPLEN]; OM_uint32 smj,smn,dsmj,dsmn; OM_uint32 mctx = 0; gss_ctx_id_t ctx = GSS_C_NO_CONTEXT; gss_buffer_desc resp,buf; long i; int conf; gss_qop_t qop; gss_name_t crname = NIL; blocknotify_t bn = (blocknotify_t) mail_parameters (NIL,GET_BLOCKNOTIFY,NIL); void *data; long ret = NIL; sprintf (tmp,"%s@%s",service,mb->host); buf.length = strlen (buf.value = tmp); /* get service name */ if (gss_import_name (&smn,&buf,GSS_C_NT_HOSTBASED_SERVICE,&crname) != GSS_S_COMPLETE) { mm_log ("Can't import Kerberos service name",WARN); (*responder) (stream,NIL,0); } else { data = (*bn) (BLOCK_SENSITIVE,NIL); /* negotiate with KDC */ smj = gss_init_sec_context (&smn,GSS_C_NO_CREDENTIAL,&ctx,crname,NIL, GSS_C_INTEG_FLAG | GSS_C_MUTUAL_FLAG | GSS_C_REPLAY_FLAG,0,GSS_C_NO_CHANNEL_BINDINGS, GSS_C_NO_BUFFER,NIL,&resp,NIL,NIL); (*bn) (BLOCK_NONSENSITIVE,data); /* while continuation needed */ while (smj == GSS_S_CONTINUE_NEEDED) { if (chal.value) fs_give ((void **) &chal.value); /* send response, get next challenge */ i = (*responder) (stream,resp.value,resp.length) && (chal.value = (*challenger) (stream,(unsigned long *) &chal.length)); gss_release_buffer (&smn,&resp); if (i) { /* negotiate continuation with KDC */ data = (*bn) (BLOCK_SENSITIVE,NIL); switch (smj = /* make sure continuation going OK */ gss_init_sec_context (&smn,GSS_C_NO_CREDENTIAL,&ctx, crname,GSS_C_NO_OID,GSS_C_INTEG_FLAG | GSS_C_MUTUAL_FLAG | GSS_C_REPLAY_FLAG,0, GSS_C_NO_CHANNEL_BINDINGS,&chal,NIL, &resp,NIL,NIL)) { case GSS_S_CONTINUE_NEEDED: case GSS_S_COMPLETE: break; default: /* error, don't need context any more */ gss_delete_sec_context (&smn,&ctx,NIL); } (*bn) (BLOCK_NONSENSITIVE,data); } else { /* error in continuation */ mm_log ("Error in negotiating Kerberos continuation",WARN); (*responder) (stream,NIL,0); /* don't need context any more */ gss_delete_sec_context (&smn,&ctx,NIL); break; } } switch (smj) { /* done - deal with final condition */ case GSS_S_COMPLETE: if (chal.value) fs_give ((void **) &chal.value); /* get prot mechanisms and max size */ if ((*responder) (stream,resp.value ? resp.value : "",resp.length) && (chal.value = (*challenger) (stream,(unsigned long *)&chal.length))&& (gss_unwrap (&smn,ctx,&chal,&resp,&conf,&qop) == GSS_S_COMPLETE) && (resp.length >= 4) && (*((char *) resp.value) & AUTH_GSSAPI_P_NONE)){ /* make copy of flags and length */ memcpy (tmp,resp.value,4); gss_release_buffer (&smn,&resp); /* no session protection */ tmp[0] = AUTH_GSSAPI_P_NONE; /* install user name */ strcpy (tmp+4,strcpy (user,mb->user[0] ? mb->user : myusername ())); buf.value = tmp; buf.length = strlen (user) + 4; /* successful negotiation */ switch (smj = gss_wrap (&smn,ctx,NIL,qop,&buf,&conf,&resp)) { case GSS_S_COMPLETE: if ((*responder) (stream,resp.value,resp.length)) ret = T; gss_release_buffer (&smn,&resp); break; default: do switch (dsmj = gss_display_status (&dsmn,smj,GSS_C_GSS_CODE, GSS_C_NO_OID,&mctx,&resp)) { case GSS_S_COMPLETE: mctx = 0; case GSS_S_CONTINUE_NEEDED: sprintf (tmp,"Unknown gss_wrap failure: %s",(char *) resp.value); mm_log (tmp,WARN); gss_release_buffer (&dsmn,&resp); } while (dsmj == GSS_S_CONTINUE_NEEDED); do switch (dsmj = gss_display_status (&dsmn,smn,GSS_C_MECH_CODE, GSS_C_NO_OID,&mctx,&resp)) { case GSS_S_COMPLETE: case GSS_S_CONTINUE_NEEDED: sprintf (tmp,"GSSAPI mechanism status: %s",(char *) resp.value); mm_log (tmp,WARN); gss_release_buffer (&dsmn,&resp); } while (dsmj == GSS_S_CONTINUE_NEEDED); (*responder) (stream,NIL,0); } } /* flush final challenge */ if (chal.value) fs_give ((void **) &chal.value); /* don't need context any more */ gss_delete_sec_context (&smn,&ctx,NIL); break; case GSS_S_CREDENTIALS_EXPIRED: if (chal.value) fs_give ((void **) &chal.value); /* retry if application kinits */ if (ki && (*ki) (mb->host,"Kerberos credentials expired")) ret = auth_gssapi_client_work (challenger,chal,responder,service,mb, stream,user,NIL); else { /* application can't kinit */ sprintf (tmp,"Kerberos credentials expired (try running kinit) for %s", mb->host); mm_log (tmp,WARN); (*responder) (stream,NIL,0); } break; case GSS_S_FAILURE: if (chal.value) fs_give ((void **) &chal.value); do switch (dsmj = gss_display_status (&dsmn,smn,GSS_C_MECH_CODE, GSS_C_NO_OID,&mctx,&resp)) { case GSS_S_COMPLETE: /* end of message, can kinit? */ if (ki && kerberos_try_kinit (smn) && (*ki) (mb->host,(char *) resp.value)) { gss_release_buffer (&dsmn,&resp); ret = auth_gssapi_client_work (challenger,chal,responder,service,mb, stream,user,NIL); break; /* done */ } else (*responder) (stream,NIL,0); case GSS_S_CONTINUE_NEEDED: sprintf (tmp,kerberos_try_kinit (smn) ? "Kerberos error: %.80s (try running kinit) for %.80s" : "GSSAPI failure: %s for %.80s",(char *) resp.value,mb->host); mm_log (tmp,WARN); gss_release_buffer (&dsmn,&resp); } while (dsmj == GSS_S_CONTINUE_NEEDED); break; default: /* miscellaneous errors */ if (chal.value) fs_give ((void **) &chal.value); do switch (dsmj = gss_display_status (&dsmn,smj,GSS_C_GSS_CODE, GSS_C_NO_OID,&mctx,&resp)) { case GSS_S_COMPLETE: mctx = 0; case GSS_S_CONTINUE_NEEDED: sprintf (tmp,"Unknown GSSAPI failure: %s",(char *) resp.value); mm_log (tmp,WARN); gss_release_buffer (&dsmn,&resp); } while (dsmj == GSS_S_CONTINUE_NEEDED); do switch (dsmj = gss_display_status (&dsmn,smn,GSS_C_MECH_CODE, GSS_C_NO_OID,&mctx,&resp)) { case GSS_S_COMPLETE: case GSS_S_CONTINUE_NEEDED: sprintf (tmp,"GSSAPI mechanism status: %s",(char *) resp.value); mm_log (tmp,WARN); gss_release_buffer (&dsmn,&resp); } while (dsmj == GSS_S_CONTINUE_NEEDED); (*responder) (stream,NIL,0); break; } /* finished with credentials name */ if (crname) gss_release_name (&smn,&crname); } return ret; /* return status */ } /* Server authenticator * Accepts: responder function * argument count * argument vector * Returns: authenticated user name or NIL */ char *auth_gssapi_server (authresponse_t responder,int argc,char *argv[]) { char *ret = NIL; char tmp[MAILTMPLEN]; unsigned long maxsize = htonl (AUTH_GSSAPI_C_MAXSIZE); int conf; OM_uint32 smj,smn,dsmj,dsmn,flags; OM_uint32 mctx = 0; gss_name_t crname,name; gss_OID mech; gss_buffer_desc chal,resp,buf; gss_cred_id_t crd; gss_ctx_id_t ctx = GSS_C_NO_CONTEXT; gss_qop_t qop = GSS_C_QOP_DEFAULT; /* make service name */ sprintf (tmp,"%s@%s",(char *) mail_parameters (NIL,GET_SERVICENAME,NIL), tcp_serverhost ()); buf.length = strlen (buf.value = tmp); /* acquire credentials */ if ((gss_import_name (&smn,&buf,GSS_C_NT_HOSTBASED_SERVICE,&crname)) == GSS_S_COMPLETE) { if ((smj = gss_acquire_cred (&smn,crname,0,NIL,GSS_C_ACCEPT,&crd,NIL,NIL)) == GSS_S_COMPLETE) { if (resp.value = (*responder) ("",0,(unsigned long *) &resp.length)) { do { /* negotiate authentication */ smj = gss_accept_sec_context (&smn,&ctx,crd,&resp, GSS_C_NO_CHANNEL_BINDINGS,&name,&mech, &chal,&flags,NIL,NIL); /* don't need response any more */ fs_give ((void **) &resp.value); switch (smj) { /* how did it go? */ case GSS_S_COMPLETE: /* successful */ case GSS_S_CONTINUE_NEEDED: if (chal.value) { /* send challenge, get next response */ resp.value = (*responder) (chal.value,chal.length, (unsigned long *) &resp.length); gss_release_buffer (&smn,&chal); } break; } } while (resp.value && resp.length && (smj == GSS_S_CONTINUE_NEEDED)); /* successful exchange? */ if ((smj == GSS_S_COMPLETE) && (gss_display_name (&smn,name,&buf,&mech) == GSS_S_COMPLETE)) { /* send security and size */ memcpy (resp.value = tmp,(void *) &maxsize,resp.length = 4); tmp[0] = AUTH_GSSAPI_P_NONE; if (gss_wrap (&smn,ctx,NIL,qop,&resp,&conf,&chal) == GSS_S_COMPLETE){ resp.value = (*responder) (chal.value,chal.length, (unsigned long *) &resp.length); gss_release_buffer (&smn,&chal); if (gss_unwrap (&smn,ctx,&resp,&chal,&conf,&qop)==GSS_S_COMPLETE) { /* client request valid */ if (chal.value && (chal.length > 4) && (chal.length < (MAILTMPLEN - 1)) && memcpy (tmp,chal.value,chal.length) && (tmp[0] & AUTH_GSSAPI_P_NONE)) { /* tie off authorization ID */ tmp[chal.length] = '\0'; ret = kerberos_login (tmp+4,buf.value,argc,argv); } /* done with user name */ gss_release_buffer (&smn,&chal); } /* finished with response */ fs_give ((void **) &resp.value); } /* don't need name buffer any more */ gss_release_buffer (&smn,&buf); } /* don't need client name any more */ gss_release_name (&smn,&name); /* don't need context any more */ if (ctx != GSS_C_NO_CONTEXT) gss_delete_sec_context (&smn,&ctx,NIL); } /* finished with credentials */ gss_release_cred (&smn,&crd); } else { /* can't acquire credentials! */ if (gss_display_name (&dsmn,crname,&buf,&mech) == GSS_S_COMPLETE) SERVER_LOG ("Failed to acquire credentials for %s",buf.value); if (smj != GSS_S_FAILURE) do switch (dsmj = gss_display_status (&dsmn,smj,GSS_C_GSS_CODE, GSS_C_NO_OID,&mctx,&resp)) { case GSS_S_COMPLETE: mctx = 0; case GSS_S_CONTINUE_NEEDED: SERVER_LOG ("Unknown GSSAPI failure: %s",resp.value); gss_release_buffer (&dsmn,&resp); } while (dsmj == GSS_S_CONTINUE_NEEDED); do switch (dsmj = gss_display_status (&dsmn,smn,GSS_C_MECH_CODE, GSS_C_NO_OID,&mctx,&resp)) { case GSS_S_COMPLETE: case GSS_S_CONTINUE_NEEDED: SERVER_LOG ("GSSAPI mechanism status: %s",resp.value); gss_release_buffer (&dsmn,&resp); } while (dsmj == GSS_S_CONTINUE_NEEDED); } /* finished with credentials name */ gss_release_name (&smn,&crname); } return ret; /* return status */ } alpine-2.10+dfsg/imap/src/c-client/nntp.h0000600000175000017500000000312211512502124021675 0ustar paulproteuspaulproteus/* ======================================================================== * Copyright 1988-2006 University of Washington * * Licensed under the Apache License, Version 2.0 (the "License"); * you may not use this file except in compliance with the License. * You may obtain a copy of the License at * * http://www.apache.org/licenses/LICENSE-2.0 * * * ======================================================================== */ /* * Program: Network News Transfer Protocol (NNTP) routines * * Author: Mark Crispin * Networks and Distributed Computing * Computing & Communications * University of Washington * Administration Building, AG-44 * Seattle, WA 98195 * Internet: MRC@CAC.Washington.EDU * * Date: 10 February 1992 * Last Edited: 30 August 2006 */ /* Constants (should be in nntp.c) */ #define NNTPTCPPORT (long) 119 /* assigned TCP contact port */ /* NNTP open options * For compatibility with the past, NOP_DEBUG must always be 1. */ #define NOP_DEBUG (long) 0x1 /* debug protocol negotiations */ #define NOP_READONLY (long) 0x2 /* read-only open */ #define NOP_TRYSSL (long) 0x4 /* try SSL first */ /* reserved for application use */ #define NOP_RESERVED (unsigned long) 0xff000000 /* Compatibility support names */ #define nntp_open(hostlist,options) \ nntp_open_full (NIL,hostlist,"nntp",NIL,options) /* Function prototypes */ SENDSTREAM *nntp_open_full (NETDRIVER *dv,char **hostlist,char *service, unsigned long port,long options); SENDSTREAM *nntp_close (SENDSTREAM *stream); long nntp_mail (SENDSTREAM *stream,ENVELOPE *msg,BODY *body); alpine-2.10+dfsg/imap/src/c-client/pop3.c0000600000175000017500000010412311512502124021575 0ustar paulproteuspaulproteus/* ======================================================================== * Copyright 1988-2007 University of Washington * * Licensed under the Apache License, Version 2.0 (the "License"); * you may not use this file except in compliance with the License. * You may obtain a copy of the License at * * http://www.apache.org/licenses/LICENSE-2.0 * * * ======================================================================== */ /* * Program: Post Office Protocol 3 (POP3) client routines * * Author: Mark Crispin * Networks and Distributed Computing * Computing & Communications * University of Washington * Administration Building, AG-44 * Seattle, WA 98195 * Internet: MRC@CAC.Washington.EDU * * Date: 6 June 1994 * Last Edited: 4 April 2007 */ #include #include #include #include "c-client.h" #include "flstring.h" #include "netmsg.h" /* Parameters */ #define POP3TCPPORT (long) 110 /* assigned TCP contact port */ #define POP3SSLPORT (long) 995 /* assigned SSL TCP contact port */ #define IDLETIMEOUT (long) 10 /* defined in RFC 1939 */ /* POP3 I/O stream local data */ typedef struct pop3_local { NETSTREAM *netstream; /* TCP I/O stream */ char *response; /* last server reply */ char *reply; /* text of last server reply */ unsigned long cached; /* current cached message uid */ unsigned long hdrsize; /* current cached header size */ FILE *txt; /* current cached file descriptor */ struct { unsigned int capa : 1; /* server has CAPA, definitely new */ unsigned int expire : 1; /* server has EXPIRE */ unsigned int logindelay : 1;/* server has LOGIN-DELAY */ unsigned int stls : 1; /* server has STLS */ unsigned int pipelining : 1;/* server has PIPELINING */ unsigned int respcodes : 1; /* server has RESP-CODES */ unsigned int top : 1; /* server has TOP */ unsigned int uidl : 1; /* server has UIDL */ unsigned int user : 1; /* server has USER */ char *implementation; /* server implementation string */ long delaysecs; /* minimum time between login (neg variable) */ long expiredays; /* server-guaranteed minimum retention days */ /* supported authenticators */ unsigned int sasl : MAXAUTHENTICATORS; } cap; unsigned int sensitive : 1; /* sensitive data in progress */ unsigned int loser : 1; /* server is a loser */ unsigned int saslcancel : 1; /* SASL cancelled by protocol */ } POP3LOCAL; /* Convenient access to local data */ #define LOCAL ((POP3LOCAL *) stream->local) /* Function prototypes */ DRIVER *pop3_valid (char *name); void *pop3_parameters (long function,void *value); void pop3_scan (MAILSTREAM *stream,char *ref,char *pat,char *contents); void pop3_list (MAILSTREAM *stream,char *ref,char *pat); void pop3_lsub (MAILSTREAM *stream,char *ref,char *pat); long pop3_subscribe (MAILSTREAM *stream,char *mailbox); long pop3_unsubscribe (MAILSTREAM *stream,char *mailbox); long pop3_create (MAILSTREAM *stream,char *mailbox); long pop3_delete (MAILSTREAM *stream,char *mailbox); long pop3_rename (MAILSTREAM *stream,char *old,char *newname); long pop3_status (MAILSTREAM *stream,char *mbx,long flags); MAILSTREAM *pop3_open (MAILSTREAM *stream); long pop3_capa (MAILSTREAM *stream,long flags); long pop3_auth (MAILSTREAM *stream,NETMBX *mb,char *pwd,char *usr); void *pop3_challenge (void *stream,unsigned long *len); long pop3_response (void *stream,char *s,unsigned long size); void pop3_close (MAILSTREAM *stream,long options); void pop3_fetchfast (MAILSTREAM *stream,char *sequence,long flags); char *pop3_header (MAILSTREAM *stream,unsigned long msgno,unsigned long *size, long flags); long pop3_text (MAILSTREAM *stream,unsigned long msgno,STRING *bs,long flags); unsigned long pop3_cache (MAILSTREAM *stream,MESSAGECACHE *elt); long pop3_ping (MAILSTREAM *stream); void pop3_check (MAILSTREAM *stream); long pop3_expunge (MAILSTREAM *stream,char *sequence,long options); long pop3_copy (MAILSTREAM *stream,char *sequence,char *mailbox,long options); long pop3_append (MAILSTREAM *stream,char *mailbox,append_t af,void *data); long pop3_send_num (MAILSTREAM *stream,char *command,unsigned long n); long pop3_send (MAILSTREAM *stream,char *command,char *args); long pop3_reply (MAILSTREAM *stream); long pop3_fake (MAILSTREAM *stream,char *text); /* POP3 mail routines */ /* Driver dispatch used by MAIL */ DRIVER pop3driver = { "pop3", /* driver name */ /* driver flags */ #ifdef INADEQUATE_MEMORY DR_LOWMEM | #endif DR_MAIL|DR_NOFAST|DR_CRLF|DR_NOSTICKY|DR_NOINTDATE|DR_NONEWMAIL, (DRIVER *) NIL, /* next driver */ pop3_valid, /* mailbox is valid for us */ pop3_parameters, /* manipulate parameters */ pop3_scan, /* scan mailboxes */ pop3_list, /* find mailboxes */ pop3_lsub, /* find subscribed mailboxes */ pop3_subscribe, /* subscribe to mailbox */ pop3_unsubscribe, /* unsubscribe from mailbox */ pop3_create, /* create mailbox */ pop3_delete, /* delete mailbox */ pop3_rename, /* rename mailbox */ pop3_status, /* status of mailbox */ pop3_open, /* open mailbox */ pop3_close, /* close mailbox */ pop3_fetchfast, /* fetch message "fast" attributes */ NIL, /* fetch message flags */ NIL, /* fetch overview */ NIL, /* fetch message structure */ pop3_header, /* fetch message header */ pop3_text, /* fetch message text */ NIL, /* fetch message */ NIL, /* unique identifier */ NIL, /* message number from UID */ NIL, /* modify flags */ NIL, /* per-message modify flags */ NIL, /* search for message based on criteria */ NIL, /* sort messages */ NIL, /* thread messages */ pop3_ping, /* ping mailbox to see if still alive */ pop3_check, /* check for new messages */ pop3_expunge, /* expunge deleted messages */ pop3_copy, /* copy messages to another mailbox */ pop3_append, /* append string message to mailbox */ NIL /* garbage collect stream */ }; /* prototype stream */ MAILSTREAM pop3proto = {&pop3driver}; /* driver parameters */ static unsigned long pop3_maxlogintrials = MAXLOGINTRIALS; static long pop3_port = 0; static long pop3_sslport = 0; /* POP3 mail validate mailbox * Accepts: mailbox name * Returns: our driver if name is valid, NIL otherwise */ DRIVER *pop3_valid (char *name) { NETMBX mb; return (mail_valid_net_parse (name,&mb) && !strcmp (mb.service,pop3driver.name) && !mb.authuser[0] && !compare_cstring (mb.mailbox,"INBOX")) ? &pop3driver : NIL; } /* News manipulate driver parameters * Accepts: function code * function-dependent value * Returns: function-dependent return value */ void *pop3_parameters (long function,void *value) { switch ((int) function) { case SET_MAXLOGINTRIALS: pop3_maxlogintrials = (unsigned long) value; break; case GET_MAXLOGINTRIALS: value = (void *) pop3_maxlogintrials; break; case SET_POP3PORT: pop3_port = (long) value; break; case GET_POP3PORT: value = (void *) pop3_port; break; case SET_SSLPOPPORT: pop3_sslport = (long) value; break; case GET_SSLPOPPORT: value = (void *) pop3_sslport; break; case GET_IDLETIMEOUT: value = (void *) IDLETIMEOUT; break; default: value = NIL; /* error case */ break; } return value; } /* POP3 mail scan mailboxes for string * Accepts: mail stream * reference * pattern to search * string to scan */ void pop3_scan (MAILSTREAM *stream,char *ref,char *pat,char *contents) { char tmp[MAILTMPLEN]; if ((ref && *ref) ? /* have a reference */ (pop3_valid (ref) && pmatch ("INBOX",pat)) : (mail_valid_net (pat,&pop3driver,NIL,tmp) && pmatch ("INBOX",tmp))) mm_log ("Scan not valid for POP3 mailboxes",ERROR); } /* POP3 mail find list of all mailboxes * Accepts: mail stream * reference * pattern to search */ void pop3_list (MAILSTREAM *stream,char *ref,char *pat) { char tmp[MAILTMPLEN]; if (ref && *ref) { /* have a reference */ if (pop3_valid (ref) && pmatch ("INBOX",pat)) { strcpy (strchr (strcpy (tmp,ref),'}')+1,"INBOX"); mm_list (stream,NIL,tmp,LATT_NOINFERIORS); } } else if (mail_valid_net (pat,&pop3driver,NIL,tmp) && pmatch ("INBOX",tmp)) { strcpy (strchr (strcpy (tmp,pat),'}')+1,"INBOX"); mm_list (stream,NIL,tmp,LATT_NOINFERIORS); } } /* POP3 mail find list of subscribed mailboxes * Accepts: mail stream * reference * pattern to search */ void pop3_lsub (MAILSTREAM *stream,char *ref,char *pat) { void *sdb = NIL; char *s,mbx[MAILTMPLEN]; if (*pat == '{') { /* if remote pattern, must be POP3 */ if (!pop3_valid (pat)) return; ref = NIL; /* good POP3 pattern, punt reference */ } /* if remote reference, must be valid POP3 */ if (ref && (*ref == '{') && !pop3_valid (ref)) return; /* kludgy application of reference */ if (ref && *ref) sprintf (mbx,"%s%s",ref,pat); else strcpy (mbx,pat); if (s = sm_read (&sdb)) do if (pop3_valid (s) && pmatch (s,mbx)) mm_lsub (stream,NIL,s,NIL); while (s = sm_read (&sdb)); /* until no more subscriptions */ } /* POP3 mail subscribe to mailbox * Accepts: mail stream * mailbox to add to subscription list * Returns: T on success, NIL on failure */ long pop3_subscribe (MAILSTREAM *stream,char *mailbox) { return sm_subscribe (mailbox); } /* POP3 mail unsubscribe to mailbox * Accepts: mail stream * mailbox to delete from subscription list * Returns: T on success, NIL on failure */ long pop3_unsubscribe (MAILSTREAM *stream,char *mailbox) { return sm_unsubscribe (mailbox); } /* POP3 mail create mailbox * Accepts: mail stream * mailbox name to create * Returns: T on success, NIL on failure */ long pop3_create (MAILSTREAM *stream,char *mailbox) { return NIL; /* never valid for POP3 */ } /* POP3 mail delete mailbox * mailbox name to delete * Returns: T on success, NIL on failure */ long pop3_delete (MAILSTREAM *stream,char *mailbox) { return NIL; /* never valid for POP3 */ } /* POP3 mail rename mailbox * Accepts: mail stream * old mailbox name * new mailbox name * Returns: T on success, NIL on failure */ long pop3_rename (MAILSTREAM *stream,char *old,char *newname) { return NIL; /* never valid for POP3 */ } /* POP3 status * Accepts: mail stream * mailbox name * status flags * Returns: T on success, NIL on failure */ long pop3_status (MAILSTREAM *stream,char *mbx,long flags) { MAILSTATUS status; unsigned long i; long ret = NIL; MAILSTREAM *tstream = (stream && LOCAL->netstream && mail_usable_network_stream (stream,mbx)) ? stream : mail_open (NIL,mbx,OP_SILENT); if (tstream) { /* have a usable stream? */ status.flags = flags; /* return status values */ status.messages = tstream->nmsgs; status.recent = tstream->recent; if (flags & SA_UNSEEN) /* must search to get unseen messages */ for (i = 1,status.unseen = 0; i <= tstream->nmsgs; i++) if (!mail_elt (tstream,i)->seen) status.unseen++; status.uidnext = tstream->uid_last + 1; status.uidvalidity = tstream->uid_validity; /* pass status to main program */ mm_status (tstream,mbx,&status); if (stream != tstream) mail_close (tstream); ret = LONGT; } return ret; /* success */ } /* POP3 mail open * Accepts: stream to open * Returns: stream on success, NIL on failure */ MAILSTREAM *pop3_open (MAILSTREAM *stream) { unsigned long i,j; char *s,*t,tmp[MAILTMPLEN],usr[MAILTMPLEN]; NETMBX mb; MESSAGECACHE *elt; /* return prototype for OP_PROTOTYPE call */ if (!stream) return &pop3proto; mail_valid_net_parse (stream->mailbox,&mb); usr[0] = '\0'; /* initially no user name */ if (stream->local) fatal ("pop3 recycle stream"); /* /anonymous not supported */ if (mb.anoflag || stream->anonymous) { mm_log ("Anonymous POP3 login not available",ERROR); return NIL; } /* /readonly not supported either */ if (mb.readonlyflag || stream->rdonly) { mm_log ("Read-only POP3 access not available",ERROR); return NIL; } /* copy other switches */ if (mb.dbgflag) stream->debug = T; if (mb.secflag) stream->secure = T; mb.trysslflag = stream->tryssl = (mb.trysslflag || stream->tryssl) ? T : NIL; stream->local = /* instantiate localdata */ (void *) memset (fs_get (sizeof (POP3LOCAL)),0,sizeof (POP3LOCAL)); stream->sequence++; /* bump sequence number */ stream->perm_deleted = T; /* deleted is only valid flag */ if ((LOCAL->netstream = /* try to open connection */ net_open (&mb,NIL,pop3_port ? pop3_port : POP3TCPPORT, (NETDRIVER *) mail_parameters (NIL,GET_SSLDRIVER,NIL), "*pop3s",pop3_sslport ? pop3_sslport : POP3SSLPORT)) && pop3_reply (stream)) { mm_log (LOCAL->reply,NIL); /* give greeting */ if (!pop3_auth (stream,&mb,tmp,usr)) pop3_close (stream,NIL); else if (pop3_send (stream,"STAT",NIL)) { int silent = stream->silent; stream->silent = T; sprintf (tmp,"{%.200s:%lu/pop3", (long) mail_parameters (NIL,GET_TRUSTDNS,NIL) ? net_host (LOCAL->netstream) : mb.host, net_port (LOCAL->netstream)); if (mb.tlsflag) strcat (tmp,"/tls"); if (mb.tlssslv23) strcat (tmp,"/tls-sslv23"); if (mb.notlsflag) strcat (tmp,"/notls"); if (mb.sslflag) strcat (tmp,"/ssl"); if (mb.novalidate) strcat (tmp,"/novalidate-cert"); if (LOCAL->loser = mb.loser) strcat (tmp,"/loser"); if (stream->secure) strcat (tmp,"/secure"); sprintf (tmp + strlen (tmp),"/user=\"%s\"}%s",usr,mb.mailbox); stream->inbox = T; /* always INBOX */ fs_give ((void **) &stream->mailbox); stream->mailbox = cpystr (tmp); /* notify upper level */ mail_exists (stream,stream->uid_last = strtoul (LOCAL->reply,NIL,10)); mail_recent (stream,stream->nmsgs); /* instantiate elt */ for (i = 0; i < stream->nmsgs;) { elt = mail_elt (stream,++i); elt->valid = elt->recent = T; elt->private.uid = i; } /* trust LIST output if new server */ if (!LOCAL->loser && LOCAL->cap.capa && pop3_send (stream,"LIST",NIL)) { while ((s = net_getline (LOCAL->netstream)) && (*s != '.')) { if ((i = strtoul (s,&t,10)) && (i <= stream->nmsgs) && (j = strtoul (t,NIL,10))) mail_elt (stream,i)->rfc822_size = j; fs_give ((void **) &s); } /* flush final dot */ if (s) fs_give ((void **) &s); else { /* lost connection */ mm_log ("POP3 connection broken while itemizing messages",ERROR); pop3_close (stream,NIL); return NIL; } } stream->silent = silent; /* notify main program */ mail_exists (stream,stream->nmsgs); /* notify if empty */ if (!(stream->nmsgs || stream->silent)) mm_log ("Mailbox is empty",WARN); } else { /* error in STAT */ mm_log (LOCAL->reply,ERROR); pop3_close (stream,NIL); /* too bad */ } } else { /* connection failed */ if (LOCAL->reply) mm_log (LOCAL->reply,ERROR); pop3_close (stream,NIL); /* failed, clean up */ } return LOCAL ? stream : NIL; /* if stream is alive, return to caller */ } /* POP3 capabilities * Accepts: stream * authenticator flags * Returns: T on success, NIL on failure */ long pop3_capa (MAILSTREAM *stream,long flags) { unsigned long i; char *s,*t,*r,*args; if (LOCAL->cap.implementation)/* zap all old capabilities */ fs_give ((void **) &LOCAL->cap.implementation); memset (&LOCAL->cap,0,sizeof (LOCAL->cap)); /* get server capabilities */ if (pop3_send (stream,"CAPA",NIL)) LOCAL->cap.capa = T; else { LOCAL->cap.user = T; /* guess worst-case old server */ return NIL; /* no CAPA on this server */ } while ((t = net_getline (LOCAL->netstream)) && (t[1] || (*t != '.'))) { if (stream->debug) mm_dlog (t); /* get optional capability arguments */ if (args = strchr (t,' ')) *args++ = '\0'; if (!compare_cstring (t,"STLS")) LOCAL->cap.stls = T; else if (!compare_cstring (t,"PIPELINING")) LOCAL->cap.pipelining = T; else if (!compare_cstring (t,"RESP-CODES")) LOCAL->cap.respcodes = T; else if (!compare_cstring (t,"TOP")) LOCAL->cap.top = T; else if (!compare_cstring (t,"UIDL")) LOCAL->cap.uidl = T; else if (!compare_cstring (t,"USER")) LOCAL->cap.user = T; else if (!compare_cstring (t,"IMPLEMENTATION") && args) LOCAL->cap.implementation = cpystr (args); else if (!compare_cstring (t,"EXPIRE") && args) { LOCAL->cap.expire = T; /* note that it is present */ if (s = strchr(args,' ')){/* separate time from possible USER */ *s++ = '\0'; /* in case they add something after USER */ if ((strlen (s) > 4) && (s[4] == ' ')) s[4] = '\0'; } LOCAL->cap.expire = /* get expiration time */ (!compare_cstring (args,"NEVER")) ? 65535 : ((s && !compare_cstring (s,"USER")) ? -atoi (args) : atoi (args)); } else if (!compare_cstring (t,"LOGIN-DELAY") && args) { LOCAL->cap.logindelay = T;/* note that it is present */ if (s = strchr(args,' ')){/* separate time from possible USER */ *s++ = '\0'; /* in case they add something after USER */ if ((strlen (s) > 4) && (s[4] == ' ')) s[4] = '\0'; } /* get delay time */ LOCAL->cap.delaysecs = (s && !compare_cstring (s,"USER")) ? -atoi (args) : atoi (args); } else if (!compare_cstring (t,"SASL") && args) for (args = strtok_r (args," ",&r); args; args = strtok_r (NIL," ",&r)) if ((i = mail_lookup_auth_name (args,flags)) && (--i < MAXAUTHENTICATORS)) LOCAL->cap.sasl |= (1 << i); fs_give ((void **) &t); } if (t) { /* flush end of text indicator */ if (stream->debug) mm_dlog (t); fs_give ((void **) &t); } return LONGT; } /* POP3 authenticate * Accepts: stream to login * parsed network mailbox structure * scratch buffer of length MAILTMPLEN * place to return user name * Returns: T on success, NIL on failure */ long pop3_auth (MAILSTREAM *stream,NETMBX *mb,char *pwd,char *usr) { unsigned long i,trial,auths = 0; char *t; AUTHENTICATOR *at; long ret = NIL; long flags = (stream->secure ? AU_SECURE : NIL) | (mb->authuser[0] ? AU_AUTHUSER : NIL); long capaok = pop3_capa (stream,flags); NETDRIVER *ssld = (NETDRIVER *) mail_parameters (NIL,GET_SSLDRIVER,NIL); sslstart_t stls = (sslstart_t) mail_parameters (NIL,GET_SSLSTART,NIL); /* server has TLS? */ if (stls && LOCAL->cap.stls && !mb->sslflag && !mb->notlsflag && pop3_send (stream,"STLS",NIL)) { mb->tlsflag = T; /* TLS OK, get into TLS at this end */ LOCAL->netstream->dtb = ssld; if (!(LOCAL->netstream->stream = (*stls) (LOCAL->netstream->stream,mb->host, (mb->tlssslv23 ? NIL : NET_TLSCLIENT) | (mb->novalidate ? NET_NOVALIDATECERT : NIL)))) { /* drat, drop this connection */ if (LOCAL->netstream) net_close (LOCAL->netstream); LOCAL->netstream= NIL; return NIL; /* TLS negotiation failed */ } pop3_capa (stream,flags); /* get capabilities now that TLS in effect */ } else if (mb->tlsflag) { /* user specified /tls but can't do it */ mm_log ("Unable to negotiate TLS with this server",ERROR); return NIL; } /* get authenticators from capabilities */ if (capaok) auths = LOCAL->cap.sasl; /* get list of authenticators */ else if (pop3_send (stream,"AUTH",NIL)) { while ((t = net_getline (LOCAL->netstream)) && (t[1] || (*t != '.'))) { if (stream->debug) mm_dlog (t); if ((i = mail_lookup_auth_name (t,flags)) && (--i < MAXAUTHENTICATORS)) auths |= (1 << i); fs_give ((void **) &t); } if (t) { /* flush end of text indicator */ if (stream->debug) mm_dlog (t); fs_give ((void **) &t); } } /* disable LOGIN if PLAIN also advertised */ if ((i = mail_lookup_auth_name ("PLAIN",NIL)) && (--i < MAXAUTHENTICATORS) && (auths & (1 << i)) && (i = mail_lookup_auth_name ("LOGIN",NIL)) && (--i < MAXAUTHENTICATORS)) auths &= ~(1 << i); if (auths) { /* got any authenticators? */ if ((long) mail_parameters (NIL,GET_TRUSTDNS,NIL)) { /* remote name for authentication */ strncpy (mb->host,(long) mail_parameters (NIL,GET_SASLUSESPTRNAME,NIL) ? net_remotehost (LOCAL->netstream) : net_host (LOCAL->netstream), NETMAXHOST-1); mb->host[NETMAXHOST-1] = '\0'; } for (t = NIL, LOCAL->saslcancel = NIL; !ret && LOCAL->netstream && auths && (at = mail_lookup_auth (find_rightmost_bit (&auths)+1)); ) { if (t) { /* previous authenticator failed? */ sprintf (pwd,"Retrying using %.80s authentication after %.80s", at->name,t); mm_log (pwd,NIL); fs_give ((void **) &t); } trial = 0; /* initial trial count */ do { if (t) { sprintf (pwd,"Retrying %s authentication after %.80s",at->name,t); mm_log (pwd,WARN); fs_give ((void **) &t); } LOCAL->saslcancel = NIL; if (pop3_send (stream,"AUTH",at->name)) { /* hide client authentication responses */ if (!(at->flags & AU_SECURE)) LOCAL->sensitive = T; if ((*at->client) (pop3_challenge,pop3_response,"pop",mb,stream, &trial,usr) && LOCAL->response) { if (*LOCAL->response == '+') ret = LONGT; /* if main program requested cancellation */ else if (!trial) mm_log ("POP3 Authentication cancelled",ERROR); } LOCAL->sensitive=NIL; /* unhide */ } /* remember response if error and no cancel */ if (!ret && trial) t = cpystr (LOCAL->reply); } while (!ret && trial && (trial < pop3_maxlogintrials) && LOCAL->netstream); } if (t) { /* previous authenticator failed? */ if (!LOCAL->saslcancel) { /* don't do this if a cancel */ sprintf (pwd,"Can not authenticate to POP3 server: %.80s",t); mm_log (pwd,ERROR); } fs_give ((void **) &t); } } else if (stream->secure) mm_log ("Can't do secure authentication with this server",ERROR); else if (mb->authuser[0]) mm_log ("Can't do /authuser with this server",ERROR); else if (!LOCAL->cap.user) mm_log ("Can't login to this server",ERROR); else { /* traditional login */ trial = 0; /* initial trial count */ do { pwd[0] = 0; /* prompt user for password */ mm_login (mb,usr,pwd,trial++); if (pwd[0]) { /* send login sequence if have password */ if (pop3_send (stream,"USER",usr)) { LOCAL->sensitive = T; /* hide this command */ if (pop3_send (stream,"PASS",pwd)) ret = LONGT; LOCAL->sensitive=NIL; /* unhide */ } if (!ret) { /* failure */ mm_log (LOCAL->reply,WARN); if (trial == pop3_maxlogintrials) mm_log ("Too many login failures",ERROR); } } /* user refused to give password */ else mm_log ("Login aborted",ERROR); } while (!ret && pwd[0] && (trial < pop3_maxlogintrials) && LOCAL->netstream); } memset (pwd,0,MAILTMPLEN); /* erase password */ /* get capabilities if logged in */ if (ret && capaok) pop3_capa (stream,flags); return ret; } /* Get challenge to authenticator in binary * Accepts: stream * pointer to returned size * Returns: challenge or NIL if not challenge */ void *pop3_challenge (void *s,unsigned long *len) { char tmp[MAILTMPLEN]; void *ret = NIL; MAILSTREAM *stream = (MAILSTREAM *) s; if (stream && LOCAL->response && (*LOCAL->response == '+') && (LOCAL->response[1] == ' ') && !(ret = rfc822_base64 ((unsigned char *) LOCAL->reply, strlen (LOCAL->reply),len))) { sprintf (tmp,"POP3 SERVER BUG (invalid challenge): %.80s",LOCAL->reply); mm_log (tmp,ERROR); } return ret; } /* Send authenticator response in BASE64 * Accepts: MAIL stream * string to send * length of string * Returns: T if successful, else NIL */ long pop3_response (void *s,char *response,unsigned long size) { MAILSTREAM *stream = (MAILSTREAM *) s; unsigned long i,j,ret; char *t,*u; if (response) { /* make CRLFless BASE64 string */ if (size) { for (t = (char *) rfc822_binary ((void *) response,size,&i),u = t,j = 0; j < i; j++) if (t[j] > ' ') *u++ = t[j]; *u = '\0'; /* tie off string for mm_dlog() */ if (stream->debug) mail_dlog (t,LOCAL->sensitive); /* append CRLF */ *u++ = '\015'; *u++ = '\012'; *u = '\0'; ret = net_sout (LOCAL->netstream,t,u - t); fs_give ((void **) &t); } else ret = net_sout (LOCAL->netstream,"\015\012",2); } else { /* abort requested */ ret = net_sout (LOCAL->netstream,"*\015\012",3); LOCAL->saslcancel = T; /* mark protocol-requested SASL cancel */ } pop3_reply (stream); /* get response */ return ret; } /* POP3 mail close * Accepts: MAIL stream * option flags */ void pop3_close (MAILSTREAM *stream,long options) { int silent = stream->silent; if (LOCAL) { /* only if a file is open */ if (LOCAL->netstream) { /* close POP3 connection */ stream->silent = T; if (options & CL_EXPUNGE) pop3_expunge (stream,NIL,NIL); stream->silent = silent; pop3_send (stream,"QUIT",NIL); mm_notify (stream,LOCAL->reply,BYE); } /* close POP3 connection */ if (LOCAL->netstream) net_close (LOCAL->netstream); /* clean up */ if (LOCAL->cap.implementation) fs_give ((void **) &LOCAL->cap.implementation); if (LOCAL->txt) fclose (LOCAL->txt); LOCAL->txt = NIL; if (LOCAL->response) fs_give ((void **) &LOCAL->response); /* nuke the local data */ fs_give ((void **) &stream->local); stream->dtb = NIL; /* log out the DTB */ } } /* POP3 mail fetch fast information * Accepts: MAIL stream * sequence * option flags * This is ugly and slow */ void pop3_fetchfast (MAILSTREAM *stream,char *sequence,long flags) { unsigned long i; MESSAGECACHE *elt; /* get sequence */ if (stream && LOCAL && ((flags & FT_UID) ? mail_uid_sequence (stream,sequence) : mail_sequence (stream,sequence))) for (i = 1; i <= stream->nmsgs; i++) if ((elt = mail_elt (stream,i))->sequence && !(elt->day && elt->rfc822_size)) { ENVELOPE **env = NIL; ENVELOPE *e = NIL; if (!stream->scache) env = &elt->private.msg.env; else if (stream->msgno == i) env = &stream->env; else env = &e; if (!*env || !elt->rfc822_size) { STRING bs; unsigned long hs; char *ht = (*stream->dtb->header) (stream,i,&hs,NIL); /* need to make an envelope? */ if (!*env) rfc822_parse_msg (env,NIL,ht,hs,NIL,BADHOST, stream->dtb->flags); /* need message size too, ugh */ if (!elt->rfc822_size) { (*stream->dtb->text) (stream,i,&bs,FT_PEEK); elt->rfc822_size = hs + SIZE (&bs) - GETPOS (&bs); } } /* if need date, have date in envelope? */ if (!elt->day && *env && (*env)->date) mail_parse_date (elt,(*env)->date); /* sigh, fill in bogus default */ if (!elt->day) elt->day = elt->month = 1; mail_free_envelope (&e); } } /* POP3 fetch header as text * Accepts: mail stream * message number * pointer to return size * flags * Returns: header text */ char *pop3_header (MAILSTREAM *stream,unsigned long msgno,unsigned long *size, long flags) { unsigned long i; char tmp[MAILTMPLEN]; MESSAGECACHE *elt; FILE *f = NIL; *size = 0; /* initially no header size */ if ((flags & FT_UID) && !(msgno = mail_msgno (stream,msgno))) return ""; /* have header text already? */ if (!(elt = mail_elt (stream,msgno))->private.msg.header.text.data) { /* if have CAPA and TOP, assume good TOP */ if (!LOCAL->loser && LOCAL->cap.top) { sprintf (tmp,"TOP %lu 0",mail_uid (stream,msgno)); if (pop3_send (stream,tmp,NIL)) f = netmsg_slurp (LOCAL->netstream,&i, &elt->private.msg.header.text.size); } /* otherwise load the cache with the message */ else if (elt->private.msg.header.text.size = pop3_cache (stream,elt)) f = LOCAL->txt; if (f) { /* got it, make sure at start of file */ fseek (f,(unsigned long) 0,SEEK_SET); /* read header from the cache */ fread (elt->private.msg.header.text.data = (unsigned char *) fs_get ((size_t) elt->private.msg.header.text.size + 1), (size_t) 1,(size_t) elt->private.msg.header.text.size,f); /* tie off header text */ elt->private.msg.header.text.data[elt->private.msg.header.text.size] = '\0'; /* close if not the cache */ if (f != LOCAL->txt) fclose (f); } } /* return size of text */ if (size) *size = elt->private.msg.header.text.size; return elt->private.msg.header.text.data ? (char *) elt->private.msg.header.text.data : ""; } /* POP3 fetch body * Accepts: mail stream * message number * pointer to stringstruct to initialize * flags * Returns: T if successful, else NIL */ long pop3_text (MAILSTREAM *stream,unsigned long msgno,STRING *bs,long flags) { MESSAGECACHE *elt; INIT (bs,mail_string,(void *) "",0); if ((flags & FT_UID) && !(msgno = mail_msgno (stream,msgno))) return NIL; elt = mail_elt (stream,msgno); pop3_cache (stream,elt); /* make sure cache loaded */ if (!LOCAL->txt) return NIL; /* error if don't have a file */ if (!(flags & FT_PEEK)) { /* mark seen if needed */ elt->seen = T; mm_flags (stream,elt->msgno); } INIT (bs,file_string,(void *) LOCAL->txt,elt->rfc822_size); SETPOS (bs,LOCAL->hdrsize); /* skip past header */ return T; } /* POP3 cache message * Accepts: mail stream * message number * Returns: header size */ unsigned long pop3_cache (MAILSTREAM *stream,MESSAGECACHE *elt) { /* already cached? */ if (LOCAL->cached != mail_uid (stream,elt->msgno)) { /* no, close current file */ if (LOCAL->txt) fclose (LOCAL->txt); LOCAL->txt = NIL; LOCAL->cached = LOCAL->hdrsize = 0; if (pop3_send_num (stream,"RETR",elt->msgno) && (LOCAL->txt = netmsg_slurp (LOCAL->netstream,&elt->rfc822_size, &LOCAL->hdrsize))) /* set as current message number */ LOCAL->cached = mail_uid (stream,elt->msgno); else elt->deleted = T; } return LOCAL->hdrsize; } /* POP3 mail ping mailbox * Accepts: MAIL stream * Returns: T if stream alive, else NIL */ long pop3_ping (MAILSTREAM *stream) { return pop3_send (stream,"NOOP",NIL); } /* POP3 mail check mailbox * Accepts: MAIL stream */ void pop3_check (MAILSTREAM *stream) { if (pop3_ping (stream)) mm_log ("Check completed",NIL); } /* POP3 mail expunge mailbox * Accepts: MAIL stream * sequence to expunge if non-NIL * expunge options * Returns: T if success, NIL if failure */ long pop3_expunge (MAILSTREAM *stream,char *sequence,long options) { char tmp[MAILTMPLEN]; MESSAGECACHE *elt; unsigned long i = 1,n = 0; long ret; if (ret = sequence ? ((options & EX_UID) ? mail_uid_sequence (stream,sequence) : mail_sequence (stream,sequence)) : LONGT) { /* build selected sequence if needed */ while (i <= stream->nmsgs) { elt = mail_elt (stream,i); if (elt->deleted && (sequence ? elt->sequence : T) && pop3_send_num (stream,"DELE",i)) { /* expunging currently cached message? */ if (LOCAL->cached == mail_uid (stream,i)) { /* yes, close current file */ if (LOCAL->txt) fclose (LOCAL->txt); LOCAL->txt = NIL; LOCAL->cached = LOCAL->hdrsize = 0; } mail_expunged (stream,i); n++; } else i++; /* try next message */ } if (!stream->silent) { /* only if not silent */ if (n) { /* did we expunge anything? */ sprintf (tmp,"Expunged %lu messages",n); mm_log (tmp,(long) NIL); } else mm_log ("No messages deleted, so no update needed",(long) NIL); } } return ret; } /* POP3 mail copy message(s) * Accepts: MAIL stream * sequence * destination mailbox * option flags * Returns: T if copy successful, else NIL */ long pop3_copy (MAILSTREAM *stream,char *sequence,char *mailbox,long options) { mailproxycopy_t pc = (mailproxycopy_t) mail_parameters (stream,GET_MAILPROXYCOPY,NIL); if (pc) return (*pc) (stream,sequence,mailbox,options); mm_log ("Copy not valid for POP3",ERROR); return NIL; } /* POP3 mail append message from stringstruct * Accepts: MAIL stream * destination mailbox * append callback * data for callback * Returns: T if append successful, else NIL */ long pop3_append (MAILSTREAM *stream,char *mailbox,append_t af,void *data) { mm_log ("Append not valid for POP3",ERROR); return NIL; } /* Internal routines */ /* Post Office Protocol 3 send command with number argument * Accepts: MAIL stream * command * number * Returns: T if successful, NIL if failure */ long pop3_send_num (MAILSTREAM *stream,char *command,unsigned long n) { char tmp[MAILTMPLEN]; sprintf (tmp,"%lu",mail_uid (stream,n)); return pop3_send (stream,command,tmp); } /* Post Office Protocol 3 send command * Accepts: MAIL stream * command * command argument * Returns: T if successful, NIL if failure */ long pop3_send (MAILSTREAM *stream,char *command,char *args) { long ret; char *s = (char *) fs_get (strlen (command) + (args ? strlen (args) + 1: 0) + 3); mail_lock (stream); /* lock up the stream */ if (!LOCAL->netstream) ret = pop3_fake (stream,"POP3 connection lost"); else { /* build the complete command */ if (args) sprintf (s,"%s %s",command,args); else strcpy (s,command); if (stream->debug) mail_dlog (s,LOCAL->sensitive); strcat (s,"\015\012"); /* send the command */ ret = net_soutr (LOCAL->netstream,s) ? pop3_reply (stream) : pop3_fake (stream,"POP3 connection broken in command"); } fs_give ((void **) &s); mail_unlock (stream); /* unlock stream */ return ret; } /* Post Office Protocol 3 get reply * Accepts: MAIL stream * Returns: T if success reply, NIL if error reply */ long pop3_reply (MAILSTREAM *stream) { char *s; /* flush old reply */ if (LOCAL->response) fs_give ((void **) &LOCAL->response); /* get reply */ if (!(LOCAL->response = net_getline (LOCAL->netstream))) return pop3_fake (stream,"POP3 connection broken in response"); if (stream->debug) mm_dlog (LOCAL->response); LOCAL->reply = (s = strchr (LOCAL->response,' ')) ? s + 1 : LOCAL->response; /* return success or failure */ return (*LOCAL->response =='+') ? T : NIL; } /* Post Office Protocol 3 set fake error * Accepts: MAIL stream * error text * Returns: NIL, always */ long pop3_fake (MAILSTREAM *stream,char *text) { mm_notify (stream,text,BYE); /* send bye alert */ if (LOCAL->netstream) net_close (LOCAL->netstream); LOCAL->netstream = NIL; /* farewell, dear TCP stream */ /* flush any old reply */ if (LOCAL->response) fs_give ((void **) &LOCAL->response); LOCAL->reply = text; /* set up pseudo-reply string */ return NIL; /* return error code */ } alpine-2.10+dfsg/imap/src/c-client/env.h0000600000175000017500000000274311512502124021516 0ustar paulproteuspaulproteus/* ======================================================================== * Copyright 1988-2008 University of Washington * * Licensed under the Apache License, Version 2.0 (the "License"); * you may not use this file except in compliance with the License. * You may obtain a copy of the License at * * http://www.apache.org/licenses/LICENSE-2.0 * * * ======================================================================== */ /* * Program: Environment routines * * Author: Mark Crispin * UW Technology * University of Washington * Seattle, WA 98195 * Internet: MRC@Washington.EDU * * Date: 1 August 1988 * Last Edited: 13 February 2008 */ /* Function prototypes */ long pmatch_full (unsigned char *s,unsigned char *pat,unsigned char delim); long dmatch (unsigned char *s,unsigned char *pat,unsigned char delim); void *env_parameters (long function,void *value); void rfc822_date (char *date); void rfc822_timezone (char *s,void *t); void internal_date (char *date); long server_input_wait (long seconds); void server_init (char *server,char *service,char *sasl, void *clkint,void *kodint,void *hupint,void *trmint, void *staint); long server_login (char *user,char *pass,char *authuser,int argc,char *argv[]); long authserver_login (char *user,char *authuser,int argc,char *argv[]); long anonymous_login (int argc,char *argv[]); char *mylocalhost (void); char *myhomedir (void); char *mailboxfile (char *dst,char *name); MAILSTREAM *default_proto (long type); alpine-2.10+dfsg/imap/src/c-client/nntp.c0000600000175000017500000022524611512502124021705 0ustar paulproteuspaulproteus/* ======================================================================== * Copyright 1988-2007 University of Washington * * Licensed under the Apache License, Version 2.0 (the "License"); * you may not use this file except in compliance with the License. * You may obtain a copy of the License at * * http://www.apache.org/licenses/LICENSE-2.0 * * * ======================================================================== */ /* * Program: Network News Transfer Protocol (NNTP) routines * * Author: Mark Crispin * Networks and Distributed Computing * Computing & Communications * University of Washington * Administration Building, AG-44 * Seattle, WA 98195 * Internet: MRC@CAC.Washington.EDU * * Date: 10 February 1992 * Last Edited: 6 September 2007 */ #include #include #include "c-client.h" #include "newsrc.h" #include "netmsg.h" #include "flstring.h" /* Constants */ #define NNTPSSLPORT (long) 563 /* assigned SSL TCP contact port */ #define NNTPGREET (long) 200 /* NNTP successful greeting */ /* NNTP successful greeting w/o posting priv */ #define NNTPGREETNOPOST (long) 201 #define NNTPEXTOK (long) 202 /* NNTP extensions OK */ #define NNTPGOK (long) 211 /* NNTP group selection OK */ #define NNTPGLIST (long) 215 /* NNTP group list being returned */ #define NNTPARTICLE (long) 220 /* NNTP article file */ #define NNTPHEAD (long) 221 /* NNTP header text */ #define NNTPBODY (long) 222 /* NNTP body text */ #define NNTPOVER (long) 224 /* NNTP overview text */ #define NNTPOK (long) 240 /* NNTP OK code */ #define NNTPAUTHED (long) 281 /* NNTP successful authentication */ /* NNTP successful authentication with data */ #define NNTPAUTHEDDATA (long) 282 #define NNTPREADY (long) 340 /* NNTP ready for data */ #define NNTPWANTAUTH2 (long) 380/* NNTP authentication needed (old) */ #define NNTPWANTPASS (long) 381 /* NNTP password needed */ #define NNTPTLSSTART (long) 382 /* NNTP continue with TLS negotiation */ #define NNTPCHALLENGE (long) 383/* NNTP challenge, want response */ #define NNTPSOFTFATAL (long) 400/* NNTP soft fatal code */ #define NNTPWANTAUTH (long) 480 /* NNTP authentication needed */ #define NNTPBADCMD (long) 500 /* NNTP unrecognized command */ #define IDLETIMEOUT (long) 3 /* defined in NNTPEXT WG base draft */ /* NNTP I/O stream local data */ typedef struct nntp_local { SENDSTREAM *nntpstream; /* NNTP stream for I/O */ unsigned int dirty : 1; /* disk copy of .newsrc needs updating */ unsigned int tlsflag : 1; /* TLS session */ unsigned int tlssslv23 : 1; /* TLS using SSLv23 client method */ unsigned int notlsflag : 1; /* TLS not used in session */ unsigned int sslflag : 1; /* SSL session */ unsigned int novalidate : 1; /* certificate not validated */ unsigned int xover : 1; /* supports XOVER */ unsigned int xhdr : 1; /* supports XHDR */ char *name; /* remote newsgroup name */ char *user; /* mailbox user */ char *newsrc; /* newsrc file */ char *over_fmt; /* overview format */ unsigned long msgno; /* current text message number */ FILE *txt; /* current text */ unsigned long txtsize; /* current text size */ } NNTPLOCAL; /* Convenient access to local data */ #define LOCAL ((NNTPLOCAL *) stream->local) /* Convenient access to protocol-specific data */ #define NNTP stream->protocol.nntp /* Convenient access to extensions */ #define EXTENSION LOCAL->nntpstream->protocol.nntp.ext /* Function prototypes */ DRIVER *nntp_valid (char *name); DRIVER *nntp_isvalid (char *name,char *mbx); void *nntp_parameters (long function,void *value); void nntp_scan (MAILSTREAM *stream,char *ref,char *pat,char *contents); void nntp_list (MAILSTREAM *stream,char *ref,char *pat); void nntp_lsub (MAILSTREAM *stream,char *ref,char *pat); long nntp_canonicalize (char *ref,char *pat,char *pattern,char *wildmat); long nntp_subscribe (MAILSTREAM *stream,char *mailbox); long nntp_unsubscribe (MAILSTREAM *stream,char *mailbox); long nntp_create (MAILSTREAM *stream,char *mailbox); long nntp_delete (MAILSTREAM *stream,char *mailbox); long nntp_rename (MAILSTREAM *stream,char *old,char *newname); long nntp_status (MAILSTREAM *stream,char *mbx,long flags); long nntp_getmap (MAILSTREAM *stream,char *name, unsigned long first,unsigned long last, unsigned long rnmsgs,unsigned long nmsgs,char *tmp); MAILSTREAM *nntp_mopen (MAILSTREAM *stream); void nntp_mclose (MAILSTREAM *stream,long options); void nntp_fetchfast (MAILSTREAM *stream,char *sequence,long flags); void nntp_flags (MAILSTREAM *stream,char *sequence,long flags); long nntp_overview (MAILSTREAM *stream,overview_t ofn); long nntp_parse_overview (OVERVIEW *ov,char *text,MESSAGECACHE *elt); long nntp_over (MAILSTREAM *stream,char *sequence); char *nntp_header (MAILSTREAM *stream,unsigned long msgno,unsigned long *size, long flags); long nntp_text (MAILSTREAM *stream,unsigned long msgno,STRING *bs,long flags); FILE *nntp_article (MAILSTREAM *stream,char *msgid,unsigned long *size, unsigned long *hsiz); void nntp_flagmsg (MAILSTREAM *stream,MESSAGECACHE *elt); long nntp_search (MAILSTREAM *stream,char *charset,SEARCHPGM *pgm,long flags); long nntp_search_msg (MAILSTREAM *stream,unsigned long msgno,SEARCHPGM *pgm, OVERVIEW *ov); unsigned long *nntp_sort (MAILSTREAM *stream,char *charset,SEARCHPGM *spg, SORTPGM *pgm,long flags); SORTCACHE **nntp_sort_loadcache (MAILSTREAM *stream,SORTPGM *pgm, unsigned long start,unsigned long last, long flags); THREADNODE *nntp_thread (MAILSTREAM *stream,char *type,char *charset, SEARCHPGM *spg,long flags); long nntp_ping (MAILSTREAM *stream); void nntp_check (MAILSTREAM *stream); long nntp_expunge (MAILSTREAM *stream,char *sequence,long options); long nntp_copy (MAILSTREAM *stream,char *sequence,char *mailbox,long options); long nntp_append (MAILSTREAM *stream,char *mailbox,append_t af,void *data); long nntp_extensions (SENDSTREAM *stream,long flags); long nntp_send (SENDSTREAM *stream,char *command,char *args); long nntp_send_work (SENDSTREAM *stream,char *command,char *args); long nntp_send_auth (SENDSTREAM *stream,long flags); long nntp_send_auth_work (SENDSTREAM *stream,NETMBX *mb,char *pwd,long flags); void *nntp_challenge (void *s,unsigned long *len); long nntp_response (void *s,char *response,unsigned long size); long nntp_reply (SENDSTREAM *stream); long nntp_fake (SENDSTREAM *stream,char *text); long nntp_soutr (void *stream,char *s); /* Driver dispatch used by MAIL */ DRIVER nntpdriver = { "nntp", /* driver name */ /* driver flags */ #ifdef INADEQUATE_MEMORY DR_LOWMEM | #endif DR_NEWS|DR_READONLY|DR_NOFAST|DR_NAMESPACE|DR_CRLF|DR_RECYCLE|DR_XPOINT | DR_NOINTDATE|DR_NONEWMAIL|DR_HALFOPEN, (DRIVER *) NIL, /* next driver */ nntp_valid, /* mailbox is valid for us */ nntp_parameters, /* manipulate parameters */ nntp_scan, /* scan mailboxes */ nntp_list, /* find mailboxes */ nntp_lsub, /* find subscribed mailboxes */ nntp_subscribe, /* subscribe to mailbox */ nntp_unsubscribe, /* unsubscribe from mailbox */ nntp_create, /* create mailbox */ nntp_delete, /* delete mailbox */ nntp_rename, /* rename mailbox */ nntp_status, /* status of mailbox */ nntp_mopen, /* open mailbox */ nntp_mclose, /* close mailbox */ nntp_fetchfast, /* fetch message "fast" attributes */ nntp_flags, /* fetch message flags */ nntp_overview, /* fetch overview */ NIL, /* fetch message structure */ nntp_header, /* fetch message header */ nntp_text, /* fetch message text */ NIL, /* fetch message */ NIL, /* unique identifier */ NIL, /* message number from UID */ NIL, /* modify flags */ nntp_flagmsg, /* per-message modify flags */ nntp_search, /* search for message based on criteria */ nntp_sort, /* sort messages */ nntp_thread, /* thread messages */ nntp_ping, /* ping mailbox to see if still alive */ nntp_check, /* check for new messages */ nntp_expunge, /* expunge deleted messages */ nntp_copy, /* copy messages to another mailbox */ nntp_append, /* append string message to mailbox */ NIL /* garbage collect stream */ }; /* prototype stream */ MAILSTREAM nntpproto = {&nntpdriver}; /* driver parameters */ static unsigned long nntp_maxlogintrials = MAXLOGINTRIALS; static long nntp_port = 0; static long nntp_sslport = 0; static unsigned long nntp_range = 0; static long nntp_hidepath = 0; /* NNTP validate mailbox * Accepts: mailbox name * Returns: our driver if name is valid, NIL otherwise */ DRIVER *nntp_valid (char *name) { char tmp[MAILTMPLEN]; return nntp_isvalid (name,tmp); } /* NNTP validate mailbox work routine * Accepts: mailbox name * buffer for returned mailbox name * Returns: our driver if name is valid, NIL otherwise */ DRIVER *nntp_isvalid (char *name,char *mbx) { NETMBX mb; if (!mail_valid_net_parse (name,&mb) || strcmp (mb.service,nntpdriver.name)|| mb.anoflag) return NIL; if (mb.mailbox[0] != '#') strcpy (mbx,mb.mailbox); /* namespace format name */ else if ((mb.mailbox[1] == 'n') && (mb.mailbox[2] == 'e') && (mb.mailbox[3] == 'w') && (mb.mailbox[4] == 's') && (mb.mailbox[5] == '.')) strcpy (mbx,mb.mailbox+6); else return NIL; /* bogus name */ return &nntpdriver; } /* News manipulate driver parameters * Accepts: function code * function-dependent value * Returns: function-dependent return value */ void *nntp_parameters (long function,void *value) { switch ((int) function) { case SET_MAXLOGINTRIALS: nntp_maxlogintrials = (unsigned long) value; break; case GET_MAXLOGINTRIALS: value = (void *) nntp_maxlogintrials; break; case SET_NNTPPORT: nntp_port = (long) value; break; case GET_NNTPPORT: value = (void *) nntp_port; break; case SET_SSLNNTPPORT: nntp_sslport = (long) value; break; case GET_SSLNNTPPORT: value = (void *) nntp_sslport; break; case SET_NNTPRANGE: nntp_range = (unsigned long) value; break; case GET_NNTPRANGE: value = (void *) nntp_range; break; case SET_NNTPHIDEPATH: nntp_hidepath = (long) value; break; case GET_NNTPHIDEPATH: value = (void *) nntp_hidepath; break; case GET_NEWSRC: if (value) value = (void *) ((NNTPLOCAL *) ((MAILSTREAM *) value)->local)->newsrc; break; case GET_IDLETIMEOUT: value = (void *) IDLETIMEOUT; break; case ENABLE_DEBUG: if (value) ((NNTPLOCAL *) ((MAILSTREAM *) value)->local)->nntpstream->debug = T; break; case DISABLE_DEBUG: if (value) ((NNTPLOCAL *) ((MAILSTREAM *) value)->local)->nntpstream->debug = NIL; break; default: value = NIL; /* error case */ break; } return value; } /* NNTP mail scan mailboxes for string * Accepts: mail stream * reference * pattern to search * string to scan */ void nntp_scan (MAILSTREAM *stream,char *ref,char *pat,char *contents) { char tmp[MAILTMPLEN]; if (nntp_canonicalize (ref,pat,tmp,NIL)) mm_log ("Scan not valid for NNTP mailboxes",ERROR); } /* NNTP list newsgroups * Accepts: mail stream * reference * pattern to search */ void nntp_list (MAILSTREAM *stream,char *ref,char *pat) { MAILSTREAM *st = stream; char *s,*t,*lcl,pattern[MAILTMPLEN],name[MAILTMPLEN],wildmat[MAILTMPLEN]; int showuppers = pat[strlen (pat) - 1] == '%'; if (!*pat) { if (nntp_canonicalize (ref,"*",pattern,NIL)) { /* tie off name at root */ if ((s = strchr (pattern,'}')) && (s = strchr (s+1,'.'))) *++s = '\0'; else pattern[0] = '\0'; mm_list (stream,'.',pattern,NIL); } } /* ask server for open newsgroups */ else if (nntp_canonicalize (ref,pat,pattern,wildmat) && ((stream && LOCAL && LOCAL->nntpstream) || (stream = mail_open (NIL,pattern,OP_HALFOPEN|OP_SILENT))) && ((nntp_send (LOCAL->nntpstream,"LIST ACTIVE", wildmat[0] ? wildmat : NIL) == NNTPGLIST) || (nntp_send (LOCAL->nntpstream,"LIST",NIL) == NNTPGLIST))) { /* namespace format name? */ if (*(lcl = strchr (strcpy (name,pattern),'}') + 1) == '#') lcl += 6; /* process data until we see final dot */ while (s = net_getline (LOCAL->nntpstream->netstream)) { if ((*s == '.') && !s[1]){/* end of text */ fs_give ((void **) &s); break; } if (t = strchr (s,' ')) { /* tie off after newsgroup name */ *t = '\0'; strcpy (lcl,s); /* make full form of name */ /* report if match */ if (pmatch_full (name,pattern,'.')) mm_list (stream,'.',name,NIL); else while (showuppers && (t = strrchr (lcl,'.'))) { *t = '\0'; /* tie off the name */ if (pmatch_full (name,pattern,'.')) mm_list (stream,'.',name,LATT_NOSELECT); } } fs_give ((void **) &s); /* clean up */ } if (stream != st) mail_close (stream); } } /* NNTP list subscribed newsgroups * Accepts: mail stream * reference * pattern to search */ void nntp_lsub (MAILSTREAM *stream,char *ref,char *pat) { void *sdb = NIL; char *s,mbx[MAILTMPLEN]; /* return data from newsrc */ if (nntp_canonicalize (ref,pat,mbx,NIL)) newsrc_lsub (stream,mbx); if (*pat == '{') { /* if remote pattern, must be NNTP */ if (!nntp_valid (pat)) return; ref = NIL; /* good NNTP pattern, punt reference */ } /* if remote reference, must be valid NNTP */ if (ref && (*ref == '{') && !nntp_valid (ref)) return; /* kludgy application of reference */ if (ref && *ref) sprintf (mbx,"%s%s",ref,pat); else strcpy (mbx,pat); if (s = sm_read (&sdb)) do if (nntp_valid (s) && pmatch (s,mbx)) mm_lsub (stream,NIL,s,NIL); while (s = sm_read (&sdb)); /* until no more subscriptions */ } /* NNTP canonicalize newsgroup name * Accepts: reference * pattern * returned single pattern * returned wildmat pattern * Returns: T on success, NIL on failure */ long nntp_canonicalize (char *ref,char *pat,char *pattern,char *wildmat) { char *s; DRIVER *ret; if (ref && *ref) { /* have a reference */ if (!nntp_valid (ref)) return NIL; strcpy (pattern,ref); /* copy reference to pattern */ /* # overrides mailbox field in reference */ if (*pat == '#') strcpy (strchr (pattern,'}') + 1,pat); /* pattern starts, reference ends, with . */ else if ((*pat == '.') && (pattern[strlen (pattern) - 1] == '.')) strcat (pattern,pat + 1); /* append, omitting one of the period */ else strcat (pattern,pat); /* anything else is just appended */ } else strcpy (pattern,pat); /* just have basic name */ if ((ret = wildmat ? /* if valid and wildmat */ nntp_isvalid (pattern,wildmat) : nntp_valid (pattern)) && wildmat) { /* don't return wildmat if specials present */ if (strpbrk (wildmat,",?![\\]")) wildmat[0] = '\0'; /* replace all % with * */ for (s = wildmat; s = strchr (s,'%'); *s = '*'); } return ret ? LONGT : NIL; } /* NNTP subscribe to mailbox * Accepts: mail stream * mailbox to add to subscription list * Returns: T on success, NIL on failure */ long nntp_subscribe (MAILSTREAM *stream,char *mailbox) { char mbx[MAILTMPLEN]; return nntp_isvalid (mailbox,mbx) ? newsrc_update (stream,mbx,':') : NIL; } /* NNTP unsubscribe to mailbox * Accepts: mail stream * mailbox to delete from subscription list * Returns: T on success, NIL on failure */ long nntp_unsubscribe (MAILSTREAM *stream,char *mailbox) { char mbx[MAILTMPLEN]; return nntp_isvalid (mailbox,mbx) ? newsrc_update (stream,mbx,'!') : NIL; } /* NNTP create mailbox * Accepts: mail stream * mailbox name to create * Returns: T on success, NIL on failure */ long nntp_create (MAILSTREAM *stream,char *mailbox) { return NIL; /* never valid for NNTP */ } /* NNTP delete mailbox * mailbox name to delete * Returns: T on success, NIL on failure */ long nntp_delete (MAILSTREAM *stream,char *mailbox) { return NIL; /* never valid for NNTP */ } /* NNTP rename mailbox * Accepts: mail stream * old mailbox name * new mailbox name * Returns: T on success, NIL on failure */ long nntp_rename (MAILSTREAM *stream,char *old,char *newname) { return NIL; /* never valid for NNTP */ } /* NNTP status * Accepts: mail stream * mailbox name * status flags * Returns: T on success, NIL on failure */ long nntp_status (MAILSTREAM *stream,char *mbx,long flags) { MAILSTATUS status; NETMBX mb; unsigned long i,j,k,rnmsgs; long ret = NIL; char *s,*name,*state,tmp[MAILTMPLEN]; char *old = (stream && !stream->halfopen) ? LOCAL->name : NIL; MAILSTREAM *tstream = NIL; if (!(mail_valid_net_parse (mbx,&mb) && !strcmp (mb.service,"nntp") && *mb.mailbox && ((mb.mailbox[0] != '#') || ((mb.mailbox[1] == 'n') && (mb.mailbox[2] == 'e') && (mb.mailbox[3] == 'w') && (mb.mailbox[4] == 's') && (mb.mailbox[5] == '.'))))) { sprintf (tmp,"Invalid NNTP name %s",mbx); mm_log (tmp,ERROR); return NIL; } /* note mailbox name */ name = (*mb.mailbox == '#') ? mb.mailbox+6 : mb.mailbox; /* stream to reuse? */ if (!(stream && LOCAL->nntpstream && mail_usable_network_stream (stream,mbx)) && !(tstream = stream = mail_open (NIL,mbx,OP_HALFOPEN|OP_SILENT| ((flags & SA_MULNEWSRC) ? OP_MULNEWSRC : NIL)))) return NIL; /* can't reuse or make a new one */ if (nntp_send (LOCAL->nntpstream,"GROUP",name) == NNTPGOK) { status.flags = flags; /* status validity flags */ k = strtoul (LOCAL->nntpstream->reply + 4,&s,10); i = strtoul (s,&s,10); /* first assigned UID */ /* next UID to be assigned */ status.uidnext = (j = strtoul (s,NIL,10)) + 1; /* maximum number of messages */ rnmsgs = status.messages = (i | j) ? status.uidnext - i : 0; if (k > status.messages) { /* check for absurdity */ sprintf (tmp,"NNTP SERVER BUG (impossible message count): %lu > %lu", k,status.messages); mm_log (tmp,WARN); } /* restrict article range if needed */ if (nntp_range && (status.messages > nntp_range)) { i = status.uidnext - (status.messages = nntp_range); if (k > nntp_range) k = nntp_range; } /* initially zero */ status.recent = status.unseen = 0; if (!status.messages); /* empty case */ /* use server guesstimate in simple case */ else if (!(flags & (SA_RECENT | SA_UNSEEN))) status.messages = k; /* have newsrc state? */ else if (state = newsrc_state (stream,name)) { /* yes, get the UID/sequence map */ if (nntp_getmap (stream,name,i,status.uidnext - 1,rnmsgs, status.messages,tmp)) { /* calculate true count */ for (status.messages = 0; (s = net_getline (LOCAL->nntpstream->netstream)) && strcmp (s,"."); ) { /* only count if in range */ if (((k = atol (s)) >= i) && (k < status.uidnext)) { newsrc_check_uid (state,k,&status.recent,&status.unseen); status.messages++; } fs_give ((void **) &s); } if (s) fs_give ((void **) &s); } /* assume c-client/NNTP map is entire range */ else while (i < status.uidnext) newsrc_check_uid (state,i++,&status.recent,&status.unseen); fs_give ((void **) &state); } /* no .newsrc state, all messages new */ else status.recent = status.unseen = status.messages; /* UID validity is a constant */ status.uidvalidity = stream->uid_validity; /* pass status to main program */ mm_status (stream,mbx,&status); ret = T; /* succes */ } /* flush temporary stream */ if (tstream) mail_close (tstream); /* else reopen old newsgroup */ else if (old && nntp_send (LOCAL->nntpstream,"GROUP",old) != NNTPGOK) { mm_log (LOCAL->nntpstream->reply,ERROR); stream->halfopen = T; /* go halfopen */ } return ret; /* success */ } /* NNTP get map * Accepts: stream * newsgroup name * first UID in map range * last UID in map range * reported total number of messages in newsgroup * calculated number of messages in range * temporary buffer * Returns: T on success, NIL on failure */ long nntp_getmap (MAILSTREAM *stream,char *name, unsigned long first,unsigned long last, unsigned long rnmsgs,unsigned long nmsgs,char *tmp) { short trylistgroup = NIL; if (rnmsgs > (nmsgs * 8)) /* small subrange? */ trylistgroup = T; /* yes, can try LISTGROUP if [X]HDR fails */ else switch ((int) nntp_send (LOCAL->nntpstream,"LISTGROUP",name)) { case NNTPGOK: /* got data */ return LONGT; default: /* else give up if server claims LISTGROUP */ if (EXTENSION.listgroup) return NIL; } /* build range */ sprintf (tmp,"%lu-%lu",first,last); if (EXTENSION.hdr) /* have HDR extension? */ return (nntp_send (LOCAL->nntpstream,"HDR Date",tmp) == NNTPHEAD) ? LONGT : NIL; if (LOCAL->xhdr) /* try the experimental extension then */ switch ((int) nntp_send (LOCAL->nntpstream,"XHDR Date",tmp)) { case NNTPHEAD: /* got an overview? */ return LONGT; case NNTPBADCMD: /* unknown command? */ LOCAL->xhdr = NIL; /* disable future XHDR attempts */ } if (trylistgroup && /* no [X]HDR, maybe do LISTGROUP after all */ (nntp_send (LOCAL->nntpstream,"LISTGROUP",name) == NNTPGOK)) return LONGT; return NIL; } /* NNTP open * Accepts: stream to open * Returns: stream on success, NIL on failure */ MAILSTREAM *nntp_mopen (MAILSTREAM *stream) { unsigned long i,j,k,nmsgs,rnmsgs; char *s,*mbx,tmp[MAILTMPLEN]; FILE *f; NETMBX mb; char *newsrc = (char *) mail_parameters (NIL,GET_NEWSRC,NIL); newsrcquery_t nq = (newsrcquery_t) mail_parameters (NIL,GET_NEWSRCQUERY,NIL); SENDSTREAM *nstream = NIL; /* return prototype for OP_PROTOTYPE call */ if (!stream) return &nntpproto; mail_valid_net_parse (stream->mailbox,&mb); /* note mailbox anme */ mbx = (*mb.mailbox == '#') ? mb.mailbox+6 : mb.mailbox; if (LOCAL) { /* recycle stream */ nstream = LOCAL->nntpstream;/* remember NNTP protocol stream */ sprintf (tmp,"Reusing connection to %s",net_host (nstream->netstream)); if (!stream->silent) mm_log (tmp,(long) NIL); if (stream->rdonly) mb.readonlyflag = T; if (LOCAL->tlsflag) mb.tlsflag = T; if (LOCAL->tlssslv23) mb.tlssslv23 = T; if (LOCAL->notlsflag) mb.notlsflag = T; if (LOCAL->sslflag) mb.sslflag = T; if (LOCAL->novalidate) mb.novalidate = T; if (LOCAL->nntpstream->loser) mb.loser = T; if (stream->secure) mb.secflag = T; LOCAL->nntpstream = NIL; /* keep nntp_mclose() from punting it */ nntp_mclose (stream,NIL); /* do close action */ stream->dtb = &nntpdriver; /* reattach this driver */ } /* copy flags */ if (mb.dbgflag) stream->debug = T; if (mb.readonlyflag) stream->rdonly = T; if (mb.secflag) stream->secure = T; mb.trysslflag = stream->tryssl = (mb.trysslflag || stream->tryssl) ? T : NIL; if (!nstream) { /* open NNTP now if not already open */ char *hostlist[2]; hostlist[0] = strcpy (tmp,mb.host); if (mb.port || nntp_port) sprintf (tmp + strlen (tmp),":%lu",mb.port ? mb.port : nntp_port); if (mb.tlsflag) strcat (tmp,"/tls"); if (mb.tlssslv23) strcat (tmp,"/tls-sslv23"); if (mb.notlsflag) strcat (tmp,"/notls"); if (mb.sslflag) strcat (tmp,"/ssl"); if (mb.novalidate) strcat (tmp,"/novalidate-cert"); if (mb.loser) strcat (tmp,"/loser"); if (mb.secflag) strcat (tmp,"/secure"); if (mb.user[0]) sprintf (tmp + strlen (tmp),"/user=\"%s\"",mb.user); hostlist[1] = NIL; if (!(nstream = nntp_open (hostlist,NOP_READONLY | (stream->debug ? NOP_DEBUG : NIL)))) return NIL; } /* always zero messages if halfopen */ if (stream->halfopen) i = j = k = rnmsgs = nmsgs = 0; /* otherwise open the newsgroup */ else if (nntp_send (nstream,"GROUP",mbx) == NNTPGOK) { k = strtoul (nstream->reply + 4,&s,10); i = strtoul (s,&s,10); stream->uid_last = j = strtoul (s,&s,10); rnmsgs = nmsgs = (i | j) ? 1 + j - i : 0; if (k > nmsgs) { /* check for absurdity */ sprintf (tmp,"NNTP SERVER BUG (impossible message count): %lu > %lu", k,nmsgs); mm_log (tmp,WARN); } /* restrict article range if needed */ if (nntp_range && (nmsgs > nntp_range)) i = 1 + j - (nmsgs = nntp_range); } else { /* no such newsgroup */ mm_log (nstream->reply,ERROR); nntp_close (nstream); /* punt stream */ return NIL; } /* instantiate local data */ stream->local = memset (fs_get (sizeof (NNTPLOCAL)),0,sizeof (NNTPLOCAL)); LOCAL->nntpstream = nstream; /* save state for future recycling */ if (mb.tlsflag) LOCAL->tlsflag = T; if (mb.tlssslv23) LOCAL->tlssslv23 = T; if (mb.notlsflag) LOCAL->notlsflag = T; if (mb.sslflag) LOCAL->sslflag = T; if (mb.novalidate) LOCAL->novalidate = T; if (mb.loser) LOCAL->nntpstream->loser = T; /* assume present until proven otherwise */ LOCAL->xhdr = LOCAL->xover = T; LOCAL->name = cpystr (mbx); /* copy newsgroup name */ if (stream->mulnewsrc) { /* want to use multiple .newsrc files? */ strcpy (tmp,newsrc); s = tmp + strlen (tmp); /* end of string */ *s++ = '-'; /* hyphen delimiter and host */ lcase (strcpy (s,(long) mail_parameters (NIL,GET_NEWSRCCANONHOST,NIL) ? net_host (nstream->netstream) : mb.host)); LOCAL->newsrc = cpystr (nq ? (*nq) (stream,tmp,newsrc) : tmp); } else LOCAL->newsrc = cpystr (newsrc); if (mb.user[0]) LOCAL->user = cpystr (mb.user); stream->sequence++; /* bump sequence number */ stream->rdonly = stream->perm_deleted = T; /* UIDs are always valid */ stream->uid_validity = 0xbeefface; sprintf (tmp,"{%s:%lu/nntp",(long) mail_parameters (NIL,GET_TRUSTDNS,NIL) ? net_host (nstream->netstream) : mb.host, net_port (nstream->netstream)); if (LOCAL->tlsflag) strcat (tmp,"/tls"); if (LOCAL->tlssslv23) strcat (tmp,"/tls-sslv23"); if (LOCAL->notlsflag) strcat (tmp,"/notls"); if (LOCAL->sslflag) strcat (tmp,"/ssl"); if (LOCAL->novalidate) strcat (tmp,"/novalidate-cert"); if (LOCAL->nntpstream->loser) strcat (tmp,"/loser"); if (stream->secure) strcat (tmp,"/secure"); if (stream->rdonly) strcat (tmp,"/readonly"); if (LOCAL->user) sprintf (tmp + strlen (tmp),"/user=\"%s\"",LOCAL->user); if (stream->halfopen) strcat (tmp,"}"); else sprintf (tmp + strlen (tmp),"}#news.%s",mbx); fs_give ((void **) &stream->mailbox); stream->mailbox = cpystr (tmp); if (EXTENSION.over && /* get overview format if have OVER */ (nntp_send (LOCAL->nntpstream,"LIST","OVERVIEW.FMT") == NNTPGLIST) && (f = netmsg_slurp (LOCAL->nntpstream->netstream,&k,NIL))) { fread (LOCAL->over_fmt = (char *) fs_get ((size_t) k + 3), (size_t) 1,(size_t) k,f); LOCAL->over_fmt[k] = '\0'; fclose (f); /* flush temp file */ } if (nmsgs) { /* if any messages exist */ short silent = stream->silent; stream->silent = T; /* don't notify main program yet */ mail_exists (stream,nmsgs); /* silently set the cache to the guesstimate */ /* get UID/sequence map, nuke holes */ if (nntp_getmap (stream,mbx,i,j,rnmsgs,nmsgs,tmp)) { for (nmsgs = 0; /* calculate true count */ (s = net_getline (nstream->netstream)) && strcmp (s,"."); ) { if ((k = atol (s)) > j){/* discard too high article numbers */ sprintf (tmp,"NNTP SERVER BUG (out of range article ID): %lu > %lu", k,j); mm_notify (stream,tmp,NIL); stream->unhealthy = T; } else if (k >= i) { /* silently ignore too-low article numbers */ /* guard against server returning extra msgs */ if (nmsgs == stream->nmsgs) mail_exists (stream,nmsgs+1); /* create elt for this message, set UID */ mail_elt (stream,++nmsgs)->private.uid = k; } fs_give ((void **) &s); } if (s) fs_give ((void **) &s); } /* assume c-client/NNTP map is entire range */ else for (k = 1; k <= nmsgs; k++) mail_elt (stream,k)->private.uid = i++; stream->unhealthy = NIL; /* set healthy */ stream->nmsgs = 0; /* whack it back down */ stream->silent = silent; /* restore old silent setting */ mail_exists (stream,nmsgs); /* notify upper level that messages exist */ /* read .newsrc entries */ mail_recent (stream,newsrc_read (mbx,stream)); } else { /* empty newsgroup or halfopen */ if (!(stream->silent || stream->halfopen)) { sprintf (tmp,"Newsgroup %s is empty",mbx); mm_log (tmp,WARN); } mail_exists (stream,(long) 0); mail_recent (stream,(long) 0); } return stream; /* return stream to caller */ } /* NNTP close * Accepts: MAIL stream * option flags */ void nntp_mclose (MAILSTREAM *stream,long options) { unsigned long i; MESSAGECACHE *elt; if (LOCAL) { /* only if a file is open */ nntp_check (stream); /* dump final checkpoint */ if (LOCAL->over_fmt) fs_give ((void **) &LOCAL->over_fmt); if (LOCAL->name) fs_give ((void **) &LOCAL->name); if (LOCAL->user) fs_give ((void **) &LOCAL->user); if (LOCAL->newsrc) fs_give ((void **) &LOCAL->newsrc); if (LOCAL->txt) fclose (LOCAL->txt); /* close NNTP connection */ if (LOCAL->nntpstream) nntp_close (LOCAL->nntpstream); for (i = 1; i <= stream->nmsgs; i++) if ((elt = mail_elt (stream,i))->private.spare.ptr) fs_give ((void **) &elt->private.spare.ptr); /* nuke the local data */ fs_give ((void **) &stream->local); stream->dtb = NIL; /* log out the DTB */ } } /* NNTP fetch fast information * Accepts: MAIL stream * sequence * option flags * This is ugly and slow */ void nntp_fetchfast (MAILSTREAM *stream,char *sequence,long flags) { unsigned long i; MESSAGECACHE *elt; /* get sequence */ if (stream && LOCAL && ((flags & FT_UID) ? mail_uid_sequence (stream,sequence) : mail_sequence (stream,sequence))) for (i = 1; i <= stream->nmsgs; i++) { if ((elt = mail_elt (stream,i))->sequence && (elt->valid = T) && !(elt->day && elt->rfc822_size)) { ENVELOPE **env = NIL; ENVELOPE *e = NIL; if (!stream->scache) env = &elt->private.msg.env; else if (stream->msgno == i) env = &stream->env; else env = &e; if (!*env || !elt->rfc822_size) { STRING bs; unsigned long hs; char *ht = (*stream->dtb->header) (stream,i,&hs,NIL); /* need to make an envelope? */ if (!*env) rfc822_parse_msg (env,NIL,ht,hs,NIL,BADHOST, stream->dtb->flags); /* need message size too, ugh */ if (!elt->rfc822_size) { (*stream->dtb->text) (stream,i,&bs,FT_PEEK); elt->rfc822_size = hs + SIZE (&bs) - GETPOS (&bs); } } /* if need date, have date in envelope? */ if (!elt->day && *env && (*env)->date) mail_parse_date (elt,(*env)->date); /* sigh, fill in bogus default */ if (!elt->day) elt->day = elt->month = 1; mail_free_envelope (&e); } } } /* NNTP fetch flags * Accepts: MAIL stream * sequence * option flags */ void nntp_flags (MAILSTREAM *stream,char *sequence,long flags) { unsigned long i; if ((flags & FT_UID) ? /* validate all elts */ mail_uid_sequence (stream,sequence) : mail_sequence (stream,sequence)) for (i = 1; i <= stream->nmsgs; i++) mail_elt (stream,i)->valid = T; } /* NNTP fetch overview * Accepts: MAIL stream, sequence bits set * overview return function * Returns: T if successful, NIL otherwise */ long nntp_overview (MAILSTREAM *stream,overview_t ofn) { unsigned long i,j,k,uid; char c,*s,*t,*v,tmp[MAILTMPLEN]; MESSAGECACHE *elt; OVERVIEW ov; if (!LOCAL->nntpstream->netstream) return NIL; /* scan sequence to load cache */ for (i = 1; i <= stream->nmsgs; i++) /* have cached overview yet? */ if ((elt = mail_elt (stream,i))->sequence && !elt->private.spare.ptr) { for (j = i + 1; /* no, find end of cache gap range */ (j <= stream->nmsgs) && (elt = mail_elt (stream,j))->sequence && !elt->private.spare.ptr; j++); /* make NNTP range */ sprintf (tmp,(i == (j - 1)) ? "%lu" : "%lu-%lu",mail_uid (stream,i), mail_uid (stream,j - 1)); i = j; /* advance beyond gap */ /* ask server for overview data to cache */ if (nntp_over (stream,tmp)) { while ((s = net_getline (LOCAL->nntpstream->netstream)) && strcmp (s,".")) { /* death to embedded newlines */ for (t = v = s; c = *v++;) if ((c != '\012') && (c != '\015')) *t++ = c; *t++ = '\0'; /* tie off string in case it was shortened */ /* cache the overview if found its sequence */ if ((uid = atol (s)) && (k = mail_msgno (stream,uid)) && (t = strchr (s,'\t'))) { if ((elt = mail_elt (stream,k))->private.spare.ptr) fs_give ((void **) &elt->private.spare.ptr); elt->private.spare.ptr = cpystr (t + 1); } else { /* shouldn't happen, snarl if it does */ sprintf (tmp,"Server returned data for unknown UID %lu",uid); mm_notify (stream,tmp,WARN); stream->unhealthy = T; } /* flush the overview */ fs_give ((void **) &s); } stream->unhealthy = NIL;/* set healthy */ /* flush the terminating dot */ if (s) fs_give ((void **) &s); } else i = stream->nmsgs; /* OVER failed, punt cache load */ } /* now scan sequence to return overviews */ if (ofn) for (i = 1; i <= stream->nmsgs; i++) if ((elt = mail_elt (stream,i))->sequence) { uid = mail_uid (stream,i);/* UID for this message */ /* parse cached overview */ if (nntp_parse_overview (&ov,s = (char *) elt->private.spare.ptr,elt)) (*ofn) (stream,uid,&ov,i); else { /* parse failed */ (*ofn) (stream,uid,NIL,i); if (s && *s) { /* unusable cached entry? */ sprintf (tmp,"Unable to parse overview for UID %lu: %.500s",uid,s); mm_notify (stream,tmp,WARN); stream->unhealthy = T; /* erase it from the cache */ fs_give ((void **) &s); } stream->unhealthy = NIL;/* set healthy */ /* insert empty cached text as necessary */ if (!s) elt->private.spare.ptr = cpystr (""); } /* clean up overview data */ if (ov.from) mail_free_address (&ov.from); if (ov.subject) fs_give ((void **) &ov.subject); } return T; } /* Send OVER to NNTP server * Accepts: mail stream * sequence to send * Returns: T if success and overviews will follow, else NIL */ long nntp_over (MAILSTREAM *stream,char *sequence) { unsigned char *s; /* test for Netscape Collabra server */ if (EXTENSION.over && LOCAL->xover && nntp_send (LOCAL->nntpstream,"OVER","0") == NNTPOVER) { /* "Netscape-Collabra/3.52 03615 NNTP" responds to the OVER command with * a bogus "Subject:From:Date:Bytes:Lines" response followed by overviews * which lack the Message-ID and References:. This violates the draft * NNTP specification (draft-ietf-nntpext-base-18.txt as of this writing). * XOVER works fine. */ while ((s = net_getline (LOCAL->nntpstream->netstream)) && strcmp (s,".")){ if (!isdigit (*s)) { /* is it that fetid piece of reptile dung? */ EXTENSION.over = NIL; /* sure smells like it */ mm_log ("Working around Netscape Collabra bug",WARN); } fs_give ((void **) &s); /* flush the overview */ } if (s) fs_give ((void **) &s); /* don't do this test again */ if (EXTENSION.over) LOCAL->xover = NIL; } if (EXTENSION.over) /* have OVER extension? */ return (nntp_send (LOCAL->nntpstream,"OVER",sequence) == NNTPOVER) ? LONGT : NIL; if (LOCAL->xover) /* try the experiment extension then */ switch ((int) nntp_send (LOCAL->nntpstream,"XOVER",sequence)) { case NNTPOVER: /* got an overview? */ return LONGT; case NNTPBADCMD: /* unknown command? */ LOCAL->xover = NIL; /* disable future XOVER attempts */ } return NIL; } /* Parse OVERVIEW struct from cached NNTP OVER response * Accepts: struct to load * cached OVER response * internaldate * Returns: T if success, NIL if fail */ long nntp_parse_overview (OVERVIEW *ov,char *text,MESSAGECACHE *elt) { char *t; /* nothing in overview yet */ memset ((void *) ov,0,sizeof (OVERVIEW)); /* no cached data */ if (!(text && *text)) return NIL; ov->subject = cpystr (text); /* make hackable copy of overview */ /* find end of Subject */ if (t = strchr (ov->subject,'\t')) { *t++ = '\0'; /* tie off Subject, point to From */ /* find end of From */ if (ov->date = strchr (t,'\t')) { *ov->date++ = '\0'; /* tie off From, point to Date */ /* load internaldate too */ if (!elt->day) mail_parse_date (elt,ov->date); /* parse From */ rfc822_parse_adrlist (&ov->from,t,BADHOST); /* find end of Date */ if (ov->message_id = strchr (ov->date,'\t')) { /* tie off Date, point to Message-ID */ *ov->message_id++ = '\0'; /* find end of Message-ID */ if (ov->references = strchr (ov->message_id,'\t')) { /* tie off Message-ID, point to References */ *ov->references++ = '\0'; /* fine end of References */ if (t = strchr (ov->references,'\t')) { *t++ = '\0'; /* tie off References, point to octet size */ /* parse size of message in octets */ ov->optional.octets = atol (t); /* find end of size */ if (t = strchr (t,'\t')) { /* parse size of message in lines */ ov->optional.lines = atol (++t); /* find Xref */ if (ov->optional.xref = strchr (t,'\t')) *ov->optional.xref++ = '\0'; } } } } } } return ov->references ? T : NIL; } /* NNTP fetch header as text * Accepts: mail stream * message number * pointer to return size * flags * Returns: header text */ char *nntp_header (MAILSTREAM *stream,unsigned long msgno,unsigned long *size, long flags) { char tmp[MAILTMPLEN]; MESSAGECACHE *elt; FILE *f; *size = 0; if ((flags & FT_UID) && !(msgno = mail_msgno (stream,msgno))) return ""; /* have header text? */ if (!(elt = mail_elt (stream,msgno))->private.msg.header.text.data) { sprintf (tmp,"%lu",mail_uid (stream,msgno)); /* get header text */ switch (nntp_send (LOCAL->nntpstream,"HEAD",tmp)) { case NNTPHEAD: if (f = netmsg_slurp (LOCAL->nntpstream->netstream,size,NIL)) { fread (elt->private.msg.header.text.data = (unsigned char *) fs_get ((size_t) *size + 3), (size_t) 1,(size_t) *size,f); fclose (f); /* flush temp file */ /* tie off header with extra CRLF and NUL */ elt->private.msg.header.text.data[*size] = '\015'; elt->private.msg.header.text.data[++*size] = '\012'; elt->private.msg.header.text.data[++*size] = '\0'; elt->private.msg.header.text.size = *size; elt->valid = T; /* make elt valid now */ break; } /* fall into default case */ default: /* failed, mark as deleted and empty */ elt->valid = elt->deleted = T; case NNTPSOFTFATAL: /* don't mark deleted if stream dead */ *size = elt->private.msg.header.text.size = 0; break; } } /* just return size of text */ else *size = elt->private.msg.header.text.size; return elt->private.msg.header.text.data ? (char *) elt->private.msg.header.text.data : ""; } /* NNTP fetch body * Accepts: mail stream * message number * pointer to stringstruct to initialize * flags * Returns: T if successful, else NIL */ long nntp_text (MAILSTREAM *stream,unsigned long msgno,STRING *bs,long flags) { char tmp[MAILTMPLEN]; MESSAGECACHE *elt; INIT (bs,mail_string,(void *) "",0); if ((flags & FT_UID) && !(msgno = mail_msgno (stream,msgno))) return NIL; elt = mail_elt (stream,msgno); /* different message, flush cache */ if (LOCAL->txt && (LOCAL->msgno != msgno)) { fclose (LOCAL->txt); LOCAL->txt = NIL; } LOCAL->msgno = msgno; /* note cached message */ if (!LOCAL->txt) { /* have file for this message? */ sprintf (tmp,"%lu",elt->private.uid); switch (nntp_send (LOCAL->nntpstream,"BODY",tmp)) { case NNTPBODY: if (LOCAL->txt = netmsg_slurp (LOCAL->nntpstream->netstream, &LOCAL->txtsize,NIL)) break; /* fall into default case */ default: /* failed, mark as deleted */ elt->deleted = T; case NNTPSOFTFATAL: /* don't mark deleted if stream dead */ return NIL; } } if (!(flags & FT_PEEK)) { /* mark seen if needed */ elt->seen = T; mm_flags (stream,elt->msgno); } INIT (bs,file_string,(void *) LOCAL->txt,LOCAL->txtsize); return T; } /* NNTP fetch article from message ID (for news: URL support) * Accepts: mail stream * message ID * pointer to return total message size * pointer to return file size * Returns: FILE * to message if successful, else NIL */ FILE *nntp_article (MAILSTREAM *stream,char *msgid,unsigned long *size, unsigned long *hsiz) { return (nntp_send (LOCAL->nntpstream,"ARTICLE",msgid) == NNTPARTICLE) ? netmsg_slurp (LOCAL->nntpstream->netstream,size,hsiz) : NIL; } /* NNTP per-message modify flag * Accepts: MAIL stream * message cache element */ void nntp_flagmsg (MAILSTREAM *stream,MESSAGECACHE *elt) { if (!LOCAL->dirty) { /* only bother checking if not dirty yet */ if (elt->valid) { /* if done, see if deleted changed */ if (elt->sequence != elt->deleted) LOCAL->dirty = T; elt->sequence = T; /* leave the sequence set */ } /* note current setting of deleted flag */ else elt->sequence = elt->deleted; } } /* NNTP search messages * Accepts: mail stream * character set * search program * option flags * Returns: T on success, NIL on failure */ long nntp_search (MAILSTREAM *stream,char *charset,SEARCHPGM *pgm,long flags) { unsigned long i; MESSAGECACHE *elt; OVERVIEW ov; char *msg; /* make sure that charset is good */ if (msg = utf8_badcharset (charset)) { MM_LOG (msg,ERROR); /* output error */ fs_give ((void **) &msg); return NIL; } utf8_searchpgm (pgm,charset); if (flags & SO_OVERVIEW) { /* only if specified to use overview */ /* identify messages that will be searched */ for (i = 1; i <= stream->nmsgs; ++i) mail_elt (stream,i)->sequence = nntp_search_msg (stream,i,pgm,NIL); nntp_overview (stream,NIL); /* load the overview cache */ } /* init in case no overview at cleanup */ memset ((void *) &ov,0,sizeof (OVERVIEW)); /* otherwise do default search */ for (i = 1; i <= stream->nmsgs; ++i) { if (((flags & SO_OVERVIEW) && ((elt = mail_elt (stream,i))->sequence) && nntp_parse_overview (&ov,(char *) elt->private.spare.ptr,elt)) ? nntp_search_msg (stream,i,pgm,&ov) : mail_search_msg (stream,i,NIL,pgm)) { if (flags & SE_UID) mm_searched (stream,mail_uid (stream,i)); else { /* mark as searched, notify mail program */ mail_elt (stream,i)->searched = T; if (!stream->silent) mm_searched (stream,i); } } /* clean up overview data */ if (ov.from) mail_free_address (&ov.from); if (ov.subject) fs_give ((void **) &ov.subject); } return LONGT; } /* NNTP search message * Accepts: MAIL stream * message number * search program * overview to search (NIL means preliminary pass) * Returns: T if found, NIL otherwise */ long nntp_search_msg (MAILSTREAM *stream,unsigned long msgno,SEARCHPGM *pgm, OVERVIEW *ov) { unsigned short d; unsigned long now = (unsigned long) time (0); MESSAGECACHE *elt = mail_elt (stream,msgno); SEARCHHEADER *hdr; SEARCHOR *or; SEARCHPGMLIST *not; if (pgm->msgno || pgm->uid) { /* message set searches */ SEARCHSET *set; /* message sequences */ if (set = pgm->msgno) { /* must be inside this sequence */ while (set) { /* run down until find matching range */ if (set->last ? ((msgno < set->first) || (msgno > set->last)) : msgno != set->first) set = set->next; else break; } if (!set) return NIL; /* not found within sequence */ } if (set = pgm->uid) { /* must be inside this sequence */ unsigned long uid = mail_uid (stream,msgno); while (set) { /* run down until find matching range */ if (set->last ? ((uid < set->first) || (uid > set->last)) : uid != set->first) set = set->next; else break; } if (!set) return NIL; /* not found within sequence */ } } /* Fast data searches */ /* message flags */ if ((pgm->answered && !elt->answered) || (pgm->unanswered && elt->answered) || (pgm->deleted && !elt->deleted) || (pgm->undeleted && elt->deleted) || (pgm->draft && !elt->draft) || (pgm->undraft && elt->draft) || (pgm->flagged && !elt->flagged) || (pgm->unflagged && elt->flagged) || (pgm->recent && !elt->recent) || (pgm->old && elt->recent) || (pgm->seen && !elt->seen) || (pgm->unseen && elt->seen)) return NIL; /* keywords */ if ((pgm->keyword && !mail_search_keyword (stream,elt,pgm->keyword,LONGT)) || (pgm->unkeyword && mail_search_keyword (stream,elt,pgm->unkeyword,NIL))) return NIL; if (ov) { /* only do this if real searching */ MESSAGECACHE delt; /* size ranges */ if ((pgm->larger && (ov->optional.octets <= pgm->larger)) || (pgm->smaller && (ov->optional.octets >= pgm->smaller))) return NIL; /* date ranges */ if ((pgm->sentbefore || pgm->senton || pgm->sentsince || pgm->before || pgm->on || pgm->since) && (!mail_parse_date (&delt,ov->date) || !(d = mail_shortdate (delt.year,delt.month,delt.day)) || (pgm->sentbefore && (d >= pgm->sentbefore)) || (pgm->senton && (d != pgm->senton)) || (pgm->sentsince && (d < pgm->sentsince)) || (pgm->before && (d >= pgm->before)) || (pgm->on && (d != pgm->on)) || (pgm->since && (d < pgm->since)))) return NIL; if (pgm->older || pgm->younger) { unsigned long msgd = mail_longdate (elt); if (pgm->older && msgd > (now - pgm->older)) return NIL; if (pgm->younger && msgd < (now - pgm->younger)) return NIL; } if ((pgm->from && !mail_search_addr (ov->from,pgm->from)) || (pgm->subject && !mail_search_header_text (ov->subject,pgm->subject))|| (pgm->message_id && !mail_search_header_text (ov->message_id,pgm->message_id)) || (pgm->references && !mail_search_header_text (ov->references,pgm->references))) return NIL; /* envelope searches */ if (pgm->bcc || pgm->cc || pgm->to || pgm->return_path || pgm->sender || pgm->reply_to || pgm->in_reply_to || pgm->newsgroups || pgm->followup_to) { ENVELOPE *env = mail_fetchenvelope (stream,msgno); if (!env) return NIL; /* no envelope obtained */ /* search headers */ if ((pgm->bcc && !mail_search_addr (env->bcc,pgm->bcc)) || (pgm->cc && !mail_search_addr (env->cc,pgm->cc)) || (pgm->to && !mail_search_addr (env->to,pgm->to))) return NIL; /* These criteria are not supported by IMAP and have to be emulated */ if ((pgm->return_path && !mail_search_addr (env->return_path,pgm->return_path)) || (pgm->sender && !mail_search_addr (env->sender,pgm->sender)) || (pgm->reply_to && !mail_search_addr (env->reply_to,pgm->reply_to)) || (pgm->in_reply_to && !mail_search_header_text (env->in_reply_to,pgm->in_reply_to)) || (pgm->newsgroups && !mail_search_header_text (env->newsgroups,pgm->newsgroups)) || (pgm->followup_to && !mail_search_header_text (env->followup_to,pgm->followup_to))) return NIL; } /* search header lines */ for (hdr = pgm->header; hdr; hdr = hdr->next) { char *t,*e,*v; SIZEDTEXT s; STRINGLIST sth,stc; sth.next = stc.next = NIL;/* only one at a time */ sth.text.data = hdr->line.data; sth.text.size = hdr->line.size; /* get the header text */ if ((t = mail_fetch_header (stream,msgno,NIL,&sth,&s.size, FT_INTERNAL | FT_PEEK)) && strchr (t,':')) { if (hdr->text.size) { /* anything matches empty search string */ /* non-empty, copy field data */ s.data = (unsigned char *) fs_get (s.size + 1); /* for each line */ for (v = (char *) s.data, e = t + s.size; t < e;) switch (*t) { default: /* non-continuation, skip leading field name */ while ((t < e) && (*t++ != ':')); if ((t < e) && (*t == ':')) t++; case '\t': case ' ': /* copy field data */ while ((t < e) && (*t != '\015') && (*t != '\012')) *v++ = *t++; *v++ = '\n'; /* tie off line */ while (((*t == '\015') || (*t == '\012')) && (t < e)) t++; } /* calculate true size */ s.size = v - (char *) s.data; *v = '\0'; /* tie off results */ stc.text.data = hdr->text.data; stc.text.size = hdr->text.size; /* search header */ if (mail_search_header (&s,&stc)) fs_give ((void **) &s.data); else { /* search failed */ fs_give ((void **) &s.data); return NIL; } } } else return NIL; /* no matching header text */ } /* search strings */ if ((pgm->text && !mail_search_text (stream,msgno,NIL,pgm->text,LONGT))|| (pgm->body && !mail_search_text (stream,msgno,NIL,pgm->body,NIL))) return NIL; } /* logical conditions */ for (or = pgm->or; or; or = or->next) if (!(nntp_search_msg (stream,msgno,or->first,ov) || nntp_search_msg (stream,msgno,or->second,ov))) return NIL; for (not = pgm->not; not; not = not->next) if (nntp_search_msg (stream,msgno,not->pgm,ov)) return NIL; return T; } /* NNTP sort messages * Accepts: mail stream * character set * search program * sort program * option flags * Returns: vector of sorted message sequences or NIL if error */ unsigned long *nntp_sort (MAILSTREAM *stream,char *charset,SEARCHPGM *spg, SORTPGM *pgm,long flags) { unsigned long i,start,last; SORTCACHE **sc; mailcache_t mailcache = (mailcache_t) mail_parameters (NIL,GET_CACHE,NIL); unsigned long *ret = NIL; sortresults_t sr = (sortresults_t) mail_parameters (NIL,GET_SORTRESULTS,NIL); if (spg) { /* only if a search needs to be done */ int silent = stream->silent; stream->silent = T; /* don't pass up mm_searched() events */ /* search for messages */ mail_search_full (stream,charset,spg,NIL); stream->silent = silent; /* restore silence state */ } /* initialize progress counters */ pgm->nmsgs = pgm->progress.cached = 0; /* pass 1: count messages to sort */ for (i = 1,start = last = 0; i <= stream->nmsgs; ++i) if (mail_elt (stream,i)->searched) { pgm->nmsgs++; /* have this in the sortcache already? */ if (!((SORTCACHE *) (*mailcache) (stream,i,CH_SORTCACHE))->date) { /* no, record as last message */ last = mail_uid (stream,i); /* and as first too if needed */ if (!start) start = last; } } if (pgm->nmsgs) { /* pass 2: load sort cache */ sc = nntp_sort_loadcache (stream,pgm,start,last,flags); /* pass 3: sort messages */ if (!pgm->abort) ret = mail_sort_cache (stream,pgm,sc,flags); fs_give ((void **) &sc); /* don't need sort vector any more */ } /* empty sort results */ else ret = (unsigned long *) memset (fs_get (sizeof (unsigned long)),0, sizeof (unsigned long)); /* also return via callback if requested */ if (sr) (*sr) (stream,ret,pgm->nmsgs); return ret; } /* Mail load sortcache * Accepts: mail stream, already searched * sort program * first UID to OVER * last UID to OVER * option flags * Returns: vector of sortcache pointers matching search */ SORTCACHE **nntp_sort_loadcache (MAILSTREAM *stream,SORTPGM *pgm, unsigned long start,unsigned long last, long flags) { unsigned long i; char c,*s,*t,*v,tmp[MAILTMPLEN]; SORTPGM *pg; SORTCACHE **sc,*r; MESSAGECACHE telt; ADDRESS *adr = NIL; mailcache_t mailcache = (mailcache_t) mail_parameters (NIL,GET_CACHE,NIL); /* verify that the sortpgm is OK */ for (pg = pgm; pg; pg = pg->next) switch (pg->function) { case SORTARRIVAL: /* sort by arrival date */ case SORTSIZE: /* sort by message size */ case SORTDATE: /* sort by date */ case SORTFROM: /* sort by first from */ case SORTSUBJECT: /* sort by subject */ break; case SORTTO: /* sort by first to */ mm_notify (stream,"[NNTPSORT] Can't do To-field sorting in NNTP",WARN); break; case SORTCC: /* sort by first cc */ mm_notify (stream,"[NNTPSORT] Can't do cc-field sorting in NNTP",WARN); break; default: fatal ("Unknown sort function"); } if (start) { /* messages need to be loaded in sortcache? */ /* yes, build range */ if (start != last) sprintf (tmp,"%lu-%lu",start,last); else sprintf (tmp,"%lu",start); /* get it from the NNTP server */ if (!nntp_over (stream,tmp)) return mail_sort_loadcache (stream,pgm); while ((s = net_getline (LOCAL->nntpstream->netstream)) && strcmp (s,".")){ /* death to embedded newlines */ for (t = v = s; c = *v++;) if ((c != '\012') && (c != '\015')) *t++ = c; *t++ = '\0'; /* tie off resulting string */ /* parse OVER response */ if ((i = mail_msgno (stream,atol (s))) && (t = strchr (s,'\t')) && (v = strchr (++t,'\t'))) { *v++ = '\0'; /* tie off subject */ /* put stripped subject in sortcache */ r = (SORTCACHE *) (*mailcache) (stream,i,CH_SORTCACHE); r->refwd = mail_strip_subject (t,&r->subject); if (t = strchr (v,'\t')) { *t++ = '\0'; /* tie off from */ if (adr = rfc822_parse_address (&adr,adr,&v,BADHOST,0)) { r->from = adr->mailbox; adr->mailbox = NIL; mail_free_address (&adr); } if (v = strchr (t,'\t')) { *v++ = '\0'; /* tie off date */ if (mail_parse_date (&telt,t)) r->date = mail_longdate (&telt); if ((v = strchr (v,'\t')) && (v = strchr (++v,'\t'))) r->size = atol (++v); } } } fs_give ((void **) &s); } if (s) fs_give ((void **) &s); } /* calculate size of sortcache index */ i = pgm->nmsgs * sizeof (SORTCACHE *); /* instantiate the index */ sc = (SORTCACHE **) memset (fs_get ((size_t) i),0,(size_t) i); /* see what needs to be loaded */ for (i = 1; !pgm->abort && (i <= stream->nmsgs); i++) if ((mail_elt (stream,i))->searched) { sc[pgm->progress.cached++] = r = (SORTCACHE *) (*mailcache) (stream,i,CH_SORTCACHE); r->pgm = pgm; /* note sort program */ r->num = (flags & SE_UID) ? mail_uid (stream,i) : i; if (!r->date) r->date = r->num; if (!r->arrival) r->arrival = mail_uid (stream,i); if (!r->size) r->size = 1; if (!r->from) r->from = cpystr (""); if (!r->to) r->to = cpystr (""); if (!r->cc) r->cc = cpystr (""); if (!r->subject) r->subject = cpystr (""); } return sc; } /* NNTP thread messages * Accepts: mail stream * thread type * character set * search program * option flags * Returns: thread node tree */ THREADNODE *nntp_thread (MAILSTREAM *stream,char *type,char *charset, SEARCHPGM *spg,long flags) { return mail_thread_msgs (stream,type,charset,spg,flags,nntp_sort); } /* NNTP ping mailbox * Accepts: MAIL stream * Returns: T if stream alive, else NIL */ long nntp_ping (MAILSTREAM *stream) { return (nntp_send (LOCAL->nntpstream,"STAT",NIL) != NNTPSOFTFATAL); } /* NNTP check mailbox * Accepts: MAIL stream */ void nntp_check (MAILSTREAM *stream) { /* never do if no updates */ if (LOCAL->dirty) newsrc_write (LOCAL->name,stream); LOCAL->dirty = NIL; } /* NNTP expunge mailbox * Accepts: MAIL stream * sequence to expunge if non-NIL * expunge options * Returns: T if success, NIL if failure */ long nntp_expunge (MAILSTREAM *stream,char *sequence,long options) { if (!stream->silent) mm_log ("Expunge ignored on readonly mailbox",NIL); return LONGT; } /* NNTP copy message(s) * Accepts: MAIL stream * sequence * destination mailbox * option flags * Returns: T if copy successful, else NIL */ long nntp_copy (MAILSTREAM *stream,char *sequence,char *mailbox,long options) { mailproxycopy_t pc = (mailproxycopy_t) mail_parameters (stream,GET_MAILPROXYCOPY,NIL); if (pc) return (*pc) (stream,sequence,mailbox,options); mm_log ("Copy not valid for NNTP",ERROR); return NIL; } /* NNTP append message from stringstruct * Accepts: MAIL stream * destination mailbox * append callback * data for callback * Returns: T if append successful, else NIL */ long nntp_append (MAILSTREAM *stream,char *mailbox,append_t af,void *data) { mm_log ("Append not valid for NNTP",ERROR); return NIL; } /* NNTP open connection * Accepts: network driver * service host list * port number * service name * NNTP open options * Returns: SEND stream on success, NIL on failure */ SENDSTREAM *nntp_open_full (NETDRIVER *dv,char **hostlist,char *service, unsigned long port,long options) { SENDSTREAM *stream = NIL; NETSTREAM *netstream = NIL; NETMBX mb; char tmp[MAILTMPLEN]; long extok = LONGT; NETDRIVER *ssld = (NETDRIVER *) mail_parameters (NIL,GET_SSLDRIVER,NIL); sslstart_t stls = (sslstart_t) mail_parameters (NIL,GET_SSLSTART,NIL); if (!(hostlist && *hostlist)) mm_log ("Missing NNTP service host",ERROR); else do { /* try to open connection */ sprintf (tmp,"{%.200s/%.20s}",*hostlist,service ? service : "nntp"); if (!mail_valid_net_parse (tmp,&mb) || mb.anoflag) { sprintf (tmp,"Invalid host specifier: %.80s",*hostlist); mm_log (tmp,ERROR); } else { /* light tryssl flag if requested */ mb.trysslflag = (options & NOP_TRYSSL) ? T : NIL; /* default port */ if (mb.port) port = mb.port; else if (!port) port = nntp_port ? nntp_port : NNTPTCPPORT; if (netstream = /* try to open ordinary connection */ net_open (&mb,dv,port, (NETDRIVER *) mail_parameters (NIL,GET_SSLDRIVER,NIL), "*nntps",nntp_sslport ? nntp_sslport : NNTPSSLPORT)) { stream = (SENDSTREAM *) fs_get (sizeof (SENDSTREAM)); /* initialize stream */ memset ((void *) stream,0,sizeof (SENDSTREAM)); stream->netstream = netstream; stream->host = cpystr ((long) mail_parameters (NIL,GET_TRUSTDNS,NIL) ? net_host (netstream) : mb.host); stream->debug = (mb.dbgflag || (options & NOP_DEBUG)) ? T : NIL; if (mb.loser) stream->loser = T; /* process greeting */ switch ((int) nntp_reply (stream)) { case NNTPGREET: /* allow posting */ NNTP.post = T; mm_notify (NIL,stream->reply + 4,(long) NIL); break; case NNTPGREETNOPOST: /* posting not allowed, must be readonly */ NNTP.post = NIL; break; default: mm_log (stream->reply,ERROR); stream = nntp_close (stream); break; } } } } while (!stream && *++hostlist); /* get extensions */ if (stream && extok) extok = nntp_extensions (stream,(mb.secflag ? AU_SECURE : NIL) | (mb.authuser[0] ? AU_AUTHUSER : NIL)); if (stream && !dv && stls && NNTP.ext.starttls && !mb.sslflag && !mb.notlsflag && (nntp_send_work (stream,"STARTTLS",NNTP.ext.multidomain ? mb.host : NIL) == NNTPTLSSTART)) { mb.tlsflag = T; /* TLS OK, get into TLS at this end */ stream->netstream->dtb = ssld; /* negotiate TLS */ if (stream->netstream->stream = (*stls) (stream->netstream->stream,mb.host, (mb.tlssslv23 ? NIL : NET_TLSCLIENT) | (mb.novalidate ? NET_NOVALIDATECERT:NIL))) extok = nntp_extensions (stream,(mb.secflag ? AU_SECURE : NIL) | (mb.authuser[0] ? AU_AUTHUSER : NIL)); else { sprintf (tmp,"Unable to negotiate TLS with this server: %.80s",mb.host); mm_log (tmp,ERROR); /* close without doing QUIT */ if (stream->netstream) net_close (stream->netstream); stream->netstream = NIL; stream = nntp_close (stream); } } else if (mb.tlsflag) { /* user specified /tls but can't do it */ mm_log ("Unable to negotiate TLS with this server",ERROR); return NIL; } if (stream) { /* have a session? */ if (mb.user[0]) { /* yes, have user name? */ if ((long) mail_parameters (NIL,GET_TRUSTDNS,NIL)) { /* remote name for authentication */ strncpy (mb.host,(long) mail_parameters (NIL,GET_SASLUSESPTRNAME,NIL) ? net_remotehost (netstream) : net_host (netstream), NETMAXHOST-1); mb.host[NETMAXHOST-1] = '\0'; } if (!nntp_send_auth_work (stream,&mb,tmp,NIL)) stream = nntp_close (stream); } /* authenticate if no-post and not readonly */ else if (!(NNTP.post || (options & NOP_READONLY) || nntp_send_auth (stream,NIL))) stream = nntp_close (stream); } /* in case server demands MODE READER */ if (stream) switch ((int) nntp_send_work (stream,"MODE","READER")) { case NNTPGREET: NNTP.post = T; break; case NNTPGREETNOPOST: NNTP.post = NIL; break; case NNTPWANTAUTH: /* server wants auth first, do so and retry */ case NNTPWANTAUTH2: /* remote name for authentication */ if ((long) mail_parameters (NIL,GET_TRUSTDNS,NIL)) { strncpy (mb.host,(long) mail_parameters (NIL,GET_SASLUSESPTRNAME,NIL) ? net_remotehost (netstream) : net_host (netstream),NETMAXHOST-1); mb.host[NETMAXHOST-1] = '\0'; } if (nntp_send_auth_work (stream,&mb,tmp,NIL)) switch ((int) nntp_send (stream,"MODE","READER")) { case NNTPGREET: NNTP.post = T; break; case NNTPGREETNOPOST: NNTP.post = NIL; break; } else stream = nntp_close (stream); break; } if (stream) { /* looks like we have a stream? */ /* yes, make sure can post if not readonly */ if (!(NNTP.post || (options & NOP_READONLY))) stream = nntp_close (stream); else if (extok) nntp_extensions (stream,(mb.secflag ? AU_SECURE : NIL) | (mb.authuser[0] ? AU_AUTHUSER : NIL)); } return stream; } /* NNTP extensions * Accepts: stream * authenticator flags * Returns: T on success, NIL on failure */ long nntp_extensions (SENDSTREAM *stream,long flags) { unsigned long i; char *t,*r,*args; /* zap all old extensions */ memset (&NNTP.ext,0,sizeof (NNTP.ext)); if (stream->loser) return NIL;/* nothing at all for losers */ /* get server extensions */ switch ((int) nntp_send_work (stream,"LIST","EXTENSIONS")) { case NNTPEXTOK: /* what NNTP base spec says */ case NNTPGLIST: /* some servers do this instead */ break; default: /* no LIST EXTENSIONS on this server */ return NIL; } NNTP.ext.ok = T; /* server offers extensions */ while ((t = net_getline (stream->netstream)) && (t[1] || (*t != '.'))) { if (stream->debug) mm_dlog (t); /* get optional capability arguments */ if (args = strchr (t,' ')) *args++ = '\0'; if (!compare_cstring (t,"LISTGROUP")) NNTP.ext.listgroup = T; else if (!compare_cstring (t,"OVER")) NNTP.ext.over = T; else if (!compare_cstring (t,"HDR")) NNTP.ext.hdr = T; else if (!compare_cstring (t,"PAT")) NNTP.ext.pat = T; else if (!compare_cstring (t,"STARTTLS")) NNTP.ext.starttls = T; else if (!compare_cstring (t,"MULTIDOMAIN")) NNTP.ext.multidomain = T; else if (!compare_cstring (t,"AUTHINFO") && args) { char *sasl = NIL; for (args = strtok_r (args," ",&r); args; args = strtok_r (NIL," ",&r)) { if (!compare_cstring (args,"USER")) NNTP.ext.authuser = T; else if (((args[0] == 'S') || (args[0] == 's')) && ((args[1] == 'A') || (args[1] == 'a')) && ((args[2] == 'S') || (args[2] == 's')) && ((args[3] == 'L') || (args[3] == 'l')) && (args[4] == ':')) sasl = args + 5; } if (sasl) { /* if SASL, look up authenticators */ for (sasl = strtok_r (sasl,",",&r); sasl; sasl = strtok_r (NIL,",",&r)) if ((i = mail_lookup_auth_name (sasl,flags)) && (--i < MAXAUTHENTICATORS)) NNTP.ext.sasl |= (1 << i); /* disable LOGIN if PLAIN also advertised */ if ((i = mail_lookup_auth_name ("PLAIN",NIL)) && (--i < MAXAUTHENTICATORS) && (NNTP.ext.sasl & (1 << i)) && (i = mail_lookup_auth_name ("LOGIN",NIL)) && (--i < MAXAUTHENTICATORS)) NNTP.ext.sasl &= ~(1 << i); } } fs_give ((void **) &t); } if (t) { /* flush end of text indicator */ if (stream->debug) mm_dlog (t); fs_give ((void **) &t); } return LONGT; } /* NNTP close connection * Accepts: SEND stream * Returns: NIL always */ SENDSTREAM *nntp_close (SENDSTREAM *stream) { if (stream) { /* send "QUIT" */ if (stream->netstream) nntp_send (stream,"QUIT",NIL); /* do close actions */ if (stream->netstream) net_close (stream->netstream); if (stream->host) fs_give ((void **) &stream->host); if (stream->reply) fs_give ((void **) &stream->reply); fs_give ((void **) &stream);/* flush the stream */ } return NIL; } /* NNTP deliver news * Accepts: SEND stream * message envelope * message body * Returns: T on success, NIL on failure */ long nntp_mail (SENDSTREAM *stream,ENVELOPE *env,BODY *body) { long ret; RFC822BUFFER buf; char *s,path[MAILTMPLEN],tmp[SENDBUFLEN+1]; long error = NIL; long retry = NIL; buf.f = nntp_soutr; /* initialize buffer */ buf.s = stream->netstream; buf.end = (buf.beg = buf.cur = tmp) + SENDBUFLEN; tmp[SENDBUFLEN] = '\0'; /* must have additional null guard byte */ /* Gabba gabba hey, we need some brain damage to send netnews!!! * * First, we give ourselves a frontal lobotomy, and put in some UUCP * syntax. It doesn't matter that it's completely bogus UUCP, and * that UUCP has nothing to do with anything we're doing. It's been * alleged that "Path: not-for-mail" is also acceptable, but we won't * make assumptions unless the user says so. * * Second, we bop ourselves on the head with a ball-peen hammer. How * dare we be so presumptious as to insert a *comment* in a Date: * header line. Why, we were actually trying to be nice to a human * by giving a symbolic timezone (such as PST) in addition to a * numeric timezone (such as -0800). But the gods of news transport * will have none of this. Unix weenies, tried and true, rule!!! * * Third, Netscape Collabra server doesn't give the NNTPWANTAUTH error * until after requesting and receiving the entire message. So we can't * call rely upon nntp_send() to do the auth retry. */ /* RFC-1036 requires this cretinism */ sprintf (path,"Path: %s!%s\015\012",net_localhost (stream->netstream), env->sender ? env->sender->mailbox : (env->from ? env->from->mailbox : "not-for-mail")); /* here's another cretinism */ if (s = strstr (env->date," (")) *s = NIL; do if ((ret = nntp_send_work (stream,"POST",NIL)) == NNTPREADY) /* output data, return success status */ ret = (net_soutr (stream->netstream, nntp_hidepath ? "Path: not-for-mail\015\012" : path) && rfc822_output_full (&buf,env,body,T)) ? nntp_send_work (stream,".",NIL) : nntp_fake (stream,"NNTP connection broken (message text)"); while (((ret == NNTPWANTAUTH) || (ret == NNTPWANTAUTH2)) && nntp_send_auth (stream,LONGT)); if (s) *s = ' '; /* put the comment in the date back */ if (ret == NNTPOK) return LONGT; else if (ret < 400) { /* if not an error reply */ sprintf (tmp,"Unexpected NNTP posting reply code %ld",ret); mm_log (tmp,WARN); /* so someone looks at this eventually */ if ((ret >= 200) && (ret < 300)) return LONGT; } return NIL; } /* NNTP send command * Accepts: SEND stream * text * Returns: reply code */ long nntp_send (SENDSTREAM *stream,char *command,char *args) { long ret; switch ((int) (ret = nntp_send_work (stream,command,args))) { case NNTPWANTAUTH: /* authenticate and retry */ case NNTPWANTAUTH2: if (nntp_send_auth (stream,LONGT)) ret = nntp_send_work (stream,command,args); else { /* we're probably hosed, nuke the session */ nntp_send (stream,"QUIT",NIL); /* close net connection */ if (stream->netstream) net_close (stream->netstream); stream->netstream = NIL; } default: /* all others just return */ break; } return ret; } /* NNTP send command worker routine * Accepts: SEND stream * text * Returns: reply code */ long nntp_send_work (SENDSTREAM *stream,char *command,char *args) { long ret; char *s = (char *) fs_get (strlen (command) + (args ? strlen (args) + 1 : 0) + 3); if (!stream->netstream) ret = nntp_fake (stream,"NNTP connection lost"); else { /* build the complete command */ if (args) sprintf (s,"%s %s",command,args); else strcpy (s,command); if (stream->debug) mail_dlog (s,stream->sensitive); strcat (s,"\015\012"); /* send the command */ ret = net_soutr (stream->netstream,s) ? nntp_reply (stream) : nntp_fake (stream,"NNTP connection broken (command)"); } fs_give ((void **) &s); return ret; } /* NNTP send authentication if needed * Accepts: SEND stream * flags (non-NIL to get new extensions) * Returns: T if need to redo command, NIL otherwise */ long nntp_send_auth (SENDSTREAM *stream,long flags) { NETMBX mb; char tmp[MAILTMPLEN]; /* remote name for authentication */ sprintf (tmp,"{%.200s/nntp",(long) mail_parameters (NIL,GET_TRUSTDNS,NIL) ? ((long) mail_parameters (NIL,GET_SASLUSESPTRNAME,NIL) ? net_remotehost (stream->netstream) : net_host (stream->netstream)): stream->host); if (stream->netstream->dtb == (NETDRIVER *) mail_parameters (NIL,GET_SSLDRIVER,NIL)) strcat (tmp,"/ssl"); strcat (tmp,"}"); mail_valid_net_parse (tmp,&mb); return nntp_send_auth_work (stream,&mb,tmp,flags); } /* NNTP send authentication worker routine * Accepts: SEND stream * NETMBX structure * scratch buffer of length MAILTMPLEN * flags (non-NIL to get new extensions) * Returns: T if authenticated, NIL otherwise */ long nntp_send_auth_work (SENDSTREAM *stream,NETMBX *mb,char *pwd,long flags) { unsigned long trial,auths; char tmp[MAILTMPLEN],usr[MAILTMPLEN]; AUTHENTICATOR *at; char *lsterr = NIL; long ret = NIL; /* try SASL first */ for (auths = NNTP.ext.sasl, stream->saslcancel = NIL; !ret && stream->netstream && auths && (at = mail_lookup_auth (find_rightmost_bit (&auths) + 1)); ) { if (lsterr) { /* previous authenticator failed? */ sprintf (tmp,"Retrying using %s authentication after %.80s", at->name,lsterr); mm_log (tmp,NIL); fs_give ((void **) &lsterr); } trial = 0; /* initial trial count */ tmp[0] = '\0'; /* empty buffer */ if (stream->netstream) do { if (lsterr) { sprintf (tmp,"Retrying %s authentication after %.80s",at->name,lsterr); mm_log (tmp,WARN); fs_give ((void **) &lsterr); } stream->saslcancel = NIL; if (nntp_send (stream,"AUTHINFO SASL",at->name) == NNTPCHALLENGE) { /* hide client authentication responses */ if (!(at->flags & AU_SECURE)) stream->sensitive = T; if ((*at->client) (nntp_challenge,nntp_response,"nntp",mb,stream, &trial,usr)) { if (stream->replycode == NNTPAUTHED) ret = LONGT; /* if main program requested cancellation */ else if (!trial) mm_log ("NNTP Authentication cancelled",ERROR); } stream->sensitive = NIL;/* unhide */ } /* remember response if error and no cancel */ if (!ret && trial) lsterr = cpystr (stream->reply); } while (!ret && stream->netstream && trial && (trial < nntp_maxlogintrials)); } if (lsterr) { /* SAIL failed? */ if (!stream->saslcancel) { /* don't do this if a cancel */ sprintf (tmp,"Can not authenticate to NNTP server: %.80s",lsterr); mm_log (tmp,ERROR); } fs_give ((void **) &lsterr); } else if (mb->secflag) /* no SASL, can't do /secure */ mm_log ("Can't do secure authentication with this server",ERROR); else if (mb->authuser[0]) /* or /authuser */ mm_log ("Can't do /authuser with this server",ERROR); /* Always try AUTHINFO USER, even if NNTP.ext.authuser isn't set. There * are servers that require it but don't return it as an extension. */ else for (trial = 0, pwd[0] = 'x'; !ret && pwd[0] && (trial < nntp_maxlogintrials) && stream->netstream; ) { pwd[0] = NIL; /* get user name and password */ mm_login (mb,usr,pwd,trial++); /* do the authentication */ if (pwd[0]) switch ((int) nntp_send_work (stream,"AUTHINFO USER",usr)) { case NNTPBADCMD: /* give up if unrecognized command */ mm_log (NNTP.ext.authuser ? stream->reply : "Can't do AUTHINFO USER to this server",ERROR); trial = nntp_maxlogintrials; break; case NNTPAUTHED: /* successful authentication */ ret = LONGT; /* guess no password was needed */ break; case NNTPWANTPASS: /* wants password */ stream->sensitive = T; /* hide this command */ if (nntp_send_work (stream,"AUTHINFO PASS",pwd) == NNTPAUTHED) ret = LONGT; /* password OK */ stream->sensitive = NIL; /* unhide */ if (ret) break; /* OK if successful */ default: /* authentication failed */ mm_log (stream->reply,WARN); if (trial == nntp_maxlogintrials) mm_log ("Too many NNTP authentication failures",ERROR); } /* user refused to give a password */ else mm_log ("Login aborted",ERROR); } memset (pwd,0,MAILTMPLEN); /* erase password */ /* get new extensions if needed */ if (ret && flags) nntp_extensions (stream,(mb->secflag ? AU_SECURE : NIL) | (mb->authuser[0] ? AU_AUTHUSER : NIL)); return ret; } /* Get challenge to authenticator in binary * Accepts: stream * pointer to returned size * Returns: challenge or NIL if not challenge */ void *nntp_challenge (void *s,unsigned long *len) { char tmp[MAILTMPLEN]; void *ret = NIL; SENDSTREAM *stream = (SENDSTREAM *) s; if ((stream->replycode == NNTPCHALLENGE) && !(ret = rfc822_base64 ((unsigned char *) stream->reply + 4, strlen (stream->reply + 4),len))) { sprintf (tmp,"NNTP SERVER BUG (invalid challenge): %.80s",stream->reply+4); mm_log (tmp,ERROR); } return ret; } /* Send authenticator response in BASE64 * Accepts: MAIL stream * string to send * length of string * Returns: T, always */ long nntp_response (void *s,char *response,unsigned long size) { SENDSTREAM *stream = (SENDSTREAM *) s; unsigned long i,j; char *t,*u; if (response) { /* make CRLFless BASE64 string */ if (size) { for (t = (char *) rfc822_binary ((void *) response,size,&i),u = t,j = 0; j < i; j++) if (t[j] > ' ') *u++ = t[j]; *u = '\0'; /* tie off string */ i = nntp_send_work (stream,t,NIL); fs_give ((void **) &t); } else i = nntp_send_work (stream,"",NIL); } else { /* abort requested */ i = nntp_send_work (stream,"*",NIL); stream->saslcancel = T; /* mark protocol-requested SASL cancel */ } return LONGT; } /* NNTP get reply * Accepts: SEND stream * Returns: reply code */ long nntp_reply (SENDSTREAM *stream) { /* flush old reply */ if (stream->reply) fs_give ((void **) &stream->reply); /* get reply */ if (!(stream->reply = net_getline (stream->netstream))) return nntp_fake (stream,"NNTP connection broken (response)"); if (stream->debug) mm_dlog (stream->reply); /* handle continuation by recursion */ if (stream->reply[3] == '-') return nntp_reply (stream); /* return response code */ return stream->replycode = atol (stream->reply); } /* NNTP set fake error * Accepts: SEND stream * error text * Returns: error code */ long nntp_fake (SENDSTREAM *stream,char *text) { if (stream->netstream) { /* close net connection if still open */ net_close (stream->netstream); stream->netstream = NIL; } /* flush any old reply */ if (stream->reply) fs_give ((void **) &stream->reply); /* set up pseudo-reply string */ stream->reply = (char *) fs_get (20+strlen (text)); sprintf (stream->reply,"%ld %s",NNTPSOFTFATAL,text); return NNTPSOFTFATAL; /* return error code */ } /* NNTP filter mail * Accepts: stream * string * Returns: T on success, NIL on failure */ long nntp_soutr (void *stream,char *s) { char c,*t; /* "." on first line */ if (s[0] == '.') net_soutr (stream,"."); /* find lines beginning with a "." */ while (t = strstr (s,"\015\012.")) { c = *(t += 3); /* remember next character after "." */ *t = '\0'; /* tie off string */ /* output prefix */ if (!net_soutr (stream,s)) return NIL; *t = c; /* restore delimiter */ s = t - 1; /* push pointer up to the "." */ } /* output remainder of text */ return *s ? net_soutr (stream,s) : T; } alpine-2.10+dfsg/imap/src/dmail/0000700000175000017500000000000011512502152020136 5ustar paulproteuspaulproteusalpine-2.10+dfsg/imap/src/dmail/Makefile0000600000175000017500000000230711512502122021577 0ustar paulproteuspaulproteus# ======================================================================== # Copyright 1988-2006 University of Washington # # Licensed under the Apache License, Version 2.0 (the "License"); # you may not use this file except in compliance with the License. # You may obtain a copy of the License at # # http://www.apache.org/licenses/LICENSE-2.0 # # # ======================================================================== # Program: dmail Makefile # # Author: Mark Crispin # Networks and Distributed Computing # Computing & Communications # University of Washington # Administration Building, AG-44 # Seattle, WA 98195 # Internet: MRC@CAC.Washington.EDU # # Date: 5 April 1993 # Last Edited: 10 September 2007 C = ../c-client CCLIENTLIB = $C/c-client.a SHELL = /bin/sh # Get local definitions from c-client directory CC = `cat $C/CCTYPE` CFLAGS = -I$C `cat $C/CFLAGS` LDFLAGS = $(CCLIENTLIB) `cat $C/LDFLAGS` dmail: $(CCLIENTLIB) dmail.o dquota.o $(CC) $(CFLAGS) -o dmail dmail.o dquota.o $(LDFLAGS) dmail.o: $C/mail.h $C/misc.h $C/osdep.h dquota.h dquota.o: dquota.h $(CCLIENTLIB): cd $C;make clean: rm -f *.o dmail # A monument to a hack of long ago and far away... love: @echo 'not war?' alpine-2.10+dfsg/imap/src/dmail/dquota.h0000600000175000017500000000162411512502122021606 0ustar paulproteuspaulproteus/* ======================================================================== * Copyright 1988-2007 University of Washington * * Licensed under the Apache License, Version 2.0 (the "License"); * you may not use this file except in compliance with the License. * You may obtain a copy of the License at * * http://www.apache.org/licenses/LICENSE-2.0 * * * ======================================================================== */ /* * Program: Procmail-Callable Mail Delivery Module Quota Hook * * Author: Mark Crispin * Networks and Distributed Computing * Computing & Communications * University of Washington * Administration Building, AG-44 * Seattle, WA 98195 * Internet: MRC@CAC.Washington.EDU * * Date: 10 September 2007 * Last Edited: 10 September 2007 */ /* Function prototypes */ long dmail_quota (STRING *msg,char *path,char *tmp,char *sender, long precedence); alpine-2.10+dfsg/imap/src/dmail/dmail.c0000600000175000017500000004633111512502122021376 0ustar paulproteuspaulproteus/* ======================================================================== * Copyright 1988-2007 University of Washington * * Licensed under the Apache License, Version 2.0 (the "License"); * you may not use this file except in compliance with the License. * You may obtain a copy of the License at * * http://www.apache.org/licenses/LICENSE-2.0 * * * ======================================================================== */ /* * Program: Procmail-Callable Mail Delivery Module * * Author: Mark Crispin * Networks and Distributed Computing * Computing & Communications * University of Washington * Administration Building, AG-44 * Seattle, WA 98195 * Internet: MRC@CAC.Washington.EDU * * Date: 5 April 1993 * Last Edited: 30 October 2008 */ #include #include #include extern int errno; /* just in case */ #include #include #include #include "c-client.h" #include "dquota.h" /* Globals */ char *version = "18"; /* dmail edit version */ int debug = NIL; /* debugging (don't fork) */ int flagseen = NIL; /* flag message as seen */ int trycreate = NIL; /* flag saying gotta create before appending */ int critical = NIL; /* flag saying in critical code */ char *sender = NIL; /* message origin */ char *keywords = NIL; /* keyword list */ long precedence = 0; /* delivery precedence - used by quota hook */ /* Function prototypes */ void file_string_init (STRING *s,void *data,unsigned long size); char file_string_next (STRING *s); void file_string_setpos (STRING *s,unsigned long i); int main (int argc,char *argv[]); int deliver (FILE *f,unsigned long msglen,char *user); long ibxpath (MAILSTREAM *ds,char **mailbox,char *path); int deliver_safely (MAILSTREAM *prt,STRING *st,char *mailbox,char *path, char *tmp); int delivery_unsafe (char *path,struct stat *sbuf,char *tmp); int fail (char *string,int code); /* File string driver for file stringstructs */ STRINGDRIVER file_string = { file_string_init, /* initialize string structure */ file_string_next, /* get next byte in string structure */ file_string_setpos /* set position in string structure */ }; /* Cache buffer for file stringstructs */ #define CHUNKLEN 16384 char chunk[CHUNKLEN]; /* Initialize file string structure for file stringstruct * Accepts: string structure * pointer to string * size of string */ void file_string_init (STRING *s,void *data,unsigned long size) { s->data = data; /* note fd */ s->size = size; /* note size */ s->chunk = chunk; s->chunksize = (unsigned long) CHUNKLEN; SETPOS (s,0); /* set initial position */ } /* Get next character from file stringstruct * Accepts: string structure * Returns: character, string structure chunk refreshed */ char file_string_next (STRING *s) { char c = *s->curpos++; /* get next byte */ SETPOS (s,GETPOS (s)); /* move to next chunk */ return c; /* return the byte */ } /* Set string pointer position for file stringstruct * Accepts: string structure * new position */ void file_string_setpos (STRING *s,unsigned long i) { if (i > s->size) i = s->size; /* don't permit setting beyond EOF */ s->offset = i; /* set new offset */ s->curpos = s->chunk; /* reset position */ /* set size of data */ if (s->cursize = min (s->chunksize,SIZE (s))) { /* move to that position in the file */ fseek ((FILE *) s->data,s->offset,SEEK_SET); fread (s->curpos,sizeof (char),(unsigned int) s->cursize,(FILE *) s->data); } } /* Main program */ int main (int argc,char *argv[]) { FILE *f = NIL; int c,ret = 0; unsigned long msglen; char *s,tmp[MAILTMPLEN]; uid_t ruid = getuid (); struct passwd *pwd = ruid ? getpwnam ("daemon") : NIL; openlog ("dmail",LOG_PID,LOG_MAIL); /* must not be root or daemon! */ if (!ruid || (pwd && (pwd->pw_uid == ruid))) _exit (fail ("dmail may not be invoked by root or daemon",EX_USAGE)); #include "linkage.c" /* process all flags */ for (--argc; argc && (*(s = *++argv)) == '-'; argc--) switch (s[1]) { case 'D': /* debug */ debug = T; /* extra debugging */ break; case 's': /* deliver as seen */ flagseen = T; break; case 'f': case 'r': /* flag giving return path */ if (sender) _exit (fail ("duplicate -r",EX_USAGE)); if (argc--) sender = cpystr (*++argv); else _exit (fail ("missing argument to -r",EX_USAGE)); break; case 'k': if (keywords) _exit (fail ("duplicate -k",EX_USAGE)); if (argc--) keywords = cpystr (*++argv); else _exit (fail ("missing argument to -k",EX_USAGE)); break; case 'p': if (s[2] && ((s[2] == '-') || isdigit (s[2]))) precedence = atol (s + 2); else if (argc-- && ((*(s = *++argv) == '-') || isdigit (*s))) precedence = atol (s); else _exit (fail ("missing argument to -p",EX_USAGE)); break; default: /* anything else */ _exit (fail ("unknown switch",EX_USAGE)); } if (argc > 1) _exit (fail ("too many recipients",EX_USAGE)); else if (!(f = tmpfile ())) _exit(fail ("can't make temp file",EX_TEMPFAIL)); /* build delivery headers */ if (sender) fprintf (f,"Return-Path: <%s>\015\012",sender); /* start Received line: */ fprintf (f,"Received: via dmail-%s.%s for %s; ",CCLIENTVERSION,version, (argc == 1) ? *argv : myusername ()); rfc822_date (tmp); fputs (tmp,f); fputs ("\015\012",f); /* copy text from standard input */ if (!fgets (tmp,MAILTMPLEN-1,stdin) || !(s = strchr (tmp,'\n')) || (s == tmp) || s[1]) _exit (fail ("bad first message line",EX_USAGE)); else if (s[-1] == '\015') { /* nuke leading "From " line */ if ((tmp[0] != 'F') || (tmp[1] != 'r') || (tmp[2] != 'o') || (tmp[3] != 'm') || (tmp[4] != ' ')) fputs (tmp,f); while ((c = getchar ()) != EOF) putc (c,f); } else { if ((tmp[0] != 'F') || (tmp[1] != 'r') || (tmp[2] != 'o') || (tmp[3] != 'm') || (tmp[4] != ' ')) { *s++ = '\015'; /* overwrite NL with CRLF */ *s++ = '\012'; *s = '\0'; /* tie off string */ fputs (tmp,f); /* write line */ } } /* copy text from standard input */ while ((c = getchar ()) != EOF) { /* add CR if needed */ if (c == '\012') putc ('\015',f); putc (c,f); } msglen = ftell (f); /* size of message */ fflush (f); /* make sure all changes written out */ if (ferror (f)) ret = fail ("error writing temp file",EX_TEMPFAIL); else if (!msglen) ret = fail ("empty message",EX_TEMPFAIL); /* single delivery */ else ret = deliver (f,msglen,argc ? *argv : myusername ()); fclose (f); /* all done with temporary file */ _exit (ret); /* normal exit */ return 0; /* stupid gcc */ } /* Deliver message to recipient list * Accepts: file description of message temporary file * size of message temporary file in bytes * recipient name * Returns: NIL if success, else error code */ int deliver (FILE *f,unsigned long msglen,char *user) { MAILSTREAM *ds = NIL; char *s,*mailbox,tmp[MAILTMPLEN],path[MAILTMPLEN]; STRING st; struct stat sbuf; /* have a mailbox specifier? */ if (mailbox = strchr (user,'+')) { *mailbox++ = '\0'; /* yes, tie off user name */ if (!*mailbox || !compare_cstring ((unsigned char *) mailbox,"INBOX")) mailbox = NIL; /* user+ and user+INBOX same as user */ } if (!*user) user = myusername (); else if (strcmp (user,myusername ())) return fail ("can't deliver to other user",EX_CANTCREAT); sprintf (tmp,"delivering to %.80s+%.80s",user,mailbox ? mailbox : "INBOX"); mm_dlog (tmp); /* prepare stringstruct */ INIT (&st,file_string,(void *) f,msglen); if (mailbox) { /* non-INBOX name */ switch (mailbox[0]) { /* make sure a valid name */ default: /* other names, try to deliver if not INBOX */ if (!strstr (mailbox,"..") && !strstr (mailbox,"//") && !strstr (mailbox,"/~") && mailboxfile (path,mailbox) && path[0] && !deliver_safely (NIL,&st,mailbox,path,tmp)) return NIL; case '%': case '*': /* wildcards not valid */ case '/': /* absolute path names not valid */ case '~': /* user names not valid */ sprintf (tmp,"invalid mailbox name %.80s+%.80s",user,mailbox); mm_log (tmp,WARN); break; } mm_dlog ("retrying delivery to INBOX"); SETPOS (&st,0); /* rewind stringstruct just in case */ } /* no -I, resolve "INBOX" into path */ if (mailboxfile (path,mailbox = "INBOX") && !path[0]) { /* clear box, get generic INBOX prototype */ if (!(ds = mail_open (NIL,"INBOX",OP_PROTOTYPE))) fatal ("no INBOX prototype"); /* standard system driver? */ if (!strcmp (ds->dtb->name,"unix") || !strcmp (ds->dtb->name,"mmdf")) { strcpy (path,sysinbox ());/* use system INBOX */ if (!lstat (path,&sbuf)) /* deliver to existing system INBOX */ return deliver_safely (ds,&st,mailbox,path,tmp); } else { /* other driver, try ~/INBOX */ if ((mailboxfile (path,"&&&&&") == path) && (s = strstr (path,"&&&&&")) && strcpy (s,"INBOX") && !lstat (path,&sbuf)){ /* deliver to existing ~/INBOX */ sprintf (tmp,"#driver.%s/INBOX",ds->dtb->name); return deliver_safely (ds,&st,cpystr (tmp),path,tmp); } } /* not dummy, deliver to driver imputed path */ if (strcmp (ds->dtb->name,"dummy")) return (ibxpath (ds,&mailbox,path) && !lstat (path,&sbuf)) ? deliver_safely (ds,&st,mailbox,path,tmp) : fail ("unable to resolve INBOX path",EX_CANTCREAT); /* dummy, empty imputed append path exist? */ if (ibxpath (ds = default_proto (T),&mailbox,path) && !lstat (path,&sbuf) && !sbuf.st_size) return deliver_safely (ds,&st,mailbox,path,tmp); /* impute path that we will create */ if (!ibxpath (ds = default_proto (NIL),&mailbox,path)) return fail ("unable to resolve INBOX",EX_CANTCREAT); } /* black box, must create, get create proto */ else if (lstat (path,&sbuf)) ds = default_proto (NIL); else { /* black box, existing file */ /* empty file, get append prototype */ if (!sbuf.st_size) ds = default_proto (T); /* non-empty, get prototype from its data */ else if (!(ds = mail_open (NIL,"INBOX",OP_PROTOTYPE))) fatal ("no INBOX prototype"); /* error if unknown format */ if (!strcmp (ds->dtb->name,"phile")) return fail ("unknown format INBOX",EX_UNAVAILABLE); /* otherwise can deliver to it */ return deliver_safely (ds,&st,mailbox,path,tmp); } sprintf (tmp,"attempting to create mailbox %.80s path %.80s",mailbox,path); mm_dlog (tmp); /* supplicate to the Evil One */ if (!path_create (ds,path)) return fail ("can't create INBOX",EX_CANTCREAT); sprintf (tmp,"created %.80s",path); mm_dlog (tmp); /* deliver the message */ return deliver_safely (ds,&st,mailbox,path,tmp); } /* Resolve INBOX from driver prototype into mailbox name and filesystem path * Accepts: driver prototype * pointer to mailbox name string pointer * buffer to return mailbox path * Returns: T if success, NIL if error */ long ibxpath (MAILSTREAM *ds,char **mailbox,char *path) { char *s,tmp[MAILTMPLEN]; long ret = T; if (!ds) return NIL; else if (!strcmp (ds->dtb->name,"unix") || !strcmp (ds->dtb->name,"mmdf")) strcpy (path,sysinbox ()); /* use system INBOX for unix and MMDF */ else if (!strcmp (ds->dtb->name,"tenex")) ret = (mailboxfile (path,"mail.txt") == path) ? T : NIL; else if (!strcmp (ds->dtb->name,"mtx")) ret = (mailboxfile (path,"INBOX.MTX") == path) ? T : NIL; else if (!strcmp (ds->dtb->name,"mbox")) ret = (mailboxfile (path,"mbox") == path) ? T : NIL; /* better not be a namespace driver */ else if (ds->dtb->flags & DR_NAMESPACE) return NIL; /* INBOX in home directory */ else ret = ((mailboxfile (path,"&&&&&") == path) && (s = strstr (path,"&&&&&")) && strcpy (s,"INBOX")) ? T : NIL; if (ret) { /* don't bother if lossage */ sprintf (tmp,"#driver.%s/INBOX",ds->dtb->name); *mailbox = cpystr (tmp); /* name of INBOX in this namespace */ } return ret; } /* Deliver safely * Accepts: prototype stream to force mailbox format * stringstruct of message temporary file or NIL for check only * mailbox name * filesystem path name * scratch buffer for messages * Returns: NIL if success, else error code */ int deliver_safely (MAILSTREAM *prt,STRING *st,char *mailbox,char *path, char *tmp) { struct stat sbuf; char *flags = NIL; int i = delivery_unsafe (path,&sbuf,tmp); if (i) return i; /* give up now if delivery unsafe */ /* directory, not file */ if ((sbuf.st_mode & S_IFMT) == S_IFDIR) { if (sbuf.st_mode & 0001) { /* listable directories may be worrisome */ sprintf (tmp,"WARNING: directory %.80s is listable",path); mm_log (tmp,WARN); } } else { /* file, not directory */ if (sbuf.st_nlink != 1) { /* multiple links may be worrisome */ sprintf (tmp,"WARNING: multiple links to file %.80s",path); mm_log (tmp,WARN); } if (sbuf.st_mode & 0111) { /* executable files may be worrisome */ sprintf (tmp,"WARNING: file %.80s is executable",path); mm_log (tmp,WARN); } } if (sbuf.st_mode & 0002) { /* public-write files may be worrisome */ sprintf (tmp,"WARNING: file %.80s is publicly-writable",path); mm_log (tmp,WARN); } if (sbuf.st_mode & 0004) { /* public-write files may be worrisome */ sprintf (tmp,"WARNING: file %.80s is publicly-readable",path); mm_log (tmp,WARN); } /* check site-written quota procedure */ if (!dmail_quota (st,path,tmp,sender,precedence)) return fail (tmp,EX_CANTCREAT); /* so far, so good */ sprintf (tmp,"%s appending to %.80s (%s %.80s)", prt ? prt->dtb->name : "default",mailbox, ((sbuf.st_mode & S_IFMT) == S_IFDIR) ? "directory" : "file",path); mm_dlog (tmp); if (keywords) { /* any keywords requested? */ if (flagseen) sprintf (flags = tmp,"\\Seen %.1000s",keywords); else flags = keywords; } else if (flagseen) flags = "\\Seen"; /* do the append now! */ if (!mail_append_full (prt,mailbox,flags,NIL,st)) { sprintf (tmp,"message delivery failed to %.80s",path); return fail (tmp,EX_CANTCREAT); } /* note success */ sprintf (tmp,"delivered to %.80s",path); mm_log (tmp,NIL); /* make sure nothing evil this way comes */ return delivery_unsafe (path,&sbuf,tmp); } /* Verify that delivery is safe * Accepts: path name * stat buffer * scratch buffer for messages * Returns: NIL if delivery is safe, error code if unsafe */ int delivery_unsafe (char *path,struct stat *sbuf,char *tmp) { u_short type; sprintf (tmp,"Verifying safe delivery to %.80s",path); mm_dlog (tmp); /* prepare message just in case */ sprintf (tmp,"delivery to %.80s unsafe: ",path); /* unsafe if can't get its status */ if (lstat (path,sbuf)) strcat (tmp,strerror (errno)); /* check file type */ else switch (sbuf->st_mode & S_IFMT) { case S_IFDIR: /* directory is always OK */ return NIL; case S_IFREG: /* file is unsafe if setuid */ if (sbuf->st_mode & S_ISUID) strcat (tmp,"setuid file"); /* or setgid */ else if (sbuf->st_mode & S_ISGID) strcat (tmp,"setgid file"); else return NIL; /* otherwise safe */ break; case S_IFCHR: strcat (tmp,"character special"); break; case S_IFBLK: strcat (tmp,"block special"); break; case S_IFLNK: strcat (tmp,"symbolic link"); break; case S_IFSOCK: strcat (tmp,"socket"); break; default: sprintf (tmp + strlen (tmp),"file type %07o",(unsigned int) type); } return fail (tmp,EX_CANTCREAT); } /* Report an error * Accepts: string to output */ int fail (char *string,int code) { mm_log (string,ERROR); /* pass up the string */ switch (code) { #if T case EX_USAGE: case EX_OSERR: case EX_SOFTWARE: case EX_NOUSER: case EX_CANTCREAT: code = EX_TEMPFAIL; /* coerce these to TEMPFAIL */ break; #endif case -1: /* quota failure... */ code = EX_CANTCREAT; /* ...really returns this code */ break; default: break; } return code; /* error code to return */ } /* Co-routines from MAIL library */ /* Message matches a search * Accepts: MAIL stream * message number */ void mm_searched (MAILSTREAM *stream,unsigned long msgno) { fatal ("mm_searched() call"); } /* Message exists (i.e. there are that many messages in the mailbox) * Accepts: MAIL stream * message number */ void mm_exists (MAILSTREAM *stream,unsigned long number) { fatal ("mm_exists() call"); } /* Message expunged * Accepts: MAIL stream * message number */ void mm_expunged (MAILSTREAM *stream,unsigned long number) { fatal ("mm_expunged() call"); } /* Message flags update seen * Accepts: MAIL stream * message number */ void mm_flags (MAILSTREAM *stream,unsigned long number) { } /* Mailbox found * Accepts: MAIL stream * delimiter * mailbox name * mailbox attributes */ void mm_list (MAILSTREAM *stream,int delimiter,char *name,long attributes) { fatal ("mm_list() call"); } /* Subscribed mailbox found * Accepts: MAIL stream * delimiter * mailbox name * mailbox attributes */ void mm_lsub (MAILSTREAM *stream,int delimiter,char *name,long attributes) { fatal ("mm_lsub() call"); } /* Mailbox status * Accepts: MAIL stream * mailbox name * mailbox status */ void mm_status (MAILSTREAM *stream,char *mailbox,MAILSTATUS *status) { fatal ("mm_status() call"); } /* Notification event * Accepts: MAIL stream * string to log * error flag */ void mm_notify (MAILSTREAM *stream,char *string,long errflg) { char tmp[MAILTMPLEN]; tmp[11] = '\0'; /* see if TRYCREATE */ if (!strcmp (ucase (strncpy (tmp,string,11)),"[TRYCREATE]")) trycreate = T; mm_log (string,errflg); /* just do mm_log action */ } /* Log an event for the user to see * Accepts: string to log * error flag */ void mm_log (char *string,long errflg) { if (trycreate)mm_dlog(string);/* debug logging only if trycreate in effect */ else { /* ordinary logging */ fprintf (stderr,"%s\n",string); switch (errflg) { case NIL: /* no error */ syslog (LOG_INFO,"%s",string); break; case PARSE: /* parsing problem */ case WARN: /* warning */ syslog (LOG_WARNING,"%s",string); break; case ERROR: /* error */ default: syslog (LOG_ERR,"%s",string); break; } } } /* Log an event to debugging telemetry * Accepts: string to log */ void mm_dlog (char *string) { if (debug) fprintf (stderr,"%s\n",string); syslog (LOG_DEBUG,"%s",string); } /* Get user name and password for this host * Accepts: parse of network mailbox name * where to return user name * where to return password * trial count */ void mm_login (NETMBX *mb,char *username,char *password,long trial) { fatal ("mm_login() call"); } /* About to enter critical code * Accepts: stream */ void mm_critical (MAILSTREAM *stream) { critical = T; /* note in critical code */ } /* About to exit critical code * Accepts: stream */ void mm_nocritical (MAILSTREAM *stream) { critical = NIL; /* note not in critical code */ } /* Disk error found * Accepts: stream * system error code * flag indicating that mailbox may be clobbered * Returns: T if user wants to abort */ long mm_diskerror (MAILSTREAM *stream,long errcode,long serious) { return T; } /* Log a fatal error event * Accepts: string to log */ void mm_fatal (char *string) { printf ("?%s\n",string); /* shouldn't happen normally */ } alpine-2.10+dfsg/imap/src/dmail/dquota.c0000600000175000017500000000234711512502122021604 0ustar paulproteuspaulproteus/* ======================================================================== * Copyright 1988-2007 University of Washington * * Licensed under the Apache License, Version 2.0 (the "License"); * you may not use this file except in compliance with the License. * You may obtain a copy of the License at * * http://www.apache.org/licenses/LICENSE-2.0 * * * ======================================================================== */ /* * Program: Procmail-Callable Mail Delivery Module Quota Hook * * Author: Mark Crispin * Networks and Distributed Computing * Computing & Communications * University of Washington * Administration Building, AG-44 * Seattle, WA 98195 * Internet: MRC@CAC.Washington.EDU * * Date: 10 September 2007 * Last Edited: 10 September 2007 */ #include "c-client.h" /* Site-written routine to validate delivery per quota and policy * Accepts: stringstruct of message temporary file * filesystem path * return path * buffer to write error message * precedence setting * Returns: T if can deliver, or NIL if quota issue and must bounce */ long dmail_quota (STRING *msg,char *path,char *tmp,char *sender, long precedence) { return LONGT; /* dummy success return */ } alpine-2.10+dfsg/imap/src/dmail/dmail.10000600000175000017500000000641511512502122021313 0ustar paulproteuspaulproteus.ig * ======================================================================== * Copyright 1988-2007 University of Washington * * Licensed under the Apache License, Version 2.0 (the "License"); * you may not use this file except in compliance with the License. * You may obtain a copy of the License at * * http://www.apache.org/licenses/LICENSE-2.0 * * * ======================================================================== .. .TH DMAIL 1 "June 18, 2007" .SH NAME dmail \- procmail Mail Delivery Module .nh .SH SYNOPSIS .B dmail .I [\-D] [\-f from_name] [-s] [-k keyword_list] [user][+folder] .SH DESCRIPTION .I dmail delivers mail to a user's INBOX or a designated folder. .I dmail may be configured as a drop-in replacement for .IR binmail (1), .IR mail.local (1) for use with a mail delivery filter such as .IR procmail (1) . .PP Because of security considerations (see below) .I dmail is not intended to be used for direct delivery by the mailer daemon; .IR tmail (1) is the preferred tool for this purpose. If .I dmail is used for mailer daemon delivery, the mailer daemon must invoke .I dmail with the .I dmail process' user id set to the recipient's user id. .PP When .I dmail exits, it returns exit status values to enable .IR procmail (1) to determine whether a message was delivered successfully or had a temporary (requeue for later delivery) or permanent (return to sender) failure. .PP If the .I user name is present, it must be the same as the logged-in user name. .PP If the .I +folder extension is included in the user argument (or appears by itself if there is no user argument), .I dmail will attempt to deliver to the designated folder. If the folder does not exist or the extension is not included, the message is delivered to the user's INBOX. If delivery is to INBOX and no INBOX currently exists, .I dmail will create a new INBOX. .I dmail recognizes the format of an existing INBOX or folder, and appends the new message in that format. .PP The \fB-D\fR flag specifies debugging; this enables additional message telemetry. .PP The \fB-f\fR or \fB-r\fR flag is used to specify a Return-Path. The header .br Return-Path: <\fIfrom_name\fR> .br is prepended to the message before delivery. .PP The .B -s flag specifies that the message will be flagged as being "seen". .PP The \fB-k\fR flag is used to specify delivery keywords, which are set on the message at delivery time if and .B only if the keywords are already defined in the mailbox. Multiple keywords can be specified by using a quoted string, e.g., .br dmail -k "$Junk Discard" +junkbox .br .SH RESTRICTIONS Absolute pathnames and .I ~user specifications are not permitted in .I +folder extensions. .SH SECURITY CONSIDERATIONS Unlike .I tmail you can use .I dmail to deliver to IMAP4 namespace names via .I +folder extensions. This means that it is possible to deliver to .IR mh (1) format mailboxes. .PP However, this can also include such namespaces as #shared, #public, and #ftp. In most cases, it is undesirable to allow anybody sending mail to the user to deliver to these namespaces. Consequently, there needs to be a rule in place in the configuration of either .IR sendmail (8) or .IR procmail (1) to prevent such abuse. .SH AUTHOR Mark Crispin, MRC@CAC.Washington.EDU .SH "SEE ALSO" binmail(1) .br procmail(1) alpine-2.10+dfsg/imap/src/mtest/0000700000175000017500000000000011512502151020203 5ustar paulproteuspaulproteusalpine-2.10+dfsg/imap/src/mtest/makefile.ntk0000600000175000017500000000262111512502124022501 0ustar paulproteuspaulproteus# ======================================================================== # Copyright 1988-2006 University of Washington # # Licensed under the Apache License, Version 2.0 (the "License"); # you may not use this file except in compliance with the License. # You may obtain a copy of the License at # # http://www.apache.org/licenses/LICENSE-2.0 # # # ======================================================================== # Program: MTEST Makefile for Windows 9x and Windows NT + Kerberos # # Author: Mark Crispin # Networks and Distributed Computing # Computing & Communications # University of Washington # Administration Building, AG-44 # Seattle, WA 98195 # Internet: MRC@CAC.Washington.EDU # # Date: 25 February 1996 # Last Edited: 30 August 2006 C = ..\c-client CCLIENTLIB = $C\cclient.lib K5 = \k5\lib K5LIB = $(K5)\comerr32.lib $(K5)\gssapi32.lib $(K5)\krb5_32.lib LIBS = $(CCLIENTLIB) $(K5LIB) ws2_32.lib winmm.lib advapi32.lib OSCOMPAT = /DWIN32 /D_WIN32_WINNT=0x0400 VSCOMPAT = /D_CRT_SECURE_NO_DEPRECATE /D_CRT_NONSTDC_NO_DEPRECATE CFLAGS= -I$C /MT /W3 $(OSCOMPAT) $(VSCOMPAT) -nologo $(EXTRACFLAGS) mtest: $(CCLIENTLIB) mtest.obj LINK /NOLOGO mtest.obj $(LIBS) mtest.obj: $C\mail.h $C\smtp.h $C\misc.h $C\osdep.h mtest.c $(CCLIENTLIB): @echo Make c-client first false clean: del *.obj *.exe *.lib *.exp || rem # A monument to a hack of long ago and far away... love: @echo not war? alpine-2.10+dfsg/imap/src/mtest/mtest.c0000600000175000017500000005537411512502124021523 0ustar paulproteuspaulproteus/* ======================================================================== * Copyright 1988-2007 University of Washington * * Licensed under the Apache License, Version 2.0 (the "License"); * you may not use this file except in compliance with the License. * You may obtain a copy of the License at * * http://www.apache.org/licenses/LICENSE-2.0 * * * ======================================================================== */ /* * Program: Mail library test program * * Author: Mark Crispin * Networks and Distributed Computing * Computing & Communications * University of Washington * Administration Building, AG-44 * Seattle, WA 98195 * Internet: MRC@CAC.Washington.EDU * * Date: 8 July 1988 * Last Edited: 5 November 2007 * * This original version of this file is * Copyright 1988 Stanford University * and was developed in the Symbolic Systems Resources Group of the Knowledge * Systems Laboratory at Stanford University in 1987-88, and was funded by the * Biomedical Research Technology Program of the NationalInstitutes of Health * under grant number RR-00785. */ #include #include #include #include "c-client.h" #include "imap4r1.h" /* Excellent reasons to hate ifdefs, and why my real code never uses them */ #ifndef unix # define unix 0 #endif #if unix # define UNIXLIKE 1 # define MACOS 0 # include #else # define UNIXLIKE 0 # ifdef noErr # define MACOS 1 # include # else # define MACOS 0 # endif #endif char *curhst = NIL; /* currently connected host */ char *curusr = NIL; /* current login user */ char personalname[MAILTMPLEN]; /* user's personal name */ static char *hostlist[] = { /* SMTP server host list */ "mailhost", "localhost", NIL }; static char *newslist[] = { /* Netnews server host list */ "news", NIL }; int main (void); void mm (MAILSTREAM *stream,long debug); void overview_header (MAILSTREAM *stream,unsigned long uid,OVERVIEW *ov, unsigned long msgno); void header (MAILSTREAM *stream,long msgno); void display_body (BODY *body,char *pfx,long i); void status (MAILSTREAM *stream); void prompt (char *msg,char *txt); void smtptest (long debug); /* Main program - initialization */ int main () { MAILSTREAM *stream = NIL; void *sdb = NIL; char *s,tmp[MAILTMPLEN]; long debug; #include "linkage.c" #if MACOS { size_t *base = (size_t *) 0x000908; /* increase stack size on a Mac */ SetApplLimit ((Ptr) (*base - (size_t) 65535L)); } #endif curusr = cpystr (((s = myusername ()) && *s) ? s : "somebody"); #if UNIXLIKE { char *suffix; struct passwd *pwd = getpwnam (curusr); if (pwd) { strcpy (tmp,pwd->pw_gecos); /* dyke out the office and phone poop */ if (suffix = strchr (tmp,',')) suffix[0] = '\0'; strcpy (personalname,tmp);/* make a permanent copy of it */ } else personalname[0] = '\0'; } #else personalname[0] = '\0'; #endif curhst = cpystr (mylocalhost ()); puts ("MTest -- C client test program"); if (!*personalname) prompt ("Personal name: ",personalname); /* user wants protocol telemetry? */ prompt ("Debug protocol (y/n)?",tmp); ucase (tmp); debug = (tmp[0] == 'Y') ? T : NIL; do { prompt ("Mailbox ('?' for help): ",tmp); if (!strcmp (tmp,"?")) { puts ("Enter INBOX, mailbox name, or IMAP mailbox as {host}mailbox"); puts ("Known local mailboxes:"); mail_list (NIL,NIL,"%"); if (s = sm_read (&sdb)) { puts ("Local subscribed mailboxes:"); do (mm_lsub (NIL,NIL,s,NIL)); while (s = sm_read (&sdb)); } puts ("or just hit return to quit"); } else if (tmp[0]) stream = mail_open (stream,tmp,debug ? OP_DEBUG : NIL); } while (!stream && tmp[0]); mm (stream,debug); /* run user interface if opened */ #if MACOS /* clean up resolver */ if (resolveropen) CloseResolver (); #endif return NIL; } /* MM command loop * Accepts: MAIL stream */ void mm (MAILSTREAM *stream,long debug) { void *sdb = NIL; char cmd[MAILTMPLEN]; char *s,*arg; unsigned long i; unsigned long last = 0; BODY *body; status (stream); /* first report message status */ while (stream) { prompt ("MTest>",cmd); /* prompt user, get command */ /* get argument */ if (arg = strchr (cmd,' ')) *arg++ = '\0'; switch (*ucase (cmd)) { /* dispatch based on command */ case 'B': /* Body command */ if (arg) last = atoi (arg); else if (!last) { puts ("?Missing message number"); break; } if (last && (last <= stream->nmsgs)) { mail_fetchstructure (stream,last,&body); if (body) display_body (body,NIL,(long) 0); else puts ("%No body information available"); } else puts ("?Bad message number"); break; case 'C': /* Check command */ mail_check (stream); status (stream); break; case 'D': /* Delete command */ if (arg) last = atoi (arg); else { if (last == 0) { puts ("?Missing message number"); break; } arg = cmd; sprintf (arg,"%lu",last); } if (last && (last <= stream->nmsgs)) mail_setflag (stream,arg,"\\DELETED"); else puts ("?Bad message number"); break; case 'E': /* Expunge command */ mail_expunge (stream); last = 0; break; case 'F': /* Find command */ if (!arg) { arg = "%"; if (s = sm_read (&sdb)) { puts ("Local network subscribed mailboxes:"); do if (*s == '{') (mm_lsub (NIL,NIL,s,NIL)); while (s = sm_read (&sdb)); } } puts ("Subscribed mailboxes:"); mail_lsub (((arg[0] == '{') && (*stream->mailbox == '{')) ? stream : NIL, NIL,arg); puts ("Known mailboxes:"); mail_list (((arg[0] == '{') && (*stream->mailbox == '{')) ? stream : NIL, NIL,arg); break; case 'G': mail_gc (stream,GC_ENV|GC_TEXTS|GC_ELT); break; case 'H': /* Headers command */ if (arg) { if (!(last = atoi (arg))) { mail_search (stream,arg); for (i = 1; i <= stream->nmsgs; ++i) if (mail_elt (stream,i)->searched) header (stream,i); break; } } else if (last == 0) { puts ("?Missing message number"); break; } if (last && (last <= stream->nmsgs)) header (stream,last); else puts ("?Bad message number"); break; case 'L': /* Literal command */ if (arg) last = atoi (arg); else if (!last) { puts ("?Missing message number"); break; } if (last && (last <= stream->nmsgs)) puts (mail_fetch_message (stream,last,NIL,NIL)); else puts ("?Bad message number"); break; case 'M': mail_status (NIL,arg ? arg : stream->mailbox, SA_MESSAGES|SA_RECENT|SA_UNSEEN|SA_UIDNEXT|SA_UIDVALIDITY); break; case 'N': /* New mailbox command */ if (!arg) { puts ("?Missing mailbox"); break; } /* get the new mailbox */ while (!(stream = mail_open (stream,arg,debug))) { prompt ("Mailbox: ",arg); if (!arg[0]) break; } last = 0; status (stream); break; case 'O': /* Overview command */ if (!arg) { puts ("?Missing UID"); break; } mail_fetch_overview (stream,arg,overview_header); break; case 'P': /* Ping command */ mail_ping (stream); status (stream); break; case 'Q': /* Quit command */ mail_close (stream); stream = NIL; break; case 'S': /* Send command */ smtptest (debug); break; case '\0': /* null command (type next message) */ if (!last || (last++ >= stream->nmsgs)) { puts ("%No next message"); break; } case 'T': /* Type command */ if (arg) last = atoi (arg); else if (!last) { puts ("?Missing message number"); break; } if (last && (last <= stream->nmsgs)) { STRINGLIST *lines = mail_newstringlist (); STRINGLIST *cur = lines; cur->text.size = strlen ((char *) (cur->text.data = (unsigned char *) cpystr ("Date"))); cur = cur->next = mail_newstringlist (); cur->text.size = strlen ((char *) (cur->text.data = (unsigned char *) cpystr ("From"))); cur = cur->next = mail_newstringlist (); cur->text.size = strlen ((char *) (cur->text.data = (unsigned char *) cpystr (">From"))); cur = cur->next = mail_newstringlist (); cur->text.size = strlen ((char *) (cur->text.data = (unsigned char *) cpystr ("Subject"))); cur = cur->next = mail_newstringlist (); cur->text.size = strlen ((char *) (cur->text.data = (unsigned char *) cpystr ("To"))); cur = cur->next = mail_newstringlist (); cur->text.size = strlen ((char *) (cur->text.data = (unsigned char *) cpystr ("cc"))); cur = cur->next = mail_newstringlist (); cur->text.size = strlen ((char *) (cur->text.data = (unsigned char *) cpystr ("Newsgroups"))); printf ("%s",mail_fetchheader_full (stream,last,lines,NIL,NIL)); puts (mail_fetchtext (stream,last)); mail_free_stringlist (&lines); } else puts ("?Bad message number"); break; case 'U': /* Undelete command */ if (arg) last = atoi (arg); else { if (!last) { puts ("?Missing message number"); break; } arg = cmd; sprintf (arg,"%lu",last); } if (last > 0 && last <= stream->nmsgs) mail_clearflag (stream,arg,"\\DELETED"); else puts ("?Bad message number"); break; case 'X': /* Xit command */ mail_expunge (stream); mail_close (stream); stream = NIL; break; case '+': mail_debug (stream); debug = T; break; case '-': mail_nodebug (stream); debug = NIL; break; case '?': /* ? command */ puts ("Body, Check, Delete, Expunge, Find, GC, Headers, Literal,"); puts (" MailboxStatus, New Mailbox, Overview, Ping, Quit, Send, Type,"); puts ("Undelete, Xit, +, -, or for next message"); break; default: /* bogus command */ printf ("?Unrecognized command: %s\n",cmd); break; } } } /* MM display header * Accepts: IMAP2 stream * message number */ void overview_header (MAILSTREAM *stream,unsigned long uid,OVERVIEW *ov, unsigned long msgno) { if (ov) { unsigned long i; char *t,tmp[MAILTMPLEN]; ADDRESS *adr; MESSAGECACHE *elt = mail_elt (stream,msgno); MESSAGECACHE selt; tmp[0] = elt->recent ? (elt->seen ? 'R': 'N') : ' '; tmp[1] = (elt->recent | elt->seen) ? ' ' : 'U'; tmp[2] = elt->flagged ? 'F' : ' '; tmp[3] = elt->answered ? 'A' : ' '; tmp[4] = elt->deleted ? 'D' : ' '; mail_parse_date (&selt,ov->date); sprintf (tmp+5,"%4lu) ",elt->msgno); mail_date (tmp+11,&selt); tmp[17] = ' '; tmp[18] = '\0'; memset (tmp+18,' ',(size_t) 20); tmp[38] = '\0'; /* tie off with null */ /* get first from address from envelope */ for (adr = ov->from; adr && !adr->host; adr = adr->next); if (adr) { /* if a personal name exists use it */ if (!(t = adr->personal)) sprintf (t = tmp+400,"%s@%s",adr->mailbox,adr->host); memcpy (tmp+18,t,(size_t) min (20,(long) strlen (t))); } strcat (tmp," "); if (i = elt->user_flags) { strcat (tmp,"{"); while (i) { strcat (tmp,stream->user_flags[find_rightmost_bit (&i)]); if (i) strcat (tmp," "); } strcat (tmp,"} "); } sprintf (tmp + strlen (tmp),"%.25s (%lu chars)", ov->subject ? ov->subject : " ",ov->optional.octets); puts (tmp); } else printf ("%%No overview for UID %lu\n",uid); } /* MM display header * Accepts: IMAP2 stream * message number */ void header (MAILSTREAM *stream,long msgno) { unsigned long i; char tmp[MAILTMPLEN]; char *t; MESSAGECACHE *cache = mail_elt (stream,msgno); mail_fetchstructure (stream,msgno,NIL); tmp[0] = cache->recent ? (cache->seen ? 'R': 'N') : ' '; tmp[1] = (cache->recent | cache->seen) ? ' ' : 'U'; tmp[2] = cache->flagged ? 'F' : ' '; tmp[3] = cache->answered ? 'A' : ' '; tmp[4] = cache->deleted ? 'D' : ' '; sprintf (tmp+5,"%4lu) ",cache->msgno); mail_date (tmp+11,cache); tmp[17] = ' '; tmp[18] = '\0'; mail_fetchfrom (tmp+18,stream,msgno,(long) 20); strcat (tmp," "); if (i = cache->user_flags) { strcat (tmp,"{"); while (i) { strcat (tmp,stream->user_flags[find_rightmost_bit (&i)]); if (i) strcat (tmp," "); } strcat (tmp,"} "); } mail_fetchsubject (t = tmp + strlen (tmp),stream,msgno,(long) 25); sprintf (t += strlen (t)," (%lu chars)",cache->rfc822_size); puts (tmp); } /* MM display body * Accepts: BODY structure pointer * prefix string * index */ void display_body (BODY *body,char *pfx,long i) { char tmp[MAILTMPLEN]; char *s = tmp; PARAMETER *par; PART *part; /* multipart doesn't have a row to itself */ if (body->type == TYPEMULTIPART) { /* if not first time, extend prefix */ if (pfx) sprintf (tmp,"%s%ld.",pfx,++i); else tmp[0] = '\0'; for (i = 0,part = body->nested.part; part; part = part->next) display_body (&part->body,tmp,i++); } else { /* non-multipart, output oneline descriptor */ if (!pfx) pfx = ""; /* dummy prefix if top level */ sprintf (s," %s%ld %s",pfx,++i,body_types[body->type]); if (body->subtype) sprintf (s += strlen (s),"/%s",body->subtype); if (body->description) sprintf (s += strlen (s)," (%s)",body->description); if (par = body->parameter) do sprintf (s += strlen (s),";%s=%s",par->attribute,par->value); while (par = par->next); if (body->id) sprintf (s += strlen (s),", id = %s",body->id); switch (body->type) { /* bytes or lines depending upon body type */ case TYPEMESSAGE: /* encapsulated message */ case TYPETEXT: /* plain text */ sprintf (s += strlen (s)," (%lu lines)",body->size.lines); break; default: sprintf (s += strlen (s)," (%lu bytes)",body->size.bytes); break; } puts (tmp); /* output this line */ /* encapsulated message? */ if ((body->type == TYPEMESSAGE) && !strcmp (body->subtype,"RFC822") && (body = body->nested.msg->body)) { if (body->type == TYPEMULTIPART) display_body (body,pfx,i-1); else { /* build encapsulation prefix */ sprintf (tmp,"%s%ld.",pfx,i); display_body (body,tmp,(long) 0); } } } } /* MM status report * Accepts: MAIL stream */ void status (MAILSTREAM *stream) { unsigned long i; char *s,date[MAILTMPLEN]; THREADER *thr; AUTHENTICATOR *auth; rfc822_date (date); puts (date); if (stream) { if (stream->mailbox) printf (" %s mailbox: %s, %lu messages, %lu recent\n", stream->dtb->name,stream->mailbox,stream->nmsgs,stream->recent); else puts ("%No mailbox is open on this stream"); if (stream->user_flags[0]) { printf ("Keywords: %s",stream->user_flags[0]); for (i = 1; i < NUSERFLAGS && stream->user_flags[i]; ++i) printf (", %s",stream->user_flags[i]); puts (""); } if (!strcmp (stream->dtb->name,"imap")) { if (LEVELIMAP4rev1 (stream)) s = "IMAP4rev1 (RFC 3501)"; else if (LEVEL1730 (stream)) s = "IMAP4 (RFC 1730)"; else if (LEVELIMAP2bis (stream)) s = "IMAP2bis"; else if (LEVEL1176 (stream)) s = "IMAP2 (RFC 1176)"; else s = "IMAP2 (RFC 1064)"; printf ("%s server %s\n",s,imap_host (stream)); if (LEVELIMAP4 (stream)) { if (i = imap_cap (stream)->auth) { s = ""; printf ("Mutually-supported SASL mechanisms:"); while (auth = mail_lookup_auth (find_rightmost_bit (&i) + 1)) { printf (" %s",auth->name); if (!strcmp (auth->name,"PLAIN")) s = "\n [LOGIN will not be listed here if PLAIN is supported]"; } puts (s); } printf ("Supported standard extensions:\n"); if (LEVELACL (stream)) puts (" Access Control lists (RFC 2086)"); if (LEVELQUOTA (stream)) puts (" Quotas (RFC 2087)"); if (LEVELLITERALPLUS (stream)) puts (" Non-synchronizing literals (RFC 2088)"); if (LEVELIDLE (stream)) puts (" IDLE unsolicited update (RFC 2177)"); if (LEVELMBX_REF (stream)) puts (" Mailbox referrals (RFC 2193)"); if (LEVELLOG_REF (stream)) puts (" Login referrals (RFC 2221)"); if (LEVELANONYMOUS (stream)) puts (" Anonymous access (RFC 2245)"); if (LEVELNAMESPACE (stream)) puts (" Multiple namespaces (RFC 2342)"); if (LEVELUIDPLUS (stream)) puts (" Extended UID behavior (RFC 2359)"); if (LEVELSTARTTLS (stream)) puts (" Transport Layer Security (RFC 2595)"); if (LEVELLOGINDISABLED (stream)) puts (" LOGIN command disabled (RFC 2595)"); if (LEVELID (stream)) puts (" Implementation identity negotiation (RFC 2971)"); if (LEVELCHILDREN (stream)) puts (" LIST children announcement (RFC 3348)"); if (LEVELMULTIAPPEND (stream)) puts (" Atomic multiple APPEND (RFC 3502)"); if (LEVELBINARY (stream)) puts (" Binary body content (RFC 3516)"); if (LEVELUNSELECT (stream)) puts (" Mailbox unselect (RFC 3691)"); if (LEVELURLAUTH (stream)) puts (" URL authenticated fetch (RFC 4467)"); if (LEVELCATENATE (stream)) puts (" Catenation (RFC 4469)"); if (LEVELCONDSTORE (stream)) puts (" Conditional STORE (RFC 4551)"); if (LEVELESEARCH (stream)) puts (" Extended SEARCH (RFC 4731)"); puts ("Supported draft extensions:"); if (LEVELSASLIR (stream)) puts (" SASL initial client response"); if (LEVELSORT (stream)) puts (" Server-based sorting"); if (LEVELTHREAD (stream)) { printf (" Server-based threading:"); for (thr = imap_cap (stream)->threader; thr; thr = thr->next) printf (" %s",thr->name); putchar ('\n'); } if (LEVELSCAN (stream)) puts (" Mailbox text scan"); if (i = imap_cap (stream)->extlevel) { printf ("Supported BODYSTRUCTURE extensions:"); switch (i) { case BODYEXTLOC: printf (" location"); case BODYEXTLANG: printf (" language"); case BODYEXTDSP: printf (" disposition"); case BODYEXTMD5: printf (" MD5\n"); } } } else putchar ('\n'); } } } /* Prompt user for input * Accepts: pointer to prompt message * pointer to input buffer */ void prompt (char *msg,char *txt) { printf ("%s",msg); gets (txt); } /* Interfaces to C-client */ void mm_searched (MAILSTREAM *stream,unsigned long number) { } void mm_exists (MAILSTREAM *stream,unsigned long number) { } void mm_expunged (MAILSTREAM *stream,unsigned long number) { } void mm_flags (MAILSTREAM *stream,unsigned long number) { } void mm_notify (MAILSTREAM *stream,char *string,long errflg) { mm_log (string,errflg); } void mm_list (MAILSTREAM *stream,int delimiter,char *mailbox,long attributes) { putchar (' '); if (delimiter) putchar (delimiter); else fputs ("NIL",stdout); putchar (' '); fputs (mailbox,stdout); if (attributes & LATT_NOINFERIORS) fputs (", no inferiors",stdout); if (attributes & LATT_NOSELECT) fputs (", no select",stdout); if (attributes & LATT_MARKED) fputs (", marked",stdout); if (attributes & LATT_UNMARKED) fputs (", unmarked",stdout); putchar ('\n'); } void mm_lsub (MAILSTREAM *stream,int delimiter,char *mailbox,long attributes) { putchar (' '); if (delimiter) putchar (delimiter); else fputs ("NIL",stdout); putchar (' '); fputs (mailbox,stdout); if (attributes & LATT_NOINFERIORS) fputs (", no inferiors",stdout); if (attributes & LATT_NOSELECT) fputs (", no select",stdout); if (attributes & LATT_MARKED) fputs (", marked",stdout); if (attributes & LATT_UNMARKED) fputs (", unmarked",stdout); putchar ('\n'); } void mm_status (MAILSTREAM *stream,char *mailbox,MAILSTATUS *status) { printf (" Mailbox %s",mailbox); if (status->flags & SA_MESSAGES) printf (", %lu messages",status->messages); if (status->flags & SA_RECENT) printf (", %lu recent",status->recent); if (status->flags & SA_UNSEEN) printf (", %lu unseen",status->unseen); if (status->flags & SA_UIDVALIDITY) printf (", %lu UID validity", status->uidvalidity); if (status->flags & SA_UIDNEXT) printf (", %lu next UID",status->uidnext); printf ("\n"); } void mm_log (char *string,long errflg) { switch ((short) errflg) { case NIL: printf ("[%s]\n",string); break; case PARSE: case WARN: printf ("%%%s\n",string); break; case ERROR: printf ("?%s\n",string); break; } } void mm_dlog (char *string) { puts (string); } void mm_login (NETMBX *mb,char *user,char *pwd,long trial) { char *s,tmp[MAILTMPLEN]; if (curhst) fs_give ((void **) &curhst); curhst = (char *) fs_get (1+strlen (mb->host)); strcpy (curhst,mb->host); sprintf (s = tmp,"{%s/%s",mb->host,mb->service); if (*mb->user) sprintf (tmp+strlen (tmp),"/user=%s",strcpy (user,mb->user)); if (*mb->authuser) sprintf (tmp+strlen (tmp),"/authuser=%s",mb->authuser); if (*mb->user) strcat (s = tmp,"} password:"); else { printf ("%s} username: ",tmp); fgets (user,NETMAXUSER-1,stdin); user[NETMAXUSER-1] = '\0'; if (s = strchr (user,'\n')) *s = '\0'; s = "password: "; } if (curusr) fs_give ((void **) &curusr); curusr = cpystr (user); strcpy (pwd,getpass (s)); } void mm_critical (MAILSTREAM *stream) { } void mm_nocritical (MAILSTREAM *stream) { } long mm_diskerror (MAILSTREAM *stream,long errcode,long serious) { #if UNIXLIKE kill (getpid (),SIGSTOP); #else abort (); #endif return NIL; } void mm_fatal (char *string) { printf ("?%s\n",string); } /* SMTP tester */ void smtptest (long debug) { SENDSTREAM *stream = NIL; char line[MAILTMPLEN]; char *text = (char *) fs_get (8*MAILTMPLEN); ENVELOPE *msg = mail_newenvelope (); BODY *body = mail_newbody (); msg->from = mail_newaddr (); msg->from->personal = cpystr (personalname); msg->from->mailbox = cpystr (curusr); msg->from->host = cpystr (curhst); msg->return_path = mail_newaddr (); msg->return_path->mailbox = cpystr (curusr); msg->return_path->host = cpystr (curhst); prompt ("To: ",line); rfc822_parse_adrlist (&msg->to,line,curhst); if (msg->to) { prompt ("cc: ",line); rfc822_parse_adrlist (&msg->cc,line,curhst); } else { prompt ("Newsgroups: ",line); if (*line) msg->newsgroups = cpystr (line); else { mail_free_body (&body); mail_free_envelope (&msg); fs_give ((void **) &text); return; } } prompt ("Subject: ",line); msg->subject = cpystr (line); puts (" Msg (end with a line with only a '.'):"); body->type = TYPETEXT; *text = '\0'; while (gets (line)) { if (line[0] == '.') { if (line[1] == '\0') break; else strcat (text,"."); } strcat (text,line); strcat (text,"\015\012"); } body->contents.text.data = (unsigned char *) text; body->contents.text.size = strlen (text); rfc822_date (line); msg->date = (char *) fs_get (1+strlen (line)); strcpy (msg->date,line); if (msg->to) { puts ("Sending..."); if (stream = smtp_open (hostlist,debug)) { if (smtp_mail (stream,"MAIL",msg,body)) puts ("[Ok]"); else printf ("[Failed - %s]\n",stream->reply); } } else { puts ("Posting..."); if (stream = nntp_open (newslist,debug)) { if (nntp_mail (stream,msg,body)) puts ("[Ok]"); else printf ("[Failed - %s]\n",stream->reply); } } if (stream) smtp_close (stream); else puts ("[Can't open connection to any server]"); mail_free_envelope (&msg); mail_free_body (&body); } alpine-2.10+dfsg/imap/src/mtest/Makefile0000600000175000017500000000231511512502124021646 0ustar paulproteuspaulproteus# ======================================================================== # Copyright 1988-2006 University of Washington # # Licensed under the Apache License, Version 2.0 (the "License"); # you may not use this file except in compliance with the License. # You may obtain a copy of the License at # # http://www.apache.org/licenses/LICENSE-2.0 # # # ======================================================================== # Program: MTEST Makefile # # Author: Mark Crispin # Networks and Distributed Computing # Computing & Communications # University of Washington # Administration Building, AG-44 # Seattle, WA 98195 # Internet: MRC@CAC.Washington.EDU # # Date: 25 February 1996 # Last Edited: 30 August 2006 C = ../c-client CCLIENTLIB = $C/c-client.a SHELL = /bin/sh # Get local definitions from c-client directory CC = `cat $C/CCTYPE` CFLAGS = -I$C `cat $C/CFLAGS` LDFLAGS = $(CCLIENTLIB) `cat $C/LDFLAGS` all: mtest mtest: $(CCLIENTLIB) mtest.o $(CC) $(CFLAGS) -o mtest mtest.o $(LDFLAGS) mtest.o: $C/mail.h $C/misc.h $C/osdep.h $C/rfc822.h $C/smtp.h $C/nntp.h $(CCLIENTLIB): cd $C;make clean: rm -f *.o mtest || true # A monument to a hack of long ago and far away... love: @echo 'not war?' alpine-2.10+dfsg/imap/src/mtest/makefile.os20000600000175000017500000000236611512502124022416 0ustar paulproteuspaulproteus# ======================================================================== # Copyright 1988-2006 University of Washington # # Licensed under the Apache License, Version 2.0 (the "License"); # you may not use this file except in compliance with the License. # You may obtain a copy of the License at # # http://www.apache.org/licenses/LICENSE-2.0 # # # ======================================================================== # Program: MTEST Makefile # # Author: Mark Crispin # Networks and Distributed Computing # Computing & Communications # University of Washington # Administration Building, AG-44 # Seattle, WA 98195 # Internet: MRC@CAC.Washington.EDU # # Date: 25 February 1996 # Last Edited: 30 August 2006 # Thanks to Nicholas Paul Sheppard who contributed the original version CC = gcc CFLAGS = -O2 -Zomf LD = gcc LDFLAGS = -s -Zomf -Zcrtdll C = ..\c-client CCLIENTLIB = $C\\c-client.lib LIBS = $(CCLIENTLIB) -l socket mtest.exe: $(CCLIENTLIB) mtest.obj $(LD) $(LDFLAGS) -o $@ $^ $(LIBS) $(CCLIENTLIB): @echo Make c-client first false mtest.obj: mtest.c $C\mail.h $C\smtp.h $C\misc.h $C\osdep.h $(CC) $(CFLAGS) -I$C -o $@ -c $< clean: if exist *.obj del *.obj # A monument to a hack of long ago and far away... love: @echo not war? alpine-2.10+dfsg/imap/src/mtest/makefile.w2k0000600000175000017500000000245011512502124022410 0ustar paulproteuspaulproteus# ======================================================================== # Copyright 1988-2006 University of Washington # # Licensed under the Apache License, Version 2.0 (the "License"); # you may not use this file except in compliance with the License. # You may obtain a copy of the License at # # http://www.apache.org/licenses/LICENSE-2.0 # # # ======================================================================== # Program: MTEST Makefile for Windows 2000/XP # # Author: Mark Crispin # Networks and Distributed Computing # Computing & Communications # University of Washington # Administration Building, AG-44 # Seattle, WA 98195 # Internet: MRC@CAC.Washington.EDU # # Date: 25 February 1996 # Last Edited: 30 August 2006 C = ..\c-client CCLIENTLIB = $C\cclient.lib LIBS = $(CCLIENTLIB) ws2_32.lib winmm.lib advapi32.lib secur32.lib crypt32.lib OSCOMPAT = /DWIN32 VSCOMPAT = /D_CRT_SECURE_NO_DEPRECATE /D_CRT_NONSTDC_NO_DEPRECATE CFLAGS= -I$C /MT /W3 $(OSCOMPAT) $(VSCOMPAT) -nologo $(EXTRACFLAGS) mtest: $(CCLIENTLIB) mtest.obj LINK /NOLOGO mtest.obj $(LIBS) mtest.obj: $C\mail.h $C\smtp.h $C\misc.h $C\osdep.h mtest.c $(CCLIENTLIB): @echo Make c-client first false clean: del *.obj *.exe *.lib *.exp || rem # A monument to a hack of long ago and far away... love: @echo not war? alpine-2.10+dfsg/imap/src/mtest/makefile.nt0000600000175000017500000000246011512502124022327 0ustar paulproteuspaulproteus# ======================================================================== # Copyright 1988-2006 University of Washington # # Licensed under the Apache License, Version 2.0 (the "License"); # you may not use this file except in compliance with the License. # You may obtain a copy of the License at # # http://www.apache.org/licenses/LICENSE-2.0 # # # ======================================================================== # Program: MTEST Makefile for Windows 9x and Windows NT # # Author: Mark Crispin # Networks and Distributed Computing # Computing & Communications # University of Washington # Administration Building, AG-44 # Seattle, WA 98195 # Internet: MRC@CAC.Washington.EDU # # Date: 25 February 1996 # Last Edited: 30 August 2006 C = ..\c-client CCLIENTLIB = $C\cclient.lib LIBS = $(CCLIENTLIB) ws2_32.lib winmm.lib advapi32.lib OSCOMPAT = /DWIN32 /D_WIN32_WINNT=0x0400 VSCOMPAT = /D_CRT_SECURE_NO_DEPRECATE /D_CRT_NONSTDC_NO_DEPRECATE CFLAGS= -I$C /MT /W3 $(OSCOMPAT) $(VSCOMPAT) -nologo $(EXTRACFLAGS) mtest: $(CCLIENTLIB) mtest.obj LINK /NOLOGO mtest.obj $(LIBS) mtest.obj: $C\mail.h $C\smtp.h $C\misc.h $C\osdep.h mtest.c $(CCLIENTLIB): @echo Make c-client first false clean: del *.obj *.exe *.lib *.exp || rem # A monument to a hack of long ago and far away... love: @echo not war? alpine-2.10+dfsg/imap/src/charset/0000700000175000017500000000000011512502151020500 5ustar paulproteuspaulproteusalpine-2.10+dfsg/imap/src/charset/jis_0212.c0000600000175000017500000015746011512502123022113 0ustar paulproteuspaulproteus/* ======================================================================== * Copyright 1988-2006 University of Washington * * Licensed under the Apache License, Version 2.0 (the "License"); * you may not use this file except in compliance with the License. * You may obtain a copy of the License at * * http://www.apache.org/licenses/LICENSE-2.0 * * * ======================================================================== */ /* * Program: JIS X0212 conversion table * * Author: Mark Crispin * Networks and Distributed Computing * Computing & Communications * University of Washington * Administration Building, AG-44 * Seattle, WA 98195 * Internet: MRC@CAC.Washington.EDU * * Date: 4 August 1997 * Last Edited: 30 August 2006 */ /* JIS X0212 is the supplemental industrial standard of Japan. */ #define BASE_JIS0212_KU 0x22 #define BASE_JIS0212_TEN 0x21 #define MAX_JIS0212_KU 76 #define MAX_JIS0212_TEN 94 #define JIS0212TOUNICODE(c,c1,ku,ten) \ ((((ku = (c & 0x7f) - BASE_JIS0212_KU) < MAX_JIS0212_KU) && \ ((ten = (c1 & 0x7f) - BASE_JIS0212_TEN) < MAX_JIS0212_TEN)) ? \ jis0212tab[ku][ten] : UBOGON) static const unsigned short jis0212tab[MAX_JIS0212_KU][MAX_JIS0212_TEN] = { { /* ku 02 */ UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON, UBOGON,UBOGON,UBOGON,UBOGON,0x02d8,0x02c7,0x00b8,0x02d9,0x02dd,0x00af, 0x02db,0x02da,0x007e,0x0384,0x0385,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON, UBOGON,UBOGON,UBOGON,0x00a1,0x00a6,0x00bf,UBOGON,UBOGON,UBOGON,UBOGON, UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON, UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON, UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON, UBOGON,UBOGON,UBOGON,UBOGON,0x00ba,0x00aa,0x00a9,0x00ae,0x2122,0x00a4, 0x2116,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON, UBOGON,UBOGON,UBOGON,UBOGON }, { /* ku 03 */ UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON, UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON, UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON, UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON, UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON, UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON, UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON, UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON, UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON, UBOGON,UBOGON,UBOGON,UBOGON }, { /* ku 04 */ UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON, UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON, UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON, UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON, UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON, UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON, UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON, UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON, UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON, UBOGON,UBOGON,UBOGON,UBOGON }, { /* ku 05 */ /* Note: ku/ten codepoints 05/87 - 05/90 are proposed for addition to * JIS X 0212; I don't know if they've been formally accepted yet. * They represent katakana VA, VI, VE, and VO, and are in the BMP but * not in Unicode's JIS conversion tables. They're useful enough that * I decided to put them here. */ UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON, UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON, UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON, UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON, UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON, UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON, UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON, UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON, UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,0x30f7,0x30f8,0x30f9,0x30fa, UBOGON,UBOGON,UBOGON,UBOGON }, { /* ku 06 */ UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON, UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON, UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON, UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON, UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON, UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON, UBOGON,UBOGON,UBOGON,UBOGON,0x0386,0x0388,0x0389,0x038a,0x03aa,UBOGON, 0x038c,UBOGON,0x038e,0x03ab,UBOGON,0x038f,UBOGON,UBOGON,UBOGON,UBOGON, 0x03ac,0x03ad,0x03ae,0x03af,0x03ca,0x0390,0x03cc,0x03c2,0x03cd,0x03cb, 0x03b0,0x03ce,UBOGON,UBOGON }, { /* ku 07 */ UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON, UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON, UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON, UBOGON,UBOGON,UBOGON,0x0402,0x0403,0x0404,0x0405,0x0406,0x0407,0x0408, 0x0409,0x040a,0x040b,0x040c,0x040e,0x040f,UBOGON,UBOGON,UBOGON,UBOGON, UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON, UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON, UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON, UBOGON,0x0452,0x0453,0x0454,0x0455,0x0456,0x0457,0x0458,0x0459,0x045a, 0x045b,0x045c,0x045e,0x045f }, { /* ku 08 */ UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON, UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON, UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON, UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON, UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON, UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON, UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON, UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON, UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON, UBOGON,UBOGON,UBOGON,UBOGON }, { /* ku 09 */ 0x00c6,0x0110,UBOGON,0x0126,UBOGON,0x0132,UBOGON,0x0141,0x013f,UBOGON, 0x014a,0x00d8,0x0152,UBOGON,0x0166,0x00de,UBOGON,UBOGON,UBOGON,UBOGON, UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON, UBOGON,UBOGON,0x00e6,0x0111,0x00f0,0x0127,0x0131,0x0133,0x0138,0x0142, 0x0140,0x0149,0x014b,0x00f8,0x0153,0x00df,0x0167,0x00fe,UBOGON,UBOGON, UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON, UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON, UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON, UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON, UBOGON,UBOGON,UBOGON,UBOGON }, { /* ku 0a */ 0x00c1,0x00c0,0x00c4,0x00c2,0x0102,0x01cd,0x0100,0x0104,0x00c5,0x00c3, 0x0106,0x0108,0x010c,0x00c7,0x010a,0x010e,0x00c9,0x00c8,0x00cb,0x00ca, 0x011a,0x0116,0x0112,0x0118,UBOGON,0x011c,0x011e,0x0122,0x0120,0x0124, 0x00cd,0x00cc,0x00cf,0x00ce,0x01cf,0x0130,0x012a,0x012e,0x0128,0x0134, 0x0136,0x0139,0x013d,0x013b,0x0143,0x0147,0x0145,0x00d1,0x00d3,0x00d2, 0x00d6,0x00d4,0x01d1,0x0150,0x014c,0x00d5,0x0154,0x0158,0x0156,0x015a, 0x015c,0x0160,0x015e,0x0164,0x0162,0x00da,0x00d9,0x00dc,0x00db,0x016c, 0x01d3,0x0170,0x016a,0x0172,0x016e,0x0168,0x01d7,0x01db,0x01d9,0x01d5, 0x0174,0x00dd,0x0178,0x0176,0x0179,0x017d,0x017b,UBOGON,UBOGON,UBOGON, UBOGON,UBOGON,UBOGON,UBOGON }, { /* ku 0b */ 0x00e1,0x00e0,0x00e4,0x00e2,0x0103,0x01ce,0x0101,0x0105,0x00e5,0x00e3, 0x0107,0x0109,0x010d,0x00e7,0x010b,0x010f,0x00e9,0x00e8,0x00eb,0x00ea, 0x011b,0x0117,0x0113,0x0119,0x01f5,0x011d,0x011f,UBOGON,0x0121,0x0125, 0x00ed,0x00ec,0x00ef,0x00ee,0x01d0,UBOGON,0x012b,0x012f,0x0129,0x0135, 0x0137,0x013a,0x013e,0x013c,0x0144,0x0148,0x0146,0x00f1,0x00f3,0x00f2, 0x00f6,0x00f4,0x01d2,0x0151,0x014d,0x00f5,0x0155,0x0159,0x0157,0x015b, 0x015d,0x0161,0x015f,0x0165,0x0163,0x00fa,0x00f9,0x00fc,0x00fb,0x016d, 0x01d4,0x0171,0x016b,0x0173,0x016f,0x0169,0x01d8,0x01dc,0x01da,0x01d6, 0x0175,0x00fd,0x00ff,0x0177,0x017a,0x017e,0x017c,UBOGON,UBOGON,UBOGON, UBOGON,UBOGON,UBOGON,UBOGON }, { /* ku 0c */ UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON, UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON, UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON, UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON, UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON, UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON, UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON, UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON, UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON, UBOGON,UBOGON,UBOGON,UBOGON }, { /* ku 0d */ UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON, UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON, UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON, UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON, UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON, UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON, UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON, UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON, UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON, UBOGON,UBOGON,UBOGON,UBOGON }, { /* ku 0e */ UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON, UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON, UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON, UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON, UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON, UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON, UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON, UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON, UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON, UBOGON,UBOGON,UBOGON,UBOGON }, { /* ku 0f */ UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON, UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON, UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON, UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON, UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON, UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON, UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON, UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON, UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON, UBOGON,UBOGON,UBOGON,UBOGON }, { /* ku 10 */ 0x4e02,0x4e04,0x4e05,0x4e0c,0x4e12,0x4e1f,0x4e23,0x4e24,0x4e28,0x4e2b, 0x4e2e,0x4e2f,0x4e30,0x4e35,0x4e40,0x4e41,0x4e44,0x4e47,0x4e51,0x4e5a, 0x4e5c,0x4e63,0x4e68,0x4e69,0x4e74,0x4e75,0x4e79,0x4e7f,0x4e8d,0x4e96, 0x4e97,0x4e9d,0x4eaf,0x4eb9,0x4ec3,0x4ed0,0x4eda,0x4edb,0x4ee0,0x4ee1, 0x4ee2,0x4ee8,0x4eef,0x4ef1,0x4ef3,0x4ef5,0x4efd,0x4efe,0x4eff,0x4f00, 0x4f02,0x4f03,0x4f08,0x4f0b,0x4f0c,0x4f12,0x4f15,0x4f16,0x4f17,0x4f19, 0x4f2e,0x4f31,0x4f60,0x4f33,0x4f35,0x4f37,0x4f39,0x4f3b,0x4f3e,0x4f40, 0x4f42,0x4f48,0x4f49,0x4f4b,0x4f4c,0x4f52,0x4f54,0x4f56,0x4f58,0x4f5f, 0x4f63,0x4f6a,0x4f6c,0x4f6e,0x4f71,0x4f77,0x4f78,0x4f79,0x4f7a,0x4f7d, 0x4f7e,0x4f81,0x4f82,0x4f84 }, { /* ku 11 */ 0x4f85,0x4f89,0x4f8a,0x4f8c,0x4f8e,0x4f90,0x4f92,0x4f93,0x4f94,0x4f97, 0x4f99,0x4f9a,0x4f9e,0x4f9f,0x4fb2,0x4fb7,0x4fb9,0x4fbb,0x4fbc,0x4fbd, 0x4fbe,0x4fc0,0x4fc1,0x4fc5,0x4fc6,0x4fc8,0x4fc9,0x4fcb,0x4fcc,0x4fcd, 0x4fcf,0x4fd2,0x4fdc,0x4fe0,0x4fe2,0x4ff0,0x4ff2,0x4ffc,0x4ffd,0x4fff, 0x5000,0x5001,0x5004,0x5007,0x500a,0x500c,0x500e,0x5010,0x5013,0x5017, 0x5018,0x501b,0x501c,0x501d,0x501e,0x5022,0x5027,0x502e,0x5030,0x5032, 0x5033,0x5035,0x5040,0x5041,0x5042,0x5045,0x5046,0x504a,0x504c,0x504e, 0x5051,0x5052,0x5053,0x5057,0x5059,0x505f,0x5060,0x5062,0x5063,0x5066, 0x5067,0x506a,0x506d,0x5070,0x5071,0x503b,0x5081,0x5083,0x5084,0x5086, 0x508a,0x508e,0x508f,0x5090 }, { /* ku 12 */ 0x5092,0x5093,0x5094,0x5096,0x509b,0x509c,0x509e,0x509f,0x50a0,0x50a1, 0x50a2,0x50aa,0x50af,0x50b0,0x50b9,0x50ba,0x50bd,0x50c0,0x50c3,0x50c4, 0x50c7,0x50cc,0x50ce,0x50d0,0x50d3,0x50d4,0x50d8,0x50dc,0x50dd,0x50df, 0x50e2,0x50e4,0x50e6,0x50e8,0x50e9,0x50ef,0x50f1,0x50f6,0x50fa,0x50fe, 0x5103,0x5106,0x5107,0x5108,0x510b,0x510c,0x510d,0x510e,0x50f2,0x5110, 0x5117,0x5119,0x511b,0x511c,0x511d,0x511e,0x5123,0x5127,0x5128,0x512c, 0x512d,0x512f,0x5131,0x5133,0x5134,0x5135,0x5138,0x5139,0x5142,0x514a, 0x514f,0x5153,0x5155,0x5157,0x5158,0x515f,0x5164,0x5166,0x517e,0x5183, 0x5184,0x518b,0x518e,0x5198,0x519d,0x51a1,0x51a3,0x51ad,0x51b8,0x51ba, 0x51bc,0x51be,0x51bf,0x51c2 }, { /* ku 13 */ 0x51c8,0x51cf,0x51d1,0x51d2,0x51d3,0x51d5,0x51d8,0x51de,0x51e2,0x51e5, 0x51ee,0x51f2,0x51f3,0x51f4,0x51f7,0x5201,0x5202,0x5205,0x5212,0x5213, 0x5215,0x5216,0x5218,0x5222,0x5228,0x5231,0x5232,0x5235,0x523c,0x5245, 0x5249,0x5255,0x5257,0x5258,0x525a,0x525c,0x525f,0x5260,0x5261,0x5266, 0x526e,0x5277,0x5278,0x5279,0x5280,0x5282,0x5285,0x528a,0x528c,0x5293, 0x5295,0x5296,0x5297,0x5298,0x529a,0x529c,0x52a4,0x52a5,0x52a6,0x52a7, 0x52af,0x52b0,0x52b6,0x52b7,0x52b8,0x52ba,0x52bb,0x52bd,0x52c0,0x52c4, 0x52c6,0x52c8,0x52cc,0x52cf,0x52d1,0x52d4,0x52d6,0x52db,0x52dc,0x52e1, 0x52e5,0x52e8,0x52e9,0x52ea,0x52ec,0x52f0,0x52f1,0x52f4,0x52f6,0x52f7, 0x5300,0x5303,0x530a,0x530b }, { /* ku 14 */ 0x530c,0x5311,0x5313,0x5318,0x531b,0x531c,0x531e,0x531f,0x5325,0x5327, 0x5328,0x5329,0x532b,0x532c,0x532d,0x5330,0x5332,0x5335,0x533c,0x533d, 0x533e,0x5342,0x534c,0x534b,0x5359,0x535b,0x5361,0x5363,0x5365,0x536c, 0x536d,0x5372,0x5379,0x537e,0x5383,0x5387,0x5388,0x538e,0x5393,0x5394, 0x5399,0x539d,0x53a1,0x53a4,0x53aa,0x53ab,0x53af,0x53b2,0x53b4,0x53b5, 0x53b7,0x53b8,0x53ba,0x53bd,0x53c0,0x53c5,0x53cf,0x53d2,0x53d3,0x53d5, 0x53da,0x53dd,0x53de,0x53e0,0x53e6,0x53e7,0x53f5,0x5402,0x5413,0x541a, 0x5421,0x5427,0x5428,0x542a,0x542f,0x5431,0x5434,0x5435,0x5443,0x5444, 0x5447,0x544d,0x544f,0x545e,0x5462,0x5464,0x5466,0x5467,0x5469,0x546b, 0x546d,0x546e,0x5474,0x547f }, { /* ku 15 */ 0x5481,0x5483,0x5485,0x5488,0x5489,0x548d,0x5491,0x5495,0x5496,0x549c, 0x549f,0x54a1,0x54a6,0x54a7,0x54a9,0x54aa,0x54ad,0x54ae,0x54b1,0x54b7, 0x54b9,0x54ba,0x54bb,0x54bf,0x54c6,0x54ca,0x54cd,0x54ce,0x54e0,0x54ea, 0x54ec,0x54ef,0x54f6,0x54fc,0x54fe,0x54ff,0x5500,0x5501,0x5505,0x5508, 0x5509,0x550c,0x550d,0x550e,0x5515,0x552a,0x552b,0x5532,0x5535,0x5536, 0x553b,0x553c,0x553d,0x5541,0x5547,0x5549,0x554a,0x554d,0x5550,0x5551, 0x5558,0x555a,0x555b,0x555e,0x5560,0x5561,0x5564,0x5566,0x557f,0x5581, 0x5582,0x5586,0x5588,0x558e,0x558f,0x5591,0x5592,0x5593,0x5594,0x5597, 0x55a3,0x55a4,0x55ad,0x55b2,0x55bf,0x55c1,0x55c3,0x55c6,0x55c9,0x55cb, 0x55cc,0x55ce,0x55d1,0x55d2 }, { /* ku 16 */ 0x55d3,0x55d7,0x55d8,0x55db,0x55de,0x55e2,0x55e9,0x55f6,0x55ff,0x5605, 0x5608,0x560a,0x560d,0x560e,0x560f,0x5610,0x5611,0x5612,0x5619,0x562c, 0x5630,0x5633,0x5635,0x5637,0x5639,0x563b,0x563c,0x563d,0x563f,0x5640, 0x5641,0x5643,0x5644,0x5646,0x5649,0x564b,0x564d,0x564f,0x5654,0x565e, 0x5660,0x5661,0x5662,0x5663,0x5666,0x5669,0x566d,0x566f,0x5671,0x5672, 0x5675,0x5684,0x5685,0x5688,0x568b,0x568c,0x5695,0x5699,0x569a,0x569d, 0x569e,0x569f,0x56a6,0x56a7,0x56a8,0x56a9,0x56ab,0x56ac,0x56ad,0x56b1, 0x56b3,0x56b7,0x56be,0x56c5,0x56c9,0x56ca,0x56cb,0x56cf,0x56d0,0x56cc, 0x56cd,0x56d9,0x56dc,0x56dd,0x56df,0x56e1,0x56e4,0x56e5,0x56e6,0x56e7, 0x56e8,0x56f1,0x56eb,0x56ed }, { /* ku 17 */ 0x56f6,0x56f7,0x5701,0x5702,0x5707,0x570a,0x570c,0x5711,0x5715,0x571a, 0x571b,0x571d,0x5720,0x5722,0x5723,0x5724,0x5725,0x5729,0x572a,0x572c, 0x572e,0x572f,0x5733,0x5734,0x573d,0x573e,0x573f,0x5745,0x5746,0x574c, 0x574d,0x5752,0x5762,0x5765,0x5767,0x5768,0x576b,0x576d,0x576e,0x576f, 0x5770,0x5771,0x5773,0x5774,0x5775,0x5777,0x5779,0x577a,0x577b,0x577c, 0x577e,0x5781,0x5783,0x578c,0x5794,0x5797,0x5799,0x579a,0x579c,0x579d, 0x579e,0x579f,0x57a1,0x5795,0x57a7,0x57a8,0x57a9,0x57ac,0x57b8,0x57bd, 0x57c7,0x57c8,0x57cc,0x57cf,0x57d5,0x57dd,0x57de,0x57e4,0x57e6,0x57e7, 0x57e9,0x57ed,0x57f0,0x57f5,0x57f6,0x57f8,0x57fd,0x57fe,0x57ff,0x5803, 0x5804,0x5808,0x5809,0x57e1 }, { /* ku 18 */ 0x580c,0x580d,0x581b,0x581e,0x581f,0x5820,0x5826,0x5827,0x582d,0x5832, 0x5839,0x583f,0x5849,0x584c,0x584d,0x584f,0x5850,0x5855,0x585f,0x5861, 0x5864,0x5867,0x5868,0x5878,0x587c,0x587f,0x5880,0x5881,0x5887,0x5888, 0x5889,0x588a,0x588c,0x588d,0x588f,0x5890,0x5894,0x5896,0x589d,0x58a0, 0x58a1,0x58a2,0x58a6,0x58a9,0x58b1,0x58b2,0x58c4,0x58bc,0x58c2,0x58c8, 0x58cd,0x58ce,0x58d0,0x58d2,0x58d4,0x58d6,0x58da,0x58dd,0x58e1,0x58e2, 0x58e9,0x58f3,0x5905,0x5906,0x590b,0x590c,0x5912,0x5913,0x5914,0x8641, 0x591d,0x5921,0x5923,0x5924,0x5928,0x592f,0x5930,0x5933,0x5935,0x5936, 0x593f,0x5943,0x5946,0x5952,0x5953,0x5959,0x595b,0x595d,0x595e,0x595f, 0x5961,0x5963,0x596b,0x596d }, { /* ku 19 */ 0x596f,0x5972,0x5975,0x5976,0x5979,0x597b,0x597c,0x598b,0x598c,0x598e, 0x5992,0x5995,0x5997,0x599f,0x59a4,0x59a7,0x59ad,0x59ae,0x59af,0x59b0, 0x59b3,0x59b7,0x59ba,0x59bc,0x59c1,0x59c3,0x59c4,0x59c8,0x59ca,0x59cd, 0x59d2,0x59dd,0x59de,0x59df,0x59e3,0x59e4,0x59e7,0x59ee,0x59ef,0x59f1, 0x59f2,0x59f4,0x59f7,0x5a00,0x5a04,0x5a0c,0x5a0d,0x5a0e,0x5a12,0x5a13, 0x5a1e,0x5a23,0x5a24,0x5a27,0x5a28,0x5a2a,0x5a2d,0x5a30,0x5a44,0x5a45, 0x5a47,0x5a48,0x5a4c,0x5a50,0x5a55,0x5a5e,0x5a63,0x5a65,0x5a67,0x5a6d, 0x5a77,0x5a7a,0x5a7b,0x5a7e,0x5a8b,0x5a90,0x5a93,0x5a96,0x5a99,0x5a9c, 0x5a9e,0x5a9f,0x5aa0,0x5aa2,0x5aa7,0x5aac,0x5ab1,0x5ab2,0x5ab3,0x5ab5, 0x5ab8,0x5aba,0x5abb,0x5abf }, { /* ku 1a */ 0x5ac4,0x5ac6,0x5ac8,0x5acf,0x5ada,0x5adc,0x5ae0,0x5ae5,0x5aea,0x5aee, 0x5af5,0x5af6,0x5afd,0x5b00,0x5b01,0x5b08,0x5b17,0x5b34,0x5b19,0x5b1b, 0x5b1d,0x5b21,0x5b25,0x5b2d,0x5b38,0x5b41,0x5b4b,0x5b4c,0x5b52,0x5b56, 0x5b5e,0x5b68,0x5b6e,0x5b6f,0x5b7c,0x5b7d,0x5b7e,0x5b7f,0x5b81,0x5b84, 0x5b86,0x5b8a,0x5b8e,0x5b90,0x5b91,0x5b93,0x5b94,0x5b96,0x5ba8,0x5ba9, 0x5bac,0x5bad,0x5baf,0x5bb1,0x5bb2,0x5bb7,0x5bba,0x5bbc,0x5bc0,0x5bc1, 0x5bcd,0x5bcf,0x5bd6,0x5bd7,0x5bd8,0x5bd9,0x5bda,0x5be0,0x5bef,0x5bf1, 0x5bf4,0x5bfd,0x5c0c,0x5c17,0x5c1e,0x5c1f,0x5c23,0x5c26,0x5c29,0x5c2b, 0x5c2c,0x5c2e,0x5c30,0x5c32,0x5c35,0x5c36,0x5c59,0x5c5a,0x5c5c,0x5c62, 0x5c63,0x5c67,0x5c68,0x5c69 }, { /* ku 1b */ 0x5c6d,0x5c70,0x5c74,0x5c75,0x5c7a,0x5c7b,0x5c7c,0x5c7d,0x5c87,0x5c88, 0x5c8a,0x5c8f,0x5c92,0x5c9d,0x5c9f,0x5ca0,0x5ca2,0x5ca3,0x5ca6,0x5caa, 0x5cb2,0x5cb4,0x5cb5,0x5cba,0x5cc9,0x5ccb,0x5cd2,0x5cdd,0x5cd7,0x5cee, 0x5cf1,0x5cf2,0x5cf4,0x5d01,0x5d06,0x5d0d,0x5d12,0x5d2b,0x5d23,0x5d24, 0x5d26,0x5d27,0x5d31,0x5d34,0x5d39,0x5d3d,0x5d3f,0x5d42,0x5d43,0x5d46, 0x5d48,0x5d55,0x5d51,0x5d59,0x5d4a,0x5d5f,0x5d60,0x5d61,0x5d62,0x5d64, 0x5d6a,0x5d6d,0x5d70,0x5d79,0x5d7a,0x5d7e,0x5d7f,0x5d81,0x5d83,0x5d88, 0x5d8a,0x5d92,0x5d93,0x5d94,0x5d95,0x5d99,0x5d9b,0x5d9f,0x5da0,0x5da7, 0x5dab,0x5db0,0x5db4,0x5db8,0x5db9,0x5dc3,0x5dc7,0x5dcb,0x5dd0,0x5dce, 0x5dd8,0x5dd9,0x5de0,0x5de4 }, { /* ku 1c */ 0x5de9,0x5df8,0x5df9,0x5e00,0x5e07,0x5e0d,0x5e12,0x5e14,0x5e15,0x5e18, 0x5e1f,0x5e20,0x5e2e,0x5e28,0x5e32,0x5e35,0x5e3e,0x5e4b,0x5e50,0x5e49, 0x5e51,0x5e56,0x5e58,0x5e5b,0x5e5c,0x5e5e,0x5e68,0x5e6a,0x5e6b,0x5e6c, 0x5e6d,0x5e6e,0x5e70,0x5e80,0x5e8b,0x5e8e,0x5ea2,0x5ea4,0x5ea5,0x5ea8, 0x5eaa,0x5eac,0x5eb1,0x5eb3,0x5ebd,0x5ebe,0x5ebf,0x5ec6,0x5ecc,0x5ecb, 0x5ece,0x5ed1,0x5ed2,0x5ed4,0x5ed5,0x5edc,0x5ede,0x5ee5,0x5eeb,0x5f02, 0x5f06,0x5f07,0x5f08,0x5f0e,0x5f19,0x5f1c,0x5f1d,0x5f21,0x5f22,0x5f23, 0x5f24,0x5f28,0x5f2b,0x5f2c,0x5f2e,0x5f30,0x5f34,0x5f36,0x5f3b,0x5f3d, 0x5f3f,0x5f40,0x5f44,0x5f45,0x5f47,0x5f4d,0x5f50,0x5f54,0x5f58,0x5f5b, 0x5f60,0x5f63,0x5f64,0x5f67 }, { /* ku 1d */ 0x5f6f,0x5f72,0x5f74,0x5f75,0x5f78,0x5f7a,0x5f7d,0x5f7e,0x5f89,0x5f8d, 0x5f8f,0x5f96,0x5f9c,0x5f9d,0x5fa2,0x5fa7,0x5fab,0x5fa4,0x5fac,0x5faf, 0x5fb0,0x5fb1,0x5fb8,0x5fc4,0x5fc7,0x5fc8,0x5fc9,0x5fcb,0x5fd0,0x5fd1, 0x5fd2,0x5fd3,0x5fd4,0x5fde,0x5fe1,0x5fe2,0x5fe8,0x5fe9,0x5fea,0x5fec, 0x5fed,0x5fee,0x5fef,0x5ff2,0x5ff3,0x5ff6,0x5ffa,0x5ffc,0x6007,0x600a, 0x600d,0x6013,0x6014,0x6017,0x6018,0x601a,0x601f,0x6024,0x602d,0x6033, 0x6035,0x6040,0x6047,0x6048,0x6049,0x604c,0x6051,0x6054,0x6056,0x6057, 0x605d,0x6061,0x6067,0x6071,0x607e,0x607f,0x6082,0x6086,0x6088,0x608a, 0x608e,0x6091,0x6093,0x6095,0x6098,0x609d,0x609e,0x60a2,0x60a4,0x60a5, 0x60a8,0x60b0,0x60b1,0x60b7 }, { /* ku 1e */ 0x60bb,0x60be,0x60c2,0x60c4,0x60c8,0x60c9,0x60ca,0x60cb,0x60ce,0x60cf, 0x60d4,0x60d5,0x60d9,0x60db,0x60dd,0x60de,0x60e2,0x60e5,0x60f2,0x60f5, 0x60f8,0x60fc,0x60fd,0x6102,0x6107,0x610a,0x610c,0x6110,0x6111,0x6112, 0x6113,0x6114,0x6116,0x6117,0x6119,0x611c,0x611e,0x6122,0x612a,0x612b, 0x6130,0x6131,0x6135,0x6136,0x6137,0x6139,0x6141,0x6145,0x6146,0x6149, 0x615e,0x6160,0x616c,0x6172,0x6178,0x617b,0x617c,0x617f,0x6180,0x6181, 0x6183,0x6184,0x618b,0x618d,0x6192,0x6193,0x6197,0x6198,0x619c,0x619d, 0x619f,0x61a0,0x61a5,0x61a8,0x61aa,0x61ad,0x61b8,0x61b9,0x61bc,0x61c0, 0x61c1,0x61c2,0x61ce,0x61cf,0x61d5,0x61dc,0x61dd,0x61de,0x61df,0x61e1, 0x61e2,0x61e7,0x61e9,0x61e5 }, { /* ku 1f */ 0x61ec,0x61ed,0x61ef,0x6201,0x6203,0x6204,0x6207,0x6213,0x6215,0x621c, 0x6220,0x6222,0x6223,0x6227,0x6229,0x622b,0x6239,0x623d,0x6242,0x6243, 0x6244,0x6246,0x624c,0x6250,0x6251,0x6252,0x6254,0x6256,0x625a,0x625c, 0x6264,0x626d,0x626f,0x6273,0x627a,0x627d,0x628d,0x628e,0x628f,0x6290, 0x62a6,0x62a8,0x62b3,0x62b6,0x62b7,0x62ba,0x62be,0x62bf,0x62c4,0x62ce, 0x62d5,0x62d6,0x62da,0x62ea,0x62f2,0x62f4,0x62fc,0x62fd,0x6303,0x6304, 0x630a,0x630b,0x630d,0x6310,0x6313,0x6316,0x6318,0x6329,0x632a,0x632d, 0x6335,0x6336,0x6339,0x633c,0x6341,0x6342,0x6343,0x6344,0x6346,0x634a, 0x634b,0x634e,0x6352,0x6353,0x6354,0x6358,0x635b,0x6365,0x6366,0x636c, 0x636d,0x6371,0x6374,0x6375 }, { /* ku 20 */ 0x6378,0x637c,0x637d,0x637f,0x6382,0x6384,0x6387,0x638a,0x6390,0x6394, 0x6395,0x6399,0x639a,0x639e,0x63a4,0x63a6,0x63ad,0x63ae,0x63af,0x63bd, 0x63c1,0x63c5,0x63c8,0x63ce,0x63d1,0x63d3,0x63d4,0x63d5,0x63dc,0x63e0, 0x63e5,0x63ea,0x63ec,0x63f2,0x63f3,0x63f5,0x63f8,0x63f9,0x6409,0x640a, 0x6410,0x6412,0x6414,0x6418,0x641e,0x6420,0x6422,0x6424,0x6425,0x6429, 0x642a,0x642f,0x6430,0x6435,0x643d,0x643f,0x644b,0x644f,0x6451,0x6452, 0x6453,0x6454,0x645a,0x645b,0x645c,0x645d,0x645f,0x6460,0x6461,0x6463, 0x646d,0x6473,0x6474,0x647b,0x647d,0x6485,0x6487,0x648f,0x6490,0x6491, 0x6498,0x6499,0x649b,0x649d,0x649f,0x64a1,0x64a3,0x64a6,0x64a8,0x64ac, 0x64b3,0x64bd,0x64be,0x64bf }, { /* ku 21 */ 0x64c4,0x64c9,0x64ca,0x64cb,0x64cc,0x64ce,0x64d0,0x64d1,0x64d5,0x64d7, 0x64e4,0x64e5,0x64e9,0x64ea,0x64ed,0x64f0,0x64f5,0x64f7,0x64fb,0x64ff, 0x6501,0x6504,0x6508,0x6509,0x650a,0x650f,0x6513,0x6514,0x6516,0x6519, 0x651b,0x651e,0x651f,0x6522,0x6526,0x6529,0x652e,0x6531,0x653a,0x653c, 0x653d,0x6543,0x6547,0x6549,0x6550,0x6552,0x6554,0x655f,0x6560,0x6567, 0x656b,0x657a,0x657d,0x6581,0x6585,0x658a,0x6592,0x6595,0x6598,0x659d, 0x65a0,0x65a3,0x65a6,0x65ae,0x65b2,0x65b3,0x65b4,0x65bf,0x65c2,0x65c8, 0x65c9,0x65ce,0x65d0,0x65d4,0x65d6,0x65d8,0x65df,0x65f0,0x65f2,0x65f4, 0x65f5,0x65f9,0x65fe,0x65ff,0x6600,0x6604,0x6608,0x6609,0x660d,0x6611, 0x6612,0x6615,0x6616,0x661d }, { /* ku 22 */ 0x661e,0x6621,0x6622,0x6623,0x6624,0x6626,0x6629,0x662a,0x662b,0x662c, 0x662e,0x6630,0x6631,0x6633,0x6639,0x6637,0x6640,0x6645,0x6646,0x664a, 0x664c,0x6651,0x664e,0x6657,0x6658,0x6659,0x665b,0x665c,0x6660,0x6661, 0x66fb,0x666a,0x666b,0x666c,0x667e,0x6673,0x6675,0x667f,0x6677,0x6678, 0x6679,0x667b,0x6680,0x667c,0x668b,0x668c,0x668d,0x6690,0x6692,0x6699, 0x669a,0x669b,0x669c,0x669f,0x66a0,0x66a4,0x66ad,0x66b1,0x66b2,0x66b5, 0x66bb,0x66bf,0x66c0,0x66c2,0x66c3,0x66c8,0x66cc,0x66ce,0x66cf,0x66d4, 0x66db,0x66df,0x66e8,0x66eb,0x66ec,0x66ee,0x66fa,0x6705,0x6707,0x670e, 0x6713,0x6719,0x671c,0x6720,0x6722,0x6733,0x673e,0x6745,0x6747,0x6748, 0x674c,0x6754,0x6755,0x675d }, { /* ku 23 */ 0x6766,0x676c,0x676e,0x6774,0x6776,0x677b,0x6781,0x6784,0x678e,0x678f, 0x6791,0x6793,0x6796,0x6798,0x6799,0x679b,0x67b0,0x67b1,0x67b2,0x67b5, 0x67bb,0x67bc,0x67bd,0x67f9,0x67c0,0x67c2,0x67c3,0x67c5,0x67c8,0x67c9, 0x67d2,0x67d7,0x67d9,0x67dc,0x67e1,0x67e6,0x67f0,0x67f2,0x67f6,0x67f7, 0x6852,0x6814,0x6819,0x681d,0x681f,0x6828,0x6827,0x682c,0x682d,0x682f, 0x6830,0x6831,0x6833,0x683b,0x683f,0x6844,0x6845,0x684a,0x684c,0x6855, 0x6857,0x6858,0x685b,0x686b,0x686e,0x686f,0x6870,0x6871,0x6872,0x6875, 0x6879,0x687a,0x687b,0x687c,0x6882,0x6884,0x6886,0x6888,0x6896,0x6898, 0x689a,0x689c,0x68a1,0x68a3,0x68a5,0x68a9,0x68aa,0x68ae,0x68b2,0x68bb, 0x68c5,0x68c8,0x68cc,0x68cf }, { /* ku 24 */ 0x68d0,0x68d1,0x68d3,0x68d6,0x68d9,0x68dc,0x68dd,0x68e5,0x68e8,0x68ea, 0x68eb,0x68ec,0x68ed,0x68f0,0x68f1,0x68f5,0x68f6,0x68fb,0x68fc,0x68fd, 0x6906,0x6909,0x690a,0x6910,0x6911,0x6913,0x6916,0x6917,0x6931,0x6933, 0x6935,0x6938,0x693b,0x6942,0x6945,0x6949,0x694e,0x6957,0x695b,0x6963, 0x6964,0x6965,0x6966,0x6968,0x6969,0x696c,0x6970,0x6971,0x6972,0x697a, 0x697b,0x697f,0x6980,0x698d,0x6992,0x6996,0x6998,0x69a1,0x69a5,0x69a6, 0x69a8,0x69ab,0x69ad,0x69af,0x69b7,0x69b8,0x69ba,0x69bc,0x69c5,0x69c8, 0x69d1,0x69d6,0x69d7,0x69e2,0x69e5,0x69ee,0x69ef,0x69f1,0x69f3,0x69f5, 0x69fe,0x6a00,0x6a01,0x6a03,0x6a0f,0x6a11,0x6a15,0x6a1a,0x6a1d,0x6a20, 0x6a24,0x6a28,0x6a30,0x6a32 }, { /* ku 25 */ 0x6a34,0x6a37,0x6a3b,0x6a3e,0x6a3f,0x6a45,0x6a46,0x6a49,0x6a4a,0x6a4e, 0x6a50,0x6a51,0x6a52,0x6a55,0x6a56,0x6a5b,0x6a64,0x6a67,0x6a6a,0x6a71, 0x6a73,0x6a7e,0x6a81,0x6a83,0x6a86,0x6a87,0x6a89,0x6a8b,0x6a91,0x6a9b, 0x6a9d,0x6a9e,0x6a9f,0x6aa5,0x6aab,0x6aaf,0x6ab0,0x6ab1,0x6ab4,0x6abd, 0x6abe,0x6abf,0x6ac6,0x6ac9,0x6ac8,0x6acc,0x6ad0,0x6ad4,0x6ad5,0x6ad6, 0x6adc,0x6add,0x6ae4,0x6ae7,0x6aec,0x6af0,0x6af1,0x6af2,0x6afc,0x6afd, 0x6b02,0x6b03,0x6b06,0x6b07,0x6b09,0x6b0f,0x6b10,0x6b11,0x6b17,0x6b1b, 0x6b1e,0x6b24,0x6b28,0x6b2b,0x6b2c,0x6b2f,0x6b35,0x6b36,0x6b3b,0x6b3f, 0x6b46,0x6b4a,0x6b4d,0x6b52,0x6b56,0x6b58,0x6b5d,0x6b60,0x6b67,0x6b6b, 0x6b6e,0x6b70,0x6b75,0x6b7d }, { /* ku 26 */ 0x6b7e,0x6b82,0x6b85,0x6b97,0x6b9b,0x6b9f,0x6ba0,0x6ba2,0x6ba3,0x6ba8, 0x6ba9,0x6bac,0x6bad,0x6bae,0x6bb0,0x6bb8,0x6bb9,0x6bbd,0x6bbe,0x6bc3, 0x6bc4,0x6bc9,0x6bcc,0x6bd6,0x6bda,0x6be1,0x6be3,0x6be6,0x6be7,0x6bee, 0x6bf1,0x6bf7,0x6bf9,0x6bff,0x6c02,0x6c04,0x6c05,0x6c09,0x6c0d,0x6c0e, 0x6c10,0x6c12,0x6c19,0x6c1f,0x6c26,0x6c27,0x6c28,0x6c2c,0x6c2e,0x6c33, 0x6c35,0x6c36,0x6c3a,0x6c3b,0x6c3f,0x6c4a,0x6c4b,0x6c4d,0x6c4f,0x6c52, 0x6c54,0x6c59,0x6c5b,0x6c5c,0x6c6b,0x6c6d,0x6c6f,0x6c74,0x6c76,0x6c78, 0x6c79,0x6c7b,0x6c85,0x6c86,0x6c87,0x6c89,0x6c94,0x6c95,0x6c97,0x6c98, 0x6c9c,0x6c9f,0x6cb0,0x6cb2,0x6cb4,0x6cc2,0x6cc6,0x6ccd,0x6ccf,0x6cd0, 0x6cd1,0x6cd2,0x6cd4,0x6cd6 }, { /* ku 27 */ 0x6cda,0x6cdc,0x6ce0,0x6ce7,0x6ce9,0x6ceb,0x6cec,0x6cee,0x6cf2,0x6cf4, 0x6d04,0x6d07,0x6d0a,0x6d0e,0x6d0f,0x6d11,0x6d13,0x6d1a,0x6d26,0x6d27, 0x6d28,0x6c67,0x6d2e,0x6d2f,0x6d31,0x6d39,0x6d3c,0x6d3f,0x6d57,0x6d5e, 0x6d5f,0x6d61,0x6d65,0x6d67,0x6d6f,0x6d70,0x6d7c,0x6d82,0x6d87,0x6d91, 0x6d92,0x6d94,0x6d96,0x6d97,0x6d98,0x6daa,0x6dac,0x6db4,0x6db7,0x6db9, 0x6dbd,0x6dbf,0x6dc4,0x6dc8,0x6dca,0x6dce,0x6dcf,0x6dd6,0x6ddb,0x6ddd, 0x6ddf,0x6de0,0x6de2,0x6de5,0x6de9,0x6def,0x6df0,0x6df4,0x6df6,0x6dfc, 0x6e00,0x6e04,0x6e1e,0x6e22,0x6e27,0x6e32,0x6e36,0x6e39,0x6e3b,0x6e3c, 0x6e44,0x6e45,0x6e48,0x6e49,0x6e4b,0x6e4f,0x6e51,0x6e52,0x6e53,0x6e54, 0x6e57,0x6e5c,0x6e5d,0x6e5e }, { /* ku 28 */ 0x6e62,0x6e63,0x6e68,0x6e73,0x6e7b,0x6e7d,0x6e8d,0x6e93,0x6e99,0x6ea0, 0x6ea7,0x6ead,0x6eae,0x6eb1,0x6eb3,0x6ebb,0x6ebf,0x6ec0,0x6ec1,0x6ec3, 0x6ec7,0x6ec8,0x6eca,0x6ecd,0x6ece,0x6ecf,0x6eeb,0x6eed,0x6eee,0x6ef9, 0x6efb,0x6efd,0x6f04,0x6f08,0x6f0a,0x6f0c,0x6f0d,0x6f16,0x6f18,0x6f1a, 0x6f1b,0x6f26,0x6f29,0x6f2a,0x6f2f,0x6f30,0x6f33,0x6f36,0x6f3b,0x6f3c, 0x6f2d,0x6f4f,0x6f51,0x6f52,0x6f53,0x6f57,0x6f59,0x6f5a,0x6f5d,0x6f5e, 0x6f61,0x6f62,0x6f68,0x6f6c,0x6f7d,0x6f7e,0x6f83,0x6f87,0x6f88,0x6f8b, 0x6f8c,0x6f8d,0x6f90,0x6f92,0x6f93,0x6f94,0x6f96,0x6f9a,0x6f9f,0x6fa0, 0x6fa5,0x6fa6,0x6fa7,0x6fa8,0x6fae,0x6faf,0x6fb0,0x6fb5,0x6fb6,0x6fbc, 0x6fc5,0x6fc7,0x6fc8,0x6fca }, { /* ku 29 */ 0x6fda,0x6fde,0x6fe8,0x6fe9,0x6ff0,0x6ff5,0x6ff9,0x6ffc,0x6ffd,0x7000, 0x7005,0x7006,0x7007,0x700d,0x7017,0x7020,0x7023,0x702f,0x7034,0x7037, 0x7039,0x703c,0x7043,0x7044,0x7048,0x7049,0x704a,0x704b,0x7054,0x7055, 0x705d,0x705e,0x704e,0x7064,0x7065,0x706c,0x706e,0x7075,0x7076,0x707e, 0x7081,0x7085,0x7086,0x7094,0x7095,0x7096,0x7097,0x7098,0x709b,0x70a4, 0x70ab,0x70b0,0x70b1,0x70b4,0x70b7,0x70ca,0x70d1,0x70d3,0x70d4,0x70d5, 0x70d6,0x70d8,0x70dc,0x70e4,0x70fa,0x7103,0x7104,0x7105,0x7106,0x7107, 0x710b,0x710c,0x710f,0x711e,0x7120,0x712b,0x712d,0x712f,0x7130,0x7131, 0x7138,0x7141,0x7145,0x7146,0x7147,0x714a,0x714b,0x7150,0x7152,0x7157, 0x715a,0x715c,0x715e,0x7160 }, { /* ku 2a */ 0x7168,0x7179,0x7180,0x7185,0x7187,0x718c,0x7192,0x719a,0x719b,0x71a0, 0x71a2,0x71af,0x71b0,0x71b2,0x71b3,0x71ba,0x71bf,0x71c0,0x71c1,0x71c4, 0x71cb,0x71cc,0x71d3,0x71d6,0x71d9,0x71da,0x71dc,0x71f8,0x71fe,0x7200, 0x7207,0x7208,0x7209,0x7213,0x7217,0x721a,0x721d,0x721f,0x7224,0x722b, 0x722f,0x7234,0x7238,0x7239,0x7241,0x7242,0x7243,0x7245,0x724e,0x724f, 0x7250,0x7253,0x7255,0x7256,0x725a,0x725c,0x725e,0x7260,0x7263,0x7268, 0x726b,0x726e,0x726f,0x7271,0x7277,0x7278,0x727b,0x727c,0x727f,0x7284, 0x7289,0x728d,0x728e,0x7293,0x729b,0x72a8,0x72ad,0x72ae,0x72b1,0x72b4, 0x72be,0x72c1,0x72c7,0x72c9,0x72cc,0x72d5,0x72d6,0x72d8,0x72df,0x72e5, 0x72f3,0x72f4,0x72fa,0x72fb }, { /* ku 2b */ 0x72fe,0x7302,0x7304,0x7305,0x7307,0x730b,0x730d,0x7312,0x7313,0x7318, 0x7319,0x731e,0x7322,0x7324,0x7327,0x7328,0x732c,0x7331,0x7332,0x7335, 0x733a,0x733b,0x733d,0x7343,0x734d,0x7350,0x7352,0x7356,0x7358,0x735d, 0x735e,0x735f,0x7360,0x7366,0x7367,0x7369,0x736b,0x736c,0x736e,0x736f, 0x7371,0x7377,0x7379,0x737c,0x7380,0x7381,0x7383,0x7385,0x7386,0x738e, 0x7390,0x7393,0x7395,0x7397,0x7398,0x739c,0x739e,0x739f,0x73a0,0x73a2, 0x73a5,0x73a6,0x73aa,0x73ab,0x73ad,0x73b5,0x73b7,0x73b9,0x73bc,0x73bd, 0x73bf,0x73c5,0x73c6,0x73c9,0x73cb,0x73cc,0x73cf,0x73d2,0x73d3,0x73d6, 0x73d9,0x73dd,0x73e1,0x73e3,0x73e6,0x73e7,0x73e9,0x73f4,0x73f5,0x73f7, 0x73f9,0x73fa,0x73fb,0x73fd }, { /* ku 2c */ 0x73ff,0x7400,0x7401,0x7404,0x7407,0x740a,0x7411,0x741a,0x741b,0x7424, 0x7426,0x7428,0x7429,0x742a,0x742b,0x742c,0x742d,0x742e,0x742f,0x7430, 0x7431,0x7439,0x7440,0x7443,0x7444,0x7446,0x7447,0x744b,0x744d,0x7451, 0x7452,0x7457,0x745d,0x7462,0x7466,0x7467,0x7468,0x746b,0x746d,0x746e, 0x7471,0x7472,0x7480,0x7481,0x7485,0x7486,0x7487,0x7489,0x748f,0x7490, 0x7491,0x7492,0x7498,0x7499,0x749a,0x749c,0x749f,0x74a0,0x74a1,0x74a3, 0x74a6,0x74a8,0x74a9,0x74aa,0x74ab,0x74ae,0x74af,0x74b1,0x74b2,0x74b5, 0x74b9,0x74bb,0x74bf,0x74c8,0x74c9,0x74cc,0x74d0,0x74d3,0x74d8,0x74da, 0x74db,0x74de,0x74df,0x74e4,0x74e8,0x74ea,0x74eb,0x74ef,0x74f4,0x74fa, 0x74fb,0x74fc,0x74ff,0x7506 }, { /* ku 2d */ 0x7512,0x7516,0x7517,0x7520,0x7521,0x7524,0x7527,0x7529,0x752a,0x752f, 0x7536,0x7539,0x753d,0x753e,0x753f,0x7540,0x7543,0x7547,0x7548,0x754e, 0x7550,0x7552,0x7557,0x755e,0x755f,0x7561,0x756f,0x7571,0x7579,0x757a, 0x757b,0x757c,0x757d,0x757e,0x7581,0x7585,0x7590,0x7592,0x7593,0x7595, 0x7599,0x759c,0x75a2,0x75a4,0x75b4,0x75ba,0x75bf,0x75c0,0x75c1,0x75c4, 0x75c6,0x75cc,0x75ce,0x75cf,0x75d7,0x75dc,0x75df,0x75e0,0x75e1,0x75e4, 0x75e7,0x75ec,0x75ee,0x75ef,0x75f1,0x75f9,0x7600,0x7602,0x7603,0x7604, 0x7607,0x7608,0x760a,0x760c,0x760f,0x7612,0x7613,0x7615,0x7616,0x7619, 0x761b,0x761c,0x761d,0x761e,0x7623,0x7625,0x7626,0x7629,0x762d,0x7632, 0x7633,0x7635,0x7638,0x7639 }, { /* ku 2e */ 0x763a,0x763c,0x764a,0x7640,0x7641,0x7643,0x7644,0x7645,0x7649,0x764b, 0x7655,0x7659,0x765f,0x7664,0x7665,0x766d,0x766e,0x766f,0x7671,0x7674, 0x7681,0x7685,0x768c,0x768d,0x7695,0x769b,0x769c,0x769d,0x769f,0x76a0, 0x76a2,0x76a3,0x76a4,0x76a5,0x76a6,0x76a7,0x76a8,0x76aa,0x76ad,0x76bd, 0x76c1,0x76c5,0x76c9,0x76cb,0x76cc,0x76ce,0x76d4,0x76d9,0x76e0,0x76e6, 0x76e8,0x76ec,0x76f0,0x76f1,0x76f6,0x76f9,0x76fc,0x7700,0x7706,0x770a, 0x770e,0x7712,0x7714,0x7715,0x7717,0x7719,0x771a,0x771c,0x7722,0x7728, 0x772d,0x772e,0x772f,0x7734,0x7735,0x7736,0x7739,0x773d,0x773e,0x7742, 0x7745,0x7746,0x774a,0x774d,0x774e,0x774f,0x7752,0x7756,0x7757,0x775c, 0x775e,0x775f,0x7760,0x7762 }, { /* ku 2f */ 0x7764,0x7767,0x776a,0x776c,0x7770,0x7772,0x7773,0x7774,0x777a,0x777d, 0x7780,0x7784,0x778c,0x778d,0x7794,0x7795,0x7796,0x779a,0x779f,0x77a2, 0x77a7,0x77aa,0x77ae,0x77af,0x77b1,0x77b5,0x77be,0x77c3,0x77c9,0x77d1, 0x77d2,0x77d5,0x77d9,0x77de,0x77df,0x77e0,0x77e4,0x77e6,0x77ea,0x77ec, 0x77f0,0x77f1,0x77f4,0x77f8,0x77fb,0x7805,0x7806,0x7809,0x780d,0x780e, 0x7811,0x781d,0x7821,0x7822,0x7823,0x782d,0x782e,0x7830,0x7835,0x7837, 0x7843,0x7844,0x7847,0x7848,0x784c,0x784e,0x7852,0x785c,0x785e,0x7860, 0x7861,0x7863,0x7864,0x7868,0x786a,0x786e,0x787a,0x787e,0x788a,0x788f, 0x7894,0x7898,0x78a1,0x789d,0x789e,0x789f,0x78a4,0x78a8,0x78ac,0x78ad, 0x78b0,0x78b1,0x78b2,0x78b3 }, { /* ku 30 */ 0x78bb,0x78bd,0x78bf,0x78c7,0x78c8,0x78c9,0x78cc,0x78ce,0x78d2,0x78d3, 0x78d5,0x78d6,0x78e4,0x78db,0x78df,0x78e0,0x78e1,0x78e6,0x78ea,0x78f2, 0x78f3,0x7900,0x78f6,0x78f7,0x78fa,0x78fb,0x78ff,0x7906,0x790c,0x7910, 0x791a,0x791c,0x791e,0x791f,0x7920,0x7925,0x7927,0x7929,0x792d,0x7931, 0x7934,0x7935,0x793b,0x793d,0x793f,0x7944,0x7945,0x7946,0x794a,0x794b, 0x794f,0x7951,0x7954,0x7958,0x795b,0x795c,0x7967,0x7969,0x796b,0x7972, 0x7979,0x797b,0x797c,0x797e,0x798b,0x798c,0x7991,0x7993,0x7994,0x7995, 0x7996,0x7998,0x799b,0x799c,0x79a1,0x79a8,0x79a9,0x79ab,0x79af,0x79b1, 0x79b4,0x79b8,0x79bb,0x79c2,0x79c4,0x79c7,0x79c8,0x79ca,0x79cf,0x79d4, 0x79d6,0x79da,0x79dd,0x79de }, { /* ku 31 */ 0x79e0,0x79e2,0x79e5,0x79ea,0x79eb,0x79ed,0x79f1,0x79f8,0x79fc,0x7a02, 0x7a03,0x7a07,0x7a09,0x7a0a,0x7a0c,0x7a11,0x7a15,0x7a1b,0x7a1e,0x7a21, 0x7a27,0x7a2b,0x7a2d,0x7a2f,0x7a30,0x7a34,0x7a35,0x7a38,0x7a39,0x7a3a, 0x7a44,0x7a45,0x7a47,0x7a48,0x7a4c,0x7a55,0x7a56,0x7a59,0x7a5c,0x7a5d, 0x7a5f,0x7a60,0x7a65,0x7a67,0x7a6a,0x7a6d,0x7a75,0x7a78,0x7a7e,0x7a80, 0x7a82,0x7a85,0x7a86,0x7a8a,0x7a8b,0x7a90,0x7a91,0x7a94,0x7a9e,0x7aa0, 0x7aa3,0x7aac,0x7ab3,0x7ab5,0x7ab9,0x7abb,0x7abc,0x7ac6,0x7ac9,0x7acc, 0x7ace,0x7ad1,0x7adb,0x7ae8,0x7ae9,0x7aeb,0x7aec,0x7af1,0x7af4,0x7afb, 0x7afd,0x7afe,0x7b07,0x7b14,0x7b1f,0x7b23,0x7b27,0x7b29,0x7b2a,0x7b2b, 0x7b2d,0x7b2e,0x7b2f,0x7b30 }, { /* ku 32 */ 0x7b31,0x7b34,0x7b3d,0x7b3f,0x7b40,0x7b41,0x7b47,0x7b4e,0x7b55,0x7b60, 0x7b64,0x7b66,0x7b69,0x7b6a,0x7b6d,0x7b6f,0x7b72,0x7b73,0x7b77,0x7b84, 0x7b89,0x7b8e,0x7b90,0x7b91,0x7b96,0x7b9b,0x7b9e,0x7ba0,0x7ba5,0x7bac, 0x7baf,0x7bb0,0x7bb2,0x7bb5,0x7bb6,0x7bba,0x7bbb,0x7bbc,0x7bbd,0x7bc2, 0x7bc5,0x7bc8,0x7bca,0x7bd4,0x7bd6,0x7bd7,0x7bd9,0x7bda,0x7bdb,0x7be8, 0x7bea,0x7bf2,0x7bf4,0x7bf5,0x7bf8,0x7bf9,0x7bfa,0x7bfc,0x7bfe,0x7c01, 0x7c02,0x7c03,0x7c04,0x7c06,0x7c09,0x7c0b,0x7c0c,0x7c0e,0x7c0f,0x7c19, 0x7c1b,0x7c20,0x7c25,0x7c26,0x7c28,0x7c2c,0x7c31,0x7c33,0x7c34,0x7c36, 0x7c39,0x7c3a,0x7c46,0x7c4a,0x7c55,0x7c51,0x7c52,0x7c53,0x7c59,0x7c5a, 0x7c5b,0x7c5c,0x7c5d,0x7c5e }, { /* ku 33 */ 0x7c61,0x7c63,0x7c67,0x7c69,0x7c6d,0x7c6e,0x7c70,0x7c72,0x7c79,0x7c7c, 0x7c7d,0x7c86,0x7c87,0x7c8f,0x7c94,0x7c9e,0x7ca0,0x7ca6,0x7cb0,0x7cb6, 0x7cb7,0x7cba,0x7cbb,0x7cbc,0x7cbf,0x7cc4,0x7cc7,0x7cc8,0x7cc9,0x7ccd, 0x7ccf,0x7cd3,0x7cd4,0x7cd5,0x7cd7,0x7cd9,0x7cda,0x7cdd,0x7ce6,0x7ce9, 0x7ceb,0x7cf5,0x7d03,0x7d07,0x7d08,0x7d09,0x7d0f,0x7d11,0x7d12,0x7d13, 0x7d16,0x7d1d,0x7d1e,0x7d23,0x7d26,0x7d2a,0x7d2d,0x7d31,0x7d3c,0x7d3d, 0x7d3e,0x7d40,0x7d41,0x7d47,0x7d48,0x7d4d,0x7d51,0x7d53,0x7d57,0x7d59, 0x7d5a,0x7d5c,0x7d5d,0x7d65,0x7d67,0x7d6a,0x7d70,0x7d78,0x7d7a,0x7d7b, 0x7d7f,0x7d81,0x7d82,0x7d83,0x7d85,0x7d86,0x7d88,0x7d8b,0x7d8c,0x7d8d, 0x7d91,0x7d96,0x7d97,0x7d9d }, { /* ku 34 */ 0x7d9e,0x7da6,0x7da7,0x7daa,0x7db3,0x7db6,0x7db7,0x7db9,0x7dc2,0x7dc3, 0x7dc4,0x7dc5,0x7dc6,0x7dcc,0x7dcd,0x7dce,0x7dd7,0x7dd9,0x7e00,0x7de2, 0x7de5,0x7de6,0x7dea,0x7deb,0x7ded,0x7df1,0x7df5,0x7df6,0x7df9,0x7dfa, 0x7e08,0x7e10,0x7e11,0x7e15,0x7e17,0x7e1c,0x7e1d,0x7e20,0x7e27,0x7e28, 0x7e2c,0x7e2d,0x7e2f,0x7e33,0x7e36,0x7e3f,0x7e44,0x7e45,0x7e47,0x7e4e, 0x7e50,0x7e52,0x7e58,0x7e5f,0x7e61,0x7e62,0x7e65,0x7e6b,0x7e6e,0x7e6f, 0x7e73,0x7e78,0x7e7e,0x7e81,0x7e86,0x7e87,0x7e8a,0x7e8d,0x7e91,0x7e95, 0x7e98,0x7e9a,0x7e9d,0x7e9e,0x7f3c,0x7f3b,0x7f3d,0x7f3e,0x7f3f,0x7f43, 0x7f44,0x7f47,0x7f4f,0x7f52,0x7f53,0x7f5b,0x7f5c,0x7f5d,0x7f61,0x7f63, 0x7f64,0x7f65,0x7f66,0x7f6d }, { /* ku 35 */ 0x7f71,0x7f7d,0x7f7e,0x7f7f,0x7f80,0x7f8b,0x7f8d,0x7f8f,0x7f90,0x7f91, 0x7f96,0x7f97,0x7f9c,0x7fa1,0x7fa2,0x7fa6,0x7faa,0x7fad,0x7fb4,0x7fbc, 0x7fbf,0x7fc0,0x7fc3,0x7fc8,0x7fce,0x7fcf,0x7fdb,0x7fdf,0x7fe3,0x7fe5, 0x7fe8,0x7fec,0x7fee,0x7fef,0x7ff2,0x7ffa,0x7ffd,0x7ffe,0x7fff,0x8007, 0x8008,0x800a,0x800d,0x800e,0x800f,0x8011,0x8013,0x8014,0x8016,0x801d, 0x801e,0x801f,0x8020,0x8024,0x8026,0x802c,0x802e,0x8030,0x8034,0x8035, 0x8037,0x8039,0x803a,0x803c,0x803e,0x8040,0x8044,0x8060,0x8064,0x8066, 0x806d,0x8071,0x8075,0x8081,0x8088,0x808e,0x809c,0x809e,0x80a6,0x80a7, 0x80ab,0x80b8,0x80b9,0x80c8,0x80cd,0x80cf,0x80d2,0x80d4,0x80d5,0x80d7, 0x80d8,0x80e0,0x80ed,0x80ee }, { /* ku 36 */ 0x80f0,0x80f2,0x80f3,0x80f6,0x80f9,0x80fa,0x80fe,0x8103,0x810b,0x8116, 0x8117,0x8118,0x811c,0x811e,0x8120,0x8124,0x8127,0x812c,0x8130,0x8135, 0x813a,0x813c,0x8145,0x8147,0x814a,0x814c,0x8152,0x8157,0x8160,0x8161, 0x8167,0x8168,0x8169,0x816d,0x816f,0x8177,0x8181,0x8190,0x8184,0x8185, 0x8186,0x818b,0x818e,0x8196,0x8198,0x819b,0x819e,0x81a2,0x81ae,0x81b2, 0x81b4,0x81bb,0x81cb,0x81c3,0x81c5,0x81ca,0x81ce,0x81cf,0x81d5,0x81d7, 0x81db,0x81dd,0x81de,0x81e1,0x81e4,0x81eb,0x81ec,0x81f0,0x81f1,0x81f2, 0x81f5,0x81f6,0x81f8,0x81f9,0x81fd,0x81ff,0x8200,0x8203,0x820f,0x8213, 0x8214,0x8219,0x821a,0x821d,0x8221,0x8222,0x8228,0x8232,0x8234,0x823a, 0x8243,0x8244,0x8245,0x8246 }, { /* ku 37 */ 0x824b,0x824e,0x824f,0x8251,0x8256,0x825c,0x8260,0x8263,0x8267,0x826d, 0x8274,0x827b,0x827d,0x827f,0x8280,0x8281,0x8283,0x8284,0x8287,0x8289, 0x828a,0x828e,0x8291,0x8294,0x8296,0x8298,0x829a,0x829b,0x82a0,0x82a1, 0x82a3,0x82a4,0x82a7,0x82a8,0x82a9,0x82aa,0x82ae,0x82b0,0x82b2,0x82b4, 0x82b7,0x82ba,0x82bc,0x82be,0x82bf,0x82c6,0x82d0,0x82d5,0x82da,0x82e0, 0x82e2,0x82e4,0x82e8,0x82ea,0x82ed,0x82ef,0x82f6,0x82f7,0x82fd,0x82fe, 0x8300,0x8301,0x8307,0x8308,0x830a,0x830b,0x8354,0x831b,0x831d,0x831e, 0x831f,0x8321,0x8322,0x832c,0x832d,0x832e,0x8330,0x8333,0x8337,0x833a, 0x833c,0x833d,0x8342,0x8343,0x8344,0x8347,0x834d,0x834e,0x8351,0x8355, 0x8356,0x8357,0x8370,0x8378 }, { /* ku 38 */ 0x837d,0x837f,0x8380,0x8382,0x8384,0x8386,0x838d,0x8392,0x8394,0x8395, 0x8398,0x8399,0x839b,0x839c,0x839d,0x83a6,0x83a7,0x83a9,0x83ac,0x83be, 0x83bf,0x83c0,0x83c7,0x83c9,0x83cf,0x83d0,0x83d1,0x83d4,0x83dd,0x8353, 0x83e8,0x83ea,0x83f6,0x83f8,0x83f9,0x83fc,0x8401,0x8406,0x840a,0x840f, 0x8411,0x8415,0x8419,0x83ad,0x842f,0x8439,0x8445,0x8447,0x8448,0x844a, 0x844d,0x844f,0x8451,0x8452,0x8456,0x8458,0x8459,0x845a,0x845c,0x8460, 0x8464,0x8465,0x8467,0x846a,0x8470,0x8473,0x8474,0x8476,0x8478,0x847c, 0x847d,0x8481,0x8485,0x8492,0x8493,0x8495,0x849e,0x84a6,0x84a8,0x84a9, 0x84aa,0x84af,0x84b1,0x84b4,0x84ba,0x84bd,0x84be,0x84c0,0x84c2,0x84c7, 0x84c8,0x84cc,0x84cf,0x84d3 }, { /* ku 39 */ 0x84dc,0x84e7,0x84ea,0x84ef,0x84f0,0x84f1,0x84f2,0x84f7,0x8532,0x84fa, 0x84fb,0x84fd,0x8502,0x8503,0x8507,0x850c,0x850e,0x8510,0x851c,0x851e, 0x8522,0x8523,0x8524,0x8525,0x8527,0x852a,0x852b,0x852f,0x8533,0x8534, 0x8536,0x853f,0x8546,0x854f,0x8550,0x8551,0x8552,0x8553,0x8556,0x8559, 0x855c,0x855d,0x855e,0x855f,0x8560,0x8561,0x8562,0x8564,0x856b,0x856f, 0x8579,0x857a,0x857b,0x857d,0x857f,0x8581,0x8585,0x8586,0x8589,0x858b, 0x858c,0x858f,0x8593,0x8598,0x859d,0x859f,0x85a0,0x85a2,0x85a5,0x85a7, 0x85b4,0x85b6,0x85b7,0x85b8,0x85bc,0x85bd,0x85be,0x85bf,0x85c2,0x85c7, 0x85ca,0x85cb,0x85ce,0x85ad,0x85d8,0x85da,0x85df,0x85e0,0x85e6,0x85e8, 0x85ed,0x85f3,0x85f6,0x85fc }, { /* ku 3a */ 0x85ff,0x8600,0x8604,0x8605,0x860d,0x860e,0x8610,0x8611,0x8612,0x8618, 0x8619,0x861b,0x861e,0x8621,0x8627,0x8629,0x8636,0x8638,0x863a,0x863c, 0x863d,0x8640,0x8642,0x8646,0x8652,0x8653,0x8656,0x8657,0x8658,0x8659, 0x865d,0x8660,0x8661,0x8662,0x8663,0x8664,0x8669,0x866c,0x866f,0x8675, 0x8676,0x8677,0x867a,0x868d,0x8691,0x8696,0x8698,0x869a,0x869c,0x86a1, 0x86a6,0x86a7,0x86a8,0x86ad,0x86b1,0x86b3,0x86b4,0x86b5,0x86b7,0x86b8, 0x86b9,0x86bf,0x86c0,0x86c1,0x86c3,0x86c5,0x86d1,0x86d2,0x86d5,0x86d7, 0x86da,0x86dc,0x86e0,0x86e3,0x86e5,0x86e7,0x8688,0x86fa,0x86fc,0x86fd, 0x8704,0x8705,0x8707,0x870b,0x870e,0x870f,0x8710,0x8713,0x8714,0x8719, 0x871e,0x871f,0x8721,0x8723 }, { /* ku 3b */ 0x8728,0x872e,0x872f,0x8731,0x8732,0x8739,0x873a,0x873c,0x873d,0x873e, 0x8740,0x8743,0x8745,0x874d,0x8758,0x875d,0x8761,0x8764,0x8765,0x876f, 0x8771,0x8772,0x877b,0x8783,0x8784,0x8785,0x8786,0x8787,0x8788,0x8789, 0x878b,0x878c,0x8790,0x8793,0x8795,0x8797,0x8798,0x8799,0x879e,0x87a0, 0x87a3,0x87a7,0x87ac,0x87ad,0x87ae,0x87b1,0x87b5,0x87be,0x87bf,0x87c1, 0x87c8,0x87c9,0x87ca,0x87ce,0x87d5,0x87d6,0x87d9,0x87da,0x87dc,0x87df, 0x87e2,0x87e3,0x87e4,0x87ea,0x87eb,0x87ed,0x87f1,0x87f3,0x87f8,0x87fa, 0x87ff,0x8801,0x8803,0x8806,0x8809,0x880a,0x880b,0x8810,0x8819,0x8812, 0x8813,0x8814,0x8818,0x881a,0x881b,0x881c,0x881e,0x881f,0x8828,0x882d, 0x882e,0x8830,0x8832,0x8835 }, { /* ku 3c */ 0x883a,0x883c,0x8841,0x8843,0x8845,0x8848,0x8849,0x884a,0x884b,0x884e, 0x8851,0x8855,0x8856,0x8858,0x885a,0x885c,0x885f,0x8860,0x8864,0x8869, 0x8871,0x8879,0x887b,0x8880,0x8898,0x889a,0x889b,0x889c,0x889f,0x88a0, 0x88a8,0x88aa,0x88ba,0x88bd,0x88be,0x88c0,0x88ca,0x88cb,0x88cc,0x88cd, 0x88ce,0x88d1,0x88d2,0x88d3,0x88db,0x88de,0x88e7,0x88ef,0x88f0,0x88f1, 0x88f5,0x88f7,0x8901,0x8906,0x890d,0x890e,0x890f,0x8915,0x8916,0x8918, 0x8919,0x891a,0x891c,0x8920,0x8926,0x8927,0x8928,0x8930,0x8931,0x8932, 0x8935,0x8939,0x893a,0x893e,0x8940,0x8942,0x8945,0x8946,0x8949,0x894f, 0x8952,0x8957,0x895a,0x895b,0x895c,0x8961,0x8962,0x8963,0x896b,0x896e, 0x8970,0x8973,0x8975,0x897a }, { /* ku 3d */ 0x897b,0x897c,0x897d,0x8989,0x898d,0x8990,0x8994,0x8995,0x899b,0x899c, 0x899f,0x89a0,0x89a5,0x89b0,0x89b4,0x89b5,0x89b6,0x89b7,0x89bc,0x89d4, 0x89d5,0x89d6,0x89d7,0x89d8,0x89e5,0x89e9,0x89eb,0x89ed,0x89f1,0x89f3, 0x89f6,0x89f9,0x89fd,0x89ff,0x8a04,0x8a05,0x8a07,0x8a0f,0x8a11,0x8a12, 0x8a14,0x8a15,0x8a1e,0x8a20,0x8a22,0x8a24,0x8a26,0x8a2b,0x8a2c,0x8a2f, 0x8a35,0x8a37,0x8a3d,0x8a3e,0x8a40,0x8a43,0x8a45,0x8a47,0x8a49,0x8a4d, 0x8a4e,0x8a53,0x8a56,0x8a57,0x8a58,0x8a5c,0x8a5d,0x8a61,0x8a65,0x8a67, 0x8a75,0x8a76,0x8a77,0x8a79,0x8a7a,0x8a7b,0x8a7e,0x8a7f,0x8a80,0x8a83, 0x8a86,0x8a8b,0x8a8f,0x8a90,0x8a92,0x8a96,0x8a97,0x8a99,0x8a9f,0x8aa7, 0x8aa9,0x8aae,0x8aaf,0x8ab3 }, { /* ku 3e */ 0x8ab6,0x8ab7,0x8abb,0x8abe,0x8ac3,0x8ac6,0x8ac8,0x8ac9,0x8aca,0x8ad1, 0x8ad3,0x8ad4,0x8ad5,0x8ad7,0x8add,0x8adf,0x8aec,0x8af0,0x8af4,0x8af5, 0x8af6,0x8afc,0x8aff,0x8b05,0x8b06,0x8b0b,0x8b11,0x8b1c,0x8b1e,0x8b1f, 0x8b0a,0x8b2d,0x8b30,0x8b37,0x8b3c,0x8b42,0x8b43,0x8b44,0x8b45,0x8b46, 0x8b48,0x8b52,0x8b53,0x8b54,0x8b59,0x8b4d,0x8b5e,0x8b63,0x8b6d,0x8b76, 0x8b78,0x8b79,0x8b7c,0x8b7e,0x8b81,0x8b84,0x8b85,0x8b8b,0x8b8d,0x8b8f, 0x8b94,0x8b95,0x8b9c,0x8b9e,0x8b9f,0x8c38,0x8c39,0x8c3d,0x8c3e,0x8c45, 0x8c47,0x8c49,0x8c4b,0x8c4f,0x8c51,0x8c53,0x8c54,0x8c57,0x8c58,0x8c5b, 0x8c5d,0x8c59,0x8c63,0x8c64,0x8c66,0x8c68,0x8c69,0x8c6d,0x8c73,0x8c75, 0x8c76,0x8c7b,0x8c7e,0x8c86 }, { /* ku 3f */ 0x8c87,0x8c8b,0x8c90,0x8c92,0x8c93,0x8c99,0x8c9b,0x8c9c,0x8ca4,0x8cb9, 0x8cba,0x8cc5,0x8cc6,0x8cc9,0x8ccb,0x8ccf,0x8cd6,0x8cd5,0x8cd9,0x8cdd, 0x8ce1,0x8ce8,0x8cec,0x8cef,0x8cf0,0x8cf2,0x8cf5,0x8cf7,0x8cf8,0x8cfe, 0x8cff,0x8d01,0x8d03,0x8d09,0x8d12,0x8d17,0x8d1b,0x8d65,0x8d69,0x8d6c, 0x8d6e,0x8d7f,0x8d82,0x8d84,0x8d88,0x8d8d,0x8d90,0x8d91,0x8d95,0x8d9e, 0x8d9f,0x8da0,0x8da6,0x8dab,0x8dac,0x8daf,0x8db2,0x8db5,0x8db7,0x8db9, 0x8dbb,0x8dc0,0x8dc5,0x8dc6,0x8dc7,0x8dc8,0x8dca,0x8dce,0x8dd1,0x8dd4, 0x8dd5,0x8dd7,0x8dd9,0x8de4,0x8de5,0x8de7,0x8dec,0x8df0,0x8dbc,0x8df1, 0x8df2,0x8df4,0x8dfd,0x8e01,0x8e04,0x8e05,0x8e06,0x8e0b,0x8e11,0x8e14, 0x8e16,0x8e20,0x8e21,0x8e22 }, { /* ku 40 */ 0x8e23,0x8e26,0x8e27,0x8e31,0x8e33,0x8e36,0x8e37,0x8e38,0x8e39,0x8e3d, 0x8e40,0x8e41,0x8e4b,0x8e4d,0x8e4e,0x8e4f,0x8e54,0x8e5b,0x8e5c,0x8e5d, 0x8e5e,0x8e61,0x8e62,0x8e69,0x8e6c,0x8e6d,0x8e6f,0x8e70,0x8e71,0x8e79, 0x8e7a,0x8e7b,0x8e82,0x8e83,0x8e89,0x8e90,0x8e92,0x8e95,0x8e9a,0x8e9b, 0x8e9d,0x8e9e,0x8ea2,0x8ea7,0x8ea9,0x8ead,0x8eae,0x8eb3,0x8eb5,0x8eba, 0x8ebb,0x8ec0,0x8ec1,0x8ec3,0x8ec4,0x8ec7,0x8ecf,0x8ed1,0x8ed4,0x8edc, 0x8ee8,0x8eee,0x8ef0,0x8ef1,0x8ef7,0x8ef9,0x8efa,0x8eed,0x8f00,0x8f02, 0x8f07,0x8f08,0x8f0f,0x8f10,0x8f16,0x8f17,0x8f18,0x8f1e,0x8f20,0x8f21, 0x8f23,0x8f25,0x8f27,0x8f28,0x8f2c,0x8f2d,0x8f2e,0x8f34,0x8f35,0x8f36, 0x8f37,0x8f3a,0x8f40,0x8f41 }, { /* ku 41 */ 0x8f43,0x8f47,0x8f4f,0x8f51,0x8f52,0x8f53,0x8f54,0x8f55,0x8f58,0x8f5d, 0x8f5e,0x8f65,0x8f9d,0x8fa0,0x8fa1,0x8fa4,0x8fa5,0x8fa6,0x8fb5,0x8fb6, 0x8fb8,0x8fbe,0x8fc0,0x8fc1,0x8fc6,0x8fca,0x8fcb,0x8fcd,0x8fd0,0x8fd2, 0x8fd3,0x8fd5,0x8fe0,0x8fe3,0x8fe4,0x8fe8,0x8fee,0x8ff1,0x8ff5,0x8ff6, 0x8ffb,0x8ffe,0x9002,0x9004,0x9008,0x900c,0x9018,0x901b,0x9028,0x9029, 0x902f,0x902a,0x902c,0x902d,0x9033,0x9034,0x9037,0x903f,0x9043,0x9044, 0x904c,0x905b,0x905d,0x9062,0x9066,0x9067,0x906c,0x9070,0x9074,0x9079, 0x9085,0x9088,0x908b,0x908c,0x908e,0x9090,0x9095,0x9097,0x9098,0x9099, 0x909b,0x90a0,0x90a1,0x90a2,0x90a5,0x90b0,0x90b2,0x90b3,0x90b4,0x90b6, 0x90bd,0x90cc,0x90be,0x90c3 }, { /* ku 42 */ 0x90c4,0x90c5,0x90c7,0x90c8,0x90d5,0x90d7,0x90d8,0x90d9,0x90dc,0x90dd, 0x90df,0x90e5,0x90d2,0x90f6,0x90eb,0x90ef,0x90f0,0x90f4,0x90fe,0x90ff, 0x9100,0x9104,0x9105,0x9106,0x9108,0x910d,0x9110,0x9114,0x9116,0x9117, 0x9118,0x911a,0x911c,0x911e,0x9120,0x9125,0x9122,0x9123,0x9127,0x9129, 0x912e,0x912f,0x9131,0x9134,0x9136,0x9137,0x9139,0x913a,0x913c,0x913d, 0x9143,0x9147,0x9148,0x914f,0x9153,0x9157,0x9159,0x915a,0x915b,0x9161, 0x9164,0x9167,0x916d,0x9174,0x9179,0x917a,0x917b,0x9181,0x9183,0x9185, 0x9186,0x918a,0x918e,0x9191,0x9193,0x9194,0x9195,0x9198,0x919e,0x91a1, 0x91a6,0x91a8,0x91ac,0x91ad,0x91ae,0x91b0,0x91b1,0x91b2,0x91b3,0x91b6, 0x91bb,0x91bc,0x91bd,0x91bf }, { /* ku 43 */ 0x91c2,0x91c3,0x91c5,0x91d3,0x91d4,0x91d7,0x91d9,0x91da,0x91de,0x91e4, 0x91e5,0x91e9,0x91ea,0x91ec,0x91ed,0x91ee,0x91ef,0x91f0,0x91f1,0x91f7, 0x91f9,0x91fb,0x91fd,0x9200,0x9201,0x9204,0x9205,0x9206,0x9207,0x9209, 0x920a,0x920c,0x9210,0x9212,0x9213,0x9216,0x9218,0x921c,0x921d,0x9223, 0x9224,0x9225,0x9226,0x9228,0x922e,0x922f,0x9230,0x9233,0x9235,0x9236, 0x9238,0x9239,0x923a,0x923c,0x923e,0x9240,0x9242,0x9243,0x9246,0x9247, 0x924a,0x924d,0x924e,0x924f,0x9251,0x9258,0x9259,0x925c,0x925d,0x9260, 0x9261,0x9265,0x9267,0x9268,0x9269,0x926e,0x926f,0x9270,0x9275,0x9276, 0x9277,0x9278,0x9279,0x927b,0x927c,0x927d,0x927f,0x9288,0x9289,0x928a, 0x928d,0x928e,0x9292,0x9297 }, { /* ku 44 */ 0x9299,0x929f,0x92a0,0x92a4,0x92a5,0x92a7,0x92a8,0x92ab,0x92af,0x92b2, 0x92b6,0x92b8,0x92ba,0x92bb,0x92bc,0x92bd,0x92bf,0x92c0,0x92c1,0x92c2, 0x92c3,0x92c5,0x92c6,0x92c7,0x92c8,0x92cb,0x92cc,0x92cd,0x92ce,0x92d0, 0x92d3,0x92d5,0x92d7,0x92d8,0x92d9,0x92dc,0x92dd,0x92df,0x92e0,0x92e1, 0x92e3,0x92e5,0x92e7,0x92e8,0x92ec,0x92ee,0x92f0,0x92f9,0x92fb,0x92ff, 0x9300,0x9302,0x9308,0x930d,0x9311,0x9314,0x9315,0x931c,0x931d,0x931e, 0x931f,0x9321,0x9324,0x9325,0x9327,0x9329,0x932a,0x9333,0x9334,0x9336, 0x9337,0x9347,0x9348,0x9349,0x9350,0x9351,0x9352,0x9355,0x9357,0x9358, 0x935a,0x935e,0x9364,0x9365,0x9367,0x9369,0x936a,0x936d,0x936f,0x9370, 0x9371,0x9373,0x9374,0x9376 }, { /* ku 45 */ 0x937a,0x937d,0x937f,0x9380,0x9381,0x9382,0x9388,0x938a,0x938b,0x938d, 0x938f,0x9392,0x9395,0x9398,0x939b,0x939e,0x93a1,0x93a3,0x93a4,0x93a6, 0x93a8,0x93ab,0x93b4,0x93b5,0x93b6,0x93ba,0x93a9,0x93c1,0x93c4,0x93c5, 0x93c6,0x93c7,0x93c9,0x93ca,0x93cb,0x93cc,0x93cd,0x93d3,0x93d9,0x93dc, 0x93de,0x93df,0x93e2,0x93e6,0x93e7,0x93f9,0x93f7,0x93f8,0x93fa,0x93fb, 0x93fd,0x9401,0x9402,0x9404,0x9408,0x9409,0x940d,0x940e,0x940f,0x9415, 0x9416,0x9417,0x941f,0x942e,0x942f,0x9431,0x9432,0x9433,0x9434,0x943b, 0x943f,0x943d,0x9443,0x9445,0x9448,0x944a,0x944c,0x9455,0x9459,0x945c, 0x945f,0x9461,0x9463,0x9468,0x946b,0x946d,0x946e,0x946f,0x9471,0x9472, 0x9484,0x9483,0x9578,0x9579 }, { /* ku 46 */ 0x957e,0x9584,0x9588,0x958c,0x958d,0x958e,0x959d,0x959e,0x959f,0x95a1, 0x95a6,0x95a9,0x95ab,0x95ac,0x95b4,0x95b6,0x95ba,0x95bd,0x95bf,0x95c6, 0x95c8,0x95c9,0x95cb,0x95d0,0x95d1,0x95d2,0x95d3,0x95d9,0x95da,0x95dd, 0x95de,0x95df,0x95e0,0x95e4,0x95e6,0x961d,0x961e,0x9622,0x9624,0x9625, 0x9626,0x962c,0x9631,0x9633,0x9637,0x9638,0x9639,0x963a,0x963c,0x963d, 0x9641,0x9652,0x9654,0x9656,0x9657,0x9658,0x9661,0x966e,0x9674,0x967b, 0x967c,0x967e,0x967f,0x9681,0x9682,0x9683,0x9684,0x9689,0x9691,0x9696, 0x969a,0x969d,0x969f,0x96a4,0x96a5,0x96a6,0x96a9,0x96ae,0x96af,0x96b3, 0x96ba,0x96ca,0x96d2,0x5db2,0x96d8,0x96da,0x96dd,0x96de,0x96df,0x96e9, 0x96ef,0x96f1,0x96fa,0x9702 }, { /* ku 47 */ 0x9703,0x9705,0x9709,0x971a,0x971b,0x971d,0x9721,0x9722,0x9723,0x9728, 0x9731,0x9733,0x9741,0x9743,0x974a,0x974e,0x974f,0x9755,0x9757,0x9758, 0x975a,0x975b,0x9763,0x9767,0x976a,0x976e,0x9773,0x9776,0x9777,0x9778, 0x977b,0x977d,0x977f,0x9780,0x9789,0x9795,0x9796,0x9797,0x9799,0x979a, 0x979e,0x979f,0x97a2,0x97ac,0x97ae,0x97b1,0x97b2,0x97b5,0x97b6,0x97b8, 0x97b9,0x97ba,0x97bc,0x97be,0x97bf,0x97c1,0x97c4,0x97c5,0x97c7,0x97c9, 0x97ca,0x97cc,0x97cd,0x97ce,0x97d0,0x97d1,0x97d4,0x97d7,0x97d8,0x97d9, 0x97dd,0x97de,0x97e0,0x97db,0x97e1,0x97e4,0x97ef,0x97f1,0x97f4,0x97f7, 0x97f8,0x97fa,0x9807,0x980a,0x9819,0x980d,0x980e,0x9814,0x9816,0x981c, 0x981e,0x9820,0x9823,0x9826 }, { /* ku 48 */ 0x982b,0x982e,0x982f,0x9830,0x9832,0x9833,0x9835,0x9825,0x983e,0x9844, 0x9847,0x984a,0x9851,0x9852,0x9853,0x9856,0x9857,0x9859,0x985a,0x9862, 0x9863,0x9865,0x9866,0x986a,0x986c,0x98ab,0x98ad,0x98ae,0x98b0,0x98b4, 0x98b7,0x98b8,0x98ba,0x98bb,0x98bf,0x98c2,0x98c5,0x98c8,0x98cc,0x98e1, 0x98e3,0x98e5,0x98e6,0x98e7,0x98ea,0x98f3,0x98f6,0x9902,0x9907,0x9908, 0x9911,0x9915,0x9916,0x9917,0x991a,0x991b,0x991c,0x991f,0x9922,0x9926, 0x9927,0x992b,0x9931,0x9932,0x9933,0x9934,0x9935,0x9939,0x993a,0x993b, 0x993c,0x9940,0x9941,0x9946,0x9947,0x9948,0x994d,0x994e,0x9954,0x9958, 0x9959,0x995b,0x995c,0x995e,0x995f,0x9960,0x999b,0x999d,0x999f,0x99a6, 0x99b0,0x99b1,0x99b2,0x99b5 }, { /* ku 49 */ 0x99b9,0x99ba,0x99bd,0x99bf,0x99c3,0x99c9,0x99d3,0x99d4,0x99d9,0x99da, 0x99dc,0x99de,0x99e7,0x99ea,0x99eb,0x99ec,0x99f0,0x99f4,0x99f5,0x99f9, 0x99fd,0x99fe,0x9a02,0x9a03,0x9a04,0x9a0b,0x9a0c,0x9a10,0x9a11,0x9a16, 0x9a1e,0x9a20,0x9a22,0x9a23,0x9a24,0x9a27,0x9a2d,0x9a2e,0x9a33,0x9a35, 0x9a36,0x9a38,0x9a47,0x9a41,0x9a44,0x9a4a,0x9a4b,0x9a4c,0x9a4e,0x9a51, 0x9a54,0x9a56,0x9a5d,0x9aaa,0x9aac,0x9aae,0x9aaf,0x9ab2,0x9ab4,0x9ab5, 0x9ab6,0x9ab9,0x9abb,0x9abe,0x9abf,0x9ac1,0x9ac3,0x9ac6,0x9ac8,0x9ace, 0x9ad0,0x9ad2,0x9ad5,0x9ad6,0x9ad7,0x9adb,0x9adc,0x9ae0,0x9ae4,0x9ae5, 0x9ae7,0x9ae9,0x9aec,0x9af2,0x9af3,0x9af5,0x9af9,0x9afa,0x9afd,0x9aff, 0x9b00,0x9b01,0x9b02,0x9b03 }, { /* ku 4a */ 0x9b04,0x9b05,0x9b08,0x9b09,0x9b0b,0x9b0c,0x9b0d,0x9b0e,0x9b10,0x9b12, 0x9b16,0x9b19,0x9b1b,0x9b1c,0x9b20,0x9b26,0x9b2b,0x9b2d,0x9b33,0x9b34, 0x9b35,0x9b37,0x9b39,0x9b3a,0x9b3d,0x9b48,0x9b4b,0x9b4c,0x9b55,0x9b56, 0x9b57,0x9b5b,0x9b5e,0x9b61,0x9b63,0x9b65,0x9b66,0x9b68,0x9b6a,0x9b6b, 0x9b6c,0x9b6d,0x9b6e,0x9b73,0x9b75,0x9b77,0x9b78,0x9b79,0x9b7f,0x9b80, 0x9b84,0x9b85,0x9b86,0x9b87,0x9b89,0x9b8a,0x9b8b,0x9b8d,0x9b8f,0x9b90, 0x9b94,0x9b9a,0x9b9d,0x9b9e,0x9ba6,0x9ba7,0x9ba9,0x9bac,0x9bb0,0x9bb1, 0x9bb2,0x9bb7,0x9bb8,0x9bbb,0x9bbc,0x9bbe,0x9bbf,0x9bc1,0x9bc7,0x9bc8, 0x9bce,0x9bd0,0x9bd7,0x9bd8,0x9bdd,0x9bdf,0x9be5,0x9be7,0x9bea,0x9beb, 0x9bef,0x9bf3,0x9bf7,0x9bf8 }, { /* ku 4b */ 0x9bf9,0x9bfa,0x9bfd,0x9bff,0x9c00,0x9c02,0x9c0b,0x9c0f,0x9c11,0x9c16, 0x9c18,0x9c19,0x9c1a,0x9c1c,0x9c1e,0x9c22,0x9c23,0x9c26,0x9c27,0x9c28, 0x9c29,0x9c2a,0x9c31,0x9c35,0x9c36,0x9c37,0x9c3d,0x9c41,0x9c43,0x9c44, 0x9c45,0x9c49,0x9c4a,0x9c4e,0x9c4f,0x9c50,0x9c53,0x9c54,0x9c56,0x9c58, 0x9c5b,0x9c5d,0x9c5e,0x9c5f,0x9c63,0x9c69,0x9c6a,0x9c5c,0x9c6b,0x9c68, 0x9c6e,0x9c70,0x9c72,0x9c75,0x9c77,0x9c7b,0x9ce6,0x9cf2,0x9cf7,0x9cf9, 0x9d0b,0x9d02,0x9d11,0x9d17,0x9d18,0x9d1c,0x9d1d,0x9d1e,0x9d2f,0x9d30, 0x9d32,0x9d33,0x9d34,0x9d3a,0x9d3c,0x9d45,0x9d3d,0x9d42,0x9d43,0x9d47, 0x9d4a,0x9d53,0x9d54,0x9d5f,0x9d63,0x9d62,0x9d65,0x9d69,0x9d6a,0x9d6b, 0x9d70,0x9d76,0x9d77,0x9d7b }, { /* ku 4c */ 0x9d7c,0x9d7e,0x9d83,0x9d84,0x9d86,0x9d8a,0x9d8d,0x9d8e,0x9d92,0x9d93, 0x9d95,0x9d96,0x9d97,0x9d98,0x9da1,0x9daa,0x9dac,0x9dae,0x9db1,0x9db5, 0x9db9,0x9dbc,0x9dbf,0x9dc3,0x9dc7,0x9dc9,0x9dca,0x9dd4,0x9dd5,0x9dd6, 0x9dd7,0x9dda,0x9dde,0x9ddf,0x9de0,0x9de5,0x9de7,0x9de9,0x9deb,0x9dee, 0x9df0,0x9df3,0x9df4,0x9dfe,0x9e0a,0x9e02,0x9e07,0x9e0e,0x9e10,0x9e11, 0x9e12,0x9e15,0x9e16,0x9e19,0x9e1c,0x9e1d,0x9e7a,0x9e7b,0x9e7c,0x9e80, 0x9e82,0x9e83,0x9e84,0x9e85,0x9e87,0x9e8e,0x9e8f,0x9e96,0x9e98,0x9e9b, 0x9e9e,0x9ea4,0x9ea8,0x9eac,0x9eae,0x9eaf,0x9eb0,0x9eb3,0x9eb4,0x9eb5, 0x9ec6,0x9ec8,0x9ecb,0x9ed5,0x9edf,0x9ee4,0x9ee7,0x9eec,0x9eed,0x9eee, 0x9ef0,0x9ef1,0x9ef2,0x9ef5 }, { /* ku 4d */ 0x9ef8,0x9eff,0x9f02,0x9f03,0x9f09,0x9f0f,0x9f10,0x9f11,0x9f12,0x9f14, 0x9f16,0x9f17,0x9f19,0x9f1a,0x9f1b,0x9f1f,0x9f22,0x9f26,0x9f2a,0x9f2b, 0x9f2f,0x9f31,0x9f32,0x9f34,0x9f37,0x9f39,0x9f3a,0x9f3c,0x9f3d,0x9f3f, 0x9f41,0x9f43,0x9f44,0x9f45,0x9f46,0x9f47,0x9f53,0x9f55,0x9f56,0x9f57, 0x9f58,0x9f5a,0x9f5d,0x9f5e,0x9f68,0x9f69,0x9f6d,0x9f6e,0x9f6f,0x9f70, 0x9f71,0x9f73,0x9f75,0x9f7a,0x9f7d,0x9f8f,0x9f90,0x9f91,0x9f92,0x9f94, 0x9f96,0x9f97,0x9f9e,0x9fa1,0x9fa2,0x9fa3,0x9fa5,UBOGON,UBOGON,UBOGON, UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON, UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON, UBOGON,UBOGON,UBOGON,UBOGON } }; alpine-2.10+dfsg/imap/src/charset/iso_8859.c0000600000175000017500000003361211512502123022141 0ustar paulproteuspaulproteus/* ======================================================================== * Copyright 1988-2006 University of Washington * * Licensed under the Apache License, Version 2.0 (the "License"); * you may not use this file except in compliance with the License. * You may obtain a copy of the License at * * http://www.apache.org/licenses/LICENSE-2.0 * * * ======================================================================== */ /* * Program: ISO-8859 conversion tables * * Author: Mark Crispin * Networks and Distributed Computing * Computing & Communications * University of Washington * Administration Building, AG-44 * Seattle, WA 98195 * Internet: MRC@CAC.Washington.EDU * * Date: 3 July 1997 * Last Edited: 30 August 2006 */ /* ISO-8859 conversion tables */ /* Latin-2 (East European) */ static const unsigned short iso8859_2tab[128] = { 0x0080,0x0081,0x0082,0x0083,0x0084,0x0085,0x0086,0x0087, 0x0088,0x0089,0x008a,0x008b,0x008c,0x008d,0x008e,0x008f, 0x0090,0x0091,0x0092,0x0093,0x0094,0x0095,0x0096,0x0097, 0x0098,0x0099,0x009a,0x009b,0x009c,0x009d,0x009e,0x009f, 0x00a0,0x0104,0x02d8,0x0141,0x00a4,0x013d,0x015a,0x00a7, 0x00a8,0x0160,0x015e,0x0164,0x0179,0x00ad,0x017d,0x017b, 0x00b0,0x0105,0x02db,0x0142,0x00b4,0x013e,0x015b,0x02c7, 0x00b8,0x0161,0x015f,0x0165,0x017a,0x02dd,0x017e,0x017c, 0x0154,0x00c1,0x00c2,0x0102,0x00c4,0x0139,0x0106,0x00c7, 0x010c,0x00c9,0x0118,0x00cb,0x011a,0x00cd,0x00ce,0x010e, 0x0110,0x0143,0x0147,0x00d3,0x00d4,0x0150,0x00d6,0x00d7, 0x0158,0x016e,0x00da,0x0170,0x00dc,0x00dd,0x0162,0x00df, 0x0155,0x00e1,0x00e2,0x0103,0x00e4,0x013a,0x0107,0x00e7, 0x010d,0x00e9,0x0119,0x00eb,0x011b,0x00ed,0x00ee,0x010f, 0x0111,0x0144,0x0148,0x00f3,0x00f4,0x0151,0x00f6,0x00f7, 0x0159,0x016f,0x00fa,0x0171,0x00fc,0x00fd,0x0163,0x02d9 }; /* Latin-3 (South European) */ static const unsigned short iso8859_3tab[128] = { 0x0080,0x0081,0x0082,0x0083,0x0084,0x0085,0x0086,0x0087, 0x0088,0x0089,0x008a,0x008b,0x008c,0x008d,0x008e,0x008f, 0x0090,0x0091,0x0092,0x0093,0x0094,0x0095,0x0096,0x0097, 0x0098,0x0099,0x009a,0x009b,0x009c,0x009d,0x009e,0x009f, 0x00a0,0x0126,0x02d8,0x00a3,0x00a4,UBOGON,0x0124,0x00a7, 0x00a8,0x0130,0x015e,0x011e,0x0134,0x00ad,UBOGON,0x017b, 0x00b0,0x0127,0x00b2,0x00b3,0x00b4,0x00b5,0x0125,0x00b7, 0x00b8,0x0131,0x015f,0x011f,0x0135,0x00bd,UBOGON,0x017c, 0x00c0,0x00c1,0x00c2,UBOGON,0x00c4,0x010a,0x0108,0x00c7, 0x00c8,0x00c9,0x00ca,0x00cb,0x00cc,0x00cd,0x00ce,0x00cf, UBOGON,0x00d1,0x00d2,0x00d3,0x00d4,0x0120,0x00d6,0x00d7, 0x011c,0x00d9,0x00da,0x00db,0x00dc,0x016c,0x015c,0x00df, 0x00e0,0x00e1,0x00e2,UBOGON,0x00e4,0x010b,0x0109,0x00e7, 0x00e8,0x00e9,0x00ea,0x00eb,0x00ec,0x00ed,0x00ee,0x00ef, UBOGON,0x00f1,0x00f2,0x00f3,0x00f4,0x0121,0x00f6,0x00f7, 0x011d,0x00f9,0x00fa,0x00fb,0x00fc,0x016d,0x015d,0x02d9 }; /* Latin-4 (North European) */ static const unsigned short iso8859_4tab[128] = { 0x0080,0x0081,0x0082,0x0083,0x0084,0x0085,0x0086,0x0087, 0x0088,0x0089,0x008a,0x008b,0x008c,0x008d,0x008e,0x008f, 0x0090,0x0091,0x0092,0x0093,0x0094,0x0095,0x0096,0x0097, 0x0098,0x0099,0x009a,0x009b,0x009c,0x009d,0x009e,0x009f, 0x00a0,0x0104,0x0138,0x0156,0x00a4,0x0128,0x013b,0x00a7, 0x00a8,0x0160,0x0112,0x0122,0x0166,0x00ad,0x017d,0x00af, 0x00b0,0x0105,0x02db,0x0157,0x00b4,0x0129,0x013c,0x02c7, 0x00b8,0x0161,0x0113,0x0123,0x0167,0x014a,0x017e,0x014b, 0x0100,0x00c1,0x00c2,0x00c3,0x00c4,0x00c5,0x00c6,0x012e, 0x010c,0x00c9,0x0118,0x00cb,0x0116,0x00cd,0x00ce,0x012a, 0x0110,0x0145,0x014c,0x0136,0x00d4,0x00d5,0x00d6,0x00d7, 0x00d8,0x0172,0x00da,0x00db,0x00dc,0x0168,0x016a,0x00df, 0x0101,0x00e1,0x00e2,0x00e3,0x00e4,0x00e5,0x00e6,0x012f, 0x010d,0x00e9,0x0119,0x00eb,0x0117,0x00ed,0x00ee,0x012b, 0x0111,0x0146,0x014d,0x0137,0x00f4,0x00f5,0x00f6,0x00f7, 0x00f8,0x0173,0x00fa,0x00fb,0x00fc,0x0169,0x016b,0x02d9 }; /* Cyrillic */ static const unsigned short iso8859_5tab[128] = { 0x0080,0x0081,0x0082,0x0083,0x0084,0x0085,0x0086,0x0087, 0x0088,0x0089,0x008a,0x008b,0x008c,0x008d,0x008e,0x008f, 0x0090,0x0091,0x0092,0x0093,0x0094,0x0095,0x0096,0x0097, 0x0098,0x0099,0x009a,0x009b,0x009c,0x009d,0x009e,0x009f, 0x00a0,0x0401,0x0402,0x0403,0x0404,0x0405,0x0406,0x0407, 0x0408,0x0409,0x040a,0x040b,0x040c,0x00ad,0x040e,0x040f, 0x0410,0x0411,0x0412,0x0413,0x0414,0x0415,0x0416,0x0417, 0x0418,0x0419,0x041a,0x041b,0x041c,0x041d,0x041e,0x041f, 0x0420,0x0421,0x0422,0x0423,0x0424,0x0425,0x0426,0x0427, 0x0428,0x0429,0x042a,0x042b,0x042c,0x042d,0x042e,0x042f, 0x0430,0x0431,0x0432,0x0433,0x0434,0x0435,0x0436,0x0437, 0x0438,0x0439,0x043a,0x043b,0x043c,0x043d,0x043e,0x043f, 0x0440,0x0441,0x0442,0x0443,0x0444,0x0445,0x0446,0x0447, 0x0448,0x0449,0x044a,0x044b,0x044c,0x044d,0x044e,0x044f, 0x2116,0x0451,0x0452,0x0453,0x0454,0x0455,0x0456,0x0457, 0x0458,0x0459,0x045a,0x045b,0x045c,0x00a7,0x045e,0x045f }; /* Arabic */ static const unsigned short iso8859_6tab[128] = { 0x0080,0x0081,0x0082,0x0083,0x0084,0x0085,0x0086,0x0087, 0x0088,0x0089,0x008a,0x008b,0x008c,0x008d,0x008e,0x008f, 0x0090,0x0091,0x0092,0x0093,0x0094,0x0095,0x0096,0x0097, 0x0098,0x0099,0x009a,0x009b,0x009c,0x009d,0x009e,0x009f, 0x00a0,UBOGON,UBOGON,UBOGON,0x00a4,UBOGON,UBOGON,UBOGON, UBOGON,UBOGON,UBOGON,UBOGON,0x060c,0x00ad,UBOGON,UBOGON, UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON, UBOGON,UBOGON,UBOGON,0x061b,UBOGON,UBOGON,UBOGON,0x061f, UBOGON,0x0621,0x0622,0x0623,0x0624,0x0625,0x0626,0x0627, 0x0628,0x0629,0x062a,0x062b,0x062c,0x062d,0x062e,0x062f, 0x0630,0x0631,0x0632,0x0633,0x0634,0x0635,0x0636,0x0637, 0x0638,0x0639,0x063a,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON, 0x0640,0x0641,0x0642,0x0643,0x0644,0x0645,0x0646,0x0647, 0x0648,0x0649,0x064a,0x064b,0x064c,0x064d,0x064e,0x064f, 0x0650,0x0651,0x0652,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON, UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON }; /* Greek */ static const unsigned short iso8859_7tab[128] = { 0x0080,0x0081,0x0082,0x0083,0x0084,0x0085,0x0086,0x0087, 0x0088,0x0089,0x008a,0x008b,0x008c,0x008d,0x008e,0x008f, 0x0090,0x0091,0x0092,0x0093,0x0094,0x0095,0x0096,0x0097, 0x0098,0x0099,0x009a,0x009b,0x009c,0x009d,0x009e,0x009f, 0x00a0,0x2018,0x2019,0x00a3,UBOGON,UBOGON,0x00a6,0x00a7, 0x00a8,0x00a9,UBOGON,0x00ab,0x00ac,0x00ad,UBOGON,0x2015, 0x00b0,0x00b1,0x00b2,0x00b3,0x0384,0x0385,0x0386,0x00b7, 0x0388,0x0389,0x038a,0x00bb,0x038c,0x00bd,0x038e,0x038f, 0x0390,0x0391,0x0392,0x0393,0x0394,0x0395,0x0396,0x0397, 0x0398,0x0399,0x039a,0x039b,0x039c,0x039d,0x039e,0x039f, 0x03a0,0x03a1,UBOGON,0x03a3,0x03a4,0x03a5,0x03a6,0x03a7, 0x03a8,0x03a9,0x03aa,0x03ab,0x03ac,0x03ad,0x03ae,0x03af, 0x03b0,0x03b1,0x03b2,0x03b3,0x03b4,0x03b5,0x03b6,0x03b7, 0x03b8,0x03b9,0x03ba,0x03bb,0x03bc,0x03bd,0x03be,0x03bf, 0x03c0,0x03c1,0x03c2,0x03c3,0x03c4,0x03c5,0x03c6,0x03c7, 0x03c8,0x03c9,0x03ca,0x03cb,0x03cc,0x03cd,0x03ce,UBOGON }; /* Hebrew */ static const unsigned short iso8859_8tab[128] = { 0x0080,0x0081,0x0082,0x0083,0x0084,0x0085,0x0086,0x0087, 0x0088,0x0089,0x008a,0x008b,0x008c,0x008d,0x008e,0x008f, 0x0090,0x0091,0x0092,0x0093,0x0094,0x0095,0x0096,0x0097, 0x0098,0x0099,0x009a,0x009b,0x009c,0x009d,0x009e,0x009f, 0x00a0,UBOGON,0x00a2,0x00a3,0x00a4,0x00a5,0x00a6,0x00a7, 0x00a8,0x00a9,0x00d7,0x00ab,0x00ac,0x00ad,0x00ae,0x00af, 0x00b0,0x00b1,0x00b2,0x00b3,0x00b4,0x00b5,0x00b6,0x00b7, 0x00b8,0x00b9,0x00f7,0x00bb,0x00bc,0x00bd,0x00be,UBOGON, UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON, UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON, UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON, UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,0x2017, 0x05d0,0x05d1,0x05d2,0x05d3,0x05d4,0x05d5,0x05d6,0x05d7, 0x05d8,0x05d9,0x05da,0x05db,0x05dc,0x05dd,0x05de,0x05df, 0x05e0,0x05e1,0x05e2,0x05e3,0x05e4,0x05e5,0x05e6,0x05e7, 0x05e8,0x05e9,0x05ea,UBOGON,UBOGON,0x200e,0x200f,UBOGON }; /* Latin-5 (Turkish) */ static const unsigned short iso8859_9tab[128] = { 0x0080,0x0081,0x0082,0x0083,0x0084,0x0085,0x0086,0x0087, 0x0088,0x0089,0x008a,0x008b,0x008c,0x008d,0x008e,0x008f, 0x0090,0x0091,0x0092,0x0093,0x0094,0x0095,0x0096,0x0097, 0x0098,0x0099,0x009a,0x009b,0x009c,0x009d,0x009e,0x009f, 0x00a0,0x00a1,0x00a2,0x00a3,0x00a4,0x00a5,0x00a6,0x00a7, 0x00a8,0x00a9,0x00aa,0x00ab,0x00ac,0x00ad,0x00ae,0x00af, 0x00b0,0x00b1,0x00b2,0x00b3,0x00b4,0x00b5,0x00b6,0x00b7, 0x00b8,0x00b9,0x00ba,0x00bb,0x00bc,0x00bd,0x00be,0x00bf, 0x00c0,0x00c1,0x00c2,0x00c3,0x00c4,0x00c5,0x00c6,0x00c7, 0x00c8,0x00c9,0x00ca,0x00cb,0x00cc,0x00cd,0x00ce,0x00cf, 0x011e,0x00d1,0x00d2,0x00d3,0x00d4,0x00d5,0x00d6,0x00d7, 0x00d8,0x00d9,0x00da,0x00db,0x00dc,0x0130,0x015e,0x00df, 0x00e0,0x00e1,0x00e2,0x00e3,0x00e4,0x00e5,0x00e6,0x00e7, 0x00e8,0x00e9,0x00ea,0x00eb,0x00ec,0x00ed,0x00ee,0x00ef, 0x011f,0x00f1,0x00f2,0x00f3,0x00f4,0x00f5,0x00f6,0x00f7, 0x00f8,0x00f9,0x00fa,0x00fb,0x00fc,0x0131,0x015f,0x00ff }; /* Latin-6 (Nordic) */ static const unsigned short iso8859_10tab[128] = { 0x0080,0x0081,0x0082,0x0083,0x0084,0x0085,0x0086,0x0087, 0x0088,0x0089,0x008a,0x008b,0x008c,0x008d,0x008e,0x008f, 0x0090,0x0091,0x0092,0x0093,0x0094,0x0095,0x0096,0x0097, 0x0098,0x0099,0x009a,0x009b,0x009c,0x009d,0x009e,0x009f, 0x00a0,0x0104,0x0112,0x0122,0x012a,0x0128,0x0136,0x00a7, 0x013b,0x0110,0x0160,0x0166,0x017d,0x00ad,0x016a,0x014a, 0x00b0,0x0105,0x0113,0x0123,0x012b,0x0129,0x0137,0x00b7, 0x013c,0x0111,0x0161,0x0167,0x017e,0x2015,0x016b,0x014b, 0x0100,0x00c1,0x00c2,0x00c3,0x00c4,0x00c5,0x00c6,0x012e, 0x010c,0x00c9,0x0118,0x00cb,0x0116,0x00cd,0x00ce,0x00cf, 0x00d0,0x0145,0x014c,0x00d3,0x00d4,0x00d5,0x00d6,0x0168, 0x00d8,0x0172,0x00da,0x00db,0x00dc,0x00dd,0x00de,0x00df, 0x0101,0x00e1,0x00e2,0x00e3,0x00e4,0x00e5,0x00e6,0x012f, 0x010d,0x00e9,0x0119,0x00eb,0x0117,0x00ed,0x00ee,0x00ef, 0x00f0,0x0146,0x014d,0x00f3,0x00f4,0x00f5,0x00f6,0x0169, 0x00f8,0x0173,0x00fa,0x00fb,0x00fc,0x00fd,0x00fe,0x0138 }; /* Thai */ #define iso8859_11tab tis620tab /* reserved for ISCII Indian */ /* Latin-7 (Baltic) */ static const unsigned short iso8859_13tab[128] = { 0x0080,0x0081,0x0082,0x0083,0x0084,0x0085,0x0086,0x0087, 0x0088,0x0089,0x008a,0x008b,0x008c,0x008d,0x008e,0x008f, 0x0090,0x0091,0x0092,0x0093,0x0094,0x0095,0x0096,0x0097, 0x0098,0x0099,0x009a,0x009b,0x009c,0x009d,0x009e,0x009f, 0x00a0,0x201d,0x00a2,0x00a3,0x00a4,0x201e,0x00a6,0x00a7, 0x00d8,0x00a9,0x0156,0x00ab,0x00ac,0x00ad,0x00ae,0x00c6, 0x00b0,0x00b1,0x00b2,0x00b3,0x201c,0x00b5,0x00b6,0x00b7, 0x00f8,0x00b9,0x0157,0x00bb,0x00bc,0x00bd,0x00be,0x00e6, 0x0104,0x012e,0x0100,0x0106,0x00c4,0x00c5,0x0118,0x0112, 0x010c,0x00c9,0x0179,0x0116,0x0122,0x0136,0x012a,0x013b, 0x0160,0x0143,0x0145,0x00d3,0x014c,0x00d5,0x00d6,0x00d7, 0x0172,0x0141,0x015a,0x016a,0x00dc,0x017b,0x017d,0x00df, 0x0105,0x012f,0x0101,0x0107,0x00e4,0x00e5,0x0119,0x0113, 0x010d,0x00e9,0x017a,0x0117,0x0123,0x0137,0x012b,0x013c, 0x0161,0x0144,0x0146,0x00f3,0x014d,0x00f5,0x00f6,0x00f7, 0x0173,0x0142,0x015b,0x016b,0x00fc,0x017c,0x017e,0x2019 }; /* Latin-8 (Celtic) */ static const unsigned short iso8859_14tab[128] = { 0x0080,0x0081,0x0082,0x0083,0x0084,0x0085,0x0086,0x0087, 0x0088,0x0089,0x008a,0x008b,0x008c,0x008d,0x008e,0x008f, 0x0090,0x0091,0x0092,0x0093,0x0094,0x0095,0x0096,0x0097, 0x0098,0x0099,0x009a,0x009b,0x009c,0x009d,0x009e,0x009f, 0x00a0,0x1e02,0x1e03,0x00a3,0x010a,0x010b,0x1e0a,0x00a7, 0x1e80,0x00a9,0x1e82,0x1e0b,0x1ef2,0x00ad,0x00ae,0x0178, 0x1e1e,0x1e1f,0x0120,0x0121,0x1e40,0x1e41,0x00b6,0x1e56, 0x1e81,0x1e57,0x1e83,0x1e60,0x1ef3,0x1e84,0x1e85,0x1e61, 0x00c0,0x00c1,0x00c2,0x00c3,0x00c4,0x00c5,0x00c6,0x00c7, 0x00c8,0x00c9,0x00ca,0x00cb,0x00cc,0x00cd,0x00ce,0x00cf, 0x0174,0x00d1,0x00d2,0x00d3,0x00d4,0x00d5,0x00d6,0x1e6a, 0x00d8,0x00d9,0x00da,0x00db,0x00dc,0x00dd,0x0176,0x00df, 0x00e0,0x00e1,0x00e2,0x00e3,0x00e4,0x00e5,0x00e6,0x00e7, 0x00e8,0x00e9,0x00ea,0x00eb,0x00ec,0x00ed,0x00ee,0x00ef, 0x0175,0x00f1,0x00f2,0x00f3,0x00f4,0x00f5,0x00f6,0x1e6b, 0x00f8,0x00f9,0x00fa,0x00fb,0x00fc,0x00fd,0x0177,0x00ff }; /* Latin-9 a.k.a. Latin-0 (Euro) */ static const unsigned short iso8859_15tab[128] = { 0x0080,0x0081,0x0082,0x0083,0x0084,0x0085,0x0086,0x0087, 0x0088,0x0089,0x008a,0x008b,0x008c,0x008d,0x008e,0x008f, 0x0090,0x0091,0x0092,0x0093,0x0094,0x0095,0x0096,0x0097, 0x0098,0x0099,0x009a,0x009b,0x009c,0x009d,0x009e,0x009f, 0x00a0,0x00a1,0x00a2,0x00a3,0x20ac,0x00a5,0x0160,0x00a7, 0x0161,0x00a9,0x00aa,0x00ab,0x00ac,0x00ad,0x00ae,0x00af, 0x00b0,0x00b1,0x00b2,0x00b3,0x017d,0x00b5,0x00b6,0x00b7, 0x017e,0x00b9,0x00ba,0x00bb,0x0152,0x0153,0x0178,0x00bf, 0x00c0,0x00c1,0x00c2,0x00c3,0x00c4,0x00c5,0x00c6,0x00c7, 0x00c8,0x00c9,0x00ca,0x00cb,0x00cc,0x00cd,0x00ce,0x00cf, 0x00d0,0x00d1,0x00d2,0x00d3,0x00d4,0x00d5,0x00d6,0x00d7, 0x00d8,0x00d9,0x00da,0x00db,0x00dc,0x00dd,0x00de,0x00df, 0x00e0,0x00e1,0x00e2,0x00e3,0x00e4,0x00e5,0x00e6,0x00e7, 0x00e8,0x00e9,0x00ea,0x00eb,0x00ec,0x00ed,0x00ee,0x00ef, 0x00f0,0x00f1,0x00f2,0x00f3,0x00f4,0x00f5,0x00f6,0x00f7, 0x00f8,0x00f9,0x00fa,0x00fb,0x00fc,0x00fd,0x00fe,0x00ff }; /* Latin-10 (Balkan) */ static const unsigned short iso8859_16tab[128] = { 0x0080,0x0081,0x0082,0x0083,0x0084,0x0085,0x0086,0x0087, 0x0088,0x0089,0x008a,0x008b,0x008c,0x008d,0x008e,0x008f, 0x0090,0x0091,0x0092,0x0093,0x0094,0x0095,0x0096,0x0097, 0x0098,0x0099,0x009a,0x009b,0x009c,0x009d,0x009e,0x009f, 0x00a0,0x0104,0x0105,0x0141,0x20ac,0x201e,0x0160,0x00a7, 0x0161,0x00a9,0x0218,0x00ab,0x0179,0x00ad,0x017a,0x017b, 0x00b0,0x00b1,0x010c,0x0142,0x017d,0x201d,0x00b6,0x00b7, 0x017e,0x010d,0x0219,0x00bb,0x0152,0x0153,0x0178,0x017c, 0x00c0,0x00c1,0x00c2,0x0102,0x00c4,0x0106,0x00c6,0x00c7, 0x00c8,0x00c9,0x00ca,0x00cb,0x00cc,0x00cd,0x00ce,0x00cf, 0x0110,0x0143,0x00d2,0x00d3,0x00d4,0x0150,0x00d6,0x015a, 0x0170,0x00d9,0x00da,0x00db,0x00dc,0x0118,0x021a,0x00df, 0x00e0,0x00e1,0x00e2,0x0103,0x00e4,0x0107,0x00e6,0x00e7, 0x00e8,0x00e9,0x00ea,0x00eb,0x00ec,0x00ed,0x00ee,0x00ef, 0x0111,0x0144,0x00f2,0x00f3,0x00f4,0x0151,0x00f6,0x015b, 0x0171,0x00f9,0x00fa,0x00fb,0x00fc,0x0119,0x021b,0x00ff }; alpine-2.10+dfsg/imap/src/charset/gb_2312.c0000600000175000017500000054673611512502123021731 0ustar paulproteuspaulproteus/* ======================================================================== * Copyright 1988-2006 University of Washington * * Licensed under the Apache License, Version 2.0 (the "License"); * you may not use this file except in compliance with the License. * You may obtain a copy of the License at * * http://www.apache.org/licenses/LICENSE-2.0 * * * ======================================================================== */ /* * Program: GBK conversion table * * Author: Mark Crispin * Networks and Distributed Computing * Computing & Communications * University of Washington * Administration Building, AG-44 * Seattle, WA 98195 * Internet: MRC@CAC.Washington.EDU * * Date: 3 July 1997 * Last Edited: 30 August 2006 */ /* GB 2312 is the national standard of the People's Republic of China * (mainland China). This is actually the GBK extended version. */ #define BASE_GB2312_KU 0x81 #define BASE_GB2312_TEN 0x40 #define MAX_GB2312_KU 125 #define MAX_GB2312_TEN 191 #define GBTOUNICODE(c,c1,ku,ten) \ ((((ku = c - BASE_GB2312_KU) < MAX_GB2312_KU) && \ ((ten = c1 - BASE_GB2312_TEN) < MAX_GB2312_TEN)) ? \ gb2312tab[ku][ten] : UBOGON) static const unsigned short gb2312tab[MAX_GB2312_KU][MAX_GB2312_TEN] = { { /* ku 01 */ 0x4e02,0x4e04,0x4e05,0x4e06,0x4e0f,0x4e12,0x4e17,0x4e1f,0x4e20,0x4e21, 0x4e23,0x4e26,0x4e29,0x4e2e,0x4e2f,0x4e31,0x4e33,0x4e35,0x4e37,0x4e3c, 0x4e40,0x4e41,0x4e42,0x4e44,0x4e46,0x4e4a,0x4e51,0x4e55,0x4e57,0x4e5a, 0x4e5b,0x4e62,0x4e63,0x4e64,0x4e65,0x4e67,0x4e68,0x4e6a,0x4e6b,0x4e6c, 0x4e6d,0x4e6e,0x4e6f,0x4e72,0x4e74,0x4e75,0x4e76,0x4e77,0x4e78,0x4e79, 0x4e7a,0x4e7b,0x4e7c,0x4e7d,0x4e7f,0x4e80,0x4e81,0x4e82,0x4e83,0x4e84, 0x4e85,0x4e87,0x4e8a,UBOGON,0x4e90,0x4e96,0x4e97,0x4e99,0x4e9c,0x4e9d, 0x4e9e,0x4ea3,0x4eaa,0x4eaf,0x4eb0,0x4eb1,0x4eb4,0x4eb6,0x4eb7,0x4eb8, 0x4eb9,0x4ebc,0x4ebd,0x4ebe,0x4ec8,0x4ecc,0x4ecf,0x4ed0,0x4ed2,0x4eda, 0x4edb,0x4edc,0x4ee0,0x4ee2,0x4ee6,0x4ee7,0x4ee9,0x4eed,0x4eee,0x4eef, 0x4ef1,0x4ef4,0x4ef8,0x4ef9,0x4efa,0x4efc,0x4efe,0x4f00,0x4f02,0x4f03, 0x4f04,0x4f05,0x4f06,0x4f07,0x4f08,0x4f0b,0x4f0c,0x4f12,0x4f13,0x4f14, 0x4f15,0x4f16,0x4f1c,0x4f1d,0x4f21,0x4f23,0x4f28,0x4f29,0x4f2c,0x4f2d, 0x4f2e,0x4f31,0x4f33,0x4f35,0x4f37,0x4f39,0x4f3b,0x4f3e,0x4f3f,0x4f40, 0x4f41,0x4f42,0x4f44,0x4f45,0x4f47,0x4f48,0x4f49,0x4f4a,0x4f4b,0x4f4c, 0x4f52,0x4f54,0x4f56,0x4f61,0x4f62,0x4f66,0x4f68,0x4f6a,0x4f6b,0x4f6d, 0x4f6e,0x4f71,0x4f72,0x4f75,0x4f77,0x4f78,0x4f79,0x4f7a,0x4f7d,0x4f80, 0x4f81,0x4f82,0x4f85,0x4f86,0x4f87,0x4f8a,0x4f8c,0x4f8e,0x4f90,0x4f92, 0x4f93,0x4f95,0x4f96,0x4f98,0x4f99,0x4f9a,0x4f9c,0x4f9e,0x4f9f,0x4fa1, 0x4fa2 }, { /* ku 02 */ 0x4fa4,0x4fab,0x4fad,0x4fb0,0x4fb1,0x4fb2,0x4fb3,0x4fb4,0x4fb6,0x4fb7, 0x4fb8,0x4fb9,0x4fba,0x4fbb,0x4fbc,0x4fbd,0x4fbe,0x4fc0,0x4fc1,0x4fc2, 0x4fc6,0x4fc7,0x4fc8,0x4fc9,0x4fcb,0x4fcc,0x4fcd,0x4fd2,0x4fd3,0x4fd4, 0x4fd5,0x4fd6,0x4fd9,0x4fdb,0x4fe0,0x4fe2,0x4fe4,0x4fe5,0x4fe7,0x4feb, 0x4fec,0x4ff0,0x4ff2,0x4ff4,0x4ff5,0x4ff6,0x4ff7,0x4ff9,0x4ffb,0x4ffc, 0x4ffd,0x4fff,0x5000,0x5001,0x5002,0x5003,0x5004,0x5005,0x5006,0x5007, 0x5008,0x5009,0x500a,UBOGON,0x500b,0x500e,0x5010,0x5011,0x5013,0x5015, 0x5016,0x5017,0x501b,0x501d,0x501e,0x5020,0x5022,0x5023,0x5024,0x5027, 0x502b,0x502f,0x5030,0x5031,0x5032,0x5033,0x5034,0x5035,0x5036,0x5037, 0x5038,0x5039,0x503b,0x503d,0x503f,0x5040,0x5041,0x5042,0x5044,0x5045, 0x5046,0x5049,0x504a,0x504b,0x504d,0x5050,0x5051,0x5052,0x5053,0x5054, 0x5056,0x5057,0x5058,0x5059,0x505b,0x505d,0x505e,0x505f,0x5060,0x5061, 0x5062,0x5063,0x5064,0x5066,0x5067,0x5068,0x5069,0x506a,0x506b,0x506d, 0x506e,0x506f,0x5070,0x5071,0x5072,0x5073,0x5074,0x5075,0x5078,0x5079, 0x507a,0x507c,0x507d,0x5081,0x5082,0x5083,0x5084,0x5086,0x5087,0x5089, 0x508a,0x508b,0x508c,0x508e,0x508f,0x5090,0x5091,0x5092,0x5093,0x5094, 0x5095,0x5096,0x5097,0x5098,0x5099,0x509a,0x509b,0x509c,0x509d,0x509e, 0x509f,0x50a0,0x50a1,0x50a2,0x50a4,0x50a6,0x50aa,0x50ab,0x50ad,0x50ae, 0x50af,0x50b0,0x50b1,0x50b3,0x50b4,0x50b5,0x50b6,0x50b7,0x50b8,0x50b9, 0x50bc }, { /* ku 03 */ 0x50bd,0x50be,0x50bf,0x50c0,0x50c1,0x50c2,0x50c3,0x50c4,0x50c5,0x50c6, 0x50c7,0x50c8,0x50c9,0x50ca,0x50cb,0x50cc,0x50cd,0x50ce,0x50d0,0x50d1, 0x50d2,0x50d3,0x50d4,0x50d5,0x50d7,0x50d8,0x50d9,0x50db,0x50dc,0x50dd, 0x50de,0x50df,0x50e0,0x50e1,0x50e2,0x50e3,0x50e4,0x50e5,0x50e8,0x50e9, 0x50ea,0x50eb,0x50ef,0x50f0,0x50f1,0x50f2,0x50f4,0x50f6,0x50f7,0x50f8, 0x50f9,0x50fa,0x50fc,0x50fd,0x50fe,0x50ff,0x5100,0x5101,0x5102,0x5103, 0x5104,0x5105,0x5108,UBOGON,0x5109,0x510a,0x510c,0x510d,0x510e,0x510f, 0x5110,0x5111,0x5113,0x5114,0x5115,0x5116,0x5117,0x5118,0x5119,0x511a, 0x511b,0x511c,0x511d,0x511e,0x511f,0x5120,0x5122,0x5123,0x5124,0x5125, 0x5126,0x5127,0x5128,0x5129,0x512a,0x512b,0x512c,0x512d,0x512e,0x512f, 0x5130,0x5131,0x5132,0x5133,0x5134,0x5135,0x5136,0x5137,0x5138,0x5139, 0x513a,0x513b,0x513c,0x513d,0x513e,0x5142,0x5147,0x514a,0x514c,0x514e, 0x514f,0x5150,0x5152,0x5153,0x5157,0x5158,0x5159,0x515b,0x515d,0x515e, 0x515f,0x5160,0x5161,0x5163,0x5164,0x5166,0x5167,0x5169,0x516a,0x516f, 0x5172,0x517a,0x517e,0x517f,0x5183,0x5184,0x5186,0x5187,0x518a,0x518b, 0x518e,0x518f,0x5190,0x5191,0x5193,0x5194,0x5198,0x519a,0x519d,0x519e, 0x519f,0x51a1,0x51a3,0x51a6,0x51a7,0x51a8,0x51a9,0x51aa,0x51ad,0x51ae, 0x51b4,0x51b8,0x51b9,0x51ba,0x51be,0x51bf,0x51c1,0x51c2,0x51c3,0x51c5, 0x51c8,0x51ca,0x51cd,0x51ce,0x51d0,0x51d2,0x51d3,0x51d4,0x51d5,0x51d6, 0x51d7 }, { /* ku 04 */ 0x51d8,0x51d9,0x51da,0x51dc,0x51de,0x51df,0x51e2,0x51e3,0x51e5,0x51e6, 0x51e7,0x51e8,0x51e9,0x51ea,0x51ec,0x51ee,0x51f1,0x51f2,0x51f4,0x51f7, 0x51fe,0x5204,0x5205,0x5209,0x520b,0x520c,0x520f,0x5210,0x5213,0x5214, 0x5215,0x521c,0x521e,0x521f,0x5221,0x5222,0x5223,0x5225,0x5226,0x5227, 0x522a,0x522c,0x522f,0x5231,0x5232,0x5234,0x5235,0x523c,0x523e,0x5244, 0x5245,0x5246,0x5247,0x5248,0x5249,0x524b,0x524e,0x524f,0x5252,0x5253, 0x5255,0x5257,0x5258,UBOGON,0x5259,0x525a,0x525b,0x525d,0x525f,0x5260, 0x5262,0x5263,0x5264,0x5266,0x5268,0x526b,0x526c,0x526d,0x526e,0x5270, 0x5271,0x5273,0x5274,0x5275,0x5276,0x5277,0x5278,0x5279,0x527a,0x527b, 0x527c,0x527e,0x5280,0x5283,0x5284,0x5285,0x5286,0x5287,0x5289,0x528a, 0x528b,0x528c,0x528d,0x528e,0x528f,0x5291,0x5292,0x5294,0x5295,0x5296, 0x5297,0x5298,0x5299,0x529a,0x529c,0x52a4,0x52a5,0x52a6,0x52a7,0x52ae, 0x52af,0x52b0,0x52b4,0x52b5,0x52b6,0x52b7,0x52b8,0x52b9,0x52ba,0x52bb, 0x52bc,0x52bd,0x52c0,0x52c1,0x52c2,0x52c4,0x52c5,0x52c6,0x52c8,0x52ca, 0x52cc,0x52cd,0x52ce,0x52cf,0x52d1,0x52d3,0x52d4,0x52d5,0x52d7,0x52d9, 0x52da,0x52db,0x52dc,0x52dd,0x52de,0x52e0,0x52e1,0x52e2,0x52e3,0x52e5, 0x52e6,0x52e7,0x52e8,0x52e9,0x52ea,0x52eb,0x52ec,0x52ed,0x52ee,0x52ef, 0x52f1,0x52f2,0x52f3,0x52f4,0x52f5,0x52f6,0x52f7,0x52f8,0x52fb,0x52fc, 0x52fd,0x5301,0x5302,0x5303,0x5304,0x5307,0x5309,0x530a,0x530b,0x530c, 0x530e }, { /* ku 05 */ 0x5311,0x5312,0x5313,0x5314,0x5318,0x531b,0x531c,0x531e,0x531f,0x5322, 0x5324,0x5325,0x5327,0x5328,0x5329,0x532b,0x532c,0x532d,0x532f,0x5330, 0x5331,0x5332,0x5333,0x5334,0x5335,0x5336,0x5337,0x5338,0x533c,0x533d, 0x5340,0x5342,0x5344,0x5346,0x534b,0x534c,0x534d,0x5350,0x5354,0x5358, 0x5359,0x535b,0x535d,0x5365,0x5368,0x536a,0x536c,0x536d,0x5372,0x5376, 0x5379,0x537b,0x537c,0x537d,0x537e,0x5380,0x5381,0x5383,0x5387,0x5388, 0x538a,0x538e,0x538f,UBOGON,0x5390,0x5391,0x5392,0x5393,0x5394,0x5396, 0x5397,0x5399,0x539b,0x539c,0x539e,0x53a0,0x53a1,0x53a4,0x53a7,0x53aa, 0x53ab,0x53ac,0x53ad,0x53af,0x53b0,0x53b1,0x53b2,0x53b3,0x53b4,0x53b5, 0x53b7,0x53b8,0x53b9,0x53ba,0x53bc,0x53bd,0x53be,0x53c0,0x53c3,0x53c4, 0x53c5,0x53c6,0x53c7,0x53ce,0x53cf,0x53d0,0x53d2,0x53d3,0x53d5,0x53da, 0x53dc,0x53dd,0x53de,0x53e1,0x53e2,0x53e7,0x53f4,0x53fa,0x53fe,0x53ff, 0x5400,0x5402,0x5405,0x5407,0x540b,0x5414,0x5418,0x5419,0x541a,0x541c, 0x5422,0x5424,0x5425,0x542a,0x5430,0x5433,0x5436,0x5437,0x543a,0x543d, 0x543f,0x5441,0x5442,0x5444,0x5445,0x5447,0x5449,0x544c,0x544d,0x544e, 0x544f,0x5451,0x545a,0x545d,0x545e,0x545f,0x5460,0x5461,0x5463,0x5465, 0x5467,0x5469,0x546a,0x546b,0x546c,0x546d,0x546e,0x546f,0x5470,0x5474, 0x5479,0x547a,0x547e,0x547f,0x5481,0x5483,0x5485,0x5487,0x5488,0x5489, 0x548a,0x548d,0x5491,0x5493,0x5497,0x5498,0x549c,0x549e,0x549f,0x54a0, 0x54a1 }, { /* ku 06 */ 0x54a2,0x54a5,0x54ae,0x54b0,0x54b2,0x54b5,0x54b6,0x54b7,0x54b9,0x54ba, 0x54bc,0x54be,0x54c3,0x54c5,0x54ca,0x54cb,0x54d6,0x54d8,0x54db,0x54e0, 0x54e1,0x54e2,0x54e3,0x54e4,0x54eb,0x54ec,0x54ef,0x54f0,0x54f1,0x54f4, 0x54f5,0x54f6,0x54f7,0x54f8,0x54f9,0x54fb,0x54fe,0x5500,0x5502,0x5503, 0x5504,0x5505,0x5508,0x550a,0x550b,0x550c,0x550d,0x550e,0x5512,0x5513, 0x5515,0x5516,0x5517,0x5518,0x5519,0x551a,0x551c,0x551d,0x551e,0x551f, 0x5521,0x5525,0x5526,UBOGON,0x5528,0x5529,0x552b,0x552d,0x5532,0x5534, 0x5535,0x5536,0x5538,0x5539,0x553a,0x553b,0x553d,0x5540,0x5542,0x5545, 0x5547,0x5548,0x554b,0x554c,0x554d,0x554e,0x554f,0x5551,0x5552,0x5553, 0x5554,0x5557,0x5558,0x5559,0x555a,0x555b,0x555d,0x555e,0x555f,0x5560, 0x5562,0x5563,0x5568,0x5569,0x556b,0x556f,0x5570,0x5571,0x5572,0x5573, 0x5574,0x5579,0x557a,0x557d,0x557f,0x5585,0x5586,0x558c,0x558d,0x558e, 0x5590,0x5592,0x5593,0x5595,0x5596,0x5597,0x559a,0x559b,0x559e,0x55a0, 0x55a1,0x55a2,0x55a3,0x55a4,0x55a5,0x55a6,0x55a8,0x55a9,0x55aa,0x55ab, 0x55ac,0x55ad,0x55ae,0x55af,0x55b0,0x55b2,0x55b4,0x55b6,0x55b8,0x55ba, 0x55bc,0x55bf,0x55c0,0x55c1,0x55c2,0x55c3,0x55c6,0x55c7,0x55c8,0x55ca, 0x55cb,0x55ce,0x55cf,0x55d0,0x55d5,0x55d7,0x55d8,0x55d9,0x55da,0x55db, 0x55de,0x55e0,0x55e2,0x55e7,0x55e9,0x55ed,0x55ee,0x55f0,0x55f1,0x55f4, 0x55f6,0x55f8,0x55f9,0x55fa,0x55fb,0x55fc,0x55ff,0x5602,0x5603,0x5604, 0x5605 }, { /* ku 07 */ 0x5606,0x5607,0x560a,0x560b,0x560d,0x5610,0x5611,0x5612,0x5613,0x5614, 0x5615,0x5616,0x5617,0x5619,0x561a,0x561c,0x561d,0x5620,0x5621,0x5622, 0x5625,0x5626,0x5628,0x5629,0x562a,0x562b,0x562e,0x562f,0x5630,0x5633, 0x5635,0x5637,0x5638,0x563a,0x563c,0x563d,0x563e,0x5640,0x5641,0x5642, 0x5643,0x5644,0x5645,0x5646,0x5647,0x5648,0x5649,0x564a,0x564b,0x564f, 0x5650,0x5651,0x5652,0x5653,0x5655,0x5656,0x565a,0x565b,0x565d,0x565e, 0x565f,0x5660,0x5661,UBOGON,0x5663,0x5665,0x5666,0x5667,0x566d,0x566e, 0x566f,0x5670,0x5672,0x5673,0x5674,0x5675,0x5677,0x5678,0x5679,0x567a, 0x567d,0x567e,0x567f,0x5680,0x5681,0x5682,0x5683,0x5684,0x5687,0x5688, 0x5689,0x568a,0x568b,0x568c,0x568d,0x5690,0x5691,0x5692,0x5694,0x5695, 0x5696,0x5697,0x5698,0x5699,0x569a,0x569b,0x569c,0x569d,0x569e,0x569f, 0x56a0,0x56a1,0x56a2,0x56a4,0x56a5,0x56a6,0x56a7,0x56a8,0x56a9,0x56aa, 0x56ab,0x56ac,0x56ad,0x56ae,0x56b0,0x56b1,0x56b2,0x56b3,0x56b4,0x56b5, 0x56b6,0x56b8,0x56b9,0x56ba,0x56bb,0x56bd,0x56be,0x56bf,0x56c0,0x56c1, 0x56c2,0x56c3,0x56c4,0x56c5,0x56c6,0x56c7,0x56c8,0x56c9,0x56cb,0x56cc, 0x56cd,0x56ce,0x56cf,0x56d0,0x56d1,0x56d2,0x56d3,0x56d5,0x56d6,0x56d8, 0x56d9,0x56dc,0x56e3,0x56e5,0x56e6,0x56e7,0x56e8,0x56e9,0x56ea,0x56ec, 0x56ee,0x56ef,0x56f2,0x56f3,0x56f6,0x56f7,0x56f8,0x56fb,0x56fc,0x5700, 0x5701,0x5702,0x5705,0x5707,0x570b,0x570c,0x570d,0x570e,0x570f,0x5710, 0x5711 }, { /* ku 08 */ 0x5712,0x5713,0x5714,0x5715,0x5716,0x5717,0x5718,0x5719,0x571a,0x571b, 0x571d,0x571e,0x5720,0x5721,0x5722,0x5724,0x5725,0x5726,0x5727,0x572b, 0x5731,0x5732,0x5734,0x5735,0x5736,0x5737,0x5738,0x573c,0x573d,0x573f, 0x5741,0x5743,0x5744,0x5745,0x5746,0x5748,0x5749,0x574b,0x5752,0x5753, 0x5754,0x5755,0x5756,0x5758,0x5759,0x5762,0x5763,0x5765,0x5767,0x576c, 0x576e,0x5770,0x5771,0x5772,0x5774,0x5775,0x5778,0x5779,0x577a,0x577d, 0x577e,0x577f,0x5780,UBOGON,0x5781,0x5787,0x5788,0x5789,0x578a,0x578d, 0x578e,0x578f,0x5790,0x5791,0x5794,0x5795,0x5796,0x5797,0x5798,0x5799, 0x579a,0x579c,0x579d,0x579e,0x579f,0x57a5,0x57a8,0x57aa,0x57ac,0x57af, 0x57b0,0x57b1,0x57b3,0x57b5,0x57b6,0x57b7,0x57b9,0x57ba,0x57bb,0x57bc, 0x57bd,0x57be,0x57bf,0x57c0,0x57c1,0x57c4,0x57c5,0x57c6,0x57c7,0x57c8, 0x57c9,0x57ca,0x57cc,0x57cd,0x57d0,0x57d1,0x57d3,0x57d6,0x57d7,0x57db, 0x57dc,0x57de,0x57e1,0x57e2,0x57e3,0x57e5,0x57e6,0x57e7,0x57e8,0x57e9, 0x57ea,0x57eb,0x57ec,0x57ee,0x57f0,0x57f1,0x57f2,0x57f3,0x57f5,0x57f6, 0x57f7,0x57fb,0x57fc,0x57fe,0x57ff,0x5801,0x5803,0x5804,0x5805,0x5808, 0x5809,0x580a,0x580c,0x580e,0x580f,0x5810,0x5812,0x5813,0x5814,0x5816, 0x5817,0x5818,0x581a,0x581b,0x581c,0x581d,0x581f,0x5822,0x5823,0x5825, 0x5826,0x5827,0x5828,0x5829,0x582b,0x582c,0x582d,0x582e,0x582f,0x5831, 0x5832,0x5833,0x5834,0x5836,0x5837,0x5838,0x5839,0x583a,0x583b,0x583c, 0x583d }, { /* ku 09 */ 0x583e,0x583f,0x5840,0x5841,0x5842,0x5843,0x5845,0x5846,0x5847,0x5848, 0x5849,0x584a,0x584b,0x584e,0x584f,0x5850,0x5852,0x5853,0x5855,0x5856, 0x5857,0x5859,0x585a,0x585b,0x585c,0x585d,0x585f,0x5860,0x5861,0x5862, 0x5863,0x5864,0x5866,0x5867,0x5868,0x5869,0x586a,0x586d,0x586e,0x586f, 0x5870,0x5871,0x5872,0x5873,0x5874,0x5875,0x5876,0x5877,0x5878,0x5879, 0x587a,0x587b,0x587c,0x587d,0x587f,0x5882,0x5884,0x5886,0x5887,0x5888, 0x588a,0x588b,0x588c,UBOGON,0x588d,0x588e,0x588f,0x5890,0x5891,0x5894, 0x5895,0x5896,0x5897,0x5898,0x589b,0x589c,0x589d,0x58a0,0x58a1,0x58a2, 0x58a3,0x58a4,0x58a5,0x58a6,0x58a7,0x58aa,0x58ab,0x58ac,0x58ad,0x58ae, 0x58af,0x58b0,0x58b1,0x58b2,0x58b3,0x58b4,0x58b5,0x58b6,0x58b7,0x58b8, 0x58b9,0x58ba,0x58bb,0x58bd,0x58be,0x58bf,0x58c0,0x58c2,0x58c3,0x58c4, 0x58c6,0x58c7,0x58c8,0x58c9,0x58ca,0x58cb,0x58cc,0x58cd,0x58ce,0x58cf, 0x58d0,0x58d2,0x58d3,0x58d4,0x58d6,0x58d7,0x58d8,0x58d9,0x58da,0x58db, 0x58dc,0x58dd,0x58de,0x58df,0x58e0,0x58e1,0x58e2,0x58e3,0x58e5,0x58e6, 0x58e7,0x58e8,0x58e9,0x58ea,0x58ed,0x58ef,0x58f1,0x58f2,0x58f4,0x58f5, 0x58f7,0x58f8,0x58fa,0x58fb,0x58fc,0x58fd,0x58fe,0x58ff,0x5900,0x5901, 0x5903,0x5905,0x5906,0x5908,0x5909,0x590a,0x590b,0x590c,0x590e,0x5910, 0x5911,0x5912,0x5913,0x5917,0x5918,0x591b,0x591d,0x591e,0x5920,0x5921, 0x5922,0x5923,0x5926,0x5928,0x592c,0x5930,0x5932,0x5933,0x5935,0x5936, 0x593b }, { /* ku 0a */ 0x593d,0x593e,0x593f,0x5940,0x5943,0x5945,0x5946,0x594a,0x594c,0x594d, 0x5950,0x5952,0x5953,0x5959,0x595b,0x595c,0x595d,0x595e,0x595f,0x5961, 0x5963,0x5964,0x5966,0x5967,0x5968,0x5969,0x596a,0x596b,0x596c,0x596d, 0x596e,0x596f,0x5970,0x5971,0x5972,0x5975,0x5977,0x597a,0x597b,0x597c, 0x597e,0x597f,0x5980,0x5985,0x5989,0x598b,0x598c,0x598e,0x598f,0x5990, 0x5991,0x5994,0x5995,0x5998,0x599a,0x599b,0x599c,0x599d,0x599f,0x59a0, 0x59a1,0x59a2,0x59a6,UBOGON,0x59a7,0x59ac,0x59ad,0x59b0,0x59b1,0x59b3, 0x59b4,0x59b5,0x59b6,0x59b7,0x59b8,0x59ba,0x59bc,0x59bd,0x59bf,0x59c0, 0x59c1,0x59c2,0x59c3,0x59c4,0x59c5,0x59c7,0x59c8,0x59c9,0x59cc,0x59cd, 0x59ce,0x59cf,0x59d5,0x59d6,0x59d9,0x59db,0x59de,0x59df,0x59e0,0x59e1, 0x59e2,0x59e4,0x59e6,0x59e7,0x59e9,0x59ea,0x59eb,0x59ed,0x59ee,0x59ef, 0x59f0,0x59f1,0x59f2,0x59f3,0x59f4,0x59f5,0x59f6,0x59f7,0x59f8,0x59fa, 0x59fc,0x59fd,0x59fe,0x5a00,0x5a02,0x5a0a,0x5a0b,0x5a0d,0x5a0e,0x5a0f, 0x5a10,0x5a12,0x5a14,0x5a15,0x5a16,0x5a17,0x5a19,0x5a1a,0x5a1b,0x5a1d, 0x5a1e,0x5a21,0x5a22,0x5a24,0x5a26,0x5a27,0x5a28,0x5a2a,0x5a2b,0x5a2c, 0x5a2d,0x5a2e,0x5a2f,0x5a30,0x5a33,0x5a35,0x5a37,0x5a38,0x5a39,0x5a3a, 0x5a3b,0x5a3d,0x5a3e,0x5a3f,0x5a41,0x5a42,0x5a43,0x5a44,0x5a45,0x5a47, 0x5a48,0x5a4b,0x5a4c,0x5a4d,0x5a4e,0x5a4f,0x5a50,0x5a51,0x5a52,0x5a53, 0x5a54,0x5a56,0x5a57,0x5a58,0x5a59,0x5a5b,0x5a5c,0x5a5d,0x5a5e,0x5a5f, 0x5a60 }, { /* ku 0b */ 0x5a61,0x5a63,0x5a64,0x5a65,0x5a66,0x5a68,0x5a69,0x5a6b,0x5a6c,0x5a6d, 0x5a6e,0x5a6f,0x5a70,0x5a71,0x5a72,0x5a73,0x5a78,0x5a79,0x5a7b,0x5a7c, 0x5a7d,0x5a7e,0x5a80,0x5a81,0x5a82,0x5a83,0x5a84,0x5a85,0x5a86,0x5a87, 0x5a88,0x5a89,0x5a8a,0x5a8b,0x5a8c,0x5a8d,0x5a8e,0x5a8f,0x5a90,0x5a91, 0x5a93,0x5a94,0x5a95,0x5a96,0x5a97,0x5a98,0x5a99,0x5a9c,0x5a9d,0x5a9e, 0x5a9f,0x5aa0,0x5aa1,0x5aa2,0x5aa3,0x5aa4,0x5aa5,0x5aa6,0x5aa7,0x5aa8, 0x5aa9,0x5aab,0x5aac,UBOGON,0x5aad,0x5aae,0x5aaf,0x5ab0,0x5ab1,0x5ab4, 0x5ab6,0x5ab7,0x5ab9,0x5aba,0x5abb,0x5abc,0x5abd,0x5abf,0x5ac0,0x5ac3, 0x5ac4,0x5ac5,0x5ac6,0x5ac7,0x5ac8,0x5aca,0x5acb,0x5acd,0x5ace,0x5acf, 0x5ad0,0x5ad1,0x5ad3,0x5ad5,0x5ad7,0x5ad9,0x5ada,0x5adb,0x5add,0x5ade, 0x5adf,0x5ae2,0x5ae4,0x5ae5,0x5ae7,0x5ae8,0x5aea,0x5aec,0x5aed,0x5aee, 0x5aef,0x5af0,0x5af2,0x5af3,0x5af4,0x5af5,0x5af6,0x5af7,0x5af8,0x5af9, 0x5afa,0x5afb,0x5afc,0x5afd,0x5afe,0x5aff,0x5b00,0x5b01,0x5b02,0x5b03, 0x5b04,0x5b05,0x5b06,0x5b07,0x5b08,0x5b0a,0x5b0b,0x5b0c,0x5b0d,0x5b0e, 0x5b0f,0x5b10,0x5b11,0x5b12,0x5b13,0x5b14,0x5b15,0x5b18,0x5b19,0x5b1a, 0x5b1b,0x5b1c,0x5b1d,0x5b1e,0x5b1f,0x5b20,0x5b21,0x5b22,0x5b23,0x5b24, 0x5b25,0x5b26,0x5b27,0x5b28,0x5b29,0x5b2a,0x5b2b,0x5b2c,0x5b2d,0x5b2e, 0x5b2f,0x5b30,0x5b31,0x5b33,0x5b35,0x5b36,0x5b38,0x5b39,0x5b3a,0x5b3b, 0x5b3c,0x5b3d,0x5b3e,0x5b3f,0x5b41,0x5b42,0x5b43,0x5b44,0x5b45,0x5b46, 0x5b47 }, { /* ku 0c */ 0x5b48,0x5b49,0x5b4a,0x5b4b,0x5b4c,0x5b4d,0x5b4e,0x5b4f,0x5b52,0x5b56, 0x5b5e,0x5b60,0x5b61,0x5b67,0x5b68,0x5b6b,0x5b6d,0x5b6e,0x5b6f,0x5b72, 0x5b74,0x5b76,0x5b77,0x5b78,0x5b79,0x5b7b,0x5b7c,0x5b7e,0x5b7f,0x5b82, 0x5b86,0x5b8a,0x5b8d,0x5b8e,0x5b90,0x5b91,0x5b92,0x5b94,0x5b96,0x5b9f, 0x5ba7,0x5ba8,0x5ba9,0x5bac,0x5bad,0x5bae,0x5baf,0x5bb1,0x5bb2,0x5bb7, 0x5bba,0x5bbb,0x5bbc,0x5bc0,0x5bc1,0x5bc3,0x5bc8,0x5bc9,0x5bca,0x5bcb, 0x5bcd,0x5bce,0x5bcf,UBOGON,0x5bd1,0x5bd4,0x5bd5,0x5bd6,0x5bd7,0x5bd8, 0x5bd9,0x5bda,0x5bdb,0x5bdc,0x5be0,0x5be2,0x5be3,0x5be6,0x5be7,0x5be9, 0x5bea,0x5beb,0x5bec,0x5bed,0x5bef,0x5bf1,0x5bf2,0x5bf3,0x5bf4,0x5bf5, 0x5bf6,0x5bf7,0x5bfd,0x5bfe,0x5c00,0x5c02,0x5c03,0x5c05,0x5c07,0x5c08, 0x5c0b,0x5c0c,0x5c0d,0x5c0e,0x5c10,0x5c12,0x5c13,0x5c17,0x5c19,0x5c1b, 0x5c1e,0x5c1f,0x5c20,0x5c21,0x5c23,0x5c26,0x5c28,0x5c29,0x5c2a,0x5c2b, 0x5c2d,0x5c2e,0x5c2f,0x5c30,0x5c32,0x5c33,0x5c35,0x5c36,0x5c37,0x5c43, 0x5c44,0x5c46,0x5c47,0x5c4c,0x5c4d,0x5c52,0x5c53,0x5c54,0x5c56,0x5c57, 0x5c58,0x5c5a,0x5c5b,0x5c5c,0x5c5d,0x5c5f,0x5c62,0x5c64,0x5c67,0x5c68, 0x5c69,0x5c6a,0x5c6b,0x5c6c,0x5c6d,0x5c70,0x5c72,0x5c73,0x5c74,0x5c75, 0x5c76,0x5c77,0x5c78,0x5c7b,0x5c7c,0x5c7d,0x5c7e,0x5c80,0x5c83,0x5c84, 0x5c85,0x5c86,0x5c87,0x5c89,0x5c8a,0x5c8b,0x5c8e,0x5c8f,0x5c92,0x5c93, 0x5c95,0x5c9d,0x5c9e,0x5c9f,0x5ca0,0x5ca1,0x5ca4,0x5ca5,0x5ca6,0x5ca7, 0x5ca8 }, { /* ku 0d */ 0x5caa,0x5cae,0x5caf,0x5cb0,0x5cb2,0x5cb4,0x5cb6,0x5cb9,0x5cba,0x5cbb, 0x5cbc,0x5cbe,0x5cc0,0x5cc2,0x5cc3,0x5cc5,0x5cc6,0x5cc7,0x5cc8,0x5cc9, 0x5cca,0x5ccc,0x5ccd,0x5cce,0x5ccf,0x5cd0,0x5cd1,0x5cd3,0x5cd4,0x5cd5, 0x5cd6,0x5cd7,0x5cd8,0x5cda,0x5cdb,0x5cdc,0x5cdd,0x5cde,0x5cdf,0x5ce0, 0x5ce2,0x5ce3,0x5ce7,0x5ce9,0x5ceb,0x5cec,0x5cee,0x5cef,0x5cf1,0x5cf2, 0x5cf3,0x5cf4,0x5cf5,0x5cf6,0x5cf7,0x5cf8,0x5cf9,0x5cfa,0x5cfc,0x5cfd, 0x5cfe,0x5cff,0x5d00,UBOGON,0x5d01,0x5d04,0x5d05,0x5d08,0x5d09,0x5d0a, 0x5d0b,0x5d0c,0x5d0d,0x5d0f,0x5d10,0x5d11,0x5d12,0x5d13,0x5d15,0x5d17, 0x5d18,0x5d19,0x5d1a,0x5d1c,0x5d1d,0x5d1f,0x5d20,0x5d21,0x5d22,0x5d23, 0x5d25,0x5d28,0x5d2a,0x5d2b,0x5d2c,0x5d2f,0x5d30,0x5d31,0x5d32,0x5d33, 0x5d35,0x5d36,0x5d37,0x5d38,0x5d39,0x5d3a,0x5d3b,0x5d3c,0x5d3f,0x5d40, 0x5d41,0x5d42,0x5d43,0x5d44,0x5d45,0x5d46,0x5d48,0x5d49,0x5d4d,0x5d4e, 0x5d4f,0x5d50,0x5d51,0x5d52,0x5d53,0x5d54,0x5d55,0x5d56,0x5d57,0x5d59, 0x5d5a,0x5d5c,0x5d5e,0x5d5f,0x5d60,0x5d61,0x5d62,0x5d63,0x5d64,0x5d65, 0x5d66,0x5d67,0x5d68,0x5d6a,0x5d6d,0x5d6e,0x5d70,0x5d71,0x5d72,0x5d73, 0x5d75,0x5d76,0x5d77,0x5d78,0x5d79,0x5d7a,0x5d7b,0x5d7c,0x5d7d,0x5d7e, 0x5d7f,0x5d80,0x5d81,0x5d83,0x5d84,0x5d85,0x5d86,0x5d87,0x5d88,0x5d89, 0x5d8a,0x5d8b,0x5d8c,0x5d8d,0x5d8e,0x5d8f,0x5d90,0x5d91,0x5d92,0x5d93, 0x5d94,0x5d95,0x5d96,0x5d97,0x5d98,0x5d9a,0x5d9b,0x5d9c,0x5d9e,0x5d9f, 0x5da0 }, { /* ku 0e */ 0x5da1,0x5da2,0x5da3,0x5da4,0x5da5,0x5da6,0x5da7,0x5da8,0x5da9,0x5daa, 0x5dab,0x5dac,0x5dad,0x5dae,0x5daf,0x5db0,0x5db1,0x5db2,0x5db3,0x5db4, 0x5db5,0x5db6,0x5db8,0x5db9,0x5dba,0x5dbb,0x5dbc,0x5dbd,0x5dbe,0x5dbf, 0x5dc0,0x5dc1,0x5dc2,0x5dc3,0x5dc4,0x5dc6,0x5dc7,0x5dc8,0x5dc9,0x5dca, 0x5dcb,0x5dcc,0x5dce,0x5dcf,0x5dd0,0x5dd1,0x5dd2,0x5dd3,0x5dd4,0x5dd5, 0x5dd6,0x5dd7,0x5dd8,0x5dd9,0x5dda,0x5ddc,0x5ddf,0x5de0,0x5de3,0x5de4, 0x5dea,0x5dec,0x5ded,UBOGON,0x5df0,0x5df5,0x5df6,0x5df8,0x5df9,0x5dfa, 0x5dfb,0x5dfc,0x5dff,0x5e00,0x5e04,0x5e07,0x5e09,0x5e0a,0x5e0b,0x5e0d, 0x5e0e,0x5e12,0x5e13,0x5e17,0x5e1e,0x5e1f,0x5e20,0x5e21,0x5e22,0x5e23, 0x5e24,0x5e25,0x5e28,0x5e29,0x5e2a,0x5e2b,0x5e2c,0x5e2f,0x5e30,0x5e32, 0x5e33,0x5e34,0x5e35,0x5e36,0x5e39,0x5e3a,0x5e3e,0x5e3f,0x5e40,0x5e41, 0x5e43,0x5e46,0x5e47,0x5e48,0x5e49,0x5e4a,0x5e4b,0x5e4d,0x5e4e,0x5e4f, 0x5e50,0x5e51,0x5e52,0x5e53,0x5e56,0x5e57,0x5e58,0x5e59,0x5e5a,0x5e5c, 0x5e5d,0x5e5f,0x5e60,0x5e63,0x5e64,0x5e65,0x5e66,0x5e67,0x5e68,0x5e69, 0x5e6a,0x5e6b,0x5e6c,0x5e6d,0x5e6e,0x5e6f,0x5e70,0x5e71,0x5e75,0x5e77, 0x5e79,0x5e7e,0x5e81,0x5e82,0x5e83,0x5e85,0x5e88,0x5e89,0x5e8c,0x5e8d, 0x5e8e,0x5e92,0x5e98,0x5e9b,0x5e9d,0x5ea1,0x5ea2,0x5ea3,0x5ea4,0x5ea8, 0x5ea9,0x5eaa,0x5eab,0x5eac,0x5eae,0x5eaf,0x5eb0,0x5eb1,0x5eb2,0x5eb4, 0x5eba,0x5ebb,0x5ebc,0x5ebd,0x5ebf,0x5ec0,0x5ec1,0x5ec2,0x5ec3,0x5ec4, 0x5ec5 }, { /* ku 0f */ 0x5ec6,0x5ec7,0x5ec8,0x5ecb,0x5ecc,0x5ecd,0x5ece,0x5ecf,0x5ed0,0x5ed4, 0x5ed5,0x5ed7,0x5ed8,0x5ed9,0x5eda,0x5edc,0x5edd,0x5ede,0x5edf,0x5ee0, 0x5ee1,0x5ee2,0x5ee3,0x5ee4,0x5ee5,0x5ee6,0x5ee7,0x5ee9,0x5eeb,0x5eec, 0x5eed,0x5eee,0x5eef,0x5ef0,0x5ef1,0x5ef2,0x5ef3,0x5ef5,0x5ef8,0x5ef9, 0x5efb,0x5efc,0x5efd,0x5f05,0x5f06,0x5f07,0x5f09,0x5f0c,0x5f0d,0x5f0e, 0x5f10,0x5f12,0x5f14,0x5f16,0x5f19,0x5f1a,0x5f1c,0x5f1d,0x5f1e,0x5f21, 0x5f22,0x5f23,0x5f24,UBOGON,0x5f28,0x5f2b,0x5f2c,0x5f2e,0x5f30,0x5f32, 0x5f33,0x5f34,0x5f35,0x5f36,0x5f37,0x5f38,0x5f3b,0x5f3d,0x5f3e,0x5f3f, 0x5f41,0x5f42,0x5f43,0x5f44,0x5f45,0x5f46,0x5f47,0x5f48,0x5f49,0x5f4a, 0x5f4b,0x5f4c,0x5f4d,0x5f4e,0x5f4f,0x5f51,0x5f54,0x5f59,0x5f5a,0x5f5b, 0x5f5c,0x5f5e,0x5f5f,0x5f60,0x5f63,0x5f65,0x5f67,0x5f68,0x5f6b,0x5f6e, 0x5f6f,0x5f72,0x5f74,0x5f75,0x5f76,0x5f78,0x5f7a,0x5f7d,0x5f7e,0x5f7f, 0x5f83,0x5f86,0x5f8d,0x5f8e,0x5f8f,0x5f91,0x5f93,0x5f94,0x5f96,0x5f9a, 0x5f9b,0x5f9d,0x5f9e,0x5f9f,0x5fa0,0x5fa2,0x5fa3,0x5fa4,0x5fa5,0x5fa6, 0x5fa7,0x5fa9,0x5fab,0x5fac,0x5faf,0x5fb0,0x5fb1,0x5fb2,0x5fb3,0x5fb4, 0x5fb6,0x5fb8,0x5fb9,0x5fba,0x5fbb,0x5fbe,0x5fbf,0x5fc0,0x5fc1,0x5fc2, 0x5fc7,0x5fc8,0x5fca,0x5fcb,0x5fce,0x5fd3,0x5fd4,0x5fd5,0x5fda,0x5fdb, 0x5fdc,0x5fde,0x5fdf,0x5fe2,0x5fe3,0x5fe5,0x5fe6,0x5fe8,0x5fe9,0x5fec, 0x5fef,0x5ff0,0x5ff2,0x5ff3,0x5ff4,0x5ff6,0x5ff7,0x5ff9,0x5ffa,0x5ffc, 0x6007 }, { /* ku 10 */ 0x6008,0x6009,0x600b,0x600c,0x6010,0x6011,0x6013,0x6017,0x6018,0x601a, 0x601e,0x601f,0x6022,0x6023,0x6024,0x602c,0x602d,0x602e,0x6030,0x6031, 0x6032,0x6033,0x6034,0x6036,0x6037,0x6038,0x6039,0x603a,0x603d,0x603e, 0x6040,0x6044,0x6045,0x6046,0x6047,0x6048,0x6049,0x604a,0x604c,0x604e, 0x604f,0x6051,0x6053,0x6054,0x6056,0x6057,0x6058,0x605b,0x605c,0x605e, 0x605f,0x6060,0x6061,0x6065,0x6066,0x606e,0x6071,0x6072,0x6074,0x6075, 0x6077,0x607e,0x6080,UBOGON,0x6081,0x6082,0x6085,0x6086,0x6087,0x6088, 0x608a,0x608b,0x608e,0x608f,0x6090,0x6091,0x6093,0x6095,0x6097,0x6098, 0x6099,0x609c,0x609e,0x60a1,0x60a2,0x60a4,0x60a5,0x60a7,0x60a9,0x60aa, 0x60ae,0x60b0,0x60b3,0x60b5,0x60b6,0x60b7,0x60b9,0x60ba,0x60bd,0x60be, 0x60bf,0x60c0,0x60c1,0x60c2,0x60c3,0x60c4,0x60c7,0x60c8,0x60c9,0x60cc, 0x60cd,0x60ce,0x60cf,0x60d0,0x60d2,0x60d3,0x60d4,0x60d6,0x60d7,0x60d9, 0x60db,0x60de,0x60e1,0x60e2,0x60e3,0x60e4,0x60e5,0x60ea,0x60f1,0x60f2, 0x60f5,0x60f7,0x60f8,0x60fb,0x60fc,0x60fd,0x60fe,0x60ff,0x6102,0x6103, 0x6104,0x6105,0x6107,0x610a,0x610b,0x610c,0x6110,0x6111,0x6112,0x6113, 0x6114,0x6116,0x6117,0x6118,0x6119,0x611b,0x611c,0x611d,0x611e,0x6121, 0x6122,0x6125,0x6128,0x6129,0x612a,0x612c,0x612d,0x612e,0x612f,0x6130, 0x6131,0x6132,0x6133,0x6134,0x6135,0x6136,0x6137,0x6138,0x6139,0x613a, 0x613b,0x613c,0x613d,0x613e,0x6140,0x6141,0x6142,0x6143,0x6144,0x6145, 0x6146 }, { /* ku 11 */ 0x6147,0x6149,0x614b,0x614d,0x614f,0x6150,0x6152,0x6153,0x6154,0x6156, 0x6157,0x6158,0x6159,0x615a,0x615b,0x615c,0x615e,0x615f,0x6160,0x6161, 0x6163,0x6164,0x6165,0x6166,0x6169,0x616a,0x616b,0x616c,0x616d,0x616e, 0x616f,0x6171,0x6172,0x6173,0x6174,0x6176,0x6178,0x6179,0x617a,0x617b, 0x617c,0x617d,0x617e,0x617f,0x6180,0x6181,0x6182,0x6183,0x6184,0x6185, 0x6186,0x6187,0x6188,0x6189,0x618a,0x618c,0x618d,0x618f,0x6190,0x6191, 0x6192,0x6193,0x6195,UBOGON,0x6196,0x6197,0x6198,0x6199,0x619a,0x619b, 0x619c,0x619e,0x619f,0x61a0,0x61a1,0x61a2,0x61a3,0x61a4,0x61a5,0x61a6, 0x61aa,0x61ab,0x61ad,0x61ae,0x61af,0x61b0,0x61b1,0x61b2,0x61b3,0x61b4, 0x61b5,0x61b6,0x61b8,0x61b9,0x61ba,0x61bb,0x61bc,0x61bd,0x61bf,0x61c0, 0x61c1,0x61c3,0x61c4,0x61c5,0x61c6,0x61c7,0x61c9,0x61cc,0x61cd,0x61ce, 0x61cf,0x61d0,0x61d3,0x61d5,0x61d6,0x61d7,0x61d8,0x61d9,0x61da,0x61db, 0x61dc,0x61dd,0x61de,0x61df,0x61e0,0x61e1,0x61e2,0x61e3,0x61e4,0x61e5, 0x61e7,0x61e8,0x61e9,0x61ea,0x61eb,0x61ec,0x61ed,0x61ee,0x61ef,0x61f0, 0x61f1,0x61f2,0x61f3,0x61f4,0x61f6,0x61f7,0x61f8,0x61f9,0x61fa,0x61fb, 0x61fc,0x61fd,0x61fe,0x6200,0x6201,0x6202,0x6203,0x6204,0x6205,0x6207, 0x6209,0x6213,0x6214,0x6219,0x621c,0x621d,0x621e,0x6220,0x6223,0x6226, 0x6227,0x6228,0x6229,0x622b,0x622d,0x622f,0x6230,0x6231,0x6232,0x6235, 0x6236,0x6238,0x6239,0x623a,0x623b,0x623c,0x6242,0x6244,0x6245,0x6246, 0x624a }, { /* ku 12 */ 0x624f,0x6250,0x6255,0x6256,0x6257,0x6259,0x625a,0x625c,0x625d,0x625e, 0x625f,0x6260,0x6261,0x6262,0x6264,0x6265,0x6268,0x6271,0x6272,0x6274, 0x6275,0x6277,0x6278,0x627a,0x627b,0x627d,0x6281,0x6282,0x6283,0x6285, 0x6286,0x6287,0x6288,0x628b,0x628c,0x628d,0x628e,0x628f,0x6290,0x6294, 0x6299,0x629c,0x629d,0x629e,0x62a3,0x62a6,0x62a7,0x62a9,0x62aa,0x62ad, 0x62ae,0x62af,0x62b0,0x62b2,0x62b3,0x62b4,0x62b6,0x62b7,0x62b8,0x62ba, 0x62be,0x62c0,0x62c1,UBOGON,0x62c3,0x62cb,0x62cf,0x62d1,0x62d5,0x62dd, 0x62de,0x62e0,0x62e1,0x62e4,0x62ea,0x62eb,0x62f0,0x62f2,0x62f5,0x62f8, 0x62f9,0x62fa,0x62fb,0x6300,0x6303,0x6304,0x6305,0x6306,0x630a,0x630b, 0x630c,0x630d,0x630f,0x6310,0x6312,0x6313,0x6314,0x6315,0x6317,0x6318, 0x6319,0x631c,0x6326,0x6327,0x6329,0x632c,0x632d,0x632e,0x6330,0x6331, 0x6333,0x6334,0x6335,0x6336,0x6337,0x6338,0x633b,0x633c,0x633e,0x633f, 0x6340,0x6341,0x6344,0x6347,0x6348,0x634a,0x6351,0x6352,0x6353,0x6354, 0x6356,0x6357,0x6358,0x6359,0x635a,0x635b,0x635c,0x635d,0x6360,0x6364, 0x6365,0x6366,0x6368,0x636a,0x636b,0x636c,0x636f,0x6370,0x6372,0x6373, 0x6374,0x6375,0x6378,0x6379,0x637c,0x637d,0x637e,0x637f,0x6381,0x6383, 0x6384,0x6385,0x6386,0x638b,0x638d,0x6391,0x6393,0x6394,0x6395,0x6397, 0x6399,0x639a,0x639b,0x639c,0x639d,0x639e,0x639f,0x63a1,0x63a4,0x63a6, 0x63ab,0x63af,0x63b1,0x63b2,0x63b5,0x63b6,0x63b9,0x63bb,0x63bd,0x63bf, 0x63c0 }, { /* ku 13 */ 0x63c1,0x63c2,0x63c3,0x63c5,0x63c7,0x63c8,0x63ca,0x63cb,0x63cc,0x63d1, 0x63d3,0x63d4,0x63d5,0x63d7,0x63d8,0x63d9,0x63da,0x63db,0x63dc,0x63dd, 0x63df,0x63e2,0x63e4,0x63e5,0x63e6,0x63e7,0x63e8,0x63eb,0x63ec,0x63ee, 0x63ef,0x63f0,0x63f1,0x63f3,0x63f5,0x63f7,0x63f9,0x63fa,0x63fb,0x63fc, 0x63fe,0x6403,0x6404,0x6406,0x6407,0x6408,0x6409,0x640a,0x640d,0x640e, 0x6411,0x6412,0x6415,0x6416,0x6417,0x6418,0x6419,0x641a,0x641d,0x641f, 0x6422,0x6423,0x6424,UBOGON,0x6425,0x6427,0x6428,0x6429,0x642b,0x642e, 0x642f,0x6430,0x6431,0x6432,0x6433,0x6435,0x6436,0x6437,0x6438,0x6439, 0x643b,0x643c,0x643e,0x6440,0x6442,0x6443,0x6449,0x644b,0x644c,0x644d, 0x644e,0x644f,0x6450,0x6451,0x6453,0x6455,0x6456,0x6457,0x6459,0x645a, 0x645b,0x645c,0x645d,0x645f,0x6460,0x6461,0x6462,0x6463,0x6464,0x6465, 0x6466,0x6468,0x646a,0x646b,0x646c,0x646e,0x646f,0x6470,0x6471,0x6472, 0x6473,0x6474,0x6475,0x6476,0x6477,0x647b,0x647c,0x647d,0x647e,0x647f, 0x6480,0x6481,0x6483,0x6486,0x6488,0x6489,0x648a,0x648b,0x648c,0x648d, 0x648e,0x648f,0x6490,0x6493,0x6494,0x6497,0x6498,0x649a,0x649b,0x649c, 0x649d,0x649f,0x64a0,0x64a1,0x64a2,0x64a3,0x64a5,0x64a6,0x64a7,0x64a8, 0x64aa,0x64ab,0x64af,0x64b1,0x64b2,0x64b3,0x64b4,0x64b6,0x64b9,0x64bb, 0x64bd,0x64be,0x64bf,0x64c1,0x64c3,0x64c4,0x64c6,0x64c7,0x64c8,0x64c9, 0x64ca,0x64cb,0x64cc,0x64cf,0x64d1,0x64d3,0x64d4,0x64d5,0x64d6,0x64d9, 0x64da }, { /* ku 14 */ 0x64db,0x64dc,0x64dd,0x64df,0x64e0,0x64e1,0x64e3,0x64e5,0x64e7,0x64e8, 0x64e9,0x64ea,0x64eb,0x64ec,0x64ed,0x64ee,0x64ef,0x64f0,0x64f1,0x64f2, 0x64f3,0x64f4,0x64f5,0x64f6,0x64f7,0x64f8,0x64f9,0x64fa,0x64fb,0x64fc, 0x64fd,0x64fe,0x64ff,0x6501,0x6502,0x6503,0x6504,0x6505,0x6506,0x6507, 0x6508,0x650a,0x650b,0x650c,0x650d,0x650e,0x650f,0x6510,0x6511,0x6513, 0x6514,0x6515,0x6516,0x6517,0x6519,0x651a,0x651b,0x651c,0x651d,0x651e, 0x651f,0x6520,0x6521,UBOGON,0x6522,0x6523,0x6524,0x6526,0x6527,0x6528, 0x6529,0x652a,0x652c,0x652d,0x6530,0x6531,0x6532,0x6533,0x6537,0x653a, 0x653c,0x653d,0x6540,0x6541,0x6542,0x6543,0x6544,0x6546,0x6547,0x654a, 0x654b,0x654d,0x654e,0x6550,0x6552,0x6553,0x6554,0x6557,0x6558,0x655a, 0x655c,0x655f,0x6560,0x6561,0x6564,0x6565,0x6567,0x6568,0x6569,0x656a, 0x656d,0x656e,0x656f,0x6571,0x6573,0x6575,0x6576,0x6578,0x6579,0x657a, 0x657b,0x657c,0x657d,0x657e,0x657f,0x6580,0x6581,0x6582,0x6583,0x6584, 0x6585,0x6586,0x6588,0x6589,0x658a,0x658d,0x658e,0x658f,0x6592,0x6594, 0x6595,0x6596,0x6598,0x659a,0x659d,0x659e,0x65a0,0x65a2,0x65a3,0x65a6, 0x65a8,0x65aa,0x65ac,0x65ae,0x65b1,0x65b2,0x65b3,0x65b4,0x65b5,0x65b6, 0x65b7,0x65b8,0x65ba,0x65bb,0x65be,0x65bf,0x65c0,0x65c2,0x65c7,0x65c8, 0x65c9,0x65ca,0x65cd,0x65d0,0x65d1,0x65d3,0x65d4,0x65d5,0x65d8,0x65d9, 0x65da,0x65db,0x65dc,0x65dd,0x65de,0x65df,0x65e1,0x65e3,0x65e4,0x65ea, 0x65eb }, { /* ku 15 */ 0x65f2,0x65f3,0x65f4,0x65f5,0x65f8,0x65f9,0x65fb,0x65fc,0x65fd,0x65fe, 0x65ff,0x6601,0x6604,0x6605,0x6607,0x6608,0x6609,0x660b,0x660d,0x6610, 0x6611,0x6612,0x6616,0x6617,0x6618,0x661a,0x661b,0x661c,0x661e,0x6621, 0x6622,0x6623,0x6624,0x6626,0x6629,0x662a,0x662b,0x662c,0x662e,0x6630, 0x6632,0x6633,0x6637,0x6638,0x6639,0x663a,0x663b,0x663d,0x663f,0x6640, 0x6642,0x6644,0x6645,0x6646,0x6647,0x6648,0x6649,0x664a,0x664d,0x664e, 0x6650,0x6651,0x6658,UBOGON,0x6659,0x665b,0x665c,0x665d,0x665e,0x6660, 0x6662,0x6663,0x6665,0x6667,0x6669,0x666a,0x666b,0x666c,0x666d,0x6671, 0x6672,0x6673,0x6675,0x6678,0x6679,0x667b,0x667c,0x667d,0x667f,0x6680, 0x6681,0x6683,0x6685,0x6686,0x6688,0x6689,0x668a,0x668b,0x668d,0x668e, 0x668f,0x6690,0x6692,0x6693,0x6694,0x6695,0x6698,0x6699,0x669a,0x669b, 0x669c,0x669e,0x669f,0x66a0,0x66a1,0x66a2,0x66a3,0x66a4,0x66a5,0x66a6, 0x66a9,0x66aa,0x66ab,0x66ac,0x66ad,0x66af,0x66b0,0x66b1,0x66b2,0x66b3, 0x66b5,0x66b6,0x66b7,0x66b8,0x66ba,0x66bb,0x66bc,0x66bd,0x66bf,0x66c0, 0x66c1,0x66c2,0x66c3,0x66c4,0x66c5,0x66c6,0x66c7,0x66c8,0x66c9,0x66ca, 0x66cb,0x66cc,0x66cd,0x66ce,0x66cf,0x66d0,0x66d1,0x66d2,0x66d3,0x66d4, 0x66d5,0x66d6,0x66d7,0x66d8,0x66da,0x66de,0x66df,0x66e0,0x66e1,0x66e2, 0x66e3,0x66e4,0x66e5,0x66e7,0x66e8,0x66ea,0x66eb,0x66ec,0x66ed,0x66ee, 0x66ef,0x66f1,0x66f5,0x66f6,0x66f8,0x66fa,0x66fb,0x66fd,0x6701,0x6702, 0x6703 }, { /* ku 16 */ 0x6704,0x6705,0x6706,0x6707,0x670c,0x670e,0x670f,0x6711,0x6712,0x6713, 0x6716,0x6718,0x6719,0x671a,0x671c,0x671e,0x6720,0x6721,0x6722,0x6723, 0x6724,0x6725,0x6727,0x6729,0x672e,0x6730,0x6732,0x6733,0x6736,0x6737, 0x6738,0x6739,0x673b,0x673c,0x673e,0x673f,0x6741,0x6744,0x6745,0x6747, 0x674a,0x674b,0x674d,0x6752,0x6754,0x6755,0x6757,0x6758,0x6759,0x675a, 0x675b,0x675d,0x6762,0x6763,0x6764,0x6766,0x6767,0x676b,0x676c,0x676e, 0x6771,0x6774,0x6776,UBOGON,0x6778,0x6779,0x677a,0x677b,0x677d,0x6780, 0x6782,0x6783,0x6785,0x6786,0x6788,0x678a,0x678c,0x678d,0x678e,0x678f, 0x6791,0x6792,0x6793,0x6794,0x6796,0x6799,0x679b,0x679f,0x67a0,0x67a1, 0x67a4,0x67a6,0x67a9,0x67ac,0x67ae,0x67b1,0x67b2,0x67b4,0x67b9,0x67ba, 0x67bb,0x67bc,0x67bd,0x67be,0x67bf,0x67c0,0x67c2,0x67c5,0x67c6,0x67c7, 0x67c8,0x67c9,0x67ca,0x67cb,0x67cc,0x67cd,0x67ce,0x67d5,0x67d6,0x67d7, 0x67db,0x67df,0x67e1,0x67e3,0x67e4,0x67e6,0x67e7,0x67e8,0x67ea,0x67eb, 0x67ed,0x67ee,0x67f2,0x67f5,0x67f6,0x67f7,0x67f8,0x67f9,0x67fa,0x67fb, 0x67fc,0x67fe,0x6801,0x6802,0x6803,0x6804,0x6806,0x680d,0x6810,0x6812, 0x6814,0x6815,0x6818,0x6819,0x681a,0x681b,0x681c,0x681e,0x681f,0x6820, 0x6822,0x6823,0x6824,0x6825,0x6826,0x6827,0x6828,0x682b,0x682c,0x682d, 0x682e,0x682f,0x6830,0x6831,0x6834,0x6835,0x6836,0x683a,0x683b,0x683f, 0x6847,0x684b,0x684d,0x684f,0x6852,0x6856,0x6857,0x6858,0x6859,0x685a, 0x685b }, { /* ku 17 */ 0x685c,0x685d,0x685e,0x685f,0x686a,0x686c,0x686d,0x686e,0x686f,0x6870, 0x6871,0x6872,0x6873,0x6875,0x6878,0x6879,0x687a,0x687b,0x687c,0x687d, 0x687e,0x687f,0x6880,0x6882,0x6884,0x6887,0x6888,0x6889,0x688a,0x688b, 0x688c,0x688d,0x688e,0x6890,0x6891,0x6892,0x6894,0x6895,0x6896,0x6898, 0x6899,0x689a,0x689b,0x689c,0x689d,0x689e,0x689f,0x68a0,0x68a1,0x68a3, 0x68a4,0x68a5,0x68a9,0x68aa,0x68ab,0x68ac,0x68ae,0x68b1,0x68b2,0x68b4, 0x68b6,0x68b7,0x68b8,UBOGON,0x68b9,0x68ba,0x68bb,0x68bc,0x68bd,0x68be, 0x68bf,0x68c1,0x68c3,0x68c4,0x68c5,0x68c6,0x68c7,0x68c8,0x68ca,0x68cc, 0x68ce,0x68cf,0x68d0,0x68d1,0x68d3,0x68d4,0x68d6,0x68d7,0x68d9,0x68db, 0x68dc,0x68dd,0x68de,0x68df,0x68e1,0x68e2,0x68e4,0x68e5,0x68e6,0x68e7, 0x68e8,0x68e9,0x68ea,0x68eb,0x68ec,0x68ed,0x68ef,0x68f2,0x68f3,0x68f4, 0x68f6,0x68f7,0x68f8,0x68fb,0x68fd,0x68fe,0x68ff,0x6900,0x6902,0x6903, 0x6904,0x6906,0x6907,0x6908,0x6909,0x690a,0x690c,0x690f,0x6911,0x6913, 0x6914,0x6915,0x6916,0x6917,0x6918,0x6919,0x691a,0x691b,0x691c,0x691d, 0x691e,0x6921,0x6922,0x6923,0x6925,0x6926,0x6927,0x6928,0x6929,0x692a, 0x692b,0x692c,0x692e,0x692f,0x6931,0x6932,0x6933,0x6935,0x6936,0x6937, 0x6938,0x693a,0x693b,0x693c,0x693e,0x6940,0x6941,0x6943,0x6944,0x6945, 0x6946,0x6947,0x6948,0x6949,0x694a,0x694b,0x694c,0x694d,0x694e,0x694f, 0x6950,0x6951,0x6952,0x6953,0x6955,0x6956,0x6958,0x6959,0x695b,0x695c, 0x695f }, { /* ku 18 */ 0x6961,0x6962,0x6964,0x6965,0x6967,0x6968,0x6969,0x696a,0x696c,0x696d, 0x696f,0x6970,0x6972,0x6973,0x6974,0x6975,0x6976,0x697a,0x697b,0x697d, 0x697e,0x697f,0x6981,0x6983,0x6985,0x698a,0x698b,0x698c,0x698e,0x698f, 0x6990,0x6991,0x6992,0x6993,0x6996,0x6997,0x6999,0x699a,0x699d,0x699e, 0x699f,0x69a0,0x69a1,0x69a2,0x69a3,0x69a4,0x69a5,0x69a6,0x69a9,0x69aa, 0x69ac,0x69ae,0x69af,0x69b0,0x69b2,0x69b3,0x69b5,0x69b6,0x69b8,0x69b9, 0x69ba,0x69bc,0x69bd,UBOGON,0x69be,0x69bf,0x69c0,0x69c2,0x69c3,0x69c4, 0x69c5,0x69c6,0x69c7,0x69c8,0x69c9,0x69cb,0x69cd,0x69cf,0x69d1,0x69d2, 0x69d3,0x69d5,0x69d6,0x69d7,0x69d8,0x69d9,0x69da,0x69dc,0x69dd,0x69de, 0x69e1,0x69e2,0x69e3,0x69e4,0x69e5,0x69e6,0x69e7,0x69e8,0x69e9,0x69ea, 0x69eb,0x69ec,0x69ee,0x69ef,0x69f0,0x69f1,0x69f3,0x69f4,0x69f5,0x69f6, 0x69f7,0x69f8,0x69f9,0x69fa,0x69fb,0x69fc,0x69fe,0x6a00,0x6a01,0x6a02, 0x6a03,0x6a04,0x6a05,0x6a06,0x6a07,0x6a08,0x6a09,0x6a0b,0x6a0c,0x6a0d, 0x6a0e,0x6a0f,0x6a10,0x6a11,0x6a12,0x6a13,0x6a14,0x6a15,0x6a16,0x6a19, 0x6a1a,0x6a1b,0x6a1c,0x6a1d,0x6a1e,0x6a20,0x6a22,0x6a23,0x6a24,0x6a25, 0x6a26,0x6a27,0x6a29,0x6a2b,0x6a2c,0x6a2d,0x6a2e,0x6a30,0x6a32,0x6a33, 0x6a34,0x6a36,0x6a37,0x6a38,0x6a39,0x6a3a,0x6a3b,0x6a3c,0x6a3f,0x6a40, 0x6a41,0x6a42,0x6a43,0x6a45,0x6a46,0x6a48,0x6a49,0x6a4a,0x6a4b,0x6a4c, 0x6a4d,0x6a4e,0x6a4f,0x6a51,0x6a52,0x6a53,0x6a54,0x6a55,0x6a56,0x6a57, 0x6a5a }, { /* ku 19 */ 0x6a5c,0x6a5d,0x6a5e,0x6a5f,0x6a60,0x6a62,0x6a63,0x6a64,0x6a66,0x6a67, 0x6a68,0x6a69,0x6a6a,0x6a6b,0x6a6c,0x6a6d,0x6a6e,0x6a6f,0x6a70,0x6a72, 0x6a73,0x6a74,0x6a75,0x6a76,0x6a77,0x6a78,0x6a7a,0x6a7b,0x6a7d,0x6a7e, 0x6a7f,0x6a81,0x6a82,0x6a83,0x6a85,0x6a86,0x6a87,0x6a88,0x6a89,0x6a8a, 0x6a8b,0x6a8c,0x6a8d,0x6a8f,0x6a92,0x6a93,0x6a94,0x6a95,0x6a96,0x6a98, 0x6a99,0x6a9a,0x6a9b,0x6a9c,0x6a9d,0x6a9e,0x6a9f,0x6aa1,0x6aa2,0x6aa3, 0x6aa4,0x6aa5,0x6aa6,UBOGON,0x6aa7,0x6aa8,0x6aaa,0x6aad,0x6aae,0x6aaf, 0x6ab0,0x6ab1,0x6ab2,0x6ab3,0x6ab4,0x6ab5,0x6ab6,0x6ab7,0x6ab8,0x6ab9, 0x6aba,0x6abb,0x6abc,0x6abd,0x6abe,0x6abf,0x6ac0,0x6ac1,0x6ac2,0x6ac3, 0x6ac4,0x6ac5,0x6ac6,0x6ac7,0x6ac8,0x6ac9,0x6aca,0x6acb,0x6acc,0x6acd, 0x6ace,0x6acf,0x6ad0,0x6ad1,0x6ad2,0x6ad3,0x6ad4,0x6ad5,0x6ad6,0x6ad7, 0x6ad8,0x6ad9,0x6ada,0x6adb,0x6adc,0x6add,0x6ade,0x6adf,0x6ae0,0x6ae1, 0x6ae2,0x6ae3,0x6ae4,0x6ae5,0x6ae6,0x6ae7,0x6ae8,0x6ae9,0x6aea,0x6aeb, 0x6aec,0x6aed,0x6aee,0x6aef,0x6af0,0x6af1,0x6af2,0x6af3,0x6af4,0x6af5, 0x6af6,0x6af7,0x6af8,0x6af9,0x6afa,0x6afb,0x6afc,0x6afd,0x6afe,0x6aff, 0x6b00,0x6b01,0x6b02,0x6b03,0x6b04,0x6b05,0x6b06,0x6b07,0x6b08,0x6b09, 0x6b0a,0x6b0b,0x6b0c,0x6b0d,0x6b0e,0x6b0f,0x6b10,0x6b11,0x6b12,0x6b13, 0x6b14,0x6b15,0x6b16,0x6b17,0x6b18,0x6b19,0x6b1a,0x6b1b,0x6b1c,0x6b1d, 0x6b1e,0x6b1f,0x6b25,0x6b26,0x6b28,0x6b29,0x6b2a,0x6b2b,0x6b2c,0x6b2d, 0x6b2e }, { /* ku 1a */ 0x6b2f,0x6b30,0x6b31,0x6b33,0x6b34,0x6b35,0x6b36,0x6b38,0x6b3b,0x6b3c, 0x6b3d,0x6b3f,0x6b40,0x6b41,0x6b42,0x6b44,0x6b45,0x6b48,0x6b4a,0x6b4b, 0x6b4d,0x6b4e,0x6b4f,0x6b50,0x6b51,0x6b52,0x6b53,0x6b54,0x6b55,0x6b56, 0x6b57,0x6b58,0x6b5a,0x6b5b,0x6b5c,0x6b5d,0x6b5e,0x6b5f,0x6b60,0x6b61, 0x6b68,0x6b69,0x6b6b,0x6b6c,0x6b6d,0x6b6e,0x6b6f,0x6b70,0x6b71,0x6b72, 0x6b73,0x6b74,0x6b75,0x6b76,0x6b77,0x6b78,0x6b7a,0x6b7d,0x6b7e,0x6b7f, 0x6b80,0x6b85,0x6b88,UBOGON,0x6b8c,0x6b8e,0x6b8f,0x6b90,0x6b91,0x6b94, 0x6b95,0x6b97,0x6b98,0x6b99,0x6b9c,0x6b9d,0x6b9e,0x6b9f,0x6ba0,0x6ba2, 0x6ba3,0x6ba4,0x6ba5,0x6ba6,0x6ba7,0x6ba8,0x6ba9,0x6bab,0x6bac,0x6bad, 0x6bae,0x6baf,0x6bb0,0x6bb1,0x6bb2,0x6bb6,0x6bb8,0x6bb9,0x6bba,0x6bbb, 0x6bbc,0x6bbd,0x6bbe,0x6bc0,0x6bc3,0x6bc4,0x6bc6,0x6bc7,0x6bc8,0x6bc9, 0x6bca,0x6bcc,0x6bce,0x6bd0,0x6bd1,0x6bd8,0x6bda,0x6bdc,0x6bdd,0x6bde, 0x6bdf,0x6be0,0x6be2,0x6be3,0x6be4,0x6be5,0x6be6,0x6be7,0x6be8,0x6be9, 0x6bec,0x6bed,0x6bee,0x6bf0,0x6bf1,0x6bf2,0x6bf4,0x6bf6,0x6bf7,0x6bf8, 0x6bfa,0x6bfb,0x6bfc,0x6bfe,0x6bff,0x6c00,0x6c01,0x6c02,0x6c03,0x6c04, 0x6c08,0x6c09,0x6c0a,0x6c0b,0x6c0c,0x6c0e,0x6c12,0x6c17,0x6c1c,0x6c1d, 0x6c1e,0x6c20,0x6c23,0x6c25,0x6c2b,0x6c2c,0x6c2d,0x6c31,0x6c33,0x6c36, 0x6c37,0x6c39,0x6c3a,0x6c3b,0x6c3c,0x6c3e,0x6c3f,0x6c43,0x6c44,0x6c45, 0x6c48,0x6c4b,0x6c4c,0x6c4d,0x6c4e,0x6c4f,0x6c51,0x6c52,0x6c53,0x6c56, 0x6c58 }, { /* ku 1b */ 0x6c59,0x6c5a,0x6c62,0x6c63,0x6c65,0x6c66,0x6c67,0x6c6b,0x6c6c,0x6c6d, 0x6c6e,0x6c6f,0x6c71,0x6c73,0x6c75,0x6c77,0x6c78,0x6c7a,0x6c7b,0x6c7c, 0x6c7f,0x6c80,0x6c84,0x6c87,0x6c8a,0x6c8b,0x6c8d,0x6c8e,0x6c91,0x6c92, 0x6c95,0x6c96,0x6c97,0x6c98,0x6c9a,0x6c9c,0x6c9d,0x6c9e,0x6ca0,0x6ca2, 0x6ca8,0x6cac,0x6caf,0x6cb0,0x6cb4,0x6cb5,0x6cb6,0x6cb7,0x6cba,0x6cc0, 0x6cc1,0x6cc2,0x6cc3,0x6cc6,0x6cc7,0x6cc8,0x6ccb,0x6ccd,0x6cce,0x6ccf, 0x6cd1,0x6cd2,0x6cd8,UBOGON,0x6cd9,0x6cda,0x6cdc,0x6cdd,0x6cdf,0x6ce4, 0x6ce6,0x6ce7,0x6ce9,0x6cec,0x6ced,0x6cf2,0x6cf4,0x6cf9,0x6cff,0x6d00, 0x6d02,0x6d03,0x6d05,0x6d06,0x6d08,0x6d09,0x6d0a,0x6d0d,0x6d0f,0x6d10, 0x6d11,0x6d13,0x6d14,0x6d15,0x6d16,0x6d18,0x6d1c,0x6d1d,0x6d1f,0x6d20, 0x6d21,0x6d22,0x6d23,0x6d24,0x6d26,0x6d28,0x6d29,0x6d2c,0x6d2d,0x6d2f, 0x6d30,0x6d34,0x6d36,0x6d37,0x6d38,0x6d3a,0x6d3f,0x6d40,0x6d42,0x6d44, 0x6d49,0x6d4c,0x6d50,0x6d55,0x6d56,0x6d57,0x6d58,0x6d5b,0x6d5d,0x6d5f, 0x6d61,0x6d62,0x6d64,0x6d65,0x6d67,0x6d68,0x6d6b,0x6d6c,0x6d6d,0x6d70, 0x6d71,0x6d72,0x6d73,0x6d75,0x6d76,0x6d79,0x6d7a,0x6d7b,0x6d7d,0x6d7e, 0x6d7f,0x6d80,0x6d81,0x6d83,0x6d84,0x6d86,0x6d87,0x6d8a,0x6d8b,0x6d8d, 0x6d8f,0x6d90,0x6d92,0x6d96,0x6d97,0x6d98,0x6d99,0x6d9a,0x6d9c,0x6da2, 0x6da5,0x6dac,0x6dad,0x6db0,0x6db1,0x6db3,0x6db4,0x6db6,0x6db7,0x6db9, 0x6dba,0x6dbb,0x6dbc,0x6dbd,0x6dbe,0x6dc1,0x6dc2,0x6dc3,0x6dc8,0x6dc9, 0x6dca }, { /* ku 1c */ 0x6dcd,0x6dce,0x6dcf,0x6dd0,0x6dd2,0x6dd3,0x6dd4,0x6dd5,0x6dd7,0x6dda, 0x6ddb,0x6ddc,0x6ddf,0x6de2,0x6de3,0x6de5,0x6de7,0x6de8,0x6de9,0x6dea, 0x6ded,0x6def,0x6df0,0x6df2,0x6df4,0x6df5,0x6df6,0x6df8,0x6dfa,0x6dfd, 0x6dfe,0x6dff,0x6e00,0x6e01,0x6e02,0x6e03,0x6e04,0x6e06,0x6e07,0x6e08, 0x6e09,0x6e0b,0x6e0f,0x6e12,0x6e13,0x6e15,0x6e18,0x6e19,0x6e1b,0x6e1c, 0x6e1e,0x6e1f,0x6e22,0x6e26,0x6e27,0x6e28,0x6e2a,0x6e2c,0x6e2e,0x6e30, 0x6e31,0x6e33,0x6e35,UBOGON,0x6e36,0x6e37,0x6e39,0x6e3b,0x6e3c,0x6e3d, 0x6e3e,0x6e3f,0x6e40,0x6e41,0x6e42,0x6e45,0x6e46,0x6e47,0x6e48,0x6e49, 0x6e4a,0x6e4b,0x6e4c,0x6e4f,0x6e50,0x6e51,0x6e52,0x6e55,0x6e57,0x6e59, 0x6e5a,0x6e5c,0x6e5d,0x6e5e,0x6e60,0x6e61,0x6e62,0x6e63,0x6e64,0x6e65, 0x6e66,0x6e67,0x6e68,0x6e69,0x6e6a,0x6e6c,0x6e6d,0x6e6f,0x6e70,0x6e71, 0x6e72,0x6e73,0x6e74,0x6e75,0x6e76,0x6e77,0x6e78,0x6e79,0x6e7a,0x6e7b, 0x6e7c,0x6e7d,0x6e80,0x6e81,0x6e82,0x6e84,0x6e87,0x6e88,0x6e8a,0x6e8b, 0x6e8c,0x6e8d,0x6e8e,0x6e91,0x6e92,0x6e93,0x6e94,0x6e95,0x6e96,0x6e97, 0x6e99,0x6e9a,0x6e9b,0x6e9d,0x6e9e,0x6ea0,0x6ea1,0x6ea3,0x6ea4,0x6ea6, 0x6ea8,0x6ea9,0x6eab,0x6eac,0x6ead,0x6eae,0x6eb0,0x6eb3,0x6eb5,0x6eb8, 0x6eb9,0x6ebc,0x6ebe,0x6ebf,0x6ec0,0x6ec3,0x6ec4,0x6ec5,0x6ec6,0x6ec8, 0x6ec9,0x6eca,0x6ecc,0x6ecd,0x6ece,0x6ed0,0x6ed2,0x6ed6,0x6ed8,0x6ed9, 0x6edb,0x6edc,0x6edd,0x6ee3,0x6ee7,0x6eea,0x6eeb,0x6eec,0x6eed,0x6eee, 0x6eef }, { /* ku 1d */ 0x6ef0,0x6ef1,0x6ef2,0x6ef3,0x6ef5,0x6ef6,0x6ef7,0x6ef8,0x6efa,0x6efb, 0x6efc,0x6efd,0x6efe,0x6eff,0x6f00,0x6f01,0x6f03,0x6f04,0x6f05,0x6f07, 0x6f08,0x6f0a,0x6f0b,0x6f0c,0x6f0d,0x6f0e,0x6f10,0x6f11,0x6f12,0x6f16, 0x6f17,0x6f18,0x6f19,0x6f1a,0x6f1b,0x6f1c,0x6f1d,0x6f1e,0x6f1f,0x6f21, 0x6f22,0x6f23,0x6f25,0x6f26,0x6f27,0x6f28,0x6f2c,0x6f2e,0x6f30,0x6f32, 0x6f34,0x6f35,0x6f37,0x6f38,0x6f39,0x6f3a,0x6f3b,0x6f3c,0x6f3d,0x6f3f, 0x6f40,0x6f41,0x6f42,UBOGON,0x6f43,0x6f44,0x6f45,0x6f48,0x6f49,0x6f4a, 0x6f4c,0x6f4e,0x6f4f,0x6f50,0x6f51,0x6f52,0x6f53,0x6f54,0x6f55,0x6f56, 0x6f57,0x6f59,0x6f5a,0x6f5b,0x6f5d,0x6f5f,0x6f60,0x6f61,0x6f63,0x6f64, 0x6f65,0x6f67,0x6f68,0x6f69,0x6f6a,0x6f6b,0x6f6c,0x6f6f,0x6f70,0x6f71, 0x6f73,0x6f75,0x6f76,0x6f77,0x6f79,0x6f7b,0x6f7d,0x6f7e,0x6f7f,0x6f80, 0x6f81,0x6f82,0x6f83,0x6f85,0x6f86,0x6f87,0x6f8a,0x6f8b,0x6f8f,0x6f90, 0x6f91,0x6f92,0x6f93,0x6f94,0x6f95,0x6f96,0x6f97,0x6f98,0x6f99,0x6f9a, 0x6f9b,0x6f9d,0x6f9e,0x6f9f,0x6fa0,0x6fa2,0x6fa3,0x6fa4,0x6fa5,0x6fa6, 0x6fa8,0x6fa9,0x6faa,0x6fab,0x6fac,0x6fad,0x6fae,0x6faf,0x6fb0,0x6fb1, 0x6fb2,0x6fb4,0x6fb5,0x6fb7,0x6fb8,0x6fba,0x6fbb,0x6fbc,0x6fbd,0x6fbe, 0x6fbf,0x6fc1,0x6fc3,0x6fc4,0x6fc5,0x6fc6,0x6fc7,0x6fc8,0x6fca,0x6fcb, 0x6fcc,0x6fcd,0x6fce,0x6fcf,0x6fd0,0x6fd3,0x6fd4,0x6fd5,0x6fd6,0x6fd7, 0x6fd8,0x6fd9,0x6fda,0x6fdb,0x6fdc,0x6fdd,0x6fdf,0x6fe2,0x6fe3,0x6fe4, 0x6fe5 }, { /* ku 1e */ 0x6fe6,0x6fe7,0x6fe8,0x6fe9,0x6fea,0x6feb,0x6fec,0x6fed,0x6ff0,0x6ff1, 0x6ff2,0x6ff3,0x6ff4,0x6ff5,0x6ff6,0x6ff7,0x6ff8,0x6ff9,0x6ffa,0x6ffb, 0x6ffc,0x6ffd,0x6ffe,0x6fff,0x7000,0x7001,0x7002,0x7003,0x7004,0x7005, 0x7006,0x7007,0x7008,0x7009,0x700a,0x700b,0x700c,0x700d,0x700e,0x700f, 0x7010,0x7012,0x7013,0x7014,0x7015,0x7016,0x7017,0x7018,0x7019,0x701c, 0x701d,0x701e,0x701f,0x7020,0x7021,0x7022,0x7024,0x7025,0x7026,0x7027, 0x7028,0x7029,0x702a,UBOGON,0x702b,0x702c,0x702d,0x702e,0x702f,0x7030, 0x7031,0x7032,0x7033,0x7034,0x7036,0x7037,0x7038,0x703a,0x703b,0x703c, 0x703d,0x703e,0x703f,0x7040,0x7041,0x7042,0x7043,0x7044,0x7045,0x7046, 0x7047,0x7048,0x7049,0x704a,0x704b,0x704d,0x704e,0x7050,0x7051,0x7052, 0x7053,0x7054,0x7055,0x7056,0x7057,0x7058,0x7059,0x705a,0x705b,0x705c, 0x705d,0x705f,0x7060,0x7061,0x7062,0x7063,0x7064,0x7065,0x7066,0x7067, 0x7068,0x7069,0x706a,0x706e,0x7071,0x7072,0x7073,0x7074,0x7077,0x7079, 0x707a,0x707b,0x707d,0x7081,0x7082,0x7083,0x7084,0x7086,0x7087,0x7088, 0x708b,0x708c,0x708d,0x708f,0x7090,0x7091,0x7093,0x7097,0x7098,0x709a, 0x709b,0x709e,0x709f,0x70a0,0x70a1,0x70a2,0x70a3,0x70a4,0x70a5,0x70a6, 0x70a7,0x70a8,0x70a9,0x70aa,0x70b0,0x70b2,0x70b4,0x70b5,0x70b6,0x70ba, 0x70be,0x70bf,0x70c4,0x70c5,0x70c6,0x70c7,0x70c9,0x70cb,0x70cc,0x70cd, 0x70ce,0x70cf,0x70d0,0x70d1,0x70d2,0x70d3,0x70d4,0x70d5,0x70d6,0x70d7, 0x70da }, { /* ku 1f */ 0x70dc,0x70dd,0x70de,0x70e0,0x70e1,0x70e2,0x70e3,0x70e5,0x70ea,0x70ee, 0x70f0,0x70f1,0x70f2,0x70f3,0x70f4,0x70f5,0x70f6,0x70f8,0x70fa,0x70fb, 0x70fc,0x70fe,0x70ff,0x7100,0x7101,0x7102,0x7103,0x7104,0x7105,0x7106, 0x7107,0x7108,0x710b,0x710c,0x710d,0x710e,0x710f,0x7111,0x7112,0x7114, 0x7117,0x711b,0x711c,0x711d,0x711e,0x711f,0x7120,0x7121,0x7122,0x7123, 0x7124,0x7125,0x7127,0x7128,0x7129,0x712a,0x712b,0x712c,0x712d,0x712e, 0x7132,0x7133,0x7134,UBOGON,0x7135,0x7137,0x7138,0x7139,0x713a,0x713b, 0x713c,0x713d,0x713e,0x713f,0x7140,0x7141,0x7142,0x7143,0x7144,0x7146, 0x7147,0x7148,0x7149,0x714b,0x714d,0x714f,0x7150,0x7151,0x7152,0x7153, 0x7154,0x7155,0x7156,0x7157,0x7158,0x7159,0x715a,0x715b,0x715d,0x715f, 0x7160,0x7161,0x7162,0x7163,0x7165,0x7169,0x716a,0x716b,0x716c,0x716d, 0x716f,0x7170,0x7171,0x7174,0x7175,0x7176,0x7177,0x7179,0x717b,0x717c, 0x717e,0x717f,0x7180,0x7181,0x7182,0x7183,0x7185,0x7186,0x7187,0x7188, 0x7189,0x718b,0x718c,0x718d,0x718e,0x7190,0x7191,0x7192,0x7193,0x7195, 0x7196,0x7197,0x719a,0x719b,0x719c,0x719d,0x719e,0x71a1,0x71a2,0x71a3, 0x71a4,0x71a5,0x71a6,0x71a7,0x71a9,0x71aa,0x71ab,0x71ad,0x71ae,0x71af, 0x71b0,0x71b1,0x71b2,0x71b4,0x71b6,0x71b7,0x71b8,0x71ba,0x71bb,0x71bc, 0x71bd,0x71be,0x71bf,0x71c0,0x71c1,0x71c2,0x71c4,0x71c5,0x71c6,0x71c7, 0x71c8,0x71c9,0x71ca,0x71cb,0x71cc,0x71cd,0x71cf,0x71d0,0x71d1,0x71d2, 0x71d3 }, { /* ku 20 */ 0x71d6,0x71d7,0x71d8,0x71d9,0x71da,0x71db,0x71dc,0x71dd,0x71de,0x71df, 0x71e1,0x71e2,0x71e3,0x71e4,0x71e6,0x71e8,0x71e9,0x71ea,0x71eb,0x71ec, 0x71ed,0x71ef,0x71f0,0x71f1,0x71f2,0x71f3,0x71f4,0x71f5,0x71f6,0x71f7, 0x71f8,0x71fa,0x71fb,0x71fc,0x71fd,0x71fe,0x71ff,0x7200,0x7201,0x7202, 0x7203,0x7204,0x7205,0x7207,0x7208,0x7209,0x720a,0x720b,0x720c,0x720d, 0x720e,0x720f,0x7210,0x7211,0x7212,0x7213,0x7214,0x7215,0x7216,0x7217, 0x7218,0x7219,0x721a,UBOGON,0x721b,0x721c,0x721e,0x721f,0x7220,0x7221, 0x7222,0x7223,0x7224,0x7225,0x7226,0x7227,0x7229,0x722b,0x722d,0x722e, 0x722f,0x7232,0x7233,0x7234,0x723a,0x723c,0x723e,0x7240,0x7241,0x7242, 0x7243,0x7244,0x7245,0x7246,0x7249,0x724a,0x724b,0x724e,0x724f,0x7250, 0x7251,0x7253,0x7254,0x7255,0x7257,0x7258,0x725a,0x725c,0x725e,0x7260, 0x7263,0x7264,0x7265,0x7268,0x726a,0x726b,0x726c,0x726d,0x7270,0x7271, 0x7273,0x7274,0x7276,0x7277,0x7278,0x727b,0x727c,0x727d,0x7282,0x7283, 0x7285,0x7286,0x7287,0x7288,0x7289,0x728c,0x728e,0x7290,0x7291,0x7293, 0x7294,0x7295,0x7296,0x7297,0x7298,0x7299,0x729a,0x729b,0x729c,0x729d, 0x729e,0x72a0,0x72a1,0x72a2,0x72a3,0x72a4,0x72a5,0x72a6,0x72a7,0x72a8, 0x72a9,0x72aa,0x72ab,0x72ae,0x72b1,0x72b2,0x72b3,0x72b5,0x72ba,0x72bb, 0x72bc,0x72bd,0x72be,0x72bf,0x72c0,0x72c5,0x72c6,0x72c7,0x72c9,0x72ca, 0x72cb,0x72cc,0x72cf,0x72d1,0x72d3,0x72d4,0x72d5,0x72d6,0x72d8,0x72da, 0x72db }, { /* ku 21 */ UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON, UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON, UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON, UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON, UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON, UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON, UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON, UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON, UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON, UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,0x3000,0x3001,0x3002, 0x00b7,0x02c9,0x02c7,0x00a8,0x3003,0x3005,0x2014,0xff5e,0x2016,0x2026, 0x2018,0x2019,0x201c,0x201d,0x3014,0x3015,0x3008,0x3009,0x300a,0x300b, 0x300c,0x300d,0x300e,0x300f,0x3016,0x3017,0x3010,0x3011,0x00b1,0x00d7, 0x00f7,0x2236,0x2227,0x2228,0x2211,0x220f,0x222a,0x2229,0x2208,0x2237, 0x221a,0x22a5,0x2225,0x2220,0x2312,0x2299,0x222b,0x222e,0x2261,0x224c, 0x2248,0x223d,0x221d,0x2260,0x226e,0x226f,0x2264,0x2265,0x221e,0x2235, 0x2234,0x2642,0x2640,0x00b0,0x2032,0x2033,0x2103,0xff04,0x00a4,0xffe0, 0xffe1,0x2030,0x00a7,0x2116,0x2606,0x2605,0x25cb,0x25cf,0x25ce,0x25c7, 0x25c6,0x25a1,0x25a0,0x25b3,0x25b2,0x203b,0x2192,0x2190,0x2191,0x2193, 0x3013 }, { /* ku 22 */ UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON, UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON, UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON, UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON, UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON, UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON, UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON, UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON, UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON, UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,0x2170,0x2171,0x2172, 0x2173,0x2174,0x2175,0x2176,0x2177,0x2178,0x2179,UBOGON,UBOGON,UBOGON, UBOGON,UBOGON,UBOGON,0x2488,0x2489,0x248a,0x248b,0x248c,0x248d,0x248e, 0x248f,0x2490,0x2491,0x2492,0x2493,0x2494,0x2495,0x2496,0x2497,0x2498, 0x2499,0x249a,0x249b,0x2474,0x2475,0x2476,0x2477,0x2478,0x2479,0x247a, 0x247b,0x247c,0x247d,0x247e,0x247f,0x2480,0x2481,0x2482,0x2483,0x2484, 0x2485,0x2486,0x2487,0x2460,0x2461,0x2462,0x2463,0x2464,0x2465,0x2466, 0x2467,0x2468,0x2469,UBOGON,UBOGON,0x3220,0x3221,0x3222,0x3223,0x3224, 0x3225,0x3226,0x3227,0x3228,0x3229,UBOGON,UBOGON,0x2160,0x2161,0x2162, 0x2163,0x2164,0x2165,0x2166,0x2167,0x2168,0x2169,0x216a,0x216b,UBOGON, UBOGON }, { /* ku 23 */ UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON, UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON, UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON, UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON, UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON, UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON, UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON, UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON, UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON, UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,0xff01,0xff02,0xff03, 0xffe5,0xff05,0xff06,0xff07,0xff08,0xff09,0xff0a,0xff0b,0xff0c,0xff0d, 0xff0e,0xff0f,0xff10,0xff11,0xff12,0xff13,0xff14,0xff15,0xff16,0xff17, 0xff18,0xff19,0xff1a,0xff1b,0xff1c,0xff1d,0xff1e,0xff1f,0xff20,0xff21, 0xff22,0xff23,0xff24,0xff25,0xff26,0xff27,0xff28,0xff29,0xff2a,0xff2b, 0xff2c,0xff2d,0xff2e,0xff2f,0xff30,0xff31,0xff32,0xff33,0xff34,0xff35, 0xff36,0xff37,0xff38,0xff39,0xff3a,0xff3b,0xff3c,0xff3d,0xff3e,0xff3f, 0xff40,0xff41,0xff42,0xff43,0xff44,0xff45,0xff46,0xff47,0xff48,0xff49, 0xff4a,0xff4b,0xff4c,0xff4d,0xff4e,0xff4f,0xff50,0xff51,0xff52,0xff53, 0xff54,0xff55,0xff56,0xff57,0xff58,0xff59,0xff5a,0xff5b,0xff5c,0xff5d, 0xffe3 }, { /* ku 24 */ UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON, UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON, UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON, UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON, UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON, UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON, UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON, UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON, UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON, UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,0x3041,0x3042,0x3043, 0x3044,0x3045,0x3046,0x3047,0x3048,0x3049,0x304a,0x304b,0x304c,0x304d, 0x304e,0x304f,0x3050,0x3051,0x3052,0x3053,0x3054,0x3055,0x3056,0x3057, 0x3058,0x3059,0x305a,0x305b,0x305c,0x305d,0x305e,0x305f,0x3060,0x3061, 0x3062,0x3063,0x3064,0x3065,0x3066,0x3067,0x3068,0x3069,0x306a,0x306b, 0x306c,0x306d,0x306e,0x306f,0x3070,0x3071,0x3072,0x3073,0x3074,0x3075, 0x3076,0x3077,0x3078,0x3079,0x307a,0x307b,0x307c,0x307d,0x307e,0x307f, 0x3080,0x3081,0x3082,0x3083,0x3084,0x3085,0x3086,0x3087,0x3088,0x3089, 0x308a,0x308b,0x308c,0x308d,0x308e,0x308f,0x3090,0x3091,0x3092,0x3093, UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON, UBOGON }, { /* ku 25 */ UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON, UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON, UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON, UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON, UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON, UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON, UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON, UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON, UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON, UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,0x30a1,0x30a2,0x30a3, 0x30a4,0x30a5,0x30a6,0x30a7,0x30a8,0x30a9,0x30aa,0x30ab,0x30ac,0x30ad, 0x30ae,0x30af,0x30b0,0x30b1,0x30b2,0x30b3,0x30b4,0x30b5,0x30b6,0x30b7, 0x30b8,0x30b9,0x30ba,0x30bb,0x30bc,0x30bd,0x30be,0x30bf,0x30c0,0x30c1, 0x30c2,0x30c3,0x30c4,0x30c5,0x30c6,0x30c7,0x30c8,0x30c9,0x30ca,0x30cb, 0x30cc,0x30cd,0x30ce,0x30cf,0x30d0,0x30d1,0x30d2,0x30d3,0x30d4,0x30d5, 0x30d6,0x30d7,0x30d8,0x30d9,0x30da,0x30db,0x30dc,0x30dd,0x30de,0x30df, 0x30e0,0x30e1,0x30e2,0x30e3,0x30e4,0x30e5,0x30e6,0x30e7,0x30e8,0x30e9, 0x30ea,0x30eb,0x30ec,0x30ed,0x30ee,0x30ef,0x30f0,0x30f1,0x30f2,0x30f3, 0x30f4,0x30f5,0x30f6,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON, UBOGON }, { /* ku 26 */ UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON, UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON, UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON, UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON, UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON, UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON, UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON, UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON, UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON, UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,0x0391,0x0392,0x0393, 0x0394,0x0395,0x0396,0x0397,0x0398,0x0399,0x039a,0x039b,0x039c,0x039d, 0x039e,0x039f,0x03a0,0x03a1,0x03a3,0x03a4,0x03a5,0x03a6,0x03a7,0x03a8, 0x03a9,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,0x03b1, 0x03b2,0x03b3,0x03b4,0x03b5,0x03b6,0x03b7,0x03b8,0x03b9,0x03ba,0x03bb, 0x03bc,0x03bd,0x03be,0x03bf,0x03c0,0x03c1,0x03c3,0x03c4,0x03c5,0x03c6, 0x03c7,0x03c8,0x03c9,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON, 0xfe35,0xfe36,0xfe39,0xfe3a,0xfe3f,0xfe40,0xfe3d,0xfe3e,0xfe41,0xfe42, 0xfe43,0xfe44,UBOGON,UBOGON,0xfe3b,0xfe3c,0xfe37,0xfe38,0xfe31,UBOGON, 0xfe33,0xfe34,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON, UBOGON }, { /* ku 27 */ UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON, UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON, UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON, UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON, UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON, UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON, UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON, UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON, UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON, UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,0x0410,0x0411,0x0412, 0x0413,0x0414,0x0415,0x0401,0x0416,0x0417,0x0418,0x0419,0x041a,0x041b, 0x041c,0x041d,0x041e,0x041f,0x0420,0x0421,0x0422,0x0423,0x0424,0x0425, 0x0426,0x0427,0x0428,0x0429,0x042a,0x042b,0x042c,0x042d,0x042e,0x042f, UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON, UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,0x0430,0x0431,0x0432,0x0433,0x0434, 0x0435,0x0451,0x0436,0x0437,0x0438,0x0439,0x043a,0x043b,0x043c,0x043d, 0x043e,0x043f,0x0440,0x0441,0x0442,0x0443,0x0444,0x0445,0x0446,0x0447, 0x0448,0x0449,0x044a,0x044b,0x044c,0x044d,0x044e,0x044f,UBOGON,UBOGON, UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON, UBOGON }, { /* ku 28 */ 0x02ca,0x02cb,0x02d9,0x2013,0x2015,0x2025,0x2035,0x2105,0x2109,0x2196, 0x2197,0x2198,0x2199,0x2215,0x221f,0x2223,0x2252,0x2266,0x2267,0x22bf, 0x2550,0x2551,0x2552,0x2553,0x2554,0x2555,0x2556,0x2557,0x2558,0x2559, 0x255a,0x255b,0x255c,0x255d,0x255e,0x255f,0x2560,0x2561,0x2562,0x2563, 0x2564,0x2565,0x2566,0x2567,0x2568,0x2569,0x256a,0x256b,0x256c,0x256d, 0x256e,0x256f,0x2570,0x2571,0x2572,0x2573,0x2581,0x2582,0x2583,0x2584, 0x2585,0x2586,0x2587,UBOGON,0x2588,0x2589,0x258a,0x258b,0x258c,0x258d, 0x258e,0x258f,0x2593,0x2594,0x2595,0x25bc,0x25bd,0x25e2,0x25e3,0x25e4, 0x25e5,0x2609,0x2295,0x3012,0x301d,0x301e,UBOGON,UBOGON,UBOGON,UBOGON, UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,0x0101,0x00e1,0x01ce, 0x00e0,0x0113,0x00e9,0x011b,0x00e8,0x012b,0x00ed,0x01d0,0x00ec,0x014d, 0x00f3,0x01d2,0x00f2,0x016b,0x00fa,0x01d4,0x00f9,0x01d6,0x01d8,0x01da, 0x01dc,0x00fc,0x00ea,0x0251,UBOGON,0x0144,0x0148,UBOGON,0x0261,UBOGON, UBOGON,UBOGON,UBOGON,0x3105,0x3106,0x3107,0x3108,0x3109,0x310a,0x310b, 0x310c,0x310d,0x310e,0x310f,0x3110,0x3111,0x3112,0x3113,0x3114,0x3115, 0x3116,0x3117,0x3118,0x3119,0x311a,0x311b,0x311c,0x311d,0x311e,0x311f, 0x3120,0x3121,0x3122,0x3123,0x3124,0x3125,0x3126,0x3127,0x3128,0x3129, UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON, UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON, UBOGON }, { /* ku 29 */ 0x3021,0x3022,0x3023,0x3024,0x3025,0x3026,0x3027,0x3028,0x3029,0x32a3, 0x338e,0x338f,0x339c,0x339d,0x339e,0x33a1,0x33c4,0x33ce,0x33d1,0x33d2, 0x33d5,0xfe30,0xffe2,0xffe4,UBOGON,0x2121,0x3231,UBOGON,0x2010,UBOGON, UBOGON,UBOGON,0x30fc,0x309b,0x309c,0x30fd,0x30fe,0x3006,0x309d,0x309e, 0xfe49,0xfe4a,0xfe4b,0xfe4c,0xfe4d,0xfe4e,0xfe4f,0xfe50,0xfe51,0xfe52, 0xfe54,0xfe55,0xfe56,0xfe57,0xfe59,0xfe5a,0xfe5b,0xfe5c,0xfe5d,0xfe5e, 0xfe5f,0xfe60,0xfe61,UBOGON,0xfe62,0xfe63,0xfe64,0xfe65,0xfe66,0xfe68, 0xfe69,0xfe6a,0xfe6b,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON, UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,0x3007,UBOGON,UBOGON,UBOGON, UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON, 0x2500,0x2501,0x2502,0x2503,0x2504,0x2505,0x2506,0x2507,0x2508,0x2509, 0x250a,0x250b,0x250c,0x250d,0x250e,0x250f,0x2510,0x2511,0x2512,0x2513, 0x2514,0x2515,0x2516,0x2517,0x2518,0x2519,0x251a,0x251b,0x251c,0x251d, 0x251e,0x251f,0x2520,0x2521,0x2522,0x2523,0x2524,0x2525,0x2526,0x2527, 0x2528,0x2529,0x252a,0x252b,0x252c,0x252d,0x252e,0x252f,0x2530,0x2531, 0x2532,0x2533,0x2534,0x2535,0x2536,0x2537,0x2538,0x2539,0x253a,0x253b, 0x253c,0x253d,0x253e,0x253f,0x2540,0x2541,0x2542,0x2543,0x2544,0x2545, 0x2546,0x2547,0x2548,0x2549,0x254a,0x254b,UBOGON,UBOGON,UBOGON,UBOGON, UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON, UBOGON }, { /* ku 2a */ 0x72dc,0x72dd,0x72df,0x72e2,0x72e3,0x72e4,0x72e5,0x72e6,0x72e7,0x72ea, 0x72eb,0x72f5,0x72f6,0x72f9,0x72fd,0x72fe,0x72ff,0x7300,0x7302,0x7304, 0x7305,0x7306,0x7307,0x7308,0x7309,0x730b,0x730c,0x730d,0x730f,0x7310, 0x7311,0x7312,0x7314,0x7318,0x7319,0x731a,0x731f,0x7320,0x7323,0x7324, 0x7326,0x7327,0x7328,0x732d,0x732f,0x7330,0x7332,0x7333,0x7335,0x7336, 0x733a,0x733b,0x733c,0x733d,0x7340,0x7341,0x7342,0x7343,0x7344,0x7345, 0x7346,0x7347,0x7348,UBOGON,0x7349,0x734a,0x734b,0x734c,0x734e,0x734f, 0x7351,0x7353,0x7354,0x7355,0x7356,0x7358,0x7359,0x735a,0x735b,0x735c, 0x735d,0x735e,0x735f,0x7361,0x7362,0x7363,0x7364,0x7365,0x7366,0x7367, 0x7368,0x7369,0x736a,0x736b,0x736e,0x7370,0x7371,UBOGON,UBOGON,UBOGON, UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON, UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON, UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON, UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON, UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON, UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON, UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON, UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON, UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON, UBOGON }, { /* ku 2b */ 0x7372,0x7373,0x7374,0x7375,0x7376,0x7377,0x7378,0x7379,0x737a,0x737b, 0x737c,0x737d,0x737f,0x7380,0x7381,0x7382,0x7383,0x7385,0x7386,0x7388, 0x738a,0x738c,0x738d,0x738f,0x7390,0x7392,0x7393,0x7394,0x7395,0x7397, 0x7398,0x7399,0x739a,0x739c,0x739d,0x739e,0x73a0,0x73a1,0x73a3,0x73a4, 0x73a5,0x73a6,0x73a7,0x73a8,0x73aa,0x73ac,0x73ad,0x73b1,0x73b4,0x73b5, 0x73b6,0x73b8,0x73b9,0x73bc,0x73bd,0x73be,0x73bf,0x73c1,0x73c3,0x73c4, 0x73c5,0x73c6,0x73c7,UBOGON,0x73cb,0x73cc,0x73ce,0x73d2,0x73d3,0x73d4, 0x73d5,0x73d6,0x73d7,0x73d8,0x73da,0x73db,0x73dc,0x73dd,0x73df,0x73e1, 0x73e2,0x73e3,0x73e4,0x73e6,0x73e8,0x73ea,0x73eb,0x73ec,0x73ee,0x73ef, 0x73f0,0x73f1,0x73f3,0x73f4,0x73f5,0x73f6,0x73f7,UBOGON,UBOGON,UBOGON, UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON, UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON, UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON, UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON, UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON, UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON, UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON, UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON, UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON, UBOGON }, { /* ku 2c */ 0x73f8,0x73f9,0x73fa,0x73fb,0x73fc,0x73fd,0x73fe,0x73ff,0x7400,0x7401, 0x7402,0x7404,0x7407,0x7408,0x740b,0x740c,0x740d,0x740e,0x7411,0x7412, 0x7413,0x7414,0x7415,0x7416,0x7417,0x7418,0x7419,0x741c,0x741d,0x741e, 0x741f,0x7420,0x7421,0x7423,0x7424,0x7427,0x7429,0x742b,0x742d,0x742f, 0x7431,0x7432,0x7437,0x7438,0x7439,0x743a,0x743b,0x743d,0x743e,0x743f, 0x7440,0x7442,0x7443,0x7444,0x7445,0x7446,0x7447,0x7448,0x7449,0x744a, 0x744b,0x744c,0x744d,UBOGON,0x744e,0x744f,0x7450,0x7451,0x7452,0x7453, 0x7454,0x7456,0x7458,0x745d,0x7460,0x7461,0x7462,0x7463,0x7464,0x7465, 0x7466,0x7467,0x7468,0x7469,0x746a,0x746b,0x746c,0x746e,0x746f,0x7471, 0x7472,0x7473,0x7474,0x7475,0x7478,0x7479,0x747a,UBOGON,UBOGON,UBOGON, UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON, UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON, UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON, UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON, UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON, UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON, UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON, UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON, UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON, UBOGON }, { /* ku 2d */ 0x747b,0x747c,0x747d,0x747f,0x7482,0x7484,0x7485,0x7486,0x7488,0x7489, 0x748a,0x748c,0x748d,0x748f,0x7491,0x7492,0x7493,0x7494,0x7495,0x7496, 0x7497,0x7498,0x7499,0x749a,0x749b,0x749d,0x749f,0x74a0,0x74a1,0x74a2, 0x74a3,0x74a4,0x74a5,0x74a6,0x74aa,0x74ab,0x74ac,0x74ad,0x74ae,0x74af, 0x74b0,0x74b1,0x74b2,0x74b3,0x74b4,0x74b5,0x74b6,0x74b7,0x74b8,0x74b9, 0x74bb,0x74bc,0x74bd,0x74be,0x74bf,0x74c0,0x74c1,0x74c2,0x74c3,0x74c4, 0x74c5,0x74c6,0x74c7,UBOGON,0x74c8,0x74c9,0x74ca,0x74cb,0x74cc,0x74cd, 0x74ce,0x74cf,0x74d0,0x74d1,0x74d3,0x74d4,0x74d5,0x74d6,0x74d7,0x74d8, 0x74d9,0x74da,0x74db,0x74dd,0x74df,0x74e1,0x74e5,0x74e7,0x74e8,0x74e9, 0x74ea,0x74eb,0x74ec,0x74ed,0x74f0,0x74f1,0x74f2,UBOGON,UBOGON,UBOGON, UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON, UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON, UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON, UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON, UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON, UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON, UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON, UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON, UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON, UBOGON }, { /* ku 2e */ 0x74f3,0x74f5,0x74f8,0x74f9,0x74fa,0x74fb,0x74fc,0x74fd,0x74fe,0x7500, 0x7501,0x7502,0x7503,0x7505,0x7506,0x7507,0x7508,0x7509,0x750a,0x750b, 0x750c,0x750e,0x7510,0x7512,0x7514,0x7515,0x7516,0x7517,0x751b,0x751d, 0x751e,0x7520,0x7521,0x7522,0x7523,0x7524,0x7526,0x7527,0x752a,0x752e, 0x7534,0x7536,0x7539,0x753c,0x753d,0x753f,0x7541,0x7542,0x7543,0x7544, 0x7546,0x7547,0x7549,0x754a,0x754d,0x7550,0x7551,0x7552,0x7553,0x7555, 0x7556,0x7557,0x7558,UBOGON,0x755d,0x755e,0x755f,0x7560,0x7561,0x7562, 0x7563,0x7564,0x7567,0x7568,0x7569,0x756b,0x756c,0x756d,0x756e,0x756f, 0x7570,0x7571,0x7573,0x7575,0x7576,0x7577,0x757a,0x757b,0x757c,0x757d, 0x757e,0x7580,0x7581,0x7582,0x7584,0x7585,0x7587,UBOGON,UBOGON,UBOGON, UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON, UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON, UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON, UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON, UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON, UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON, UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON, UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON, UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON, UBOGON }, { /* ku 2f */ 0x7588,0x7589,0x758a,0x758c,0x758d,0x758e,0x7590,0x7593,0x7595,0x7598, 0x759b,0x759c,0x759e,0x75a2,0x75a6,0x75a7,0x75a8,0x75a9,0x75aa,0x75ad, 0x75b6,0x75b7,0x75ba,0x75bb,0x75bf,0x75c0,0x75c1,0x75c6,0x75cb,0x75cc, 0x75ce,0x75cf,0x75d0,0x75d1,0x75d3,0x75d7,0x75d9,0x75da,0x75dc,0x75dd, 0x75df,0x75e0,0x75e1,0x75e5,0x75e9,0x75ec,0x75ed,0x75ee,0x75ef,0x75f2, 0x75f3,0x75f5,0x75f6,0x75f7,0x75f8,0x75fa,0x75fb,0x75fd,0x75fe,0x7602, 0x7604,0x7606,0x7607,UBOGON,0x7608,0x7609,0x760b,0x760d,0x760e,0x760f, 0x7611,0x7612,0x7613,0x7614,0x7616,0x761a,0x761c,0x761d,0x761e,0x7621, 0x7623,0x7627,0x7628,0x762c,0x762e,0x762f,0x7631,0x7632,0x7636,0x7637, 0x7639,0x763a,0x763b,0x763d,0x7641,0x7642,0x7644,UBOGON,UBOGON,UBOGON, UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON, UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON, UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON, UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON, UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON, UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON, UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON, UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON, UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON, UBOGON }, { /* ku 30 */ 0x7645,0x7646,0x7647,0x7648,0x7649,0x764a,0x764b,0x764e,0x764f,0x7650, 0x7651,0x7652,0x7653,0x7655,0x7657,0x7658,0x7659,0x765a,0x765b,0x765d, 0x765f,0x7660,0x7661,0x7662,0x7664,0x7665,0x7666,0x7667,0x7668,0x7669, 0x766a,0x766c,0x766d,0x766e,0x7670,0x7671,0x7672,0x7673,0x7674,0x7675, 0x7676,0x7677,0x7679,0x767a,0x767c,0x767f,0x7680,0x7681,0x7683,0x7685, 0x7689,0x768a,0x768c,0x768d,0x768f,0x7690,0x7692,0x7694,0x7695,0x7697, 0x7698,0x769a,0x769b,UBOGON,0x769c,0x769d,0x769e,0x769f,0x76a0,0x76a1, 0x76a2,0x76a3,0x76a5,0x76a6,0x76a7,0x76a8,0x76a9,0x76aa,0x76ab,0x76ac, 0x76ad,0x76af,0x76b0,0x76b3,0x76b5,0x76b6,0x76b7,0x76b8,0x76b9,0x76ba, 0x76bb,0x76bc,0x76bd,0x76be,0x76c0,0x76c1,0x76c3,0x554a,0x963f,0x57c3, 0x6328,0x54ce,0x5509,0x54c0,0x7691,0x764c,0x853c,0x77ee,0x827e,0x788d, 0x7231,0x9698,0x978d,0x6c28,0x5b89,0x4ffa,0x6309,0x6697,0x5cb8,0x80fa, 0x6848,0x80ae,0x6602,0x76ce,0x51f9,0x6556,0x71ac,0x7ff1,0x8884,0x50b2, 0x5965,0x61ca,0x6fb3,0x82ad,0x634c,0x6252,0x53ed,0x5427,0x7b06,0x516b, 0x75a4,0x5df4,0x62d4,0x8dcb,0x9776,0x628a,0x8019,0x575d,0x9738,0x7f62, 0x7238,0x767d,0x67cf,0x767e,0x6446,0x4f70,0x8d25,0x62dc,0x7a17,0x6591, 0x73ed,0x642c,0x6273,0x822c,0x9881,0x677f,0x7248,0x626e,0x62cc,0x4f34, 0x74e3,0x534a,0x529e,0x7eca,0x90a6,0x5e2e,0x6886,0x699c,0x8180,0x7ed1, 0x68d2,0x78c5,0x868c,0x9551,0x508d,0x8c24,0x82de,0x80de,0x5305,0x8912, 0x5265 }, { /* ku 31 */ 0x76c4,0x76c7,0x76c9,0x76cb,0x76cc,0x76d3,0x76d5,0x76d9,0x76da,0x76dc, 0x76dd,0x76de,0x76e0,0x76e1,0x76e2,0x76e3,0x76e4,0x76e6,0x76e7,0x76e8, 0x76e9,0x76ea,0x76eb,0x76ec,0x76ed,0x76f0,0x76f3,0x76f5,0x76f6,0x76f7, 0x76fa,0x76fb,0x76fd,0x76ff,0x7700,0x7702,0x7703,0x7705,0x7706,0x770a, 0x770c,0x770e,0x770f,0x7710,0x7711,0x7712,0x7713,0x7714,0x7715,0x7716, 0x7717,0x7718,0x771b,0x771c,0x771d,0x771e,0x7721,0x7723,0x7724,0x7725, 0x7727,0x772a,0x772b,UBOGON,0x772c,0x772e,0x7730,0x7731,0x7732,0x7733, 0x7734,0x7739,0x773b,0x773d,0x773e,0x773f,0x7742,0x7744,0x7745,0x7746, 0x7748,0x7749,0x774a,0x774b,0x774c,0x774d,0x774e,0x774f,0x7752,0x7753, 0x7754,0x7755,0x7756,0x7757,0x7758,0x7759,0x775c,0x8584,0x96f9,0x4fdd, 0x5821,0x9971,0x5b9d,0x62b1,0x62a5,0x66b4,0x8c79,0x9c8d,0x7206,0x676f, 0x7891,0x60b2,0x5351,0x5317,0x8f88,0x80cc,0x8d1d,0x94a1,0x500d,0x72c8, 0x5907,0x60eb,0x7119,0x88ab,0x5954,0x82ef,0x672c,0x7b28,0x5d29,0x7ef7, 0x752d,0x6cf5,0x8e66,0x8ff8,0x903c,0x9f3b,0x6bd4,0x9119,0x7b14,0x5f7c, 0x78a7,0x84d6,0x853d,0x6bd5,0x6bd9,0x6bd6,0x5e01,0x5e87,0x75f9,0x95ed, 0x655d,0x5f0a,0x5fc5,0x8f9f,0x58c1,0x81c2,0x907f,0x965b,0x97ad,0x8fb9, 0x7f16,0x8d2c,0x6241,0x4fbf,0x53d8,0x535e,0x8fa8,0x8fa9,0x8fab,0x904d, 0x6807,0x5f6a,0x8198,0x8868,0x9cd6,0x618b,0x522b,0x762a,0x5f6c,0x658c, 0x6fd2,0x6ee8,0x5bbe,0x6448,0x5175,0x51b0,0x67c4,0x4e19,0x79c9,0x997c, 0x70b3 }, { /* ku 32 */ 0x775d,0x775e,0x775f,0x7760,0x7764,0x7767,0x7769,0x776a,0x776d,0x776e, 0x776f,0x7770,0x7771,0x7772,0x7773,0x7774,0x7775,0x7776,0x7777,0x7778, 0x777a,0x777b,0x777c,0x7781,0x7782,0x7783,0x7786,0x7787,0x7788,0x7789, 0x778a,0x778b,0x778f,0x7790,0x7793,0x7794,0x7795,0x7796,0x7797,0x7798, 0x7799,0x779a,0x779b,0x779c,0x779d,0x779e,0x77a1,0x77a3,0x77a4,0x77a6, 0x77a8,0x77ab,0x77ad,0x77ae,0x77af,0x77b1,0x77b2,0x77b4,0x77b6,0x77b7, 0x77b8,0x77b9,0x77ba,UBOGON,0x77bc,0x77be,0x77c0,0x77c1,0x77c2,0x77c3, 0x77c4,0x77c5,0x77c6,0x77c7,0x77c8,0x77c9,0x77ca,0x77cb,0x77cc,0x77ce, 0x77cf,0x77d0,0x77d1,0x77d2,0x77d3,0x77d4,0x77d5,0x77d6,0x77d8,0x77d9, 0x77da,0x77dd,0x77de,0x77df,0x77e0,0x77e1,0x77e4,0x75c5,0x5e76,0x73bb, 0x83e0,0x64ad,0x62e8,0x94b5,0x6ce2,0x535a,0x52c3,0x640f,0x94c2,0x7b94, 0x4f2f,0x5e1b,0x8236,0x8116,0x818a,0x6e24,0x6cca,0x9a73,0x6355,0x535c, 0x54fa,0x8865,0x57e0,0x4e0d,0x5e03,0x6b65,0x7c3f,0x90e8,0x6016,0x64e6, 0x731c,0x88c1,0x6750,0x624d,0x8d22,0x776c,0x8e29,0x91c7,0x5f69,0x83dc, 0x8521,0x9910,0x53c2,0x8695,0x6b8b,0x60ed,0x60e8,0x707f,0x82cd,0x8231, 0x4ed3,0x6ca7,0x85cf,0x64cd,0x7cd9,0x69fd,0x66f9,0x8349,0x5395,0x7b56, 0x4fa7,0x518c,0x6d4b,0x5c42,0x8e6d,0x63d2,0x53c9,0x832c,0x8336,0x67e5, 0x78b4,0x643d,0x5bdf,0x5c94,0x5dee,0x8be7,0x62c6,0x67f4,0x8c7a,0x6400, 0x63ba,0x8749,0x998b,0x8c17,0x7f20,0x94f2,0x4ea7,0x9610,0x98a4,0x660c, 0x7316 }, { /* ku 33 */ 0x77e6,0x77e8,0x77ea,0x77ef,0x77f0,0x77f1,0x77f2,0x77f4,0x77f5,0x77f7, 0x77f9,0x77fa,0x77fb,0x77fc,0x7803,0x7804,0x7805,0x7806,0x7807,0x7808, 0x780a,0x780b,0x780e,0x780f,0x7810,0x7813,0x7815,0x7819,0x781b,0x781e, 0x7820,0x7821,0x7822,0x7824,0x7828,0x782a,0x782b,0x782e,0x782f,0x7831, 0x7832,0x7833,0x7835,0x7836,0x783d,0x783f,0x7841,0x7842,0x7843,0x7844, 0x7846,0x7848,0x7849,0x784a,0x784b,0x784d,0x784f,0x7851,0x7853,0x7854, 0x7858,0x7859,0x785a,UBOGON,0x785b,0x785c,0x785e,0x785f,0x7860,0x7861, 0x7862,0x7863,0x7864,0x7865,0x7866,0x7867,0x7868,0x7869,0x786f,0x7870, 0x7871,0x7872,0x7873,0x7874,0x7875,0x7876,0x7878,0x7879,0x787a,0x787b, 0x787d,0x787e,0x787f,0x7880,0x7881,0x7882,0x7883,0x573a,0x5c1d,0x5e38, 0x957f,0x507f,0x80a0,0x5382,0x655e,0x7545,0x5531,0x5021,0x8d85,0x6284, 0x949e,0x671d,0x5632,0x6f6e,0x5de2,0x5435,0x7092,0x8f66,0x626f,0x64a4, 0x63a3,0x5f7b,0x6f88,0x90f4,0x81e3,0x8fb0,0x5c18,0x6668,0x5ff1,0x6c89, 0x9648,0x8d81,0x886c,0x6491,0x79f0,0x57ce,0x6a59,0x6210,0x5448,0x4e58, 0x7a0b,0x60e9,0x6f84,0x8bda,0x627f,0x901e,0x9a8b,0x79e4,0x5403,0x75f4, 0x6301,0x5319,0x6c60,0x8fdf,0x5f1b,0x9a70,0x803b,0x9f7f,0x4f88,0x5c3a, 0x8d64,0x7fc5,0x65a5,0x70bd,0x5145,0x51b2,0x866b,0x5d07,0x5ba0,0x62bd, 0x916c,0x7574,0x8e0c,0x7a20,0x6101,0x7b79,0x4ec7,0x7ef8,0x7785,0x4e11, 0x81ed,0x521d,0x51fa,0x6a71,0x53a8,0x8e87,0x9504,0x96cf,0x6ec1,0x9664, 0x695a }, { /* ku 34 */ 0x7884,0x7885,0x7886,0x7888,0x788a,0x788b,0x788f,0x7890,0x7892,0x7894, 0x7895,0x7896,0x7899,0x789d,0x789e,0x78a0,0x78a2,0x78a4,0x78a6,0x78a8, 0x78a9,0x78aa,0x78ab,0x78ac,0x78ad,0x78ae,0x78af,0x78b5,0x78b6,0x78b7, 0x78b8,0x78ba,0x78bb,0x78bc,0x78bd,0x78bf,0x78c0,0x78c2,0x78c3,0x78c4, 0x78c6,0x78c7,0x78c8,0x78cc,0x78cd,0x78ce,0x78cf,0x78d1,0x78d2,0x78d3, 0x78d6,0x78d7,0x78d8,0x78da,0x78db,0x78dc,0x78dd,0x78de,0x78df,0x78e0, 0x78e1,0x78e2,0x78e3,UBOGON,0x78e4,0x78e5,0x78e6,0x78e7,0x78e9,0x78ea, 0x78eb,0x78ed,0x78ee,0x78ef,0x78f0,0x78f1,0x78f3,0x78f5,0x78f6,0x78f8, 0x78f9,0x78fb,0x78fc,0x78fd,0x78fe,0x78ff,0x7900,0x7902,0x7903,0x7904, 0x7906,0x7907,0x7908,0x7909,0x790a,0x790b,0x790c,0x7840,0x50a8,0x77d7, 0x6410,0x89e6,0x5904,0x63e3,0x5ddd,0x7a7f,0x693d,0x4f20,0x8239,0x5598, 0x4e32,0x75ae,0x7a97,0x5e62,0x5e8a,0x95ef,0x521b,0x5439,0x708a,0x6376, 0x9524,0x5782,0x6625,0x693f,0x9187,0x5507,0x6df3,0x7eaf,0x8822,0x6233, 0x7ef0,0x75b5,0x8328,0x78c1,0x96cc,0x8f9e,0x6148,0x74f7,0x8bcd,0x6b64, 0x523a,0x8d50,0x6b21,0x806a,0x8471,0x56f1,0x5306,0x4ece,0x4e1b,0x51d1, 0x7c97,0x918b,0x7c07,0x4fc3,0x8e7f,0x7be1,0x7a9c,0x6467,0x5d14,0x50ac, 0x8106,0x7601,0x7cb9,0x6dec,0x7fe0,0x6751,0x5b58,0x5bf8,0x78cb,0x64ae, 0x6413,0x63aa,0x632b,0x9519,0x642d,0x8fbe,0x7b54,0x7629,0x6253,0x5927, 0x5446,0x6b79,0x50a3,0x6234,0x5e26,0x6b86,0x4ee3,0x8d37,0x888b,0x5f85, 0x902e }, { /* ku 35 */ 0x790d,0x790e,0x790f,0x7910,0x7911,0x7912,0x7914,0x7915,0x7916,0x7917, 0x7918,0x7919,0x791a,0x791b,0x791c,0x791d,0x791f,0x7920,0x7921,0x7922, 0x7923,0x7925,0x7926,0x7927,0x7928,0x7929,0x792a,0x792b,0x792c,0x792d, 0x792e,0x792f,0x7930,0x7931,0x7932,0x7933,0x7935,0x7936,0x7937,0x7938, 0x7939,0x793d,0x793f,0x7942,0x7943,0x7944,0x7945,0x7947,0x794a,0x794b, 0x794c,0x794d,0x794e,0x794f,0x7950,0x7951,0x7952,0x7954,0x7955,0x7958, 0x7959,0x7961,0x7963,UBOGON,0x7964,0x7966,0x7969,0x796a,0x796b,0x796c, 0x796e,0x7970,0x7971,0x7972,0x7973,0x7974,0x7975,0x7976,0x7979,0x797b, 0x797c,0x797d,0x797e,0x797f,0x7982,0x7983,0x7986,0x7987,0x7988,0x7989, 0x798b,0x798c,0x798d,0x798e,0x7990,0x7991,0x7992,0x6020,0x803d,0x62c5, 0x4e39,0x5355,0x90f8,0x63b8,0x80c6,0x65e6,0x6c2e,0x4f46,0x60ee,0x6de1, 0x8bde,0x5f39,0x86cb,0x5f53,0x6321,0x515a,0x8361,0x6863,0x5200,0x6363, 0x8e48,0x5012,0x5c9b,0x7977,0x5bfc,0x5230,0x7a3b,0x60bc,0x9053,0x76d7, 0x5fb7,0x5f97,0x7684,0x8e6c,0x706f,0x767b,0x7b49,0x77aa,0x51f3,0x9093, 0x5824,0x4f4e,0x6ef4,0x8fea,0x654c,0x7b1b,0x72c4,0x6da4,0x7fdf,0x5ae1, 0x62b5,0x5e95,0x5730,0x8482,0x7b2c,0x5e1d,0x5f1f,0x9012,0x7f14,0x98a0, 0x6382,0x6ec7,0x7898,0x70b9,0x5178,0x975b,0x57ab,0x7535,0x4f43,0x7538, 0x5e97,0x60e6,0x5960,0x6dc0,0x6bbf,0x7889,0x53fc,0x96d5,0x51cb,0x5201, 0x6389,0x540a,0x9493,0x8c03,0x8dcc,0x7239,0x789f,0x8776,0x8fed,0x8c0d, 0x53e0 }, { /* ku 36 */ 0x7993,0x7994,0x7995,0x7996,0x7997,0x7998,0x7999,0x799b,0x799c,0x799d, 0x799e,0x799f,0x79a0,0x79a1,0x79a2,0x79a3,0x79a4,0x79a5,0x79a6,0x79a8, 0x79a9,0x79aa,0x79ab,0x79ac,0x79ad,0x79ae,0x79af,0x79b0,0x79b1,0x79b2, 0x79b4,0x79b5,0x79b6,0x79b7,0x79b8,0x79bc,0x79bf,0x79c2,0x79c4,0x79c5, 0x79c7,0x79c8,0x79ca,0x79cc,0x79ce,0x79cf,0x79d0,0x79d3,0x79d4,0x79d6, 0x79d7,0x79d9,0x79da,0x79db,0x79dc,0x79dd,0x79de,0x79e0,0x79e1,0x79e2, 0x79e5,0x79e8,0x79ea,UBOGON,0x79ec,0x79ee,0x79f1,0x79f2,0x79f3,0x79f4, 0x79f5,0x79f6,0x79f7,0x79f9,0x79fa,0x79fc,0x79fe,0x79ff,0x7a01,0x7a04, 0x7a05,0x7a07,0x7a08,0x7a09,0x7a0a,0x7a0c,0x7a0f,0x7a10,0x7a11,0x7a12, 0x7a13,0x7a15,0x7a16,0x7a18,0x7a19,0x7a1b,0x7a1c,0x4e01,0x76ef,0x53ee, 0x9489,0x9876,0x9f0e,0x952d,0x5b9a,0x8ba2,0x4e22,0x4e1c,0x51ac,0x8463, 0x61c2,0x52a8,0x680b,0x4f97,0x606b,0x51bb,0x6d1e,0x515c,0x6296,0x6597, 0x9661,0x8c46,0x9017,0x75d8,0x90fd,0x7763,0x6bd2,0x728a,0x72ec,0x8bfb, 0x5835,0x7779,0x8d4c,0x675c,0x9540,0x809a,0x5ea6,0x6e21,0x5992,0x7aef, 0x77ed,0x953b,0x6bb5,0x65ad,0x7f0e,0x5806,0x5151,0x961f,0x5bf9,0x58a9, 0x5428,0x8e72,0x6566,0x987f,0x56e4,0x949d,0x76fe,0x9041,0x6387,0x54c6, 0x591a,0x593a,0x579b,0x8eb2,0x6735,0x8dfa,0x8235,0x5241,0x60f0,0x5815, 0x86fe,0x5ce8,0x9e45,0x4fc4,0x989d,0x8bb9,0x5a25,0x6076,0x5384,0x627c, 0x904f,0x9102,0x997f,0x6069,0x800c,0x513f,0x8033,0x5c14,0x9975,0x6d31, 0x4e8c }, { /* ku 37 */ 0x7a1d,0x7a1f,0x7a21,0x7a22,0x7a24,0x7a25,0x7a26,0x7a27,0x7a28,0x7a29, 0x7a2a,0x7a2b,0x7a2c,0x7a2d,0x7a2e,0x7a2f,0x7a30,0x7a31,0x7a32,0x7a34, 0x7a35,0x7a36,0x7a38,0x7a3a,0x7a3e,0x7a40,0x7a41,0x7a42,0x7a43,0x7a44, 0x7a45,0x7a47,0x7a48,0x7a49,0x7a4a,0x7a4b,0x7a4c,0x7a4d,0x7a4e,0x7a4f, 0x7a50,0x7a52,0x7a53,0x7a54,0x7a55,0x7a56,0x7a58,0x7a59,0x7a5a,0x7a5b, 0x7a5c,0x7a5d,0x7a5e,0x7a5f,0x7a60,0x7a61,0x7a62,0x7a63,0x7a64,0x7a65, 0x7a66,0x7a67,0x7a68,UBOGON,0x7a69,0x7a6a,0x7a6b,0x7a6c,0x7a6d,0x7a6e, 0x7a6f,0x7a71,0x7a72,0x7a73,0x7a75,0x7a7b,0x7a7c,0x7a7d,0x7a7e,0x7a82, 0x7a85,0x7a87,0x7a89,0x7a8a,0x7a8b,0x7a8c,0x7a8e,0x7a8f,0x7a90,0x7a93, 0x7a94,0x7a99,0x7a9a,0x7a9b,0x7a9e,0x7aa1,0x7aa2,0x8d30,0x53d1,0x7f5a, 0x7b4f,0x4f10,0x4e4f,0x9600,0x6cd5,0x73d0,0x85e9,0x5e06,0x756a,0x7ffb, 0x6a0a,0x77fe,0x9492,0x7e41,0x51e1,0x70e6,0x53cd,0x8fd4,0x8303,0x8d29, 0x72af,0x996d,0x6cdb,0x574a,0x82b3,0x65b9,0x80aa,0x623f,0x9632,0x59a8, 0x4eff,0x8bbf,0x7eba,0x653e,0x83f2,0x975e,0x5561,0x98de,0x80a5,0x532a, 0x8bfd,0x5420,0x80ba,0x5e9f,0x6cb8,0x8d39,0x82ac,0x915a,0x5429,0x6c1b, 0x5206,0x7eb7,0x575f,0x711a,0x6c7e,0x7c89,0x594b,0x4efd,0x5fff,0x6124, 0x7caa,0x4e30,0x5c01,0x67ab,0x8702,0x5cf0,0x950b,0x98ce,0x75af,0x70fd, 0x9022,0x51af,0x7f1d,0x8bbd,0x5949,0x51e4,0x4f5b,0x5426,0x592b,0x6577, 0x80a4,0x5b75,0x6276,0x62c2,0x8f90,0x5e45,0x6c1f,0x7b26,0x4f0f,0x4fd8, 0x670d }, { /* ku 38 */ 0x7aa3,0x7aa4,0x7aa7,0x7aa9,0x7aaa,0x7aab,0x7aae,0x7aaf,0x7ab0,0x7ab1, 0x7ab2,0x7ab4,0x7ab5,0x7ab6,0x7ab7,0x7ab8,0x7ab9,0x7aba,0x7abb,0x7abc, 0x7abd,0x7abe,0x7ac0,0x7ac1,0x7ac2,0x7ac3,0x7ac4,0x7ac5,0x7ac6,0x7ac7, 0x7ac8,0x7ac9,0x7aca,0x7acc,0x7acd,0x7ace,0x7acf,0x7ad0,0x7ad1,0x7ad2, 0x7ad3,0x7ad4,0x7ad5,0x7ad7,0x7ad8,0x7ada,0x7adb,0x7adc,0x7add,0x7ae1, 0x7ae2,0x7ae4,0x7ae7,0x7ae8,0x7ae9,0x7aea,0x7aeb,0x7aec,0x7aee,0x7af0, 0x7af1,0x7af2,0x7af3,UBOGON,0x7af4,0x7af5,0x7af6,0x7af7,0x7af8,0x7afb, 0x7afc,0x7afe,0x7b00,0x7b01,0x7b02,0x7b05,0x7b07,0x7b09,0x7b0c,0x7b0d, 0x7b0e,0x7b10,0x7b12,0x7b13,0x7b16,0x7b17,0x7b18,0x7b1a,0x7b1c,0x7b1d, 0x7b1f,0x7b21,0x7b22,0x7b23,0x7b27,0x7b29,0x7b2d,0x6d6e,0x6daa,0x798f, 0x88b1,0x5f17,0x752b,0x629a,0x8f85,0x4fef,0x91dc,0x65a7,0x812f,0x8151, 0x5e9c,0x8150,0x8d74,0x526f,0x8986,0x8d4b,0x590d,0x5085,0x4ed8,0x961c, 0x7236,0x8179,0x8d1f,0x5bcc,0x8ba3,0x9644,0x5987,0x7f1a,0x5490,0x5676, 0x560e,0x8be5,0x6539,0x6982,0x9499,0x76d6,0x6e89,0x5e72,0x7518,0x6746, 0x67d1,0x7aff,0x809d,0x8d76,0x611f,0x79c6,0x6562,0x8d63,0x5188,0x521a, 0x94a2,0x7f38,0x809b,0x7eb2,0x5c97,0x6e2f,0x6760,0x7bd9,0x768b,0x9ad8, 0x818f,0x7f94,0x7cd5,0x641e,0x9550,0x7a3f,0x544a,0x54e5,0x6b4c,0x6401, 0x6208,0x9e3d,0x80f3,0x7599,0x5272,0x9769,0x845b,0x683c,0x86e4,0x9601, 0x9694,0x94ec,0x4e2a,0x5404,0x7ed9,0x6839,0x8ddf,0x8015,0x66f4,0x5e9a, 0x7fb9 }, { /* ku 39 */ 0x7b2f,0x7b30,0x7b32,0x7b34,0x7b35,0x7b36,0x7b37,0x7b39,0x7b3b,0x7b3d, 0x7b3f,0x7b40,0x7b41,0x7b42,0x7b43,0x7b44,0x7b46,0x7b48,0x7b4a,0x7b4d, 0x7b4e,0x7b53,0x7b55,0x7b57,0x7b59,0x7b5c,0x7b5e,0x7b5f,0x7b61,0x7b63, 0x7b64,0x7b65,0x7b66,0x7b67,0x7b68,0x7b69,0x7b6a,0x7b6b,0x7b6c,0x7b6d, 0x7b6f,0x7b70,0x7b73,0x7b74,0x7b76,0x7b78,0x7b7a,0x7b7c,0x7b7d,0x7b7f, 0x7b81,0x7b82,0x7b83,0x7b84,0x7b86,0x7b87,0x7b88,0x7b89,0x7b8a,0x7b8b, 0x7b8c,0x7b8e,0x7b8f,UBOGON,0x7b91,0x7b92,0x7b93,0x7b96,0x7b98,0x7b99, 0x7b9a,0x7b9b,0x7b9e,0x7b9f,0x7ba0,0x7ba3,0x7ba4,0x7ba5,0x7bae,0x7baf, 0x7bb0,0x7bb2,0x7bb3,0x7bb5,0x7bb6,0x7bb7,0x7bb9,0x7bba,0x7bbb,0x7bbc, 0x7bbd,0x7bbe,0x7bbf,0x7bc0,0x7bc2,0x7bc3,0x7bc4,0x57c2,0x803f,0x6897, 0x5de5,0x653b,0x529f,0x606d,0x9f9a,0x4f9b,0x8eac,0x516c,0x5bab,0x5f13, 0x5de9,0x6c5e,0x62f1,0x8d21,0x5171,0x94a9,0x52fe,0x6c9f,0x82df,0x72d7, 0x57a2,0x6784,0x8d2d,0x591f,0x8f9c,0x83c7,0x5495,0x7b8d,0x4f30,0x6cbd, 0x5b64,0x59d1,0x9f13,0x53e4,0x86ca,0x9aa8,0x8c37,0x80a1,0x6545,0x987e, 0x56fa,0x96c7,0x522e,0x74dc,0x5250,0x5be1,0x6302,0x8902,0x4e56,0x62d0, 0x602a,0x68fa,0x5173,0x5b98,0x51a0,0x89c2,0x7ba1,0x9986,0x7f50,0x60ef, 0x704c,0x8d2f,0x5149,0x5e7f,0x901b,0x7470,0x89c4,0x572d,0x7845,0x5f52, 0x9f9f,0x95fa,0x8f68,0x9b3c,0x8be1,0x7678,0x6842,0x67dc,0x8dea,0x8d35, 0x523d,0x8f8a,0x6eda,0x68cd,0x9505,0x90ed,0x56fd,0x679c,0x88f9,0x8fc7, 0x54c8 }, { /* ku 3a */ 0x7bc5,0x7bc8,0x7bc9,0x7bca,0x7bcb,0x7bcd,0x7bce,0x7bcf,0x7bd0,0x7bd2, 0x7bd4,0x7bd5,0x7bd6,0x7bd7,0x7bd8,0x7bdb,0x7bdc,0x7bde,0x7bdf,0x7be0, 0x7be2,0x7be3,0x7be4,0x7be7,0x7be8,0x7be9,0x7beb,0x7bec,0x7bed,0x7bef, 0x7bf0,0x7bf2,0x7bf3,0x7bf4,0x7bf5,0x7bf6,0x7bf8,0x7bf9,0x7bfa,0x7bfb, 0x7bfd,0x7bff,0x7c00,0x7c01,0x7c02,0x7c03,0x7c04,0x7c05,0x7c06,0x7c08, 0x7c09,0x7c0a,0x7c0d,0x7c0e,0x7c10,0x7c11,0x7c12,0x7c13,0x7c14,0x7c15, 0x7c17,0x7c18,0x7c19,UBOGON,0x7c1a,0x7c1b,0x7c1c,0x7c1d,0x7c1e,0x7c20, 0x7c21,0x7c22,0x7c23,0x7c24,0x7c25,0x7c28,0x7c29,0x7c2b,0x7c2c,0x7c2d, 0x7c2e,0x7c2f,0x7c30,0x7c31,0x7c32,0x7c33,0x7c34,0x7c35,0x7c36,0x7c37, 0x7c39,0x7c3a,0x7c3b,0x7c3c,0x7c3d,0x7c3e,0x7c42,0x9ab8,0x5b69,0x6d77, 0x6c26,0x4ea5,0x5bb3,0x9a87,0x9163,0x61a8,0x90af,0x97e9,0x542b,0x6db5, 0x5bd2,0x51fd,0x558a,0x7f55,0x7ff0,0x64bc,0x634d,0x65f1,0x61be,0x608d, 0x710a,0x6c57,0x6c49,0x592f,0x676d,0x822a,0x58d5,0x568e,0x8c6a,0x6beb, 0x90dd,0x597d,0x8017,0x53f7,0x6d69,0x5475,0x559d,0x8377,0x83cf,0x6838, 0x79be,0x548c,0x4f55,0x5408,0x76d2,0x8c89,0x9602,0x6cb3,0x6db8,0x8d6b, 0x8910,0x9e64,0x8d3a,0x563f,0x9ed1,0x75d5,0x5f88,0x72e0,0x6068,0x54fc, 0x4ea8,0x6a2a,0x8861,0x6052,0x8f70,0x54c4,0x70d8,0x8679,0x9e3f,0x6d2a, 0x5b8f,0x5f18,0x7ea2,0x5589,0x4faf,0x7334,0x543c,0x539a,0x5019,0x540e, 0x547c,0x4e4e,0x5ffd,0x745a,0x58f6,0x846b,0x80e1,0x8774,0x72d0,0x7cca, 0x6e56 }, { /* ku 3b */ 0x7c43,0x7c44,0x7c45,0x7c46,0x7c47,0x7c48,0x7c49,0x7c4a,0x7c4b,0x7c4c, 0x7c4e,0x7c4f,0x7c50,0x7c51,0x7c52,0x7c53,0x7c54,0x7c55,0x7c56,0x7c57, 0x7c58,0x7c59,0x7c5a,0x7c5b,0x7c5c,0x7c5d,0x7c5e,0x7c5f,0x7c60,0x7c61, 0x7c62,0x7c63,0x7c64,0x7c65,0x7c66,0x7c67,0x7c68,0x7c69,0x7c6a,0x7c6b, 0x7c6c,0x7c6d,0x7c6e,0x7c6f,0x7c70,0x7c71,0x7c72,0x7c75,0x7c76,0x7c77, 0x7c78,0x7c79,0x7c7a,0x7c7e,0x7c7f,0x7c80,0x7c81,0x7c82,0x7c83,0x7c84, 0x7c85,0x7c86,0x7c87,UBOGON,0x7c88,0x7c8a,0x7c8b,0x7c8c,0x7c8d,0x7c8e, 0x7c8f,0x7c90,0x7c93,0x7c94,0x7c96,0x7c99,0x7c9a,0x7c9b,0x7ca0,0x7ca1, 0x7ca3,0x7ca6,0x7ca7,0x7ca8,0x7ca9,0x7cab,0x7cac,0x7cad,0x7caf,0x7cb0, 0x7cb4,0x7cb5,0x7cb6,0x7cb7,0x7cb8,0x7cba,0x7cbb,0x5f27,0x864e,0x552c, 0x62a4,0x4e92,0x6caa,0x6237,0x82b1,0x54d7,0x534e,0x733e,0x6ed1,0x753b, 0x5212,0x5316,0x8bdd,0x69d0,0x5f8a,0x6000,0x6dee,0x574f,0x6b22,0x73af, 0x6853,0x8fd8,0x7f13,0x6362,0x60a3,0x5524,0x75ea,0x8c62,0x7115,0x6da3, 0x5ba6,0x5e7b,0x8352,0x614c,0x9ec4,0x78fa,0x8757,0x7c27,0x7687,0x51f0, 0x60f6,0x714c,0x6643,0x5e4c,0x604d,0x8c0e,0x7070,0x6325,0x8f89,0x5fbd, 0x6062,0x86d4,0x56de,0x6bc1,0x6094,0x6167,0x5349,0x60e0,0x6666,0x8d3f, 0x79fd,0x4f1a,0x70e9,0x6c47,0x8bb3,0x8bf2,0x7ed8,0x8364,0x660f,0x5a5a, 0x9b42,0x6d51,0x6df7,0x8c41,0x6d3b,0x4f19,0x706b,0x83b7,0x6216,0x60d1, 0x970d,0x8d27,0x7978,0x51fb,0x573e,0x57fa,0x673a,0x7578,0x7a3d,0x79ef, 0x7b95 }, { /* ku 3c */ 0x7cbf,0x7cc0,0x7cc2,0x7cc3,0x7cc4,0x7cc6,0x7cc9,0x7ccb,0x7cce,0x7ccf, 0x7cd0,0x7cd1,0x7cd2,0x7cd3,0x7cd4,0x7cd8,0x7cda,0x7cdb,0x7cdd,0x7cde, 0x7ce1,0x7ce2,0x7ce3,0x7ce4,0x7ce5,0x7ce6,0x7ce7,0x7ce9,0x7cea,0x7ceb, 0x7cec,0x7ced,0x7cee,0x7cf0,0x7cf1,0x7cf2,0x7cf3,0x7cf4,0x7cf5,0x7cf6, 0x7cf7,0x7cf9,0x7cfa,0x7cfc,0x7cfd,0x7cfe,0x7cff,0x7d00,0x7d01,0x7d02, 0x7d03,0x7d04,0x7d05,0x7d06,0x7d07,0x7d08,0x7d09,0x7d0b,0x7d0c,0x7d0d, 0x7d0e,0x7d0f,0x7d10,UBOGON,0x7d11,0x7d12,0x7d13,0x7d14,0x7d15,0x7d16, 0x7d17,0x7d18,0x7d19,0x7d1a,0x7d1b,0x7d1c,0x7d1d,0x7d1e,0x7d1f,0x7d21, 0x7d23,0x7d24,0x7d25,0x7d26,0x7d28,0x7d29,0x7d2a,0x7d2c,0x7d2d,0x7d2e, 0x7d30,0x7d31,0x7d32,0x7d33,0x7d34,0x7d35,0x7d36,0x808c,0x9965,0x8ff9, 0x6fc0,0x8ba5,0x9e21,0x59ec,0x7ee9,0x7f09,0x5409,0x6781,0x68d8,0x8f91, 0x7c4d,0x96c6,0x53ca,0x6025,0x75be,0x6c72,0x5373,0x5ac9,0x7ea7,0x6324, 0x51e0,0x810a,0x5df1,0x84df,0x6280,0x5180,0x5b63,0x4f0e,0x796d,0x5242, 0x60b8,0x6d4e,0x5bc4,0x5bc2,0x8ba1,0x8bb0,0x65e2,0x5fcc,0x9645,0x5993, 0x7ee7,0x7eaa,0x5609,0x67b7,0x5939,0x4f73,0x5bb6,0x52a0,0x835a,0x988a, 0x8d3e,0x7532,0x94be,0x5047,0x7a3c,0x4ef7,0x67b6,0x9a7e,0x5ac1,0x6b7c, 0x76d1,0x575a,0x5c16,0x7b3a,0x95f4,0x714e,0x517c,0x80a9,0x8270,0x5978, 0x7f04,0x8327,0x68c0,0x67ec,0x78b1,0x7877,0x62e3,0x6361,0x7b80,0x4fed, 0x526a,0x51cf,0x8350,0x69db,0x9274,0x8df5,0x8d31,0x89c1,0x952e,0x7bad, 0x4ef6 }, { /* ku 3d */ 0x7d37,0x7d38,0x7d39,0x7d3a,0x7d3b,0x7d3c,0x7d3d,0x7d3e,0x7d3f,0x7d40, 0x7d41,0x7d42,0x7d43,0x7d44,0x7d45,0x7d46,0x7d47,0x7d48,0x7d49,0x7d4a, 0x7d4b,0x7d4c,0x7d4d,0x7d4e,0x7d4f,0x7d50,0x7d51,0x7d52,0x7d53,0x7d54, 0x7d55,0x7d56,0x7d57,0x7d58,0x7d59,0x7d5a,0x7d5b,0x7d5c,0x7d5d,0x7d5e, 0x7d5f,0x7d60,0x7d61,0x7d62,0x7d63,0x7d64,0x7d65,0x7d66,0x7d67,0x7d68, 0x7d69,0x7d6a,0x7d6b,0x7d6c,0x7d6d,0x7d6f,0x7d70,0x7d71,0x7d72,0x7d73, 0x7d74,0x7d75,0x7d76,UBOGON,0x7d78,0x7d79,0x7d7a,0x7d7b,0x7d7c,0x7d7d, 0x7d7e,0x7d7f,0x7d80,0x7d81,0x7d82,0x7d83,0x7d84,0x7d85,0x7d86,0x7d87, 0x7d88,0x7d89,0x7d8a,0x7d8b,0x7d8c,0x7d8d,0x7d8e,0x7d8f,0x7d90,0x7d91, 0x7d92,0x7d93,0x7d94,0x7d95,0x7d96,0x7d97,0x7d98,0x5065,0x8230,0x5251, 0x996f,0x6e10,0x6e85,0x6da7,0x5efa,0x50f5,0x59dc,0x5c06,0x6d46,0x6c5f, 0x7586,0x848b,0x6868,0x5956,0x8bb2,0x5320,0x9171,0x964d,0x8549,0x6912, 0x7901,0x7126,0x80f6,0x4ea4,0x90ca,0x6d47,0x9a84,0x5a07,0x56bc,0x6405, 0x94f0,0x77eb,0x4fa5,0x811a,0x72e1,0x89d2,0x997a,0x7f34,0x7ede,0x527f, 0x6559,0x9175,0x8f7f,0x8f83,0x53eb,0x7a96,0x63ed,0x63a5,0x7686,0x79f8, 0x8857,0x9636,0x622a,0x52ab,0x8282,0x6854,0x6770,0x6377,0x776b,0x7aed, 0x6d01,0x7ed3,0x89e3,0x59d0,0x6212,0x85c9,0x82a5,0x754c,0x501f,0x4ecb, 0x75a5,0x8beb,0x5c4a,0x5dfe,0x7b4b,0x65a4,0x91d1,0x4eca,0x6d25,0x895f, 0x7d27,0x9526,0x4ec5,0x8c28,0x8fdb,0x9773,0x664b,0x7981,0x8fd1,0x70ec, 0x6d78 }, { /* ku 3e */ 0x7d99,0x7d9a,0x7d9b,0x7d9c,0x7d9d,0x7d9e,0x7d9f,0x7da0,0x7da1,0x7da2, 0x7da3,0x7da4,0x7da5,0x7da7,0x7da8,0x7da9,0x7daa,0x7dab,0x7dac,0x7dad, 0x7daf,0x7db0,0x7db1,0x7db2,0x7db3,0x7db4,0x7db5,0x7db6,0x7db7,0x7db8, 0x7db9,0x7dba,0x7dbb,0x7dbc,0x7dbd,0x7dbe,0x7dbf,0x7dc0,0x7dc1,0x7dc2, 0x7dc3,0x7dc4,0x7dc5,0x7dc6,0x7dc7,0x7dc8,0x7dc9,0x7dca,0x7dcb,0x7dcc, 0x7dcd,0x7dce,0x7dcf,0x7dd0,0x7dd1,0x7dd2,0x7dd3,0x7dd4,0x7dd5,0x7dd6, 0x7dd7,0x7dd8,0x7dd9,UBOGON,0x7dda,0x7ddb,0x7ddc,0x7ddd,0x7dde,0x7ddf, 0x7de0,0x7de1,0x7de2,0x7de3,0x7de4,0x7de5,0x7de6,0x7de7,0x7de8,0x7de9, 0x7dea,0x7deb,0x7dec,0x7ded,0x7dee,0x7def,0x7df0,0x7df1,0x7df2,0x7df3, 0x7df4,0x7df5,0x7df6,0x7df7,0x7df8,0x7df9,0x7dfa,0x5c3d,0x52b2,0x8346, 0x5162,0x830e,0x775b,0x6676,0x9cb8,0x4eac,0x60ca,0x7cbe,0x7cb3,0x7ecf, 0x4e95,0x8b66,0x666f,0x9888,0x9759,0x5883,0x656c,0x955c,0x5f84,0x75c9, 0x9756,0x7adf,0x7ade,0x51c0,0x70af,0x7a98,0x63ea,0x7a76,0x7ea0,0x7396, 0x97ed,0x4e45,0x7078,0x4e5d,0x9152,0x53a9,0x6551,0x65e7,0x81fc,0x8205, 0x548e,0x5c31,0x759a,0x97a0,0x62d8,0x72d9,0x75bd,0x5c45,0x9a79,0x83ca, 0x5c40,0x5480,0x77e9,0x4e3e,0x6cae,0x805a,0x62d2,0x636e,0x5de8,0x5177, 0x8ddd,0x8e1e,0x952f,0x4ff1,0x53e5,0x60e7,0x70ac,0x5267,0x6350,0x9e43, 0x5a1f,0x5026,0x7737,0x5377,0x7ee2,0x6485,0x652b,0x6289,0x6398,0x5014, 0x7235,0x89c9,0x51b3,0x8bc0,0x7edd,0x5747,0x83cc,0x94a7,0x519b,0x541b, 0x5cfb }, { /* ku 3f */ 0x7dfb,0x7dfc,0x7dfd,0x7dfe,0x7dff,0x7e00,0x7e01,0x7e02,0x7e03,0x7e04, 0x7e05,0x7e06,0x7e07,0x7e08,0x7e09,0x7e0a,0x7e0b,0x7e0c,0x7e0d,0x7e0e, 0x7e0f,0x7e10,0x7e11,0x7e12,0x7e13,0x7e14,0x7e15,0x7e16,0x7e17,0x7e18, 0x7e19,0x7e1a,0x7e1b,0x7e1c,0x7e1d,0x7e1e,0x7e1f,0x7e20,0x7e21,0x7e22, 0x7e23,0x7e24,0x7e25,0x7e26,0x7e27,0x7e28,0x7e29,0x7e2a,0x7e2b,0x7e2c, 0x7e2d,0x7e2e,0x7e2f,0x7e30,0x7e31,0x7e32,0x7e33,0x7e34,0x7e35,0x7e36, 0x7e37,0x7e38,0x7e39,UBOGON,0x7e3a,0x7e3c,0x7e3d,0x7e3e,0x7e3f,0x7e40, 0x7e42,0x7e43,0x7e44,0x7e45,0x7e46,0x7e48,0x7e49,0x7e4a,0x7e4b,0x7e4c, 0x7e4d,0x7e4e,0x7e4f,0x7e50,0x7e51,0x7e52,0x7e53,0x7e54,0x7e55,0x7e56, 0x7e57,0x7e58,0x7e59,0x7e5a,0x7e5b,0x7e5c,0x7e5d,0x4fca,0x7ae3,0x6d5a, 0x90e1,0x9a8f,0x5580,0x5496,0x5361,0x54af,0x5f00,0x63e9,0x6977,0x51ef, 0x6168,0x520a,0x582a,0x52d8,0x574e,0x780d,0x770b,0x5eb7,0x6177,0x7ce0, 0x625b,0x6297,0x4ea2,0x7095,0x8003,0x62f7,0x70e4,0x9760,0x5777,0x82db, 0x67ef,0x68f5,0x78d5,0x9897,0x79d1,0x58f3,0x54b3,0x53ef,0x6e34,0x514b, 0x523b,0x5ba2,0x8bfe,0x80af,0x5543,0x57a6,0x6073,0x5751,0x542d,0x7a7a, 0x6050,0x5b54,0x63a7,0x62a0,0x53e3,0x6263,0x5bc7,0x67af,0x54ed,0x7a9f, 0x82e6,0x9177,0x5e93,0x88e4,0x5938,0x57ae,0x630e,0x8de8,0x80ef,0x5757, 0x7b77,0x4fa9,0x5feb,0x5bbd,0x6b3e,0x5321,0x7b50,0x72c2,0x6846,0x77ff, 0x7736,0x65f7,0x51b5,0x4e8f,0x76d4,0x5cbf,0x7aa5,0x8475,0x594e,0x9b41, 0x5080 }, { /* ku 40 */ 0x7e5e,0x7e5f,0x7e60,0x7e61,0x7e62,0x7e63,0x7e64,0x7e65,0x7e66,0x7e67, 0x7e68,0x7e69,0x7e6a,0x7e6b,0x7e6c,0x7e6d,0x7e6e,0x7e6f,0x7e70,0x7e71, 0x7e72,0x7e73,0x7e74,0x7e75,0x7e76,0x7e77,0x7e78,0x7e79,0x7e7a,0x7e7b, 0x7e7c,0x7e7d,0x7e7e,0x7e7f,0x7e80,0x7e81,0x7e83,0x7e84,0x7e85,0x7e86, 0x7e87,0x7e88,0x7e89,0x7e8a,0x7e8b,0x7e8c,0x7e8d,0x7e8e,0x7e8f,0x7e90, 0x7e91,0x7e92,0x7e93,0x7e94,0x7e95,0x7e96,0x7e97,0x7e98,0x7e99,0x7e9a, 0x7e9c,0x7e9d,0x7e9e,UBOGON,0x7eae,0x7eb4,0x7ebb,0x7ebc,0x7ed6,0x7ee4, 0x7eec,0x7ef9,0x7f0a,0x7f10,0x7f1e,0x7f37,0x7f39,0x7f3b,0x7f3c,0x7f3d, 0x7f3e,0x7f3f,0x7f40,0x7f41,0x7f43,0x7f46,0x7f47,0x7f48,0x7f49,0x7f4a, 0x7f4b,0x7f4c,0x7f4d,0x7f4e,0x7f4f,0x7f52,0x7f53,0x9988,0x6127,0x6e83, 0x5764,0x6606,0x6346,0x56f0,0x62ec,0x6269,0x5ed3,0x9614,0x5783,0x62c9, 0x5587,0x8721,0x814a,0x8fa3,0x5566,0x83b1,0x6765,0x8d56,0x84dd,0x5a6a, 0x680f,0x62e6,0x7bee,0x9611,0x5170,0x6f9c,0x8c30,0x63fd,0x89c8,0x61d2, 0x7f06,0x70c2,0x6ee5,0x7405,0x6994,0x72fc,0x5eca,0x90ce,0x6717,0x6d6a, 0x635e,0x52b3,0x7262,0x8001,0x4f6c,0x59e5,0x916a,0x70d9,0x6d9d,0x52d2, 0x4e50,0x96f7,0x956d,0x857e,0x78ca,0x7d2f,0x5121,0x5792,0x64c2,0x808b, 0x7c7b,0x6cea,0x68f1,0x695e,0x51b7,0x5398,0x68a8,0x7281,0x9ece,0x7bf1, 0x72f8,0x79bb,0x6f13,0x7406,0x674e,0x91cc,0x9ca4,0x793c,0x8389,0x8354, 0x540f,0x6817,0x4e3d,0x5389,0x52b1,0x783e,0x5386,0x5229,0x5088,0x4f8b, 0x4fd0 }, { /* ku 41 */ 0x7f56,0x7f59,0x7f5b,0x7f5c,0x7f5d,0x7f5e,0x7f60,0x7f63,0x7f64,0x7f65, 0x7f66,0x7f67,0x7f6b,0x7f6c,0x7f6d,0x7f6f,0x7f70,0x7f73,0x7f75,0x7f76, 0x7f77,0x7f78,0x7f7a,0x7f7b,0x7f7c,0x7f7d,0x7f7f,0x7f80,0x7f82,0x7f83, 0x7f84,0x7f85,0x7f86,0x7f87,0x7f88,0x7f89,0x7f8b,0x7f8d,0x7f8f,0x7f90, 0x7f91,0x7f92,0x7f93,0x7f95,0x7f96,0x7f97,0x7f98,0x7f99,0x7f9b,0x7f9c, 0x7fa0,0x7fa2,0x7fa3,0x7fa5,0x7fa6,0x7fa8,0x7fa9,0x7faa,0x7fab,0x7fac, 0x7fad,0x7fae,0x7fb1,UBOGON,0x7fb3,0x7fb4,0x7fb5,0x7fb6,0x7fb7,0x7fba, 0x7fbb,0x7fbe,0x7fc0,0x7fc2,0x7fc3,0x7fc4,0x7fc6,0x7fc7,0x7fc8,0x7fc9, 0x7fcb,0x7fcd,0x7fcf,0x7fd0,0x7fd1,0x7fd2,0x7fd3,0x7fd6,0x7fd7,0x7fd9, 0x7fda,0x7fdb,0x7fdc,0x7fdd,0x7fde,0x7fe2,0x7fe3,0x75e2,0x7acb,0x7c92, 0x6ca5,0x96b6,0x529b,0x7483,0x54e9,0x4fe9,0x8054,0x83b2,0x8fde,0x9570, 0x5ec9,0x601c,0x6d9f,0x5e18,0x655b,0x8138,0x94fe,0x604b,0x70bc,0x7ec3, 0x7cae,0x51c9,0x6881,0x7cb1,0x826f,0x4e24,0x8f86,0x91cf,0x667e,0x4eae, 0x8c05,0x64a9,0x804a,0x50da,0x7597,0x71ce,0x5be5,0x8fbd,0x6f66,0x4e86, 0x6482,0x9563,0x5ed6,0x6599,0x5217,0x88c2,0x70c8,0x52a3,0x730e,0x7433, 0x6797,0x78f7,0x9716,0x4e34,0x90bb,0x9cde,0x6dcb,0x51db,0x8d41,0x541d, 0x62ce,0x73b2,0x83f1,0x96f6,0x9f84,0x94c3,0x4f36,0x7f9a,0x51cc,0x7075, 0x9675,0x5cad,0x9886,0x53e6,0x4ee4,0x6e9c,0x7409,0x69b4,0x786b,0x998f, 0x7559,0x5218,0x7624,0x6d41,0x67f3,0x516d,0x9f99,0x804b,0x5499,0x7b3c, 0x7abf }, { /* ku 42 */ 0x7fe4,0x7fe7,0x7fe8,0x7fea,0x7feb,0x7fec,0x7fed,0x7fef,0x7ff2,0x7ff4, 0x7ff5,0x7ff6,0x7ff7,0x7ff8,0x7ff9,0x7ffa,0x7ffd,0x7ffe,0x7fff,0x8002, 0x8007,0x8008,0x8009,0x800a,0x800e,0x800f,0x8011,0x8013,0x801a,0x801b, 0x801d,0x801e,0x801f,0x8021,0x8023,0x8024,0x802b,0x802c,0x802d,0x802e, 0x802f,0x8030,0x8032,0x8034,0x8039,0x803a,0x803c,0x803e,0x8040,0x8041, 0x8044,0x8045,0x8047,0x8048,0x8049,0x804e,0x804f,0x8050,0x8051,0x8053, 0x8055,0x8056,0x8057,UBOGON,0x8059,0x805b,0x805c,0x805d,0x805e,0x805f, 0x8060,0x8061,0x8062,0x8063,0x8064,0x8065,0x8066,0x8067,0x8068,0x806b, 0x806c,0x806d,0x806e,0x806f,0x8070,0x8072,0x8073,0x8074,0x8075,0x8076, 0x8077,0x8078,0x8079,0x807a,0x807b,0x807c,0x807d,0x9686,0x5784,0x62e2, 0x9647,0x697c,0x5a04,0x6402,0x7bd3,0x6f0f,0x964b,0x82a6,0x5362,0x9885, 0x5e90,0x7089,0x63b3,0x5364,0x864f,0x9c81,0x9e93,0x788c,0x9732,0x8def, 0x8d42,0x9e7f,0x6f5e,0x7984,0x5f55,0x9646,0x622e,0x9a74,0x5415,0x94dd, 0x4fa3,0x65c5,0x5c65,0x5c61,0x7f15,0x8651,0x6c2f,0x5f8b,0x7387,0x6ee4, 0x7eff,0x5ce6,0x631b,0x5b6a,0x6ee6,0x5375,0x4e71,0x63a0,0x7565,0x62a1, 0x8f6e,0x4f26,0x4ed1,0x6ca6,0x7eb6,0x8bba,0x841d,0x87ba,0x7f57,0x903b, 0x9523,0x7ba9,0x9aa1,0x88f8,0x843d,0x6d1b,0x9a86,0x7edc,0x5988,0x9ebb, 0x739b,0x7801,0x8682,0x9a6c,0x9a82,0x561b,0x5417,0x57cb,0x4e70,0x9ea6, 0x5356,0x8fc8,0x8109,0x7792,0x9992,0x86ee,0x6ee1,0x8513,0x66fc,0x6162, 0x6f2b }, { /* ku 43 */ 0x807e,0x8081,0x8082,0x8085,0x8088,0x808a,0x808d,0x808e,0x808f,0x8090, 0x8091,0x8092,0x8094,0x8095,0x8097,0x8099,0x809e,0x80a3,0x80a6,0x80a7, 0x80a8,0x80ac,0x80b0,0x80b3,0x80b5,0x80b6,0x80b8,0x80b9,0x80bb,0x80c5, 0x80c7,0x80c8,0x80c9,0x80ca,0x80cb,0x80cf,0x80d0,0x80d1,0x80d2,0x80d3, 0x80d4,0x80d5,0x80d8,0x80df,0x80e0,0x80e2,0x80e3,0x80e6,0x80ee,0x80f5, 0x80f7,0x80f9,0x80fb,0x80fe,0x80ff,0x8100,0x8101,0x8103,0x8104,0x8105, 0x8107,0x8108,0x810b,UBOGON,0x810c,0x8115,0x8117,0x8119,0x811b,0x811c, 0x811d,0x811f,0x8120,0x8121,0x8122,0x8123,0x8124,0x8125,0x8126,0x8127, 0x8128,0x8129,0x812a,0x812b,0x812d,0x812e,0x8130,0x8133,0x8134,0x8135, 0x8137,0x8139,0x813a,0x813b,0x813c,0x813d,0x813f,0x8c29,0x8292,0x832b, 0x76f2,0x6c13,0x5fd9,0x83bd,0x732b,0x8305,0x951a,0x6bdb,0x77db,0x94c6, 0x536f,0x8302,0x5192,0x5e3d,0x8c8c,0x8d38,0x4e48,0x73ab,0x679a,0x6885, 0x9176,0x9709,0x7164,0x6ca1,0x7709,0x5a92,0x9541,0x6bcf,0x7f8e,0x6627, 0x5bd0,0x59b9,0x5a9a,0x95e8,0x95f7,0x4eec,0x840c,0x8499,0x6aac,0x76df, 0x9530,0x731b,0x68a6,0x5b5f,0x772f,0x919a,0x9761,0x7cdc,0x8ff7,0x8c1c, 0x5f25,0x7c73,0x79d8,0x89c5,0x6ccc,0x871c,0x5bc6,0x5e42,0x68c9,0x7720, 0x7ef5,0x5195,0x514d,0x52c9,0x5a29,0x7f05,0x9762,0x82d7,0x63cf,0x7784, 0x85d0,0x79d2,0x6e3a,0x5e99,0x5999,0x8511,0x706d,0x6c11,0x62bf,0x76bf, 0x654f,0x60af,0x95fd,0x660e,0x879f,0x9e23,0x94ed,0x540d,0x547d,0x8c2c, 0x6478 }, { /* ku 44 */ 0x8140,0x8141,0x8142,0x8143,0x8144,0x8145,0x8147,0x8149,0x814d,0x814e, 0x814f,0x8152,0x8156,0x8157,0x8158,0x815b,0x815c,0x815d,0x815e,0x815f, 0x8161,0x8162,0x8163,0x8164,0x8166,0x8168,0x816a,0x816b,0x816c,0x816f, 0x8172,0x8173,0x8175,0x8176,0x8177,0x8178,0x8181,0x8183,0x8184,0x8185, 0x8186,0x8187,0x8189,0x818b,0x818c,0x818d,0x818e,0x8190,0x8192,0x8193, 0x8194,0x8195,0x8196,0x8197,0x8199,0x819a,0x819e,0x819f,0x81a0,0x81a1, 0x81a2,0x81a4,0x81a5,UBOGON,0x81a7,0x81a9,0x81ab,0x81ac,0x81ad,0x81ae, 0x81af,0x81b0,0x81b1,0x81b2,0x81b4,0x81b5,0x81b6,0x81b7,0x81b8,0x81b9, 0x81bc,0x81bd,0x81be,0x81bf,0x81c4,0x81c5,0x81c7,0x81c8,0x81c9,0x81cb, 0x81cd,0x81ce,0x81cf,0x81d0,0x81d1,0x81d2,0x81d3,0x6479,0x8611,0x6a21, 0x819c,0x78e8,0x6469,0x9b54,0x62b9,0x672b,0x83ab,0x58a8,0x9ed8,0x6cab, 0x6f20,0x5bde,0x964c,0x8c0b,0x725f,0x67d0,0x62c7,0x7261,0x4ea9,0x59c6, 0x6bcd,0x5893,0x66ae,0x5e55,0x52df,0x6155,0x6728,0x76ee,0x7766,0x7267, 0x7a46,0x62ff,0x54ea,0x5450,0x94a0,0x90a3,0x5a1c,0x7eb3,0x6c16,0x4e43, 0x5976,0x8010,0x5948,0x5357,0x7537,0x96be,0x56ca,0x6320,0x8111,0x607c, 0x95f9,0x6dd6,0x5462,0x9981,0x5185,0x5ae9,0x80fd,0x59ae,0x9713,0x502a, 0x6ce5,0x5c3c,0x62df,0x4f60,0x533f,0x817b,0x9006,0x6eba,0x852b,0x62c8, 0x5e74,0x78be,0x64b5,0x637b,0x5ff5,0x5a18,0x917f,0x9e1f,0x5c3f,0x634f, 0x8042,0x5b7d,0x556e,0x954a,0x954d,0x6d85,0x60a8,0x67e0,0x72de,0x51dd, 0x5b81 }, { /* ku 45 */ 0x81d4,0x81d5,0x81d6,0x81d7,0x81d8,0x81d9,0x81da,0x81db,0x81dc,0x81dd, 0x81de,0x81df,0x81e0,0x81e1,0x81e2,0x81e4,0x81e5,0x81e6,0x81e8,0x81e9, 0x81eb,0x81ee,0x81ef,0x81f0,0x81f1,0x81f2,0x81f5,0x81f6,0x81f7,0x81f8, 0x81f9,0x81fa,0x81fd,0x81ff,0x8203,0x8207,0x8208,0x8209,0x820a,0x820b, 0x820e,0x820f,0x8211,0x8213,0x8215,0x8216,0x8217,0x8218,0x8219,0x821a, 0x821d,0x8220,0x8224,0x8225,0x8226,0x8227,0x8229,0x822e,0x8232,0x823a, 0x823c,0x823d,0x823f,UBOGON,0x8240,0x8241,0x8242,0x8243,0x8245,0x8246, 0x8248,0x824a,0x824c,0x824d,0x824e,0x8250,0x8251,0x8252,0x8253,0x8254, 0x8255,0x8256,0x8257,0x8259,0x825b,0x825c,0x825d,0x825e,0x8260,0x8261, 0x8262,0x8263,0x8264,0x8265,0x8266,0x8267,0x8269,0x62e7,0x6cde,0x725b, 0x626d,0x94ae,0x7ebd,0x8113,0x6d53,0x519c,0x5f04,0x5974,0x52aa,0x6012, 0x5973,0x6696,0x8650,0x759f,0x632a,0x61e6,0x7cef,0x8bfa,0x54e6,0x6b27, 0x9e25,0x6bb4,0x85d5,0x5455,0x5076,0x6ca4,0x556a,0x8db4,0x722c,0x5e15, 0x6015,0x7436,0x62cd,0x6392,0x724c,0x5f98,0x6e43,0x6d3e,0x6500,0x6f58, 0x76d8,0x78d0,0x76fc,0x7554,0x5224,0x53db,0x4e53,0x5e9e,0x65c1,0x802a, 0x80d6,0x629b,0x5486,0x5228,0x70ae,0x888d,0x8dd1,0x6ce1,0x5478,0x80da, 0x57f9,0x88f4,0x8d54,0x966a,0x914d,0x4f69,0x6c9b,0x55b7,0x76c6,0x7830, 0x62a8,0x70f9,0x6f8e,0x5f6d,0x84ec,0x68da,0x787c,0x7bf7,0x81a8,0x670b, 0x9e4f,0x6367,0x78b0,0x576f,0x7812,0x9739,0x6279,0x62ab,0x5288,0x7435, 0x6bd7 }, { /* ku 46 */ 0x826a,0x826b,0x826c,0x826d,0x8271,0x8275,0x8276,0x8277,0x8278,0x827b, 0x827c,0x8280,0x8281,0x8283,0x8285,0x8286,0x8287,0x8289,0x828c,0x8290, 0x8293,0x8294,0x8295,0x8296,0x829a,0x829b,0x829e,0x82a0,0x82a2,0x82a3, 0x82a7,0x82b2,0x82b5,0x82b6,0x82ba,0x82bb,0x82bc,0x82bf,0x82c0,0x82c2, 0x82c3,0x82c5,0x82c6,0x82c9,0x82d0,0x82d6,0x82d9,0x82da,0x82dd,0x82e2, 0x82e7,0x82e8,0x82e9,0x82ea,0x82ec,0x82ed,0x82ee,0x82f0,0x82f2,0x82f3, 0x82f5,0x82f6,0x82f8,UBOGON,0x82fa,0x82fc,0x82fd,0x82fe,0x82ff,0x8300, 0x830a,0x830b,0x830d,0x8310,0x8312,0x8313,0x8316,0x8318,0x8319,0x831d, 0x831e,0x831f,0x8320,0x8321,0x8322,0x8323,0x8324,0x8325,0x8326,0x8329, 0x832a,0x832e,0x8330,0x8332,0x8337,0x833b,0x833d,0x5564,0x813e,0x75b2, 0x76ae,0x5339,0x75de,0x50fb,0x5c41,0x8b6c,0x7bc7,0x504f,0x7247,0x9a97, 0x98d8,0x6f02,0x74e2,0x7968,0x6487,0x77a5,0x62fc,0x9891,0x8d2b,0x54c1, 0x8058,0x4e52,0x576a,0x82f9,0x840d,0x5e73,0x51ed,0x74f6,0x8bc4,0x5c4f, 0x5761,0x6cfc,0x9887,0x5a46,0x7834,0x9b44,0x8feb,0x7c95,0x5256,0x6251, 0x94fa,0x4ec6,0x8386,0x8461,0x83e9,0x84b2,0x57d4,0x6734,0x5703,0x666e, 0x6d66,0x8c31,0x66dd,0x7011,0x671f,0x6b3a,0x6816,0x621a,0x59bb,0x4e03, 0x51c4,0x6f06,0x67d2,0x6c8f,0x5176,0x68cb,0x5947,0x6b67,0x7566,0x5d0e, 0x8110,0x9f50,0x65d7,0x7948,0x7941,0x9a91,0x8d77,0x5c82,0x4e5e,0x4f01, 0x542f,0x5951,0x780c,0x5668,0x6c14,0x8fc4,0x5f03,0x6c7d,0x6ce3,0x8bab, 0x6390 }, { /* ku 47 */ 0x833e,0x833f,0x8341,0x8342,0x8344,0x8345,0x8348,0x834a,0x834b,0x834c, 0x834d,0x834e,0x8353,0x8355,0x8356,0x8357,0x8358,0x8359,0x835d,0x8362, 0x8370,0x8371,0x8372,0x8373,0x8374,0x8375,0x8376,0x8379,0x837a,0x837e, 0x837f,0x8380,0x8381,0x8382,0x8383,0x8384,0x8387,0x8388,0x838a,0x838b, 0x838c,0x838d,0x838f,0x8390,0x8391,0x8394,0x8395,0x8396,0x8397,0x8399, 0x839a,0x839d,0x839f,0x83a1,0x83a2,0x83a3,0x83a4,0x83a5,0x83a6,0x83a7, 0x83ac,0x83ad,0x83ae,UBOGON,0x83af,0x83b5,0x83bb,0x83be,0x83bf,0x83c2, 0x83c3,0x83c4,0x83c6,0x83c8,0x83c9,0x83cb,0x83cd,0x83ce,0x83d0,0x83d1, 0x83d2,0x83d3,0x83d5,0x83d7,0x83d9,0x83da,0x83db,0x83de,0x83e2,0x83e3, 0x83e4,0x83e6,0x83e7,0x83e8,0x83eb,0x83ec,0x83ed,0x6070,0x6d3d,0x7275, 0x6266,0x948e,0x94c5,0x5343,0x8fc1,0x7b7e,0x4edf,0x8c26,0x4e7e,0x9ed4, 0x94b1,0x94b3,0x524d,0x6f5c,0x9063,0x6d45,0x8c34,0x5811,0x5d4c,0x6b20, 0x6b49,0x67aa,0x545b,0x8154,0x7f8c,0x5899,0x8537,0x5f3a,0x62a2,0x6a47, 0x9539,0x6572,0x6084,0x6865,0x77a7,0x4e54,0x4fa8,0x5de7,0x9798,0x64ac, 0x7fd8,0x5ced,0x4fcf,0x7a8d,0x5207,0x8304,0x4e14,0x602f,0x7a83,0x94a6, 0x4fb5,0x4eb2,0x79e6,0x7434,0x52e4,0x82b9,0x64d2,0x79bd,0x5bdd,0x6c81, 0x9752,0x8f7b,0x6c22,0x503e,0x537f,0x6e05,0x64ce,0x6674,0x6c30,0x60c5, 0x9877,0x8bf7,0x5e86,0x743c,0x7a77,0x79cb,0x4e18,0x90b1,0x7403,0x6c42, 0x56da,0x914b,0x6cc5,0x8d8b,0x533a,0x86c6,0x66f2,0x8eaf,0x5c48,0x9a71, 0x6e20 }, { /* ku 48 */ 0x83ee,0x83ef,0x83f3,0x83f4,0x83f5,0x83f6,0x83f7,0x83fa,0x83fb,0x83fc, 0x83fe,0x83ff,0x8400,0x8402,0x8405,0x8407,0x8408,0x8409,0x840a,0x8410, 0x8412,0x8413,0x8414,0x8415,0x8416,0x8417,0x8419,0x841a,0x841b,0x841e, 0x841f,0x8420,0x8421,0x8422,0x8423,0x8429,0x842a,0x842b,0x842c,0x842d, 0x842e,0x842f,0x8430,0x8432,0x8433,0x8434,0x8435,0x8436,0x8437,0x8439, 0x843a,0x843b,0x843e,0x843f,0x8440,0x8441,0x8442,0x8443,0x8444,0x8445, 0x8447,0x8448,0x8449,UBOGON,0x844a,0x844b,0x844c,0x844d,0x844e,0x844f, 0x8450,0x8452,0x8453,0x8454,0x8455,0x8456,0x8458,0x845d,0x845e,0x845f, 0x8460,0x8462,0x8464,0x8465,0x8466,0x8467,0x8468,0x846a,0x846e,0x846f, 0x8470,0x8472,0x8474,0x8477,0x8479,0x847b,0x847c,0x53d6,0x5a36,0x9f8b, 0x8da3,0x53bb,0x5708,0x98a7,0x6743,0x919b,0x6cc9,0x5168,0x75ca,0x62f3, 0x72ac,0x5238,0x529d,0x7f3a,0x7094,0x7638,0x5374,0x9e4a,0x69b7,0x786e, 0x96c0,0x88d9,0x7fa4,0x7136,0x71c3,0x5189,0x67d3,0x74e4,0x58e4,0x6518, 0x56b7,0x8ba9,0x9976,0x6270,0x7ed5,0x60f9,0x70ed,0x58ec,0x4ec1,0x4eba, 0x5fcd,0x97e7,0x4efb,0x8ba4,0x5203,0x598a,0x7eab,0x6254,0x4ecd,0x65e5, 0x620e,0x8338,0x84c9,0x8363,0x878d,0x7194,0x6eb6,0x5bb9,0x7ed2,0x5197, 0x63c9,0x67d4,0x8089,0x8339,0x8815,0x5112,0x5b7a,0x5982,0x8fb1,0x4e73, 0x6c5d,0x5165,0x8925,0x8f6f,0x962e,0x854a,0x745e,0x9510,0x95f0,0x6da6, 0x82e5,0x5f31,0x6492,0x6d12,0x8428,0x816e,0x9cc3,0x585e,0x8d5b,0x4e09, 0x53c1 }, { /* ku 49 */ 0x847d,0x847e,0x847f,0x8480,0x8481,0x8483,0x8484,0x8485,0x8486,0x848a, 0x848d,0x848f,0x8490,0x8491,0x8492,0x8493,0x8494,0x8495,0x8496,0x8498, 0x849a,0x849b,0x849d,0x849e,0x849f,0x84a0,0x84a2,0x84a3,0x84a4,0x84a5, 0x84a6,0x84a7,0x84a8,0x84a9,0x84aa,0x84ab,0x84ac,0x84ad,0x84ae,0x84b0, 0x84b1,0x84b3,0x84b5,0x84b6,0x84b7,0x84bb,0x84bc,0x84be,0x84c0,0x84c2, 0x84c3,0x84c5,0x84c6,0x84c7,0x84c8,0x84cb,0x84cc,0x84ce,0x84cf,0x84d2, 0x84d4,0x84d5,0x84d7,UBOGON,0x84d8,0x84d9,0x84da,0x84db,0x84dc,0x84de, 0x84e1,0x84e2,0x84e4,0x84e7,0x84e8,0x84e9,0x84ea,0x84eb,0x84ed,0x84ee, 0x84ef,0x84f1,0x84f2,0x84f3,0x84f4,0x84f5,0x84f6,0x84f7,0x84f8,0x84f9, 0x84fa,0x84fb,0x84fd,0x84fe,0x8500,0x8501,0x8502,0x4f1e,0x6563,0x6851, 0x55d3,0x4e27,0x6414,0x9a9a,0x626b,0x5ac2,0x745f,0x8272,0x6da9,0x68ee, 0x50e7,0x838e,0x7802,0x6740,0x5239,0x6c99,0x7eb1,0x50bb,0x5565,0x715e, 0x7b5b,0x6652,0x73ca,0x82eb,0x6749,0x5c71,0x5220,0x717d,0x886b,0x95ea, 0x9655,0x64c5,0x8d61,0x81b3,0x5584,0x6c55,0x6247,0x7f2e,0x5892,0x4f24, 0x5546,0x8d4f,0x664c,0x4e0a,0x5c1a,0x88f3,0x68a2,0x634e,0x7a0d,0x70e7, 0x828d,0x52fa,0x97f6,0x5c11,0x54e8,0x90b5,0x7ecd,0x5962,0x8d4a,0x86c7, 0x820c,0x820d,0x8d66,0x6444,0x5c04,0x6151,0x6d89,0x793e,0x8bbe,0x7837, 0x7533,0x547b,0x4f38,0x8eab,0x6df1,0x5a20,0x7ec5,0x795e,0x6c88,0x5ba1, 0x5a76,0x751a,0x80be,0x614e,0x6e17,0x58f0,0x751f,0x7525,0x7272,0x5347, 0x7ef3 }, { /* ku 4a */ 0x8503,0x8504,0x8505,0x8506,0x8507,0x8508,0x8509,0x850a,0x850b,0x850d, 0x850e,0x850f,0x8510,0x8512,0x8514,0x8515,0x8516,0x8518,0x8519,0x851b, 0x851c,0x851d,0x851e,0x8520,0x8522,0x8523,0x8524,0x8525,0x8526,0x8527, 0x8528,0x8529,0x852a,0x852d,0x852e,0x852f,0x8530,0x8531,0x8532,0x8533, 0x8534,0x8535,0x8536,0x853e,0x853f,0x8540,0x8541,0x8542,0x8544,0x8545, 0x8546,0x8547,0x854b,0x854c,0x854d,0x854e,0x854f,0x8550,0x8551,0x8552, 0x8553,0x8554,0x8555,UBOGON,0x8557,0x8558,0x855a,0x855b,0x855c,0x855d, 0x855f,0x8560,0x8561,0x8562,0x8563,0x8565,0x8566,0x8567,0x8569,0x856a, 0x856b,0x856c,0x856d,0x856e,0x856f,0x8570,0x8571,0x8573,0x8575,0x8576, 0x8577,0x8578,0x857c,0x857d,0x857f,0x8580,0x8581,0x7701,0x76db,0x5269, 0x80dc,0x5723,0x5e08,0x5931,0x72ee,0x65bd,0x6e7f,0x8bd7,0x5c38,0x8671, 0x5341,0x77f3,0x62fe,0x65f6,0x4ec0,0x98df,0x8680,0x5b9e,0x8bc6,0x53f2, 0x77e2,0x4f7f,0x5c4e,0x9a76,0x59cb,0x5f0f,0x793a,0x58eb,0x4e16,0x67ff, 0x4e8b,0x62ed,0x8a93,0x901d,0x52bf,0x662f,0x55dc,0x566c,0x9002,0x4ed5, 0x4f8d,0x91ca,0x9970,0x6c0f,0x5e02,0x6043,0x5ba4,0x89c6,0x8bd5,0x6536, 0x624b,0x9996,0x5b88,0x5bff,0x6388,0x552e,0x53d7,0x7626,0x517d,0x852c, 0x67a2,0x68b3,0x6b8a,0x6292,0x8f93,0x53d4,0x8212,0x6dd1,0x758f,0x4e66, 0x8d4e,0x5b70,0x719f,0x85af,0x6691,0x66d9,0x7f72,0x8700,0x9ecd,0x9f20, 0x5c5e,0x672f,0x8ff0,0x6811,0x675f,0x620d,0x7ad6,0x5885,0x5eb6,0x6570, 0x6f31 }, { /* ku 4b */ 0x8582,0x8583,0x8586,0x8588,0x8589,0x858a,0x858b,0x858c,0x858d,0x858e, 0x8590,0x8591,0x8592,0x8593,0x8594,0x8595,0x8596,0x8597,0x8598,0x8599, 0x859a,0x859d,0x859e,0x859f,0x85a0,0x85a1,0x85a2,0x85a3,0x85a5,0x85a6, 0x85a7,0x85a9,0x85ab,0x85ac,0x85ad,0x85b1,0x85b2,0x85b3,0x85b4,0x85b5, 0x85b6,0x85b8,0x85ba,0x85bb,0x85bc,0x85bd,0x85be,0x85bf,0x85c0,0x85c2, 0x85c3,0x85c4,0x85c5,0x85c6,0x85c7,0x85c8,0x85ca,0x85cb,0x85cc,0x85cd, 0x85ce,0x85d1,0x85d2,UBOGON,0x85d4,0x85d6,0x85d7,0x85d8,0x85d9,0x85da, 0x85db,0x85dd,0x85de,0x85df,0x85e0,0x85e1,0x85e2,0x85e3,0x85e5,0x85e6, 0x85e7,0x85e8,0x85ea,0x85eb,0x85ec,0x85ed,0x85ee,0x85ef,0x85f0,0x85f1, 0x85f2,0x85f3,0x85f4,0x85f5,0x85f6,0x85f7,0x85f8,0x6055,0x5237,0x800d, 0x6454,0x8870,0x7529,0x5e05,0x6813,0x62f4,0x971c,0x53cc,0x723d,0x8c01, 0x6c34,0x7761,0x7a0e,0x542e,0x77ac,0x987a,0x821c,0x8bf4,0x7855,0x6714, 0x70c1,0x65af,0x6495,0x5636,0x601d,0x79c1,0x53f8,0x4e1d,0x6b7b,0x8086, 0x5bfa,0x55e3,0x56db,0x4f3a,0x4f3c,0x9972,0x5df3,0x677e,0x8038,0x6002, 0x9882,0x9001,0x5b8b,0x8bbc,0x8bf5,0x641c,0x8258,0x64de,0x55fd,0x82cf, 0x9165,0x4fd7,0x7d20,0x901f,0x7c9f,0x50f3,0x5851,0x6eaf,0x5bbf,0x8bc9, 0x8083,0x9178,0x849c,0x7b97,0x867d,0x968b,0x968f,0x7ee5,0x9ad3,0x788e, 0x5c81,0x7a57,0x9042,0x96a7,0x795f,0x5b59,0x635f,0x7b0b,0x84d1,0x68ad, 0x5506,0x7f29,0x7410,0x7d22,0x9501,0x6240,0x584c,0x4ed6,0x5b83,0x5979, 0x5854 }, { /* ku 4c */ 0x85f9,0x85fa,0x85fc,0x85fd,0x85fe,0x8600,0x8601,0x8602,0x8603,0x8604, 0x8606,0x8607,0x8608,0x8609,0x860a,0x860b,0x860c,0x860d,0x860e,0x860f, 0x8610,0x8612,0x8613,0x8614,0x8615,0x8617,0x8618,0x8619,0x861a,0x861b, 0x861c,0x861d,0x861e,0x861f,0x8620,0x8621,0x8622,0x8623,0x8624,0x8625, 0x8626,0x8628,0x862a,0x862b,0x862c,0x862d,0x862e,0x862f,0x8630,0x8631, 0x8632,0x8633,0x8634,0x8635,0x8636,0x8637,0x8639,0x863a,0x863b,0x863d, 0x863e,0x863f,0x8640,UBOGON,0x8641,0x8642,0x8643,0x8644,0x8645,0x8646, 0x8647,0x8648,0x8649,0x864a,0x864b,0x864c,0x8652,0x8653,0x8655,0x8656, 0x8657,0x8658,0x8659,0x865b,0x865c,0x865d,0x865f,0x8660,0x8661,0x8663, 0x8664,0x8665,0x8666,0x8667,0x8668,0x8669,0x866a,0x736d,0x631e,0x8e4b, 0x8e0f,0x80ce,0x82d4,0x62ac,0x53f0,0x6cf0,0x915e,0x592a,0x6001,0x6c70, 0x574d,0x644a,0x8d2a,0x762b,0x6ee9,0x575b,0x6a80,0x75f0,0x6f6d,0x8c2d, 0x8c08,0x5766,0x6bef,0x8892,0x78b3,0x63a2,0x53f9,0x70ad,0x6c64,0x5858, 0x642a,0x5802,0x68e0,0x819b,0x5510,0x7cd6,0x5018,0x8eba,0x6dcc,0x8d9f, 0x70eb,0x638f,0x6d9b,0x6ed4,0x7ee6,0x8404,0x6843,0x9003,0x6dd8,0x9676, 0x8ba8,0x5957,0x7279,0x85e4,0x817e,0x75bc,0x8a8a,0x68af,0x5254,0x8e22, 0x9511,0x63d0,0x9898,0x8e44,0x557c,0x4f53,0x66ff,0x568f,0x60d5,0x6d95, 0x5243,0x5c49,0x5929,0x6dfb,0x586b,0x7530,0x751c,0x606c,0x8214,0x8146, 0x6311,0x6761,0x8fe2,0x773a,0x8df3,0x8d34,0x94c1,0x5e16,0x5385,0x542c, 0x70c3 }, { /* ku 4d */ 0x866d,0x866f,0x8670,0x8672,0x8673,0x8674,0x8675,0x8676,0x8677,0x8678, 0x8683,0x8684,0x8685,0x8686,0x8687,0x8688,0x8689,0x868e,0x868f,0x8690, 0x8691,0x8692,0x8694,0x8696,0x8697,0x8698,0x8699,0x869a,0x869b,0x869e, 0x869f,0x86a0,0x86a1,0x86a2,0x86a5,0x86a6,0x86ab,0x86ad,0x86ae,0x86b2, 0x86b3,0x86b7,0x86b8,0x86b9,0x86bb,0x86bc,0x86bd,0x86be,0x86bf,0x86c1, 0x86c2,0x86c3,0x86c5,0x86c8,0x86cc,0x86cd,0x86d2,0x86d3,0x86d5,0x86d6, 0x86d7,0x86da,0x86dc,UBOGON,0x86dd,0x86e0,0x86e1,0x86e2,0x86e3,0x86e5, 0x86e6,0x86e7,0x86e8,0x86ea,0x86eb,0x86ec,0x86ef,0x86f5,0x86f6,0x86f7, 0x86fa,0x86fb,0x86fc,0x86fd,0x86ff,0x8701,0x8704,0x8705,0x8706,0x870b, 0x870c,0x870e,0x870f,0x8710,0x8711,0x8714,0x8716,0x6c40,0x5ef7,0x505c, 0x4ead,0x5ead,0x633a,0x8247,0x901a,0x6850,0x916e,0x77b3,0x540c,0x94dc, 0x5f64,0x7ae5,0x6876,0x6345,0x7b52,0x7edf,0x75db,0x5077,0x6295,0x5934, 0x900f,0x51f8,0x79c3,0x7a81,0x56fe,0x5f92,0x9014,0x6d82,0x5c60,0x571f, 0x5410,0x5154,0x6e4d,0x56e2,0x63a8,0x9893,0x817f,0x8715,0x892a,0x9000, 0x541e,0x5c6f,0x81c0,0x62d6,0x6258,0x8131,0x9e35,0x9640,0x9a6e,0x9a7c, 0x692d,0x59a5,0x62d3,0x553e,0x6316,0x54c7,0x86d9,0x6d3c,0x5a03,0x74e6, 0x889c,0x6b6a,0x5916,0x8c4c,0x5f2f,0x6e7e,0x73a9,0x987d,0x4e38,0x70f7, 0x5b8c,0x7897,0x633d,0x665a,0x7696,0x60cb,0x5b9b,0x5a49,0x4e07,0x8155, 0x6c6a,0x738b,0x4ea1,0x6789,0x7f51,0x5f80,0x65fa,0x671b,0x5fd8,0x5984, 0x5a01 }, { /* ku 4e */ 0x8719,0x871b,0x871d,0x871f,0x8720,0x8724,0x8726,0x8727,0x8728,0x872a, 0x872b,0x872c,0x872d,0x872f,0x8730,0x8732,0x8733,0x8735,0x8736,0x8738, 0x8739,0x873a,0x873c,0x873d,0x8740,0x8741,0x8742,0x8743,0x8744,0x8745, 0x8746,0x874a,0x874b,0x874d,0x874f,0x8750,0x8751,0x8752,0x8754,0x8755, 0x8756,0x8758,0x875a,0x875b,0x875c,0x875d,0x875e,0x875f,0x8761,0x8762, 0x8766,0x8767,0x8768,0x8769,0x876a,0x876b,0x876c,0x876d,0x876f,0x8771, 0x8772,0x8773,0x8775,UBOGON,0x8777,0x8778,0x8779,0x877a,0x877f,0x8780, 0x8781,0x8784,0x8786,0x8787,0x8789,0x878a,0x878c,0x878e,0x878f,0x8790, 0x8791,0x8792,0x8794,0x8795,0x8796,0x8798,0x8799,0x879a,0x879b,0x879c, 0x879d,0x879e,0x87a0,0x87a1,0x87a2,0x87a3,0x87a4,0x5dcd,0x5fae,0x5371, 0x97e6,0x8fdd,0x6845,0x56f4,0x552f,0x60df,0x4e3a,0x6f4d,0x7ef4,0x82c7, 0x840e,0x59d4,0x4f1f,0x4f2a,0x5c3e,0x7eac,0x672a,0x851a,0x5473,0x754f, 0x80c3,0x5582,0x9b4f,0x4f4d,0x6e2d,0x8c13,0x5c09,0x6170,0x536b,0x761f, 0x6e29,0x868a,0x6587,0x95fb,0x7eb9,0x543b,0x7a33,0x7d0a,0x95ee,0x55e1, 0x7fc1,0x74ee,0x631d,0x8717,0x6da1,0x7a9d,0x6211,0x65a1,0x5367,0x63e1, 0x6c83,0x5deb,0x545c,0x94a8,0x4e4c,0x6c61,0x8bec,0x5c4b,0x65e0,0x829c, 0x68a7,0x543e,0x5434,0x6bcb,0x6b66,0x4e94,0x6342,0x5348,0x821e,0x4f0d, 0x4fae,0x575e,0x620a,0x96fe,0x6664,0x7269,0x52ff,0x52a1,0x609f,0x8bef, 0x6614,0x7199,0x6790,0x897f,0x7852,0x77fd,0x6670,0x563b,0x5438,0x9521, 0x727a }, { /* ku 4f */ 0x87a5,0x87a6,0x87a7,0x87a9,0x87aa,0x87ae,0x87b0,0x87b1,0x87b2,0x87b4, 0x87b6,0x87b7,0x87b8,0x87b9,0x87bb,0x87bc,0x87be,0x87bf,0x87c1,0x87c2, 0x87c3,0x87c4,0x87c5,0x87c7,0x87c8,0x87c9,0x87cc,0x87cd,0x87ce,0x87cf, 0x87d0,0x87d4,0x87d5,0x87d6,0x87d7,0x87d8,0x87d9,0x87da,0x87dc,0x87dd, 0x87de,0x87df,0x87e1,0x87e2,0x87e3,0x87e4,0x87e6,0x87e7,0x87e8,0x87e9, 0x87eb,0x87ec,0x87ed,0x87ef,0x87f0,0x87f1,0x87f2,0x87f3,0x87f4,0x87f5, 0x87f6,0x87f7,0x87f8,UBOGON,0x87fa,0x87fb,0x87fc,0x87fd,0x87ff,0x8800, 0x8801,0x8802,0x8804,0x8805,0x8806,0x8807,0x8808,0x8809,0x880b,0x880c, 0x880d,0x880e,0x880f,0x8810,0x8811,0x8812,0x8814,0x8817,0x8818,0x8819, 0x881a,0x881c,0x881d,0x881e,0x881f,0x8820,0x8823,0x7a00,0x606f,0x5e0c, 0x6089,0x819d,0x5915,0x60dc,0x7184,0x70ef,0x6eaa,0x6c50,0x7280,0x6a84, 0x88ad,0x5e2d,0x4e60,0x5ab3,0x559c,0x94e3,0x6d17,0x7cfb,0x9699,0x620f, 0x7ec6,0x778e,0x867e,0x5323,0x971e,0x8f96,0x6687,0x5ce1,0x4fa0,0x72ed, 0x4e0b,0x53a6,0x590f,0x5413,0x6380,0x9528,0x5148,0x4ed9,0x9c9c,0x7ea4, 0x54b8,0x8d24,0x8854,0x8237,0x95f2,0x6d8e,0x5f26,0x5acc,0x663e,0x9669, 0x73b0,0x732e,0x53bf,0x817a,0x9985,0x7fa1,0x5baa,0x9677,0x9650,0x7ebf, 0x76f8,0x53a2,0x9576,0x9999,0x7bb1,0x8944,0x6e58,0x4e61,0x7fd4,0x7965, 0x8be6,0x60f3,0x54cd,0x4eab,0x9879,0x5df7,0x6a61,0x50cf,0x5411,0x8c61, 0x8427,0x785d,0x9704,0x524a,0x54ee,0x56a3,0x9500,0x6d88,0x5bb5,0x6dc6, 0x6653 }, { /* ku 50 */ 0x8824,0x8825,0x8826,0x8827,0x8828,0x8829,0x882a,0x882b,0x882c,0x882d, 0x882e,0x882f,0x8830,0x8831,0x8833,0x8834,0x8835,0x8836,0x8837,0x8838, 0x883a,0x883b,0x883d,0x883e,0x883f,0x8841,0x8842,0x8843,0x8846,0x8847, 0x8848,0x8849,0x884a,0x884b,0x884e,0x884f,0x8850,0x8851,0x8852,0x8853, 0x8855,0x8856,0x8858,0x885a,0x885b,0x885c,0x885d,0x885e,0x885f,0x8860, 0x8866,0x8867,0x886a,0x886d,0x886f,0x8871,0x8873,0x8874,0x8875,0x8876, 0x8878,0x8879,0x887a,UBOGON,0x887b,0x887c,0x8880,0x8883,0x8886,0x8887, 0x8889,0x888a,0x888c,0x888e,0x888f,0x8890,0x8891,0x8893,0x8894,0x8895, 0x8897,0x8898,0x8899,0x889a,0x889b,0x889d,0x889e,0x889f,0x88a0,0x88a1, 0x88a3,0x88a5,0x88a6,0x88a7,0x88a8,0x88a9,0x88aa,0x5c0f,0x5b5d,0x6821, 0x8096,0x5578,0x7b11,0x6548,0x6954,0x4e9b,0x6b47,0x874e,0x978b,0x534f, 0x631f,0x643a,0x90aa,0x659c,0x80c1,0x8c10,0x5199,0x68b0,0x5378,0x87f9, 0x61c8,0x6cc4,0x6cfb,0x8c22,0x5c51,0x85aa,0x82af,0x950c,0x6b23,0x8f9b, 0x65b0,0x5ffb,0x5fc3,0x4fe1,0x8845,0x661f,0x8165,0x7329,0x60fa,0x5174, 0x5211,0x578b,0x5f62,0x90a2,0x884c,0x9192,0x5e78,0x674f,0x6027,0x59d3, 0x5144,0x51f6,0x80f8,0x5308,0x6c79,0x96c4,0x718a,0x4f11,0x4fee,0x7f9e, 0x673d,0x55c5,0x9508,0x79c0,0x8896,0x7ee3,0x589f,0x620c,0x9700,0x865a, 0x5618,0x987b,0x5f90,0x8bb8,0x84c4,0x9157,0x53d9,0x65ed,0x5e8f,0x755c, 0x6064,0x7d6e,0x5a7f,0x7eea,0x7eed,0x8f69,0x55a7,0x5ba3,0x60ac,0x65cb, 0x7384 }, { /* ku 51 */ 0x88ac,0x88ae,0x88af,0x88b0,0x88b2,0x88b3,0x88b4,0x88b5,0x88b6,0x88b8, 0x88b9,0x88ba,0x88bb,0x88bd,0x88be,0x88bf,0x88c0,0x88c3,0x88c4,0x88c7, 0x88c8,0x88ca,0x88cb,0x88cc,0x88cd,0x88cf,0x88d0,0x88d1,0x88d3,0x88d6, 0x88d7,0x88da,0x88db,0x88dc,0x88dd,0x88de,0x88e0,0x88e1,0x88e6,0x88e7, 0x88e9,0x88ea,0x88eb,0x88ec,0x88ed,0x88ee,0x88ef,0x88f2,0x88f5,0x88f6, 0x88f7,0x88fa,0x88fb,0x88fd,0x88ff,0x8900,0x8901,0x8903,0x8904,0x8905, 0x8906,0x8907,0x8908,UBOGON,0x8909,0x890b,0x890c,0x890d,0x890e,0x890f, 0x8911,0x8914,0x8915,0x8916,0x8917,0x8918,0x891c,0x891d,0x891e,0x891f, 0x8920,0x8922,0x8923,0x8924,0x8926,0x8927,0x8928,0x8929,0x892c,0x892d, 0x892e,0x892f,0x8931,0x8932,0x8933,0x8935,0x8937,0x9009,0x7663,0x7729, 0x7eda,0x9774,0x859b,0x5b66,0x7a74,0x96ea,0x8840,0x52cb,0x718f,0x5faa, 0x65ec,0x8be2,0x5bfb,0x9a6f,0x5de1,0x6b89,0x6c5b,0x8bad,0x8baf,0x900a, 0x8fc5,0x538b,0x62bc,0x9e26,0x9e2d,0x5440,0x4e2b,0x82bd,0x7259,0x869c, 0x5d16,0x8859,0x6daf,0x96c5,0x54d1,0x4e9a,0x8bb6,0x7109,0x54bd,0x9609, 0x70df,0x6df9,0x76d0,0x4e25,0x7814,0x8712,0x5ca9,0x5ef6,0x8a00,0x989c, 0x960e,0x708e,0x6cbf,0x5944,0x63a9,0x773c,0x884d,0x6f14,0x8273,0x5830, 0x71d5,0x538c,0x781a,0x96c1,0x5501,0x5f66,0x7130,0x5bb4,0x8c1a,0x9a8c, 0x6b83,0x592e,0x9e2f,0x79e7,0x6768,0x626c,0x4f6f,0x75a1,0x7f8a,0x6d0b, 0x9633,0x6c27,0x4ef0,0x75d2,0x517b,0x6837,0x6f3e,0x9080,0x8170,0x5996, 0x7476 }, { /* ku 52 */ 0x8938,0x8939,0x893a,0x893b,0x893c,0x893d,0x893e,0x893f,0x8940,0x8942, 0x8943,0x8945,0x8946,0x8947,0x8948,0x8949,0x894a,0x894b,0x894c,0x894d, 0x894e,0x894f,0x8950,0x8951,0x8952,0x8953,0x8954,0x8955,0x8956,0x8957, 0x8958,0x8959,0x895a,0x895b,0x895c,0x895d,0x8960,0x8961,0x8962,0x8963, 0x8964,0x8965,0x8967,0x8968,0x8969,0x896a,0x896b,0x896c,0x896d,0x896e, 0x896f,0x8970,0x8971,0x8972,0x8973,0x8974,0x8975,0x8976,0x8977,0x8978, 0x8979,0x897a,0x897c,UBOGON,0x897d,0x897e,0x8980,0x8982,0x8984,0x8985, 0x8987,0x8988,0x8989,0x898a,0x898b,0x898c,0x898d,0x898e,0x898f,0x8990, 0x8991,0x8992,0x8993,0x8994,0x8995,0x8996,0x8997,0x8998,0x8999,0x899a, 0x899b,0x899c,0x899d,0x899e,0x899f,0x89a0,0x89a1,0x6447,0x5c27,0x9065, 0x7a91,0x8c23,0x59da,0x54ac,0x8200,0x836f,0x8981,0x8000,0x6930,0x564e, 0x8036,0x7237,0x91ce,0x51b6,0x4e5f,0x9875,0x6396,0x4e1a,0x53f6,0x66f3, 0x814b,0x591c,0x6db2,0x4e00,0x58f9,0x533b,0x63d6,0x94f1,0x4f9d,0x4f0a, 0x8863,0x9890,0x5937,0x9057,0x79fb,0x4eea,0x80f0,0x7591,0x6c82,0x5b9c, 0x59e8,0x5f5d,0x6905,0x8681,0x501a,0x5df2,0x4e59,0x77e3,0x4ee5,0x827a, 0x6291,0x6613,0x9091,0x5c79,0x4ebf,0x5f79,0x81c6,0x9038,0x8084,0x75ab, 0x4ea6,0x88d4,0x610f,0x6bc5,0x5fc6,0x4e49,0x76ca,0x6ea2,0x8be3,0x8bae, 0x8c0a,0x8bd1,0x5f02,0x7ffc,0x7fcc,0x7ece,0x8335,0x836b,0x56e0,0x6bb7, 0x97f3,0x9634,0x59fb,0x541f,0x94f6,0x6deb,0x5bc5,0x996e,0x5c39,0x5f15, 0x9690 }, { /* ku 53 */ 0x89a2,0x89a3,0x89a4,0x89a5,0x89a6,0x89a7,0x89a8,0x89a9,0x89aa,0x89ab, 0x89ac,0x89ad,0x89ae,0x89af,0x89b0,0x89b1,0x89b2,0x89b3,0x89b4,0x89b5, 0x89b6,0x89b7,0x89b8,0x89b9,0x89ba,0x89bb,0x89bc,0x89bd,0x89be,0x89bf, 0x89c0,0x89c3,0x89cd,0x89d3,0x89d4,0x89d5,0x89d7,0x89d8,0x89d9,0x89db, 0x89dd,0x89df,0x89e0,0x89e1,0x89e2,0x89e4,0x89e7,0x89e8,0x89e9,0x89ea, 0x89ec,0x89ed,0x89ee,0x89f0,0x89f1,0x89f2,0x89f4,0x89f5,0x89f6,0x89f7, 0x89f8,0x89f9,0x89fa,UBOGON,0x89fb,0x89fc,0x89fd,0x89fe,0x89ff,0x8a01, 0x8a02,0x8a03,0x8a04,0x8a05,0x8a06,0x8a08,0x8a09,0x8a0a,0x8a0b,0x8a0c, 0x8a0d,0x8a0e,0x8a0f,0x8a10,0x8a11,0x8a12,0x8a13,0x8a14,0x8a15,0x8a16, 0x8a17,0x8a18,0x8a19,0x8a1a,0x8a1b,0x8a1c,0x8a1d,0x5370,0x82f1,0x6a31, 0x5a74,0x9e70,0x5e94,0x7f28,0x83b9,0x8424,0x8425,0x8367,0x8747,0x8fce, 0x8d62,0x76c8,0x5f71,0x9896,0x786c,0x6620,0x54df,0x62e5,0x4f63,0x81c3, 0x75c8,0x5eb8,0x96cd,0x8e0a,0x86f9,0x548f,0x6cf3,0x6d8c,0x6c38,0x607f, 0x52c7,0x7528,0x5e7d,0x4f18,0x60a0,0x5fe7,0x5c24,0x7531,0x90ae,0x94c0, 0x72b9,0x6cb9,0x6e38,0x9149,0x6709,0x53cb,0x53f3,0x4f51,0x91c9,0x8bf1, 0x53c8,0x5e7c,0x8fc2,0x6de4,0x4e8e,0x76c2,0x6986,0x865e,0x611a,0x8206, 0x4f59,0x4fde,0x903e,0x9c7c,0x6109,0x6e1d,0x6e14,0x9685,0x4e88,0x5a31, 0x96e8,0x4e0e,0x5c7f,0x79b9,0x5b87,0x8bed,0x7fbd,0x7389,0x57df,0x828b, 0x90c1,0x5401,0x9047,0x55bb,0x5cea,0x5fa1,0x6108,0x6b32,0x72f1,0x80b2, 0x8a89 }, { /* ku 54 */ 0x8a1e,0x8a1f,0x8a20,0x8a21,0x8a22,0x8a23,0x8a24,0x8a25,0x8a26,0x8a27, 0x8a28,0x8a29,0x8a2a,0x8a2b,0x8a2c,0x8a2d,0x8a2e,0x8a2f,0x8a30,0x8a31, 0x8a32,0x8a33,0x8a34,0x8a35,0x8a36,0x8a37,0x8a38,0x8a39,0x8a3a,0x8a3b, 0x8a3c,0x8a3d,0x8a3f,0x8a40,0x8a41,0x8a42,0x8a43,0x8a44,0x8a45,0x8a46, 0x8a47,0x8a49,0x8a4a,0x8a4b,0x8a4c,0x8a4d,0x8a4e,0x8a4f,0x8a50,0x8a51, 0x8a52,0x8a53,0x8a54,0x8a55,0x8a56,0x8a57,0x8a58,0x8a59,0x8a5a,0x8a5b, 0x8a5c,0x8a5d,0x8a5e,UBOGON,0x8a5f,0x8a60,0x8a61,0x8a62,0x8a63,0x8a64, 0x8a65,0x8a66,0x8a67,0x8a68,0x8a69,0x8a6a,0x8a6b,0x8a6c,0x8a6d,0x8a6e, 0x8a6f,0x8a70,0x8a71,0x8a72,0x8a73,0x8a74,0x8a75,0x8a76,0x8a77,0x8a78, 0x8a7a,0x8a7b,0x8a7c,0x8a7d,0x8a7e,0x8a7f,0x8a80,0x6d74,0x5bd3,0x88d5, 0x9884,0x8c6b,0x9a6d,0x9e33,0x6e0a,0x51a4,0x5143,0x57a3,0x8881,0x539f, 0x63f4,0x8f95,0x56ed,0x5458,0x5706,0x733f,0x6e90,0x7f18,0x8fdc,0x82d1, 0x613f,0x6028,0x9662,0x66f0,0x7ea6,0x8d8a,0x8dc3,0x94a5,0x5cb3,0x7ca4, 0x6708,0x60a6,0x9605,0x8018,0x4e91,0x90e7,0x5300,0x9668,0x5141,0x8fd0, 0x8574,0x915d,0x6655,0x97f5,0x5b55,0x531d,0x7838,0x6742,0x683d,0x54c9, 0x707e,0x5bb0,0x8f7d,0x518d,0x5728,0x54b1,0x6512,0x6682,0x8d5e,0x8d43, 0x810f,0x846c,0x906d,0x7cdf,0x51ff,0x85fb,0x67a3,0x65e9,0x6fa1,0x86a4, 0x8e81,0x566a,0x9020,0x7682,0x7076,0x71e5,0x8d23,0x62e9,0x5219,0x6cfd, 0x8d3c,0x600e,0x589e,0x618e,0x66fe,0x8d60,0x624e,0x55b3,0x6e23,0x672d, 0x8f67 }, { /* ku 55 */ 0x8a81,0x8a82,0x8a83,0x8a84,0x8a85,0x8a86,0x8a87,0x8a88,0x8a8b,0x8a8c, 0x8a8d,0x8a8e,0x8a8f,0x8a90,0x8a91,0x8a92,0x8a94,0x8a95,0x8a96,0x8a97, 0x8a98,0x8a99,0x8a9a,0x8a9b,0x8a9c,0x8a9d,0x8a9e,0x8a9f,0x8aa0,0x8aa1, 0x8aa2,0x8aa3,0x8aa4,0x8aa5,0x8aa6,0x8aa7,0x8aa8,0x8aa9,0x8aaa,0x8aab, 0x8aac,0x8aad,0x8aae,0x8aaf,0x8ab0,0x8ab1,0x8ab2,0x8ab3,0x8ab4,0x8ab5, 0x8ab6,0x8ab7,0x8ab8,0x8ab9,0x8aba,0x8abb,0x8abc,0x8abd,0x8abe,0x8abf, 0x8ac0,0x8ac1,0x8ac2,UBOGON,0x8ac3,0x8ac4,0x8ac5,0x8ac6,0x8ac7,0x8ac8, 0x8ac9,0x8aca,0x8acb,0x8acc,0x8acd,0x8ace,0x8acf,0x8ad0,0x8ad1,0x8ad2, 0x8ad3,0x8ad4,0x8ad5,0x8ad6,0x8ad7,0x8ad8,0x8ad9,0x8ada,0x8adb,0x8adc, 0x8add,0x8ade,0x8adf,0x8ae0,0x8ae1,0x8ae2,0x8ae3,0x94e1,0x95f8,0x7728, 0x6805,0x69a8,0x548b,0x4e4d,0x70b8,0x8bc8,0x6458,0x658b,0x5b85,0x7a84, 0x503a,0x5be8,0x77bb,0x6be1,0x8a79,0x7c98,0x6cbe,0x76cf,0x65a9,0x8f97, 0x5d2d,0x5c55,0x8638,0x6808,0x5360,0x6218,0x7ad9,0x6e5b,0x7efd,0x6a1f, 0x7ae0,0x5f70,0x6f33,0x5f20,0x638c,0x6da8,0x6756,0x4e08,0x5e10,0x8d26, 0x4ed7,0x80c0,0x7634,0x969c,0x62db,0x662d,0x627e,0x6cbc,0x8d75,0x7167, 0x7f69,0x5146,0x8087,0x53ec,0x906e,0x6298,0x54f2,0x86f0,0x8f99,0x8005, 0x9517,0x8517,0x8fd9,0x6d59,0x73cd,0x659f,0x771f,0x7504,0x7827,0x81fb, 0x8d1e,0x9488,0x4fa6,0x6795,0x75b9,0x8bca,0x9707,0x632f,0x9547,0x9635, 0x84b8,0x6323,0x7741,0x5f81,0x72f0,0x4e89,0x6014,0x6574,0x62ef,0x6b63, 0x653f }, { /* ku 56 */ 0x8ae4,0x8ae5,0x8ae6,0x8ae7,0x8ae8,0x8ae9,0x8aea,0x8aeb,0x8aec,0x8aed, 0x8aee,0x8aef,0x8af0,0x8af1,0x8af2,0x8af3,0x8af4,0x8af5,0x8af6,0x8af7, 0x8af8,0x8af9,0x8afa,0x8afb,0x8afc,0x8afd,0x8afe,0x8aff,0x8b00,0x8b01, 0x8b02,0x8b03,0x8b04,0x8b05,0x8b06,0x8b08,0x8b09,0x8b0a,0x8b0b,0x8b0c, 0x8b0d,0x8b0e,0x8b0f,0x8b10,0x8b11,0x8b12,0x8b13,0x8b14,0x8b15,0x8b16, 0x8b17,0x8b18,0x8b19,0x8b1a,0x8b1b,0x8b1c,0x8b1d,0x8b1e,0x8b1f,0x8b20, 0x8b21,0x8b22,0x8b23,UBOGON,0x8b24,0x8b25,0x8b27,0x8b28,0x8b29,0x8b2a, 0x8b2b,0x8b2c,0x8b2d,0x8b2e,0x8b2f,0x8b30,0x8b31,0x8b32,0x8b33,0x8b34, 0x8b35,0x8b36,0x8b37,0x8b38,0x8b39,0x8b3a,0x8b3b,0x8b3c,0x8b3d,0x8b3e, 0x8b3f,0x8b40,0x8b41,0x8b42,0x8b43,0x8b44,0x8b45,0x5e27,0x75c7,0x90d1, 0x8bc1,0x829d,0x679d,0x652f,0x5431,0x8718,0x77e5,0x80a2,0x8102,0x6c41, 0x4e4b,0x7ec7,0x804c,0x76f4,0x690d,0x6b96,0x6267,0x503c,0x4f84,0x5740, 0x6307,0x6b62,0x8dbe,0x53ea,0x65e8,0x7eb8,0x5fd7,0x631a,0x63b7,0x81f3, 0x81f4,0x7f6e,0x5e1c,0x5cd9,0x5236,0x667a,0x79e9,0x7a1a,0x8d28,0x7099, 0x75d4,0x6ede,0x6cbb,0x7a92,0x4e2d,0x76c5,0x5fe0,0x949f,0x8877,0x7ec8, 0x79cd,0x80bf,0x91cd,0x4ef2,0x4f17,0x821f,0x5468,0x5dde,0x6d32,0x8bcc, 0x7ca5,0x8f74,0x8098,0x5e1a,0x5492,0x76b1,0x5b99,0x663c,0x9aa4,0x73e0, 0x682a,0x86db,0x6731,0x732a,0x8bf8,0x8bdb,0x9010,0x7af9,0x70db,0x716e, 0x62c4,0x77a9,0x5631,0x4e3b,0x8457,0x67f1,0x52a9,0x86c0,0x8d2e,0x94f8, 0x7b51 }, { /* ku 57 */ 0x8b46,0x8b47,0x8b48,0x8b49,0x8b4a,0x8b4b,0x8b4c,0x8b4d,0x8b4e,0x8b4f, 0x8b50,0x8b51,0x8b52,0x8b53,0x8b54,0x8b55,0x8b56,0x8b57,0x8b58,0x8b59, 0x8b5a,0x8b5b,0x8b5c,0x8b5d,0x8b5e,0x8b5f,0x8b60,0x8b61,0x8b62,0x8b63, 0x8b64,0x8b65,0x8b67,0x8b68,0x8b69,0x8b6a,0x8b6b,0x8b6d,0x8b6e,0x8b6f, 0x8b70,0x8b71,0x8b72,0x8b73,0x8b74,0x8b75,0x8b76,0x8b77,0x8b78,0x8b79, 0x8b7a,0x8b7b,0x8b7c,0x8b7d,0x8b7e,0x8b7f,0x8b80,0x8b81,0x8b82,0x8b83, 0x8b84,0x8b85,0x8b86,UBOGON,0x8b87,0x8b88,0x8b89,0x8b8a,0x8b8b,0x8b8c, 0x8b8d,0x8b8e,0x8b8f,0x8b90,0x8b91,0x8b92,0x8b93,0x8b94,0x8b95,0x8b96, 0x8b97,0x8b98,0x8b99,0x8b9a,0x8b9b,0x8b9c,0x8b9d,0x8b9e,0x8b9f,0x8bac, 0x8bb1,0x8bbb,0x8bc7,0x8bd0,0x8bea,0x8c09,0x8c1e,0x4f4f,0x6ce8,0x795d, 0x9a7b,0x6293,0x722a,0x62fd,0x4e13,0x7816,0x8f6c,0x64b0,0x8d5a,0x7bc6, 0x6869,0x5e84,0x88c5,0x5986,0x649e,0x58ee,0x72b6,0x690e,0x9525,0x8ffd, 0x8d58,0x5760,0x7f00,0x8c06,0x51c6,0x6349,0x62d9,0x5353,0x684c,0x7422, 0x8301,0x914c,0x5544,0x7740,0x707c,0x6d4a,0x5179,0x54a8,0x8d44,0x59ff, 0x6ecb,0x6dc4,0x5b5c,0x7d2b,0x4ed4,0x7c7d,0x6ed3,0x5b50,0x81ea,0x6e0d, 0x5b57,0x9b03,0x68d5,0x8e2a,0x5b97,0x7efc,0x603b,0x7eb5,0x90b9,0x8d70, 0x594f,0x63cd,0x79df,0x8db3,0x5352,0x65cf,0x7956,0x8bc5,0x963b,0x7ec4, 0x94bb,0x7e82,0x5634,0x9189,0x6700,0x7f6a,0x5c0a,0x9075,0x6628,0x5de6, 0x4f50,0x67de,0x505a,0x4f5c,0x5750,0x5ea7,UBOGON,UBOGON,UBOGON,UBOGON, UBOGON }, { /* ku 58 */ 0x8c38,0x8c39,0x8c3a,0x8c3b,0x8c3c,0x8c3d,0x8c3e,0x8c3f,0x8c40,0x8c42, 0x8c43,0x8c44,0x8c45,0x8c48,0x8c4a,0x8c4b,0x8c4d,0x8c4e,0x8c4f,0x8c50, 0x8c51,0x8c52,0x8c53,0x8c54,0x8c56,0x8c57,0x8c58,0x8c59,0x8c5b,0x8c5c, 0x8c5d,0x8c5e,0x8c5f,0x8c60,0x8c63,0x8c64,0x8c65,0x8c66,0x8c67,0x8c68, 0x8c69,0x8c6c,0x8c6d,0x8c6e,0x8c6f,0x8c70,0x8c71,0x8c72,0x8c74,0x8c75, 0x8c76,0x8c77,0x8c7b,0x8c7c,0x8c7d,0x8c7e,0x8c7f,0x8c80,0x8c81,0x8c83, 0x8c84,0x8c86,0x8c87,UBOGON,0x8c88,0x8c8b,0x8c8d,0x8c8e,0x8c8f,0x8c90, 0x8c91,0x8c92,0x8c93,0x8c95,0x8c96,0x8c97,0x8c99,0x8c9a,0x8c9b,0x8c9c, 0x8c9d,0x8c9e,0x8c9f,0x8ca0,0x8ca1,0x8ca2,0x8ca3,0x8ca4,0x8ca5,0x8ca6, 0x8ca7,0x8ca8,0x8ca9,0x8caa,0x8cab,0x8cac,0x8cad,0x4e8d,0x4e0c,0x5140, 0x4e10,0x5eff,0x5345,0x4e15,0x4e98,0x4e1e,0x9b32,0x5b6c,0x5669,0x4e28, 0x79ba,0x4e3f,0x5315,0x4e47,0x592d,0x723b,0x536e,0x6c10,0x56df,0x80e4, 0x9997,0x6bd3,0x777e,0x9f17,0x4e36,0x4e9f,0x9f10,0x4e5c,0x4e69,0x4e93, 0x8288,0x5b5b,0x556c,0x560f,0x4ec4,0x538d,0x539d,0x53a3,0x53a5,0x53ae, 0x9765,0x8d5d,0x531a,0x53f5,0x5326,0x532e,0x533e,0x8d5c,0x5366,0x5363, 0x5202,0x5208,0x520e,0x522d,0x5233,0x523f,0x5240,0x524c,0x525e,0x5261, 0x525c,0x84af,0x527d,0x5282,0x5281,0x5290,0x5293,0x5182,0x7f54,0x4ebb, 0x4ec3,0x4ec9,0x4ec2,0x4ee8,0x4ee1,0x4eeb,0x4ede,0x4f1b,0x4ef3,0x4f22, 0x4f64,0x4ef5,0x4f25,0x4f27,0x4f09,0x4f2b,0x4f5e,0x4f67,0x6538,0x4f5a, 0x4f5d }, { /* ku 59 */ 0x8cae,0x8caf,0x8cb0,0x8cb1,0x8cb2,0x8cb3,0x8cb4,0x8cb5,0x8cb6,0x8cb7, 0x8cb8,0x8cb9,0x8cba,0x8cbb,0x8cbc,0x8cbd,0x8cbe,0x8cbf,0x8cc0,0x8cc1, 0x8cc2,0x8cc3,0x8cc4,0x8cc5,0x8cc6,0x8cc7,0x8cc8,0x8cc9,0x8cca,0x8ccb, 0x8ccc,0x8ccd,0x8cce,0x8ccf,0x8cd0,0x8cd1,0x8cd2,0x8cd3,0x8cd4,0x8cd5, 0x8cd6,0x8cd7,0x8cd8,0x8cd9,0x8cda,0x8cdb,0x8cdc,0x8cdd,0x8cde,0x8cdf, 0x8ce0,0x8ce1,0x8ce2,0x8ce3,0x8ce4,0x8ce5,0x8ce6,0x8ce7,0x8ce8,0x8ce9, 0x8cea,0x8ceb,0x8cec,UBOGON,0x8ced,0x8cee,0x8cef,0x8cf0,0x8cf1,0x8cf2, 0x8cf3,0x8cf4,0x8cf5,0x8cf6,0x8cf7,0x8cf8,0x8cf9,0x8cfa,0x8cfb,0x8cfc, 0x8cfd,0x8cfe,0x8cff,0x8d00,0x8d01,0x8d02,0x8d03,0x8d04,0x8d05,0x8d06, 0x8d07,0x8d08,0x8d09,0x8d0a,0x8d0b,0x8d0c,0x8d0d,0x4f5f,0x4f57,0x4f32, 0x4f3d,0x4f76,0x4f74,0x4f91,0x4f89,0x4f83,0x4f8f,0x4f7e,0x4f7b,0x4faa, 0x4f7c,0x4fac,0x4f94,0x4fe6,0x4fe8,0x4fea,0x4fc5,0x4fda,0x4fe3,0x4fdc, 0x4fd1,0x4fdf,0x4ff8,0x5029,0x504c,0x4ff3,0x502c,0x500f,0x502e,0x502d, 0x4ffe,0x501c,0x500c,0x5025,0x5028,0x507e,0x5043,0x5055,0x5048,0x504e, 0x506c,0x507b,0x50a5,0x50a7,0x50a9,0x50ba,0x50d6,0x5106,0x50ed,0x50ec, 0x50e6,0x50ee,0x5107,0x510b,0x4edd,0x6c3d,0x4f58,0x4f65,0x4fce,0x9fa0, 0x6c46,0x7c74,0x516e,0x5dfd,0x9ec9,0x9998,0x5181,0x5914,0x52f9,0x530d, 0x8a07,0x5310,0x51eb,0x5919,0x5155,0x4ea0,0x5156,0x4eb3,0x886e,0x88a4, 0x4eb5,0x8114,0x88d2,0x7980,0x5b34,0x8803,0x7fb8,0x51ab,0x51b1,0x51bd, 0x51bc }, { /* ku 5a */ 0x8d0e,0x8d0f,0x8d10,0x8d11,0x8d12,0x8d13,0x8d14,0x8d15,0x8d16,0x8d17, 0x8d18,0x8d19,0x8d1a,0x8d1b,0x8d1c,0x8d20,0x8d51,0x8d52,0x8d57,0x8d5f, 0x8d65,0x8d68,0x8d69,0x8d6a,0x8d6c,0x8d6e,0x8d6f,0x8d71,0x8d72,0x8d78, 0x8d79,0x8d7a,0x8d7b,0x8d7c,0x8d7d,0x8d7e,0x8d7f,0x8d80,0x8d82,0x8d83, 0x8d86,0x8d87,0x8d88,0x8d89,0x8d8c,0x8d8d,0x8d8e,0x8d8f,0x8d90,0x8d92, 0x8d93,0x8d95,0x8d96,0x8d97,0x8d98,0x8d99,0x8d9a,0x8d9b,0x8d9c,0x8d9d, 0x8d9e,0x8da0,0x8da1,UBOGON,0x8da2,0x8da4,0x8da5,0x8da6,0x8da7,0x8da8, 0x8da9,0x8daa,0x8dab,0x8dac,0x8dad,0x8dae,0x8daf,0x8db0,0x8db2,0x8db6, 0x8db7,0x8db9,0x8dbb,0x8dbd,0x8dc0,0x8dc1,0x8dc2,0x8dc5,0x8dc7,0x8dc8, 0x8dc9,0x8dca,0x8dcd,0x8dd0,0x8dd2,0x8dd3,0x8dd4,0x51c7,0x5196,0x51a2, 0x51a5,0x8ba0,0x8ba6,0x8ba7,0x8baa,0x8bb4,0x8bb5,0x8bb7,0x8bc2,0x8bc3, 0x8bcb,0x8bcf,0x8bce,0x8bd2,0x8bd3,0x8bd4,0x8bd6,0x8bd8,0x8bd9,0x8bdc, 0x8bdf,0x8be0,0x8be4,0x8be8,0x8be9,0x8bee,0x8bf0,0x8bf3,0x8bf6,0x8bf9, 0x8bfc,0x8bff,0x8c00,0x8c02,0x8c04,0x8c07,0x8c0c,0x8c0f,0x8c11,0x8c12, 0x8c14,0x8c15,0x8c16,0x8c19,0x8c1b,0x8c18,0x8c1d,0x8c1f,0x8c20,0x8c21, 0x8c25,0x8c27,0x8c2a,0x8c2b,0x8c2e,0x8c2f,0x8c32,0x8c33,0x8c35,0x8c36, 0x5369,0x537a,0x961d,0x9622,0x9621,0x9631,0x962a,0x963d,0x963c,0x9642, 0x9649,0x9654,0x965f,0x9667,0x966c,0x9672,0x9674,0x9688,0x968d,0x9697, 0x96b0,0x9097,0x909b,0x909d,0x9099,0x90ac,0x90a1,0x90b4,0x90b3,0x90b6, 0x90ba }, { /* ku 5b */ 0x8dd5,0x8dd8,0x8dd9,0x8ddc,0x8de0,0x8de1,0x8de2,0x8de5,0x8de6,0x8de7, 0x8de9,0x8ded,0x8dee,0x8df0,0x8df1,0x8df2,0x8df4,0x8df6,0x8dfc,0x8dfe, 0x8dff,0x8e00,0x8e01,0x8e02,0x8e03,0x8e04,0x8e06,0x8e07,0x8e08,0x8e0b, 0x8e0d,0x8e0e,0x8e10,0x8e11,0x8e12,0x8e13,0x8e15,0x8e16,0x8e17,0x8e18, 0x8e19,0x8e1a,0x8e1b,0x8e1c,0x8e20,0x8e21,0x8e24,0x8e25,0x8e26,0x8e27, 0x8e28,0x8e2b,0x8e2d,0x8e30,0x8e32,0x8e33,0x8e34,0x8e36,0x8e37,0x8e38, 0x8e3b,0x8e3c,0x8e3e,UBOGON,0x8e3f,0x8e43,0x8e45,0x8e46,0x8e4c,0x8e4d, 0x8e4e,0x8e4f,0x8e50,0x8e53,0x8e54,0x8e55,0x8e56,0x8e57,0x8e58,0x8e5a, 0x8e5b,0x8e5c,0x8e5d,0x8e5e,0x8e5f,0x8e60,0x8e61,0x8e62,0x8e63,0x8e64, 0x8e65,0x8e67,0x8e68,0x8e6a,0x8e6b,0x8e6e,0x8e71,0x90b8,0x90b0,0x90cf, 0x90c5,0x90be,0x90d0,0x90c4,0x90c7,0x90d3,0x90e6,0x90e2,0x90dc,0x90d7, 0x90db,0x90eb,0x90ef,0x90fe,0x9104,0x9122,0x911e,0x9123,0x9131,0x912f, 0x9139,0x9143,0x9146,0x520d,0x5942,0x52a2,0x52ac,0x52ad,0x52be,0x54ff, 0x52d0,0x52d6,0x52f0,0x53df,0x71ee,0x77cd,0x5ef4,0x51f5,0x51fc,0x9b2f, 0x53b6,0x5f01,0x755a,0x5def,0x574c,0x57a9,0x57a1,0x587e,0x58bc,0x58c5, 0x58d1,0x5729,0x572c,0x572a,0x5733,0x5739,0x572e,0x572f,0x575c,0x573b, 0x5742,0x5769,0x5785,0x576b,0x5786,0x577c,0x577b,0x5768,0x576d,0x5776, 0x5773,0x57ad,0x57a4,0x578c,0x57b2,0x57cf,0x57a7,0x57b4,0x5793,0x57a0, 0x57d5,0x57d8,0x57da,0x57d9,0x57d2,0x57b8,0x57f4,0x57ef,0x57f8,0x57e4, 0x57dd }, { /* ku 5c */ 0x8e73,0x8e75,0x8e77,0x8e78,0x8e79,0x8e7a,0x8e7b,0x8e7d,0x8e7e,0x8e80, 0x8e82,0x8e83,0x8e84,0x8e86,0x8e88,0x8e89,0x8e8a,0x8e8b,0x8e8c,0x8e8d, 0x8e8e,0x8e91,0x8e92,0x8e93,0x8e95,0x8e96,0x8e97,0x8e98,0x8e99,0x8e9a, 0x8e9b,0x8e9d,0x8e9f,0x8ea0,0x8ea1,0x8ea2,0x8ea3,0x8ea4,0x8ea5,0x8ea6, 0x8ea7,0x8ea8,0x8ea9,0x8eaa,0x8ead,0x8eae,0x8eb0,0x8eb1,0x8eb3,0x8eb4, 0x8eb5,0x8eb6,0x8eb7,0x8eb8,0x8eb9,0x8ebb,0x8ebc,0x8ebd,0x8ebe,0x8ebf, 0x8ec0,0x8ec1,0x8ec2,UBOGON,0x8ec3,0x8ec4,0x8ec5,0x8ec6,0x8ec7,0x8ec8, 0x8ec9,0x8eca,0x8ecb,0x8ecc,0x8ecd,0x8ecf,0x8ed0,0x8ed1,0x8ed2,0x8ed3, 0x8ed4,0x8ed5,0x8ed6,0x8ed7,0x8ed8,0x8ed9,0x8eda,0x8edb,0x8edc,0x8edd, 0x8ede,0x8edf,0x8ee0,0x8ee1,0x8ee2,0x8ee3,0x8ee4,0x580b,0x580d,0x57fd, 0x57ed,0x5800,0x581e,0x5819,0x5844,0x5820,0x5865,0x586c,0x5881,0x5889, 0x589a,0x5880,0x99a8,0x9f19,0x61ff,0x8279,0x827d,0x827f,0x828f,0x828a, 0x82a8,0x8284,0x828e,0x8291,0x8297,0x8299,0x82ab,0x82b8,0x82be,0x82b0, 0x82c8,0x82ca,0x82e3,0x8298,0x82b7,0x82ae,0x82cb,0x82cc,0x82c1,0x82a9, 0x82b4,0x82a1,0x82aa,0x829f,0x82c4,0x82ce,0x82a4,0x82e1,0x8309,0x82f7, 0x82e4,0x830f,0x8307,0x82dc,0x82f4,0x82d2,0x82d8,0x830c,0x82fb,0x82d3, 0x8311,0x831a,0x8306,0x8314,0x8315,0x82e0,0x82d5,0x831c,0x8351,0x835b, 0x835c,0x8308,0x8392,0x833c,0x8334,0x8331,0x839b,0x835e,0x832f,0x834f, 0x8347,0x8343,0x835f,0x8340,0x8317,0x8360,0x832d,0x833a,0x8333,0x8366, 0x8365 }, { /* ku 5d */ 0x8ee5,0x8ee6,0x8ee7,0x8ee8,0x8ee9,0x8eea,0x8eeb,0x8eec,0x8eed,0x8eee, 0x8eef,0x8ef0,0x8ef1,0x8ef2,0x8ef3,0x8ef4,0x8ef5,0x8ef6,0x8ef7,0x8ef8, 0x8ef9,0x8efa,0x8efb,0x8efc,0x8efd,0x8efe,0x8eff,0x8f00,0x8f01,0x8f02, 0x8f03,0x8f04,0x8f05,0x8f06,0x8f07,0x8f08,0x8f09,0x8f0a,0x8f0b,0x8f0c, 0x8f0d,0x8f0e,0x8f0f,0x8f10,0x8f11,0x8f12,0x8f13,0x8f14,0x8f15,0x8f16, 0x8f17,0x8f18,0x8f19,0x8f1a,0x8f1b,0x8f1c,0x8f1d,0x8f1e,0x8f1f,0x8f20, 0x8f21,0x8f22,0x8f23,UBOGON,0x8f24,0x8f25,0x8f26,0x8f27,0x8f28,0x8f29, 0x8f2a,0x8f2b,0x8f2c,0x8f2d,0x8f2e,0x8f2f,0x8f30,0x8f31,0x8f32,0x8f33, 0x8f34,0x8f35,0x8f36,0x8f37,0x8f38,0x8f39,0x8f3a,0x8f3b,0x8f3c,0x8f3d, 0x8f3e,0x8f3f,0x8f40,0x8f41,0x8f42,0x8f43,0x8f44,0x8368,0x831b,0x8369, 0x836c,0x836a,0x836d,0x836e,0x83b0,0x8378,0x83b3,0x83b4,0x83a0,0x83aa, 0x8393,0x839c,0x8385,0x837c,0x83b6,0x83a9,0x837d,0x83b8,0x837b,0x8398, 0x839e,0x83a8,0x83ba,0x83bc,0x83c1,0x8401,0x83e5,0x83d8,0x5807,0x8418, 0x840b,0x83dd,0x83fd,0x83d6,0x841c,0x8438,0x8411,0x8406,0x83d4,0x83df, 0x840f,0x8403,0x83f8,0x83f9,0x83ea,0x83c5,0x83c0,0x8426,0x83f0,0x83e1, 0x845c,0x8451,0x845a,0x8459,0x8473,0x8487,0x8488,0x847a,0x8489,0x8478, 0x843c,0x8446,0x8469,0x8476,0x848c,0x848e,0x8431,0x846d,0x84c1,0x84cd, 0x84d0,0x84e6,0x84bd,0x84d3,0x84ca,0x84bf,0x84ba,0x84e0,0x84a1,0x84b9, 0x84b4,0x8497,0x84e5,0x84e3,0x850c,0x750d,0x8538,0x84f0,0x8539,0x851f, 0x853a }, { /* ku 5e */ 0x8f45,0x8f46,0x8f47,0x8f48,0x8f49,0x8f4a,0x8f4b,0x8f4c,0x8f4d,0x8f4e, 0x8f4f,0x8f50,0x8f51,0x8f52,0x8f53,0x8f54,0x8f55,0x8f56,0x8f57,0x8f58, 0x8f59,0x8f5a,0x8f5b,0x8f5c,0x8f5d,0x8f5e,0x8f5f,0x8f60,0x8f61,0x8f62, 0x8f63,0x8f64,0x8f65,0x8f6a,0x8f80,0x8f8c,0x8f92,0x8f9d,0x8fa0,0x8fa1, 0x8fa2,0x8fa4,0x8fa5,0x8fa6,0x8fa7,0x8faa,0x8fac,0x8fad,0x8fae,0x8faf, 0x8fb2,0x8fb3,0x8fb4,0x8fb5,0x8fb7,0x8fb8,0x8fba,0x8fbb,0x8fbc,0x8fbf, 0x8fc0,0x8fc3,0x8fc6,UBOGON,0x8fc9,0x8fca,0x8fcb,0x8fcc,0x8fcd,0x8fcf, 0x8fd2,0x8fd6,0x8fd7,0x8fda,0x8fe0,0x8fe1,0x8fe3,0x8fe7,0x8fec,0x8fef, 0x8ff1,0x8ff2,0x8ff4,0x8ff5,0x8ff6,0x8ffa,0x8ffb,0x8ffc,0x8ffe,0x8fff, 0x9007,0x9008,0x900c,0x900e,0x9013,0x9015,0x9018,0x8556,0x853b,0x84ff, 0x84fc,0x8559,0x8548,0x8568,0x8564,0x855e,0x857a,0x77a2,0x8543,0x8572, 0x857b,0x85a4,0x85a8,0x8587,0x858f,0x8579,0x85ae,0x859c,0x8585,0x85b9, 0x85b7,0x85b0,0x85d3,0x85c1,0x85dc,0x85ff,0x8627,0x8605,0x8629,0x8616, 0x863c,0x5efe,0x5f08,0x593c,0x5941,0x8037,0x5955,0x595a,0x5958,0x530f, 0x5c22,0x5c25,0x5c2c,0x5c34,0x624c,0x626a,0x629f,0x62bb,0x62ca,0x62da, 0x62d7,0x62ee,0x6322,0x62f6,0x6339,0x634b,0x6343,0x63ad,0x63f6,0x6371, 0x637a,0x638e,0x63b4,0x636d,0x63ac,0x638a,0x6369,0x63ae,0x63bc,0x63f2, 0x63f8,0x63e0,0x63ff,0x63c4,0x63de,0x63ce,0x6452,0x63c6,0x63be,0x6445, 0x6441,0x640b,0x641b,0x6420,0x640c,0x6426,0x6421,0x645e,0x6484,0x646d, 0x6496 }, { /* ku 5f */ 0x9019,0x901c,0x9023,0x9024,0x9025,0x9027,0x9028,0x9029,0x902a,0x902b, 0x902c,0x9030,0x9031,0x9032,0x9033,0x9034,0x9037,0x9039,0x903a,0x903d, 0x903f,0x9040,0x9043,0x9045,0x9046,0x9048,0x9049,0x904a,0x904b,0x904c, 0x904e,0x9054,0x9055,0x9056,0x9059,0x905a,0x905c,0x905d,0x905e,0x905f, 0x9060,0x9061,0x9064,0x9066,0x9067,0x9069,0x906a,0x906b,0x906c,0x906f, 0x9070,0x9071,0x9072,0x9073,0x9076,0x9077,0x9078,0x9079,0x907a,0x907b, 0x907c,0x907e,0x9081,UBOGON,0x9084,0x9085,0x9086,0x9087,0x9089,0x908a, 0x908c,0x908d,0x908e,0x908f,0x9090,0x9092,0x9094,0x9096,0x9098,0x909a, 0x909c,0x909e,0x909f,0x90a0,0x90a4,0x90a5,0x90a7,0x90a8,0x90a9,0x90ab, 0x90ad,0x90b2,0x90b7,0x90bc,0x90bd,0x90bf,0x90c0,0x647a,0x64b7,0x64b8, 0x6499,0x64ba,0x64c0,0x64d0,0x64d7,0x64e4,0x64e2,0x6509,0x6525,0x652e, 0x5f0b,0x5fd2,0x7519,0x5f11,0x535f,0x53f1,0x53fd,0x53e9,0x53e8,0x53fb, 0x5412,0x5416,0x5406,0x544b,0x5452,0x5453,0x5454,0x5456,0x5443,0x5421, 0x5457,0x5459,0x5423,0x5432,0x5482,0x5494,0x5477,0x5471,0x5464,0x549a, 0x549b,0x5484,0x5476,0x5466,0x549d,0x54d0,0x54ad,0x54c2,0x54b4,0x54d2, 0x54a7,0x54a6,0x54d3,0x54d4,0x5472,0x54a3,0x54d5,0x54bb,0x54bf,0x54cc, 0x54d9,0x54da,0x54dc,0x54a9,0x54aa,0x54a4,0x54dd,0x54cf,0x54de,0x551b, 0x54e7,0x5520,0x54fd,0x5514,0x54f3,0x5522,0x5523,0x550f,0x5511,0x5527, 0x552a,0x5567,0x558f,0x55b5,0x5549,0x556d,0x5541,0x5555,0x553f,0x5550, 0x553c }, { /* ku 60 */ 0x90c2,0x90c3,0x90c6,0x90c8,0x90c9,0x90cb,0x90cc,0x90cd,0x90d2,0x90d4, 0x90d5,0x90d6,0x90d8,0x90d9,0x90da,0x90de,0x90df,0x90e0,0x90e3,0x90e4, 0x90e5,0x90e9,0x90ea,0x90ec,0x90ee,0x90f0,0x90f1,0x90f2,0x90f3,0x90f5, 0x90f6,0x90f7,0x90f9,0x90fa,0x90fb,0x90fc,0x90ff,0x9100,0x9101,0x9103, 0x9105,0x9106,0x9107,0x9108,0x9109,0x910a,0x910b,0x910c,0x910d,0x910e, 0x910f,0x9110,0x9111,0x9112,0x9113,0x9114,0x9115,0x9116,0x9117,0x9118, 0x911a,0x911b,0x911c,UBOGON,0x911d,0x911f,0x9120,0x9121,0x9124,0x9125, 0x9126,0x9127,0x9128,0x9129,0x912a,0x912b,0x912c,0x912d,0x912e,0x9130, 0x9132,0x9133,0x9134,0x9135,0x9136,0x9137,0x9138,0x913a,0x913b,0x913c, 0x913d,0x913e,0x913f,0x9140,0x9141,0x9142,0x9144,0x5537,0x5556,0x5575, 0x5576,0x5577,0x5533,0x5530,0x555c,0x558b,0x55d2,0x5583,0x55b1,0x55b9, 0x5588,0x5581,0x559f,0x557e,0x55d6,0x5591,0x557b,0x55df,0x55bd,0x55be, 0x5594,0x5599,0x55ea,0x55f7,0x55c9,0x561f,0x55d1,0x55eb,0x55ec,0x55d4, 0x55e6,0x55dd,0x55c4,0x55ef,0x55e5,0x55f2,0x55f3,0x55cc,0x55cd,0x55e8, 0x55f5,0x55e4,0x8f94,0x561e,0x5608,0x560c,0x5601,0x5624,0x5623,0x55fe, 0x5600,0x5627,0x562d,0x5658,0x5639,0x5657,0x562c,0x564d,0x5662,0x5659, 0x565c,0x564c,0x5654,0x5686,0x5664,0x5671,0x566b,0x567b,0x567c,0x5685, 0x5693,0x56af,0x56d4,0x56d7,0x56dd,0x56e1,0x56f5,0x56eb,0x56f9,0x56ff, 0x5704,0x570a,0x5709,0x571c,0x5e0f,0x5e19,0x5e14,0x5e11,0x5e31,0x5e3b, 0x5e3c }, { /* ku 61 */ 0x9145,0x9147,0x9148,0x9151,0x9153,0x9154,0x9155,0x9156,0x9158,0x9159, 0x915b,0x915c,0x915f,0x9160,0x9166,0x9167,0x9168,0x916b,0x916d,0x9173, 0x917a,0x917b,0x917c,0x9180,0x9181,0x9182,0x9183,0x9184,0x9186,0x9188, 0x918a,0x918e,0x918f,0x9193,0x9194,0x9195,0x9196,0x9197,0x9198,0x9199, 0x919c,0x919d,0x919e,0x919f,0x91a0,0x91a1,0x91a4,0x91a5,0x91a6,0x91a7, 0x91a8,0x91a9,0x91ab,0x91ac,0x91b0,0x91b1,0x91b2,0x91b3,0x91b6,0x91b7, 0x91b8,0x91b9,0x91bb,UBOGON,0x91bc,0x91bd,0x91be,0x91bf,0x91c0,0x91c1, 0x91c2,0x91c3,0x91c4,0x91c5,0x91c6,0x91c8,0x91cb,0x91d0,0x91d2,0x91d3, 0x91d4,0x91d5,0x91d6,0x91d7,0x91d8,0x91d9,0x91da,0x91db,0x91dd,0x91de, 0x91df,0x91e0,0x91e1,0x91e2,0x91e3,0x91e4,0x91e5,0x5e37,0x5e44,0x5e54, 0x5e5b,0x5e5e,0x5e61,0x5c8c,0x5c7a,0x5c8d,0x5c90,0x5c96,0x5c88,0x5c98, 0x5c99,0x5c91,0x5c9a,0x5c9c,0x5cb5,0x5ca2,0x5cbd,0x5cac,0x5cab,0x5cb1, 0x5ca3,0x5cc1,0x5cb7,0x5cc4,0x5cd2,0x5ce4,0x5ccb,0x5ce5,0x5d02,0x5d03, 0x5d27,0x5d26,0x5d2e,0x5d24,0x5d1e,0x5d06,0x5d1b,0x5d58,0x5d3e,0x5d34, 0x5d3d,0x5d6c,0x5d5b,0x5d6f,0x5d5d,0x5d6b,0x5d4b,0x5d4a,0x5d69,0x5d74, 0x5d82,0x5d99,0x5d9d,0x8c73,0x5db7,0x5dc5,0x5f73,0x5f77,0x5f82,0x5f87, 0x5f89,0x5f8c,0x5f95,0x5f99,0x5f9c,0x5fa8,0x5fad,0x5fb5,0x5fbc,0x8862, 0x5f61,0x72ad,0x72b0,0x72b4,0x72b7,0x72b8,0x72c3,0x72c1,0x72ce,0x72cd, 0x72d2,0x72e8,0x72ef,0x72e9,0x72f2,0x72f4,0x72f7,0x7301,0x72f3,0x7303, 0x72fa }, { /* ku 62 */ 0x91e6,0x91e7,0x91e8,0x91e9,0x91ea,0x91eb,0x91ec,0x91ed,0x91ee,0x91ef, 0x91f0,0x91f1,0x91f2,0x91f3,0x91f4,0x91f5,0x91f6,0x91f7,0x91f8,0x91f9, 0x91fa,0x91fb,0x91fc,0x91fd,0x91fe,0x91ff,0x9200,0x9201,0x9202,0x9203, 0x9204,0x9205,0x9206,0x9207,0x9208,0x9209,0x920a,0x920b,0x920c,0x920d, 0x920e,0x920f,0x9210,0x9211,0x9212,0x9213,0x9214,0x9215,0x9216,0x9217, 0x9218,0x9219,0x921a,0x921b,0x921c,0x921d,0x921e,0x921f,0x9220,0x9221, 0x9222,0x9223,0x9224,UBOGON,0x9225,0x9226,0x9227,0x9228,0x9229,0x922a, 0x922b,0x922c,0x922d,0x922e,0x922f,0x9230,0x9231,0x9232,0x9233,0x9234, 0x9235,0x9236,0x9237,0x9238,0x9239,0x923a,0x923b,0x923c,0x923d,0x923e, 0x923f,0x9240,0x9241,0x9242,0x9243,0x9244,0x9245,0x72fb,0x7317,0x7313, 0x7321,0x730a,0x731e,0x731d,0x7315,0x7322,0x7339,0x7325,0x732c,0x7338, 0x7331,0x7350,0x734d,0x7357,0x7360,0x736c,0x736f,0x737e,0x821b,0x5925, 0x98e7,0x5924,0x5902,0x9963,0x9967,0x9968,0x9969,0x996a,0x996b,0x996c, 0x9974,0x9977,0x997d,0x9980,0x9984,0x9987,0x998a,0x998d,0x9990,0x9991, 0x9993,0x9994,0x9995,0x5e80,0x5e91,0x5e8b,0x5e96,0x5ea5,0x5ea0,0x5eb9, 0x5eb5,0x5ebe,0x5eb3,0x8d53,0x5ed2,0x5ed1,0x5edb,0x5ee8,0x5eea,0x81ba, 0x5fc4,0x5fc9,0x5fd6,0x5fcf,0x6003,0x5fee,0x6004,0x5fe1,0x5fe4,0x5ffe, 0x6005,0x6006,0x5fea,0x5fed,0x5ff8,0x6019,0x6035,0x6026,0x601b,0x600f, 0x600d,0x6029,0x602b,0x600a,0x603f,0x6021,0x6078,0x6079,0x607b,0x607a, 0x6042 }, { /* ku 63 */ 0x9246,0x9247,0x9248,0x9249,0x924a,0x924b,0x924c,0x924d,0x924e,0x924f, 0x9250,0x9251,0x9252,0x9253,0x9254,0x9255,0x9256,0x9257,0x9258,0x9259, 0x925a,0x925b,0x925c,0x925d,0x925e,0x925f,0x9260,0x9261,0x9262,0x9263, 0x9264,0x9265,0x9266,0x9267,0x9268,0x9269,0x926a,0x926b,0x926c,0x926d, 0x926e,0x926f,0x9270,0x9271,0x9272,0x9273,0x9275,0x9276,0x9277,0x9278, 0x9279,0x927a,0x927b,0x927c,0x927d,0x927e,0x927f,0x9280,0x9281,0x9282, 0x9283,0x9284,0x9285,UBOGON,0x9286,0x9287,0x9288,0x9289,0x928a,0x928b, 0x928c,0x928d,0x928f,0x9290,0x9291,0x9292,0x9293,0x9294,0x9295,0x9296, 0x9297,0x9298,0x9299,0x929a,0x929b,0x929c,0x929d,0x929e,0x929f,0x92a0, 0x92a1,0x92a2,0x92a3,0x92a4,0x92a5,0x92a6,0x92a7,0x606a,0x607d,0x6096, 0x609a,0x60ad,0x609d,0x6083,0x6092,0x608c,0x609b,0x60ec,0x60bb,0x60b1, 0x60dd,0x60d8,0x60c6,0x60da,0x60b4,0x6120,0x6126,0x6115,0x6123,0x60f4, 0x6100,0x610e,0x612b,0x614a,0x6175,0x61ac,0x6194,0x61a7,0x61b7,0x61d4, 0x61f5,0x5fdd,0x96b3,0x95e9,0x95eb,0x95f1,0x95f3,0x95f5,0x95f6,0x95fc, 0x95fe,0x9603,0x9604,0x9606,0x9608,0x960a,0x960b,0x960c,0x960d,0x960f, 0x9612,0x9615,0x9616,0x9617,0x9619,0x961a,0x4e2c,0x723f,0x6215,0x6c35, 0x6c54,0x6c5c,0x6c4a,0x6ca3,0x6c85,0x6c90,0x6c94,0x6c8c,0x6c68,0x6c69, 0x6c74,0x6c76,0x6c86,0x6ca9,0x6cd0,0x6cd4,0x6cad,0x6cf7,0x6cf8,0x6cf1, 0x6cd7,0x6cb2,0x6ce0,0x6cd6,0x6cfa,0x6ceb,0x6cee,0x6cb1,0x6cd3,0x6cef, 0x6cfe }, { /* ku 64 */ 0x92a8,0x92a9,0x92aa,0x92ab,0x92ac,0x92ad,0x92af,0x92b0,0x92b1,0x92b2, 0x92b3,0x92b4,0x92b5,0x92b6,0x92b7,0x92b8,0x92b9,0x92ba,0x92bb,0x92bc, 0x92bd,0x92be,0x92bf,0x92c0,0x92c1,0x92c2,0x92c3,0x92c4,0x92c5,0x92c6, 0x92c7,0x92c9,0x92ca,0x92cb,0x92cc,0x92cd,0x92ce,0x92cf,0x92d0,0x92d1, 0x92d2,0x92d3,0x92d4,0x92d5,0x92d6,0x92d7,0x92d8,0x92d9,0x92da,0x92db, 0x92dc,0x92dd,0x92de,0x92df,0x92e0,0x92e1,0x92e2,0x92e3,0x92e4,0x92e5, 0x92e6,0x92e7,0x92e8,UBOGON,0x92e9,0x92ea,0x92eb,0x92ec,0x92ed,0x92ee, 0x92ef,0x92f0,0x92f1,0x92f2,0x92f3,0x92f4,0x92f5,0x92f6,0x92f7,0x92f8, 0x92f9,0x92fa,0x92fb,0x92fc,0x92fd,0x92fe,0x92ff,0x9300,0x9301,0x9302, 0x9303,0x9304,0x9305,0x9306,0x9307,0x9308,0x9309,0x6d39,0x6d27,0x6d0c, 0x6d43,0x6d48,0x6d07,0x6d04,0x6d19,0x6d0e,0x6d2b,0x6d4d,0x6d2e,0x6d35, 0x6d1a,0x6d4f,0x6d52,0x6d54,0x6d33,0x6d91,0x6d6f,0x6d9e,0x6da0,0x6d5e, 0x6d93,0x6d94,0x6d5c,0x6d60,0x6d7c,0x6d63,0x6e1a,0x6dc7,0x6dc5,0x6dde, 0x6e0e,0x6dbf,0x6de0,0x6e11,0x6de6,0x6ddd,0x6dd9,0x6e16,0x6dab,0x6e0c, 0x6dae,0x6e2b,0x6e6e,0x6e4e,0x6e6b,0x6eb2,0x6e5f,0x6e86,0x6e53,0x6e54, 0x6e32,0x6e25,0x6e44,0x6edf,0x6eb1,0x6e98,0x6ee0,0x6f2d,0x6ee2,0x6ea5, 0x6ea7,0x6ebd,0x6ebb,0x6eb7,0x6ed7,0x6eb4,0x6ecf,0x6e8f,0x6ec2,0x6e9f, 0x6f62,0x6f46,0x6f47,0x6f24,0x6f15,0x6ef9,0x6f2f,0x6f36,0x6f4b,0x6f74, 0x6f2a,0x6f09,0x6f29,0x6f89,0x6f8d,0x6f8c,0x6f78,0x6f72,0x6f7c,0x6f7a, 0x6fd1 }, { /* ku 65 */ 0x930a,0x930b,0x930c,0x930d,0x930e,0x930f,0x9310,0x9311,0x9312,0x9313, 0x9314,0x9315,0x9316,0x9317,0x9318,0x9319,0x931a,0x931b,0x931c,0x931d, 0x931e,0x931f,0x9320,0x9321,0x9322,0x9323,0x9324,0x9325,0x9326,0x9327, 0x9328,0x9329,0x932a,0x932b,0x932c,0x932d,0x932e,0x932f,0x9330,0x9331, 0x9332,0x9333,0x9334,0x9335,0x9336,0x9337,0x9338,0x9339,0x933a,0x933b, 0x933c,0x933d,0x933f,0x9340,0x9341,0x9342,0x9343,0x9344,0x9345,0x9346, 0x9347,0x9348,0x9349,UBOGON,0x934a,0x934b,0x934c,0x934d,0x934e,0x934f, 0x9350,0x9351,0x9352,0x9353,0x9354,0x9355,0x9356,0x9357,0x9358,0x9359, 0x935a,0x935b,0x935c,0x935d,0x935e,0x935f,0x9360,0x9361,0x9362,0x9363, 0x9364,0x9365,0x9366,0x9367,0x9368,0x9369,0x936b,0x6fc9,0x6fa7,0x6fb9, 0x6fb6,0x6fc2,0x6fe1,0x6fee,0x6fde,0x6fe0,0x6fef,0x701a,0x7023,0x701b, 0x7039,0x7035,0x704f,0x705e,0x5b80,0x5b84,0x5b95,0x5b93,0x5ba5,0x5bb8, 0x752f,0x9a9e,0x6434,0x5be4,0x5bee,0x8930,0x5bf0,0x8e47,0x8b07,0x8fb6, 0x8fd3,0x8fd5,0x8fe5,0x8fee,0x8fe4,0x8fe9,0x8fe6,0x8ff3,0x8fe8,0x9005, 0x9004,0x900b,0x9026,0x9011,0x900d,0x9016,0x9021,0x9035,0x9036,0x902d, 0x902f,0x9044,0x9051,0x9052,0x9050,0x9068,0x9058,0x9062,0x905b,0x66b9, 0x9074,0x907d,0x9082,0x9088,0x9083,0x908b,0x5f50,0x5f57,0x5f56,0x5f58, 0x5c3b,0x54ab,0x5c50,0x5c59,0x5b71,0x5c63,0x5c66,0x7fbc,0x5f2a,0x5f29, 0x5f2d,0x8274,0x5f3c,0x9b3b,0x5c6e,0x5981,0x5983,0x598d,0x59a9,0x59aa, 0x59a3 }, { /* ku 66 */ 0x936c,0x936d,0x936e,0x936f,0x9370,0x9371,0x9372,0x9373,0x9374,0x9375, 0x9376,0x9377,0x9378,0x9379,0x937a,0x937b,0x937c,0x937d,0x937e,0x937f, 0x9380,0x9381,0x9382,0x9383,0x9384,0x9385,0x9386,0x9387,0x9388,0x9389, 0x938a,0x938b,0x938c,0x938d,0x938e,0x9390,0x9391,0x9392,0x9393,0x9394, 0x9395,0x9396,0x9397,0x9398,0x9399,0x939a,0x939b,0x939c,0x939d,0x939e, 0x939f,0x93a0,0x93a1,0x93a2,0x93a3,0x93a4,0x93a5,0x93a6,0x93a7,0x93a8, 0x93a9,0x93aa,0x93ab,UBOGON,0x93ac,0x93ad,0x93ae,0x93af,0x93b0,0x93b1, 0x93b2,0x93b3,0x93b4,0x93b5,0x93b6,0x93b7,0x93b8,0x93b9,0x93ba,0x93bb, 0x93bc,0x93bd,0x93be,0x93bf,0x93c0,0x93c1,0x93c2,0x93c3,0x93c4,0x93c5, 0x93c6,0x93c7,0x93c8,0x93c9,0x93cb,0x93cc,0x93cd,0x5997,0x59ca,0x59ab, 0x599e,0x59a4,0x59d2,0x59b2,0x59af,0x59d7,0x59be,0x5a05,0x5a06,0x59dd, 0x5a08,0x59e3,0x59d8,0x59f9,0x5a0c,0x5a09,0x5a32,0x5a34,0x5a11,0x5a23, 0x5a13,0x5a40,0x5a67,0x5a4a,0x5a55,0x5a3c,0x5a62,0x5a75,0x80ec,0x5aaa, 0x5a9b,0x5a77,0x5a7a,0x5abe,0x5aeb,0x5ab2,0x5ad2,0x5ad4,0x5ab8,0x5ae0, 0x5ae3,0x5af1,0x5ad6,0x5ae6,0x5ad8,0x5adc,0x5b09,0x5b17,0x5b16,0x5b32, 0x5b37,0x5b40,0x5c15,0x5c1c,0x5b5a,0x5b65,0x5b73,0x5b51,0x5b53,0x5b62, 0x9a75,0x9a77,0x9a78,0x9a7a,0x9a7f,0x9a7d,0x9a80,0x9a81,0x9a85,0x9a88, 0x9a8a,0x9a90,0x9a92,0x9a93,0x9a96,0x9a98,0x9a9b,0x9a9c,0x9a9d,0x9a9f, 0x9aa0,0x9aa2,0x9aa3,0x9aa5,0x9aa7,0x7e9f,0x7ea1,0x7ea3,0x7ea5,0x7ea8, 0x7ea9 }, { /* ku 67 */ 0x93ce,0x93cf,0x93d0,0x93d1,0x93d2,0x93d3,0x93d4,0x93d5,0x93d7,0x93d8, 0x93d9,0x93da,0x93db,0x93dc,0x93dd,0x93de,0x93df,0x93e0,0x93e1,0x93e2, 0x93e3,0x93e4,0x93e5,0x93e6,0x93e7,0x93e8,0x93e9,0x93ea,0x93eb,0x93ec, 0x93ed,0x93ee,0x93ef,0x93f0,0x93f1,0x93f2,0x93f3,0x93f4,0x93f5,0x93f6, 0x93f7,0x93f8,0x93f9,0x93fa,0x93fb,0x93fc,0x93fd,0x93fe,0x93ff,0x9400, 0x9401,0x9402,0x9403,0x9404,0x9405,0x9406,0x9407,0x9408,0x9409,0x940a, 0x940b,0x940c,0x940d,UBOGON,0x940e,0x940f,0x9410,0x9411,0x9412,0x9413, 0x9414,0x9415,0x9416,0x9417,0x9418,0x9419,0x941a,0x941b,0x941c,0x941d, 0x941e,0x941f,0x9420,0x9421,0x9422,0x9423,0x9424,0x9425,0x9426,0x9427, 0x9428,0x9429,0x942a,0x942b,0x942c,0x942d,0x942e,0x7ead,0x7eb0,0x7ebe, 0x7ec0,0x7ec1,0x7ec2,0x7ec9,0x7ecb,0x7ecc,0x7ed0,0x7ed4,0x7ed7,0x7edb, 0x7ee0,0x7ee1,0x7ee8,0x7eeb,0x7eee,0x7eef,0x7ef1,0x7ef2,0x7f0d,0x7ef6, 0x7efa,0x7efb,0x7efe,0x7f01,0x7f02,0x7f03,0x7f07,0x7f08,0x7f0b,0x7f0c, 0x7f0f,0x7f11,0x7f12,0x7f17,0x7f19,0x7f1c,0x7f1b,0x7f1f,0x7f21,0x7f22, 0x7f23,0x7f24,0x7f25,0x7f26,0x7f27,0x7f2a,0x7f2b,0x7f2c,0x7f2d,0x7f2f, 0x7f30,0x7f31,0x7f32,0x7f33,0x7f35,0x5e7a,0x757f,0x5ddb,0x753e,0x9095, 0x738e,0x7391,0x73ae,0x73a2,0x739f,0x73cf,0x73c2,0x73d1,0x73b7,0x73b3, 0x73c0,0x73c9,0x73c8,0x73e5,0x73d9,0x987c,0x740a,0x73e9,0x73e7,0x73de, 0x73ba,0x73f2,0x740f,0x742a,0x745b,0x7426,0x7425,0x7428,0x7430,0x742e, 0x742c }, { /* ku 68 */ 0x942f,0x9430,0x9431,0x9432,0x9433,0x9434,0x9435,0x9436,0x9437,0x9438, 0x9439,0x943a,0x943b,0x943c,0x943d,0x943f,0x9440,0x9441,0x9442,0x9443, 0x9444,0x9445,0x9446,0x9447,0x9448,0x9449,0x944a,0x944b,0x944c,0x944d, 0x944e,0x944f,0x9450,0x9451,0x9452,0x9453,0x9454,0x9455,0x9456,0x9457, 0x9458,0x9459,0x945a,0x945b,0x945c,0x945d,0x945e,0x945f,0x9460,0x9461, 0x9462,0x9463,0x9464,0x9465,0x9466,0x9467,0x9468,0x9469,0x946a,0x946c, 0x946d,0x946e,0x946f,UBOGON,0x9470,0x9471,0x9472,0x9473,0x9474,0x9475, 0x9476,0x9477,0x9478,0x9479,0x947a,0x947b,0x947c,0x947d,0x947e,0x947f, 0x9480,0x9481,0x9482,0x9483,0x9484,0x9491,0x9496,0x9498,0x94c7,0x94cf, 0x94d3,0x94d4,0x94da,0x94e6,0x94fb,0x951c,0x9520,0x741b,0x741a,0x7441, 0x745c,0x7457,0x7455,0x7459,0x7477,0x746d,0x747e,0x749c,0x748e,0x7480, 0x7481,0x7487,0x748b,0x749e,0x74a8,0x74a9,0x7490,0x74a7,0x74d2,0x74ba, 0x97ea,0x97eb,0x97ec,0x674c,0x6753,0x675e,0x6748,0x6769,0x67a5,0x6787, 0x676a,0x6773,0x6798,0x67a7,0x6775,0x67a8,0x679e,0x67ad,0x678b,0x6777, 0x677c,0x67f0,0x6809,0x67d8,0x680a,0x67e9,0x67b0,0x680c,0x67d9,0x67b5, 0x67da,0x67b3,0x67dd,0x6800,0x67c3,0x67b8,0x67e2,0x680e,0x67c1,0x67fd, 0x6832,0x6833,0x6860,0x6861,0x684e,0x6862,0x6844,0x6864,0x6883,0x681d, 0x6855,0x6866,0x6841,0x6867,0x6840,0x683e,0x684a,0x6849,0x6829,0x68b5, 0x688f,0x6874,0x6877,0x6893,0x686b,0x68c2,0x696e,0x68fc,0x691f,0x6920, 0x68f9 }, { /* ku 69 */ 0x9527,0x9533,0x953d,0x9543,0x9548,0x954b,0x9555,0x955a,0x9560,0x956e, 0x9574,0x9575,0x9577,0x9578,0x9579,0x957a,0x957b,0x957c,0x957d,0x957e, 0x9580,0x9581,0x9582,0x9583,0x9584,0x9585,0x9586,0x9587,0x9588,0x9589, 0x958a,0x958b,0x958c,0x958d,0x958e,0x958f,0x9590,0x9591,0x9592,0x9593, 0x9594,0x9595,0x9596,0x9597,0x9598,0x9599,0x959a,0x959b,0x959c,0x959d, 0x959e,0x959f,0x95a0,0x95a1,0x95a2,0x95a3,0x95a4,0x95a5,0x95a6,0x95a7, 0x95a8,0x95a9,0x95aa,UBOGON,0x95ab,0x95ac,0x95ad,0x95ae,0x95af,0x95b0, 0x95b1,0x95b2,0x95b3,0x95b4,0x95b5,0x95b6,0x95b7,0x95b8,0x95b9,0x95ba, 0x95bb,0x95bc,0x95bd,0x95be,0x95bf,0x95c0,0x95c1,0x95c2,0x95c3,0x95c4, 0x95c5,0x95c6,0x95c7,0x95c8,0x95c9,0x95ca,0x95cb,0x6924,0x68f0,0x690b, 0x6901,0x6957,0x68e3,0x6910,0x6971,0x6939,0x6960,0x6942,0x695d,0x6984, 0x696b,0x6980,0x6998,0x6978,0x6934,0x69cc,0x6987,0x6988,0x69ce,0x6989, 0x6966,0x6963,0x6979,0x699b,0x69a7,0x69bb,0x69ab,0x69ad,0x69d4,0x69b1, 0x69c1,0x69ca,0x69df,0x6995,0x69e0,0x698d,0x69ff,0x6a2f,0x69ed,0x6a17, 0x6a18,0x6a65,0x69f2,0x6a44,0x6a3e,0x6aa0,0x6a50,0x6a5b,0x6a35,0x6a8e, 0x6a79,0x6a3d,0x6a28,0x6a58,0x6a7c,0x6a91,0x6a90,0x6aa9,0x6a97,0x6aab, 0x7337,0x7352,0x6b81,0x6b82,0x6b87,0x6b84,0x6b92,0x6b93,0x6b8d,0x6b9a, 0x6b9b,0x6ba1,0x6baa,0x8f6b,0x8f6d,0x8f71,0x8f72,0x8f73,0x8f75,0x8f76, 0x8f78,0x8f77,0x8f79,0x8f7a,0x8f7c,0x8f7e,0x8f81,0x8f82,0x8f84,0x8f87, 0x8f8b }, { /* ku 6a */ 0x95cc,0x95cd,0x95ce,0x95cf,0x95d0,0x95d1,0x95d2,0x95d3,0x95d4,0x95d5, 0x95d6,0x95d7,0x95d8,0x95d9,0x95da,0x95db,0x95dc,0x95dd,0x95de,0x95df, 0x95e0,0x95e1,0x95e2,0x95e3,0x95e4,0x95e5,0x95e6,0x95e7,0x95ec,0x95ff, 0x9607,0x9613,0x9618,0x961b,0x961e,0x9620,0x9623,0x9624,0x9625,0x9626, 0x9627,0x9628,0x9629,0x962b,0x962c,0x962d,0x962f,0x9630,0x9637,0x9638, 0x9639,0x963a,0x963e,0x9641,0x9643,0x964a,0x964e,0x964f,0x9651,0x9652, 0x9653,0x9656,0x9657,UBOGON,0x9658,0x9659,0x965a,0x965c,0x965d,0x965e, 0x9660,0x9663,0x9665,0x9666,0x966b,0x966d,0x966e,0x966f,0x9670,0x9671, 0x9673,0x9678,0x9679,0x967a,0x967b,0x967c,0x967d,0x967e,0x967f,0x9680, 0x9681,0x9682,0x9683,0x9684,0x9687,0x9689,0x968a,0x8f8d,0x8f8e,0x8f8f, 0x8f98,0x8f9a,0x8ece,0x620b,0x6217,0x621b,0x621f,0x6222,0x6221,0x6225, 0x6224,0x622c,0x81e7,0x74ef,0x74f4,0x74ff,0x750f,0x7511,0x7513,0x6534, 0x65ee,0x65ef,0x65f0,0x660a,0x6619,0x6772,0x6603,0x6615,0x6600,0x7085, 0x66f7,0x661d,0x6634,0x6631,0x6636,0x6635,0x8006,0x665f,0x6654,0x6641, 0x664f,0x6656,0x6661,0x6657,0x6677,0x6684,0x668c,0x66a7,0x669d,0x66be, 0x66db,0x66dc,0x66e6,0x66e9,0x8d32,0x8d33,0x8d36,0x8d3b,0x8d3d,0x8d40, 0x8d45,0x8d46,0x8d48,0x8d49,0x8d47,0x8d4d,0x8d55,0x8d59,0x89c7,0x89ca, 0x89cb,0x89cc,0x89ce,0x89cf,0x89d0,0x89d1,0x726e,0x729f,0x725d,0x7266, 0x726f,0x727e,0x727f,0x7284,0x728b,0x728d,0x728f,0x7292,0x6308,0x6332, 0x63b0 }, { /* ku 6b */ 0x968c,0x968e,0x9691,0x9692,0x9693,0x9695,0x9696,0x969a,0x969b,0x969d, 0x969e,0x969f,0x96a0,0x96a1,0x96a2,0x96a3,0x96a4,0x96a5,0x96a6,0x96a8, 0x96a9,0x96aa,0x96ab,0x96ac,0x96ad,0x96ae,0x96af,0x96b1,0x96b2,0x96b4, 0x96b5,0x96b7,0x96b8,0x96ba,0x96bb,0x96bf,0x96c2,0x96c3,0x96c8,0x96ca, 0x96cb,0x96d0,0x96d1,0x96d3,0x96d4,0x96d6,0x96d7,0x96d8,0x96d9,0x96da, 0x96db,0x96dc,0x96dd,0x96de,0x96df,0x96e1,0x96e2,0x96e3,0x96e4,0x96e5, 0x96e6,0x96e7,0x96eb,UBOGON,0x96ec,0x96ed,0x96ee,0x96f0,0x96f1,0x96f2, 0x96f4,0x96f5,0x96f8,0x96fa,0x96fb,0x96fc,0x96fd,0x96ff,0x9702,0x9703, 0x9705,0x970a,0x970b,0x970c,0x9710,0x9711,0x9712,0x9714,0x9715,0x9717, 0x9718,0x9719,0x971a,0x971b,0x971d,0x971f,0x9720,0x643f,0x64d8,0x8004, 0x6bea,0x6bf3,0x6bfd,0x6bf5,0x6bf9,0x6c05,0x6c07,0x6c06,0x6c0d,0x6c15, 0x6c18,0x6c19,0x6c1a,0x6c21,0x6c29,0x6c24,0x6c2a,0x6c32,0x6535,0x6555, 0x656b,0x724d,0x7252,0x7256,0x7230,0x8662,0x5216,0x809f,0x809c,0x8093, 0x80bc,0x670a,0x80bd,0x80b1,0x80ab,0x80ad,0x80b4,0x80b7,0x80e7,0x80e8, 0x80e9,0x80ea,0x80db,0x80c2,0x80c4,0x80d9,0x80cd,0x80d7,0x6710,0x80dd, 0x80eb,0x80f1,0x80f4,0x80ed,0x810d,0x810e,0x80f2,0x80fc,0x6715,0x8112, 0x8c5a,0x8136,0x811e,0x812c,0x8118,0x8132,0x8148,0x814c,0x8153,0x8174, 0x8159,0x815a,0x8171,0x8160,0x8169,0x817c,0x817d,0x816d,0x8167,0x584d, 0x5ab5,0x8188,0x8182,0x8191,0x6ed5,0x81a3,0x81aa,0x81cc,0x6726,0x81ca, 0x81bb }, { /* ku 6c */ 0x9721,0x9722,0x9723,0x9724,0x9725,0x9726,0x9727,0x9728,0x9729,0x972b, 0x972c,0x972e,0x972f,0x9731,0x9733,0x9734,0x9735,0x9736,0x9737,0x973a, 0x973b,0x973c,0x973d,0x973f,0x9740,0x9741,0x9742,0x9743,0x9744,0x9745, 0x9746,0x9747,0x9748,0x9749,0x974a,0x974b,0x974c,0x974d,0x974e,0x974f, 0x9750,0x9751,0x9754,0x9755,0x9757,0x9758,0x975a,0x975c,0x975d,0x975f, 0x9763,0x9764,0x9766,0x9767,0x9768,0x976a,0x976b,0x976c,0x976d,0x976e, 0x976f,0x9770,0x9771,UBOGON,0x9772,0x9775,0x9777,0x9778,0x9779,0x977a, 0x977b,0x977d,0x977e,0x977f,0x9780,0x9781,0x9782,0x9783,0x9784,0x9786, 0x9787,0x9788,0x9789,0x978a,0x978c,0x978e,0x978f,0x9790,0x9793,0x9795, 0x9796,0x9797,0x9799,0x979a,0x979b,0x979c,0x979d,0x81c1,0x81a6,0x6b24, 0x6b37,0x6b39,0x6b43,0x6b46,0x6b59,0x98d1,0x98d2,0x98d3,0x98d5,0x98d9, 0x98da,0x6bb3,0x5f40,0x6bc2,0x89f3,0x6590,0x9f51,0x6593,0x65bc,0x65c6, 0x65c4,0x65c3,0x65cc,0x65ce,0x65d2,0x65d6,0x7080,0x709c,0x7096,0x709d, 0x70bb,0x70c0,0x70b7,0x70ab,0x70b1,0x70e8,0x70ca,0x7110,0x7113,0x7116, 0x712f,0x7131,0x7173,0x715c,0x7168,0x7145,0x7172,0x714a,0x7178,0x717a, 0x7198,0x71b3,0x71b5,0x71a8,0x71a0,0x71e0,0x71d4,0x71e7,0x71f9,0x721d, 0x7228,0x706c,0x7118,0x7166,0x71b9,0x623e,0x623d,0x6243,0x6248,0x6249, 0x793b,0x7940,0x7946,0x7949,0x795b,0x795c,0x7953,0x795a,0x7962,0x7957, 0x7960,0x796f,0x7967,0x797a,0x7985,0x798a,0x799a,0x79a7,0x79b3,0x5fd1, 0x5fd0 }, { /* ku 6d */ 0x979e,0x979f,0x97a1,0x97a2,0x97a4,0x97a5,0x97a6,0x97a7,0x97a8,0x97a9, 0x97aa,0x97ac,0x97ae,0x97b0,0x97b1,0x97b3,0x97b5,0x97b6,0x97b7,0x97b8, 0x97b9,0x97ba,0x97bb,0x97bc,0x97bd,0x97be,0x97bf,0x97c0,0x97c1,0x97c2, 0x97c3,0x97c4,0x97c5,0x97c6,0x97c7,0x97c8,0x97c9,0x97ca,0x97cb,0x97cc, 0x97cd,0x97ce,0x97cf,0x97d0,0x97d1,0x97d2,0x97d3,0x97d4,0x97d5,0x97d6, 0x97d7,0x97d8,0x97d9,0x97da,0x97db,0x97dc,0x97dd,0x97de,0x97df,0x97e0, 0x97e1,0x97e2,0x97e3,UBOGON,0x97e4,0x97e5,0x97e8,0x97ee,0x97ef,0x97f0, 0x97f1,0x97f2,0x97f4,0x97f7,0x97f8,0x97f9,0x97fa,0x97fb,0x97fc,0x97fd, 0x97fe,0x97ff,0x9800,0x9801,0x9802,0x9803,0x9804,0x9805,0x9806,0x9807, 0x9808,0x9809,0x980a,0x980b,0x980c,0x980d,0x980e,0x603c,0x605d,0x605a, 0x6067,0x6041,0x6059,0x6063,0x60ab,0x6106,0x610d,0x615d,0x61a9,0x619d, 0x61cb,0x61d1,0x6206,0x8080,0x807f,0x6c93,0x6cf6,0x6dfc,0x77f6,0x77f8, 0x7800,0x7809,0x7817,0x7818,0x7811,0x65ab,0x782d,0x781c,0x781d,0x7839, 0x783a,0x783b,0x781f,0x783c,0x7825,0x782c,0x7823,0x7829,0x784e,0x786d, 0x7856,0x7857,0x7826,0x7850,0x7847,0x784c,0x786a,0x789b,0x7893,0x789a, 0x7887,0x789c,0x78a1,0x78a3,0x78b2,0x78b9,0x78a5,0x78d4,0x78d9,0x78c9, 0x78ec,0x78f2,0x7905,0x78f4,0x7913,0x7924,0x791e,0x7934,0x9f9b,0x9ef9, 0x9efb,0x9efc,0x76f1,0x7704,0x770d,0x76f9,0x7707,0x7708,0x771a,0x7722, 0x7719,0x772d,0x7726,0x7735,0x7738,0x7750,0x7751,0x7747,0x7743,0x775a, 0x7768 }, { /* ku 6e */ 0x980f,0x9810,0x9811,0x9812,0x9813,0x9814,0x9815,0x9816,0x9817,0x9818, 0x9819,0x981a,0x981b,0x981c,0x981d,0x981e,0x981f,0x9820,0x9821,0x9822, 0x9823,0x9824,0x9825,0x9826,0x9827,0x9828,0x9829,0x982a,0x982b,0x982c, 0x982d,0x982e,0x982f,0x9830,0x9831,0x9832,0x9833,0x9834,0x9835,0x9836, 0x9837,0x9838,0x9839,0x983a,0x983b,0x983c,0x983d,0x983e,0x983f,0x9840, 0x9841,0x9842,0x9843,0x9844,0x9845,0x9846,0x9847,0x9848,0x9849,0x984a, 0x984b,0x984c,0x984d,UBOGON,0x984e,0x984f,0x9850,0x9851,0x9852,0x9853, 0x9854,0x9855,0x9856,0x9857,0x9858,0x9859,0x985a,0x985b,0x985c,0x985d, 0x985e,0x985f,0x9860,0x9861,0x9862,0x9863,0x9864,0x9865,0x9866,0x9867, 0x9868,0x9869,0x986a,0x986b,0x986c,0x986d,0x986e,0x7762,0x7765,0x777f, 0x778d,0x777d,0x7780,0x778c,0x7791,0x779f,0x77a0,0x77b0,0x77b5,0x77bd, 0x753a,0x7540,0x754e,0x754b,0x7548,0x755b,0x7572,0x7579,0x7583,0x7f58, 0x7f61,0x7f5f,0x8a48,0x7f68,0x7f74,0x7f71,0x7f79,0x7f81,0x7f7e,0x76cd, 0x76e5,0x8832,0x9485,0x9486,0x9487,0x948b,0x948a,0x948c,0x948d,0x948f, 0x9490,0x9494,0x9497,0x9495,0x949a,0x949b,0x949c,0x94a3,0x94a4,0x94ab, 0x94aa,0x94ad,0x94ac,0x94af,0x94b0,0x94b2,0x94b4,0x94b6,0x94b7,0x94b8, 0x94b9,0x94ba,0x94bc,0x94bd,0x94bf,0x94c4,0x94c8,0x94c9,0x94ca,0x94cb, 0x94cc,0x94cd,0x94ce,0x94d0,0x94d1,0x94d2,0x94d5,0x94d6,0x94d7,0x94d9, 0x94d8,0x94db,0x94de,0x94df,0x94e0,0x94e2,0x94e4,0x94e5,0x94e7,0x94e8, 0x94ea }, { /* ku 6f */ 0x986f,0x9870,0x9871,0x9872,0x9873,0x9874,0x988b,0x988e,0x9892,0x9895, 0x9899,0x98a3,0x98a8,0x98a9,0x98aa,0x98ab,0x98ac,0x98ad,0x98ae,0x98af, 0x98b0,0x98b1,0x98b2,0x98b3,0x98b4,0x98b5,0x98b6,0x98b7,0x98b8,0x98b9, 0x98ba,0x98bb,0x98bc,0x98bd,0x98be,0x98bf,0x98c0,0x98c1,0x98c2,0x98c3, 0x98c4,0x98c5,0x98c6,0x98c7,0x98c8,0x98c9,0x98ca,0x98cb,0x98cc,0x98cd, 0x98cf,0x98d0,0x98d4,0x98d6,0x98d7,0x98db,0x98dc,0x98dd,0x98e0,0x98e1, 0x98e2,0x98e3,0x98e4,UBOGON,0x98e5,0x98e6,0x98e9,0x98ea,0x98eb,0x98ec, 0x98ed,0x98ee,0x98ef,0x98f0,0x98f1,0x98f2,0x98f3,0x98f4,0x98f5,0x98f6, 0x98f7,0x98f8,0x98f9,0x98fa,0x98fb,0x98fc,0x98fd,0x98fe,0x98ff,0x9900, 0x9901,0x9902,0x9903,0x9904,0x9905,0x9906,0x9907,0x94e9,0x94eb,0x94ee, 0x94ef,0x94f3,0x94f4,0x94f5,0x94f7,0x94f9,0x94fc,0x94fd,0x94ff,0x9503, 0x9502,0x9506,0x9507,0x9509,0x950a,0x950d,0x950e,0x950f,0x9512,0x9513, 0x9514,0x9515,0x9516,0x9518,0x951b,0x951d,0x951e,0x951f,0x9522,0x952a, 0x952b,0x9529,0x952c,0x9531,0x9532,0x9534,0x9536,0x9537,0x9538,0x953c, 0x953e,0x953f,0x9542,0x9535,0x9544,0x9545,0x9546,0x9549,0x954c,0x954e, 0x954f,0x9552,0x9553,0x9554,0x9556,0x9557,0x9558,0x9559,0x955b,0x955e, 0x955f,0x955d,0x9561,0x9562,0x9564,0x9565,0x9566,0x9567,0x9568,0x9569, 0x956a,0x956b,0x956c,0x956f,0x9571,0x9572,0x9573,0x953a,0x77e7,0x77ec, 0x96c9,0x79d5,0x79ed,0x79e3,0x79eb,0x7a06,0x5d47,0x7a03,0x7a02,0x7a1e, 0x7a14 }, { /* ku 70 */ 0x9908,0x9909,0x990a,0x990b,0x990c,0x990e,0x990f,0x9911,0x9912,0x9913, 0x9914,0x9915,0x9916,0x9917,0x9918,0x9919,0x991a,0x991b,0x991c,0x991d, 0x991e,0x991f,0x9920,0x9921,0x9922,0x9923,0x9924,0x9925,0x9926,0x9927, 0x9928,0x9929,0x992a,0x992b,0x992c,0x992d,0x992f,0x9930,0x9931,0x9932, 0x9933,0x9934,0x9935,0x9936,0x9937,0x9938,0x9939,0x993a,0x993b,0x993c, 0x993d,0x993e,0x993f,0x9940,0x9941,0x9942,0x9943,0x9944,0x9945,0x9946, 0x9947,0x9948,0x9949,UBOGON,0x994a,0x994b,0x994c,0x994d,0x994e,0x994f, 0x9950,0x9951,0x9952,0x9953,0x9956,0x9957,0x9958,0x9959,0x995a,0x995b, 0x995c,0x995d,0x995e,0x995f,0x9960,0x9961,0x9962,0x9964,0x9966,0x9973, 0x9978,0x9979,0x997b,0x997e,0x9982,0x9983,0x9989,0x7a39,0x7a37,0x7a51, 0x9ecf,0x99a5,0x7a70,0x7688,0x768e,0x7693,0x7699,0x76a4,0x74de,0x74e0, 0x752c,0x9e20,0x9e22,0x9e28,0x9e29,0x9e2a,0x9e2b,0x9e2c,0x9e32,0x9e31, 0x9e36,0x9e38,0x9e37,0x9e39,0x9e3a,0x9e3e,0x9e41,0x9e42,0x9e44,0x9e46, 0x9e47,0x9e48,0x9e49,0x9e4b,0x9e4c,0x9e4e,0x9e51,0x9e55,0x9e57,0x9e5a, 0x9e5b,0x9e5c,0x9e5e,0x9e63,0x9e66,0x9e67,0x9e68,0x9e69,0x9e6a,0x9e6b, 0x9e6c,0x9e71,0x9e6d,0x9e73,0x7592,0x7594,0x7596,0x75a0,0x759d,0x75ac, 0x75a3,0x75b3,0x75b4,0x75b8,0x75c4,0x75b1,0x75b0,0x75c3,0x75c2,0x75d6, 0x75cd,0x75e3,0x75e8,0x75e6,0x75e4,0x75eb,0x75e7,0x7603,0x75f1,0x75fc, 0x75ff,0x7610,0x7600,0x7605,0x760c,0x7617,0x760a,0x7625,0x7618,0x7615, 0x7619 }, { /* ku 71 */ 0x998c,0x998e,0x999a,0x999b,0x999c,0x999d,0x999e,0x999f,0x99a0,0x99a1, 0x99a2,0x99a3,0x99a4,0x99a6,0x99a7,0x99a9,0x99aa,0x99ab,0x99ac,0x99ad, 0x99ae,0x99af,0x99b0,0x99b1,0x99b2,0x99b3,0x99b4,0x99b5,0x99b6,0x99b7, 0x99b8,0x99b9,0x99ba,0x99bb,0x99bc,0x99bd,0x99be,0x99bf,0x99c0,0x99c1, 0x99c2,0x99c3,0x99c4,0x99c5,0x99c6,0x99c7,0x99c8,0x99c9,0x99ca,0x99cb, 0x99cc,0x99cd,0x99ce,0x99cf,0x99d0,0x99d1,0x99d2,0x99d3,0x99d4,0x99d5, 0x99d6,0x99d7,0x99d8,UBOGON,0x99d9,0x99da,0x99db,0x99dc,0x99dd,0x99de, 0x99df,0x99e0,0x99e1,0x99e2,0x99e3,0x99e4,0x99e5,0x99e6,0x99e7,0x99e8, 0x99e9,0x99ea,0x99eb,0x99ec,0x99ed,0x99ee,0x99ef,0x99f0,0x99f1,0x99f2, 0x99f3,0x99f4,0x99f5,0x99f6,0x99f7,0x99f8,0x99f9,0x761b,0x763c,0x7622, 0x7620,0x7640,0x762d,0x7630,0x763f,0x7635,0x7643,0x763e,0x7633,0x764d, 0x765e,0x7654,0x765c,0x7656,0x766b,0x766f,0x7fca,0x7ae6,0x7a78,0x7a79, 0x7a80,0x7a86,0x7a88,0x7a95,0x7aa6,0x7aa0,0x7aac,0x7aa8,0x7aad,0x7ab3, 0x8864,0x8869,0x8872,0x887d,0x887f,0x8882,0x88a2,0x88c6,0x88b7,0x88bc, 0x88c9,0x88e2,0x88ce,0x88e3,0x88e5,0x88f1,0x891a,0x88fc,0x88e8,0x88fe, 0x88f0,0x8921,0x8919,0x8913,0x891b,0x890a,0x8934,0x892b,0x8936,0x8941, 0x8966,0x897b,0x758b,0x80e5,0x76b2,0x76b4,0x77dc,0x8012,0x8014,0x8016, 0x801c,0x8020,0x8022,0x8025,0x8026,0x8027,0x8029,0x8028,0x8031,0x800b, 0x8035,0x8043,0x8046,0x804d,0x8052,0x8069,0x8071,0x8983,0x9878,0x9880, 0x9883 }, { /* ku 72 */ 0x99fa,0x99fb,0x99fc,0x99fd,0x99fe,0x99ff,0x9a00,0x9a01,0x9a02,0x9a03, 0x9a04,0x9a05,0x9a06,0x9a07,0x9a08,0x9a09,0x9a0a,0x9a0b,0x9a0c,0x9a0d, 0x9a0e,0x9a0f,0x9a10,0x9a11,0x9a12,0x9a13,0x9a14,0x9a15,0x9a16,0x9a17, 0x9a18,0x9a19,0x9a1a,0x9a1b,0x9a1c,0x9a1d,0x9a1e,0x9a1f,0x9a20,0x9a21, 0x9a22,0x9a23,0x9a24,0x9a25,0x9a26,0x9a27,0x9a28,0x9a29,0x9a2a,0x9a2b, 0x9a2c,0x9a2d,0x9a2e,0x9a2f,0x9a30,0x9a31,0x9a32,0x9a33,0x9a34,0x9a35, 0x9a36,0x9a37,0x9a38,UBOGON,0x9a39,0x9a3a,0x9a3b,0x9a3c,0x9a3d,0x9a3e, 0x9a3f,0x9a40,0x9a41,0x9a42,0x9a43,0x9a44,0x9a45,0x9a46,0x9a47,0x9a48, 0x9a49,0x9a4a,0x9a4b,0x9a4c,0x9a4d,0x9a4e,0x9a4f,0x9a50,0x9a51,0x9a52, 0x9a53,0x9a54,0x9a55,0x9a56,0x9a57,0x9a58,0x9a59,0x9889,0x988c,0x988d, 0x988f,0x9894,0x989a,0x989b,0x989e,0x989f,0x98a1,0x98a2,0x98a5,0x98a6, 0x864d,0x8654,0x866c,0x866e,0x867f,0x867a,0x867c,0x867b,0x86a8,0x868d, 0x868b,0x86ac,0x869d,0x86a7,0x86a3,0x86aa,0x8693,0x86a9,0x86b6,0x86c4, 0x86b5,0x86ce,0x86b0,0x86ba,0x86b1,0x86af,0x86c9,0x86cf,0x86b4,0x86e9, 0x86f1,0x86f2,0x86ed,0x86f3,0x86d0,0x8713,0x86de,0x86f4,0x86df,0x86d8, 0x86d1,0x8703,0x8707,0x86f8,0x8708,0x870a,0x870d,0x8709,0x8723,0x873b, 0x871e,0x8725,0x872e,0x871a,0x873e,0x8748,0x8734,0x8731,0x8729,0x8737, 0x873f,0x8782,0x8722,0x877d,0x877e,0x877b,0x8760,0x8770,0x874c,0x876e, 0x878b,0x8753,0x8763,0x877c,0x8764,0x8759,0x8765,0x8793,0x87af,0x87a8, 0x87d2 }, { /* ku 73 */ 0x9a5a,0x9a5b,0x9a5c,0x9a5d,0x9a5e,0x9a5f,0x9a60,0x9a61,0x9a62,0x9a63, 0x9a64,0x9a65,0x9a66,0x9a67,0x9a68,0x9a69,0x9a6a,0x9a6b,0x9a72,0x9a83, 0x9a89,0x9a8d,0x9a8e,0x9a94,0x9a95,0x9a99,0x9aa6,0x9aa9,0x9aaa,0x9aab, 0x9aac,0x9aad,0x9aae,0x9aaf,0x9ab2,0x9ab3,0x9ab4,0x9ab5,0x9ab9,0x9abb, 0x9abd,0x9abe,0x9abf,0x9ac3,0x9ac4,0x9ac6,0x9ac7,0x9ac8,0x9ac9,0x9aca, 0x9acd,0x9ace,0x9acf,0x9ad0,0x9ad2,0x9ad4,0x9ad5,0x9ad6,0x9ad7,0x9ad9, 0x9ada,0x9adb,0x9adc,UBOGON,0x9add,0x9ade,0x9ae0,0x9ae2,0x9ae3,0x9ae4, 0x9ae5,0x9ae7,0x9ae8,0x9ae9,0x9aea,0x9aec,0x9aee,0x9af0,0x9af1,0x9af2, 0x9af3,0x9af4,0x9af5,0x9af6,0x9af7,0x9af8,0x9afa,0x9afc,0x9afd,0x9afe, 0x9aff,0x9b00,0x9b01,0x9b02,0x9b04,0x9b05,0x9b06,0x87c6,0x8788,0x8785, 0x87ad,0x8797,0x8783,0x87ab,0x87e5,0x87ac,0x87b5,0x87b3,0x87cb,0x87d3, 0x87bd,0x87d1,0x87c0,0x87ca,0x87db,0x87ea,0x87e0,0x87ee,0x8816,0x8813, 0x87fe,0x880a,0x881b,0x8821,0x8839,0x883c,0x7f36,0x7f42,0x7f44,0x7f45, 0x8210,0x7afa,0x7afd,0x7b08,0x7b03,0x7b04,0x7b15,0x7b0a,0x7b2b,0x7b0f, 0x7b47,0x7b38,0x7b2a,0x7b19,0x7b2e,0x7b31,0x7b20,0x7b25,0x7b24,0x7b33, 0x7b3e,0x7b1e,0x7b58,0x7b5a,0x7b45,0x7b75,0x7b4c,0x7b5d,0x7b60,0x7b6e, 0x7b7b,0x7b62,0x7b72,0x7b71,0x7b90,0x7ba6,0x7ba7,0x7bb8,0x7bac,0x7b9d, 0x7ba8,0x7b85,0x7baa,0x7b9c,0x7ba2,0x7bab,0x7bb4,0x7bd1,0x7bc1,0x7bcc, 0x7bdd,0x7bda,0x7be5,0x7be6,0x7bea,0x7c0c,0x7bfe,0x7bfc,0x7c0f,0x7c16, 0x7c0b }, { /* ku 74 */ 0x9b07,0x9b09,0x9b0a,0x9b0b,0x9b0c,0x9b0d,0x9b0e,0x9b10,0x9b11,0x9b12, 0x9b14,0x9b15,0x9b16,0x9b17,0x9b18,0x9b19,0x9b1a,0x9b1b,0x9b1c,0x9b1d, 0x9b1e,0x9b20,0x9b21,0x9b22,0x9b24,0x9b25,0x9b26,0x9b27,0x9b28,0x9b29, 0x9b2a,0x9b2b,0x9b2c,0x9b2d,0x9b2e,0x9b30,0x9b31,0x9b33,0x9b34,0x9b35, 0x9b36,0x9b37,0x9b38,0x9b39,0x9b3a,0x9b3d,0x9b3e,0x9b3f,0x9b40,0x9b46, 0x9b4a,0x9b4b,0x9b4c,0x9b4e,0x9b50,0x9b52,0x9b53,0x9b55,0x9b56,0x9b57, 0x9b58,0x9b59,0x9b5a,UBOGON,0x9b5b,0x9b5c,0x9b5d,0x9b5e,0x9b5f,0x9b60, 0x9b61,0x9b62,0x9b63,0x9b64,0x9b65,0x9b66,0x9b67,0x9b68,0x9b69,0x9b6a, 0x9b6b,0x9b6c,0x9b6d,0x9b6e,0x9b6f,0x9b70,0x9b71,0x9b72,0x9b73,0x9b74, 0x9b75,0x9b76,0x9b77,0x9b78,0x9b79,0x9b7a,0x9b7b,0x7c1f,0x7c2a,0x7c26, 0x7c38,0x7c41,0x7c40,0x81fe,0x8201,0x8202,0x8204,0x81ec,0x8844,0x8221, 0x8222,0x8223,0x822d,0x822f,0x8228,0x822b,0x8238,0x823b,0x8233,0x8234, 0x823e,0x8244,0x8249,0x824b,0x824f,0x825a,0x825f,0x8268,0x887e,0x8885, 0x8888,0x88d8,0x88df,0x895e,0x7f9d,0x7f9f,0x7fa7,0x7faf,0x7fb0,0x7fb2, 0x7c7c,0x6549,0x7c91,0x7c9d,0x7c9c,0x7c9e,0x7ca2,0x7cb2,0x7cbc,0x7cbd, 0x7cc1,0x7cc7,0x7ccc,0x7ccd,0x7cc8,0x7cc5,0x7cd7,0x7ce8,0x826e,0x66a8, 0x7fbf,0x7fce,0x7fd5,0x7fe5,0x7fe1,0x7fe6,0x7fe9,0x7fee,0x7ff3,0x7cf8, 0x7d77,0x7da6,0x7dae,0x7e47,0x7e9b,0x9eb8,0x9eb4,0x8d73,0x8d84,0x8d94, 0x8d91,0x8db1,0x8d67,0x8d6d,0x8c47,0x8c49,0x914a,0x9150,0x914e,0x914f, 0x9164 }, { /* ku 75 */ 0x9b7c,0x9b7d,0x9b7e,0x9b7f,0x9b80,0x9b81,0x9b82,0x9b83,0x9b84,0x9b85, 0x9b86,0x9b87,0x9b88,0x9b89,0x9b8a,0x9b8b,0x9b8c,0x9b8d,0x9b8e,0x9b8f, 0x9b90,0x9b91,0x9b92,0x9b93,0x9b94,0x9b95,0x9b96,0x9b97,0x9b98,0x9b99, 0x9b9a,0x9b9b,0x9b9c,0x9b9d,0x9b9e,0x9b9f,0x9ba0,0x9ba1,0x9ba2,0x9ba3, 0x9ba4,0x9ba5,0x9ba6,0x9ba7,0x9ba8,0x9ba9,0x9baa,0x9bab,0x9bac,0x9bad, 0x9bae,0x9baf,0x9bb0,0x9bb1,0x9bb2,0x9bb3,0x9bb4,0x9bb5,0x9bb6,0x9bb7, 0x9bb8,0x9bb9,0x9bba,UBOGON,0x9bbb,0x9bbc,0x9bbd,0x9bbe,0x9bbf,0x9bc0, 0x9bc1,0x9bc2,0x9bc3,0x9bc4,0x9bc5,0x9bc6,0x9bc7,0x9bc8,0x9bc9,0x9bca, 0x9bcb,0x9bcc,0x9bcd,0x9bce,0x9bcf,0x9bd0,0x9bd1,0x9bd2,0x9bd3,0x9bd4, 0x9bd5,0x9bd6,0x9bd7,0x9bd8,0x9bd9,0x9bda,0x9bdb,0x9162,0x9161,0x9170, 0x9169,0x916f,0x917d,0x917e,0x9172,0x9174,0x9179,0x918c,0x9185,0x9190, 0x918d,0x9191,0x91a2,0x91a3,0x91aa,0x91ad,0x91ae,0x91af,0x91b5,0x91b4, 0x91ba,0x8c55,0x9e7e,0x8db8,0x8deb,0x8e05,0x8e59,0x8e69,0x8db5,0x8dbf, 0x8dbc,0x8dba,0x8dc4,0x8dd6,0x8dd7,0x8dda,0x8dde,0x8dce,0x8dcf,0x8ddb, 0x8dc6,0x8dec,0x8df7,0x8df8,0x8de3,0x8df9,0x8dfb,0x8de4,0x8e09,0x8dfd, 0x8e14,0x8e1d,0x8e1f,0x8e2c,0x8e2e,0x8e23,0x8e2f,0x8e3a,0x8e40,0x8e39, 0x8e35,0x8e3d,0x8e31,0x8e49,0x8e41,0x8e42,0x8e51,0x8e52,0x8e4a,0x8e70, 0x8e76,0x8e7c,0x8e6f,0x8e74,0x8e85,0x8e8f,0x8e94,0x8e90,0x8e9c,0x8e9e, 0x8c78,0x8c82,0x8c8a,0x8c85,0x8c98,0x8c94,0x659b,0x89d6,0x89de,0x89da, 0x89dc }, { /* ku 76 */ 0x9bdc,0x9bdd,0x9bde,0x9bdf,0x9be0,0x9be1,0x9be2,0x9be3,0x9be4,0x9be5, 0x9be6,0x9be7,0x9be8,0x9be9,0x9bea,0x9beb,0x9bec,0x9bed,0x9bee,0x9bef, 0x9bf0,0x9bf1,0x9bf2,0x9bf3,0x9bf4,0x9bf5,0x9bf6,0x9bf7,0x9bf8,0x9bf9, 0x9bfa,0x9bfb,0x9bfc,0x9bfd,0x9bfe,0x9bff,0x9c00,0x9c01,0x9c02,0x9c03, 0x9c04,0x9c05,0x9c06,0x9c07,0x9c08,0x9c09,0x9c0a,0x9c0b,0x9c0c,0x9c0d, 0x9c0e,0x9c0f,0x9c10,0x9c11,0x9c12,0x9c13,0x9c14,0x9c15,0x9c16,0x9c17, 0x9c18,0x9c19,0x9c1a,UBOGON,0x9c1b,0x9c1c,0x9c1d,0x9c1e,0x9c1f,0x9c20, 0x9c21,0x9c22,0x9c23,0x9c24,0x9c25,0x9c26,0x9c27,0x9c28,0x9c29,0x9c2a, 0x9c2b,0x9c2c,0x9c2d,0x9c2e,0x9c2f,0x9c30,0x9c31,0x9c32,0x9c33,0x9c34, 0x9c35,0x9c36,0x9c37,0x9c38,0x9c39,0x9c3a,0x9c3b,0x89e5,0x89eb,0x89ef, 0x8a3e,0x8b26,0x9753,0x96e9,0x96f3,0x96ef,0x9706,0x9701,0x9708,0x970f, 0x970e,0x972a,0x972d,0x9730,0x973e,0x9f80,0x9f83,0x9f85,0x9f86,0x9f87, 0x9f88,0x9f89,0x9f8a,0x9f8c,0x9efe,0x9f0b,0x9f0d,0x96b9,0x96bc,0x96bd, 0x96ce,0x96d2,0x77bf,0x96e0,0x928e,0x92ae,0x92c8,0x933e,0x936a,0x93ca, 0x938f,0x943e,0x946b,0x9c7f,0x9c82,0x9c85,0x9c86,0x9c87,0x9c88,0x7a23, 0x9c8b,0x9c8e,0x9c90,0x9c91,0x9c92,0x9c94,0x9c95,0x9c9a,0x9c9b,0x9c9e, 0x9c9f,0x9ca0,0x9ca1,0x9ca2,0x9ca3,0x9ca5,0x9ca6,0x9ca7,0x9ca8,0x9ca9, 0x9cab,0x9cad,0x9cae,0x9cb0,0x9cb1,0x9cb2,0x9cb3,0x9cb4,0x9cb5,0x9cb6, 0x9cb7,0x9cba,0x9cbb,0x9cbc,0x9cbd,0x9cc4,0x9cc5,0x9cc6,0x9cc7,0x9cca, 0x9ccb }, { /* ku 77 */ 0x9c3c,0x9c3d,0x9c3e,0x9c3f,0x9c40,0x9c41,0x9c42,0x9c43,0x9c44,0x9c45, 0x9c46,0x9c47,0x9c48,0x9c49,0x9c4a,0x9c4b,0x9c4c,0x9c4d,0x9c4e,0x9c4f, 0x9c50,0x9c51,0x9c52,0x9c53,0x9c54,0x9c55,0x9c56,0x9c57,0x9c58,0x9c59, 0x9c5a,0x9c5b,0x9c5c,0x9c5d,0x9c5e,0x9c5f,0x9c60,0x9c61,0x9c62,0x9c63, 0x9c64,0x9c65,0x9c66,0x9c67,0x9c68,0x9c69,0x9c6a,0x9c6b,0x9c6c,0x9c6d, 0x9c6e,0x9c6f,0x9c70,0x9c71,0x9c72,0x9c73,0x9c74,0x9c75,0x9c76,0x9c77, 0x9c78,0x9c79,0x9c7a,UBOGON,0x9c7b,0x9c7d,0x9c7e,0x9c80,0x9c83,0x9c84, 0x9c89,0x9c8a,0x9c8c,0x9c8f,0x9c93,0x9c96,0x9c97,0x9c98,0x9c99,0x9c9d, 0x9caa,0x9cac,0x9caf,0x9cb9,0x9cbe,0x9cbf,0x9cc0,0x9cc1,0x9cc2,0x9cc8, 0x9cc9,0x9cd1,0x9cd2,0x9cda,0x9cdb,0x9ce0,0x9ce1,0x9ccc,0x9ccd,0x9cce, 0x9ccf,0x9cd0,0x9cd3,0x9cd4,0x9cd5,0x9cd7,0x9cd8,0x9cd9,0x9cdc,0x9cdd, 0x9cdf,0x9ce2,0x977c,0x9785,0x9791,0x9792,0x9794,0x97af,0x97ab,0x97a3, 0x97b2,0x97b4,0x9ab1,0x9ab0,0x9ab7,0x9e58,0x9ab6,0x9aba,0x9abc,0x9ac1, 0x9ac0,0x9ac5,0x9ac2,0x9acb,0x9acc,0x9ad1,0x9b45,0x9b43,0x9b47,0x9b49, 0x9b48,0x9b4d,0x9b51,0x98e8,0x990d,0x992e,0x9955,0x9954,0x9adf,0x9ae1, 0x9ae6,0x9aef,0x9aeb,0x9afb,0x9aed,0x9af9,0x9b08,0x9b0f,0x9b13,0x9b1f, 0x9b23,0x9ebd,0x9ebe,0x7e3b,0x9e82,0x9e87,0x9e88,0x9e8b,0x9e92,0x93d6, 0x9e9d,0x9e9f,0x9edb,0x9edc,0x9edd,0x9ee0,0x9edf,0x9ee2,0x9ee9,0x9ee7, 0x9ee5,0x9eea,0x9eef,0x9f22,0x9f2c,0x9f2f,0x9f39,0x9f37,0x9f3d,0x9f3e, 0x9f44 }, { /* ku 78 */ 0x9ce3,0x9ce4,0x9ce5,0x9ce6,0x9ce7,0x9ce8,0x9ce9,0x9cea,0x9ceb,0x9cec, 0x9ced,0x9cee,0x9cef,0x9cf0,0x9cf1,0x9cf2,0x9cf3,0x9cf4,0x9cf5,0x9cf6, 0x9cf7,0x9cf8,0x9cf9,0x9cfa,0x9cfb,0x9cfc,0x9cfd,0x9cfe,0x9cff,0x9d00, 0x9d01,0x9d02,0x9d03,0x9d04,0x9d05,0x9d06,0x9d07,0x9d08,0x9d09,0x9d0a, 0x9d0b,0x9d0c,0x9d0d,0x9d0e,0x9d0f,0x9d10,0x9d11,0x9d12,0x9d13,0x9d14, 0x9d15,0x9d16,0x9d17,0x9d18,0x9d19,0x9d1a,0x9d1b,0x9d1c,0x9d1d,0x9d1e, 0x9d1f,0x9d20,0x9d21,UBOGON,0x9d22,0x9d23,0x9d24,0x9d25,0x9d26,0x9d27, 0x9d28,0x9d29,0x9d2a,0x9d2b,0x9d2c,0x9d2d,0x9d2e,0x9d2f,0x9d30,0x9d31, 0x9d32,0x9d33,0x9d34,0x9d35,0x9d36,0x9d37,0x9d38,0x9d39,0x9d3a,0x9d3b, 0x9d3c,0x9d3d,0x9d3e,0x9d3f,0x9d40,0x9d41,0x9d42,UBOGON,UBOGON,UBOGON, UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON, UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON, UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON, UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON, UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON, UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON, UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON, UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON, UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON, UBOGON }, { /* ku 79 */ 0x9d43,0x9d44,0x9d45,0x9d46,0x9d47,0x9d48,0x9d49,0x9d4a,0x9d4b,0x9d4c, 0x9d4d,0x9d4e,0x9d4f,0x9d50,0x9d51,0x9d52,0x9d53,0x9d54,0x9d55,0x9d56, 0x9d57,0x9d58,0x9d59,0x9d5a,0x9d5b,0x9d5c,0x9d5d,0x9d5e,0x9d5f,0x9d60, 0x9d61,0x9d62,0x9d63,0x9d64,0x9d65,0x9d66,0x9d67,0x9d68,0x9d69,0x9d6a, 0x9d6b,0x9d6c,0x9d6d,0x9d6e,0x9d6f,0x9d70,0x9d71,0x9d72,0x9d73,0x9d74, 0x9d75,0x9d76,0x9d77,0x9d78,0x9d79,0x9d7a,0x9d7b,0x9d7c,0x9d7d,0x9d7e, 0x9d7f,0x9d80,0x9d81,UBOGON,0x9d82,0x9d83,0x9d84,0x9d85,0x9d86,0x9d87, 0x9d88,0x9d89,0x9d8a,0x9d8b,0x9d8c,0x9d8d,0x9d8e,0x9d8f,0x9d90,0x9d91, 0x9d92,0x9d93,0x9d94,0x9d95,0x9d96,0x9d97,0x9d98,0x9d99,0x9d9a,0x9d9b, 0x9d9c,0x9d9d,0x9d9e,0x9d9f,0x9da0,0x9da1,0x9da2,UBOGON,UBOGON,UBOGON, UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON, UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON, UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON, UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON, UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON, UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON, UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON, UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON, UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON, UBOGON }, { /* ku 7a */ 0x9da3,0x9da4,0x9da5,0x9da6,0x9da7,0x9da8,0x9da9,0x9daa,0x9dab,0x9dac, 0x9dad,0x9dae,0x9daf,0x9db0,0x9db1,0x9db2,0x9db3,0x9db4,0x9db5,0x9db6, 0x9db7,0x9db8,0x9db9,0x9dba,0x9dbb,0x9dbc,0x9dbd,0x9dbe,0x9dbf,0x9dc0, 0x9dc1,0x9dc2,0x9dc3,0x9dc4,0x9dc5,0x9dc6,0x9dc7,0x9dc8,0x9dc9,0x9dca, 0x9dcb,0x9dcc,0x9dcd,0x9dce,0x9dcf,0x9dd0,0x9dd1,0x9dd2,0x9dd3,0x9dd4, 0x9dd5,0x9dd6,0x9dd7,0x9dd8,0x9dd9,0x9dda,0x9ddb,0x9ddc,0x9ddd,0x9dde, 0x9ddf,0x9de0,0x9de1,UBOGON,0x9de2,0x9de3,0x9de4,0x9de5,0x9de6,0x9de7, 0x9de8,0x9de9,0x9dea,0x9deb,0x9dec,0x9ded,0x9dee,0x9def,0x9df0,0x9df1, 0x9df2,0x9df3,0x9df4,0x9df5,0x9df6,0x9df7,0x9df8,0x9df9,0x9dfa,0x9dfb, 0x9dfc,0x9dfd,0x9dfe,0x9dff,0x9e00,0x9e01,0x9e02,UBOGON,UBOGON,UBOGON, UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON, UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON, UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON, UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON, UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON, UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON, UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON, UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON, UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON, UBOGON }, { /* ku 7b */ 0x9e03,0x9e04,0x9e05,0x9e06,0x9e07,0x9e08,0x9e09,0x9e0a,0x9e0b,0x9e0c, 0x9e0d,0x9e0e,0x9e0f,0x9e10,0x9e11,0x9e12,0x9e13,0x9e14,0x9e15,0x9e16, 0x9e17,0x9e18,0x9e19,0x9e1a,0x9e1b,0x9e1c,0x9e1d,0x9e1e,0x9e24,0x9e27, 0x9e2e,0x9e30,0x9e34,0x9e3b,0x9e3c,0x9e40,0x9e4d,0x9e50,0x9e52,0x9e53, 0x9e54,0x9e56,0x9e59,0x9e5d,0x9e5f,0x9e60,0x9e61,0x9e62,0x9e65,0x9e6e, 0x9e6f,0x9e72,0x9e74,0x9e75,0x9e76,0x9e77,0x9e78,0x9e79,0x9e7a,0x9e7b, 0x9e7c,0x9e7d,0x9e80,UBOGON,0x9e81,0x9e83,0x9e84,0x9e85,0x9e86,0x9e89, 0x9e8a,0x9e8c,0x9e8d,0x9e8e,0x9e8f,0x9e90,0x9e91,0x9e94,0x9e95,0x9e96, 0x9e97,0x9e98,0x9e99,0x9e9a,0x9e9b,0x9e9c,0x9e9e,0x9ea0,0x9ea1,0x9ea2, 0x9ea3,0x9ea4,0x9ea5,0x9ea7,0x9ea8,0x9ea9,0x9eaa,UBOGON,UBOGON,UBOGON, UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON, UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON, UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON, UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON, UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON, UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON, UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON, UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON, UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON, UBOGON }, { /* ku 7c */ 0x9eab,0x9eac,0x9ead,0x9eae,0x9eaf,0x9eb0,0x9eb1,0x9eb2,0x9eb3,0x9eb5, 0x9eb6,0x9eb7,0x9eb9,0x9eba,0x9ebc,0x9ebf,0x9ec0,0x9ec1,0x9ec2,0x9ec3, 0x9ec5,0x9ec6,0x9ec7,0x9ec8,0x9eca,0x9ecb,0x9ecc,0x9ed0,0x9ed2,0x9ed3, 0x9ed5,0x9ed6,0x9ed7,0x9ed9,0x9eda,0x9ede,0x9ee1,0x9ee3,0x9ee4,0x9ee6, 0x9ee8,0x9eeb,0x9eec,0x9eed,0x9eee,0x9ef0,0x9ef1,0x9ef2,0x9ef3,0x9ef4, 0x9ef5,0x9ef6,0x9ef7,0x9ef8,0x9efa,0x9efd,0x9eff,0x9f00,0x9f01,0x9f02, 0x9f03,0x9f04,0x9f05,UBOGON,0x9f06,0x9f07,0x9f08,0x9f09,0x9f0a,0x9f0c, 0x9f0f,0x9f11,0x9f12,0x9f14,0x9f15,0x9f16,0x9f18,0x9f1a,0x9f1b,0x9f1c, 0x9f1d,0x9f1e,0x9f1f,0x9f21,0x9f23,0x9f24,0x9f25,0x9f26,0x9f27,0x9f28, 0x9f29,0x9f2a,0x9f2b,0x9f2d,0x9f2e,0x9f30,0x9f31,UBOGON,UBOGON,UBOGON, UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON, UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON, UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON, UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON, UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON, UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON, UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON, UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON, UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON, UBOGON }, { /* ku 7d */ 0x9f32,0x9f33,0x9f34,0x9f35,0x9f36,0x9f38,0x9f3a,0x9f3c,0x9f3f,0x9f40, 0x9f41,0x9f42,0x9f43,0x9f45,0x9f46,0x9f47,0x9f48,0x9f49,0x9f4a,0x9f4b, 0x9f4c,0x9f4d,0x9f4e,0x9f4f,0x9f52,0x9f53,0x9f54,0x9f55,0x9f56,0x9f57, 0x9f58,0x9f59,0x9f5a,0x9f5b,0x9f5c,0x9f5d,0x9f5e,0x9f5f,0x9f60,0x9f61, 0x9f62,0x9f63,0x9f64,0x9f65,0x9f66,0x9f67,0x9f68,0x9f69,0x9f6a,0x9f6b, 0x9f6c,0x9f6d,0x9f6e,0x9f6f,0x9f70,0x9f71,0x9f72,0x9f73,0x9f74,0x9f75, 0x9f76,0x9f77,0x9f78,UBOGON,0x9f79,0x9f7a,0x9f7b,0x9f7c,0x9f7d,0x9f7e, 0x9f81,0x9f82,0x9f8d,0x9f8e,0x9f8f,0x9f90,0x9f91,0x9f92,0x9f93,0x9f94, 0x9f95,0x9f96,0x9f97,0x9f98,0x9f9c,0x9f9d,0x9f9e,0x9fa1,0x9fa2,0x9fa3, 0x9fa4,0x9fa5,0xf92c,0xf979,0xf995,0xf9e7,0xf9f1,UBOGON,UBOGON,UBOGON, UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON, UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON, UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON, UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON, UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON, UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON, UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON, UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON, UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON, UBOGON } }; alpine-2.10+dfsg/imap/src/charset/decomtab.c0000600000175000017500000050657611512502123022446 0ustar paulproteuspaulproteus/* ======================================================================== * Copyright 1988-2006 University of Washington * * Licensed under the Apache License, Version 2.0 (the "License"); * you may not use this file except in compliance with the License. * You may obtain a copy of the License at * * http://www.apache.org/licenses/LICENSE-2.0 * * * ======================================================================== */ /* * Program: Unicode decomposition tables (current as of Unicode 5.0) * * Author: Mark Crispin * Networks and Distributed Computing * Computing & Communications * University of Washington * Administration Building, AG-44 * Seattle, WA 98195 * Internet: MRC@CAC.Washington.EDU * * Date: 13 April 2006 * Last Edited: 6 December 2006 */ /* BMP decompositions */ #define UCS4_BMPLOMIN 0x00a0 #define UCS4_BMPLOMAX 0x33ff #define UCS4_BMPLOIXMASK 0x1fff #define UCS4_BMPLOSIZEMASK 0xe000 #define UCS4_BMPLOSIZESHIFT 13 /* BMP low decomposition indices - sssi iiii iiii iiii */ static unsigned short ucs4_dbmploixtab[13152] = { 0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000, 0x2001,0x0000,0x0003,0x0000,0x0000,0x0000,0x0000,0x2004, 0x0000,0x0000,0x0006,0x0007,0x2008,0x000a,0x0000,0x0000, 0x200b,0x000d,0x000e,0x0000,0x400f,0x4012,0x4015,0x0000, 0x2018,0x201a,0x201c,0x201e,0x2020,0x2022,0x0000,0x2024, 0x2026,0x2028,0x202a,0x202c,0x202e,0x2030,0x2032,0x2034, 0x0000,0x2036,0x2038,0x203a,0x203c,0x203e,0x2040,0x0000, 0x0000,0x2042,0x2044,0x2046,0x2048,0x204a,0x0000,0x0000, 0x204c,0x204e,0x2050,0x2052,0x2054,0x2056,0x0000,0x2058, 0x205a,0x205c,0x205e,0x2060,0x2062,0x2064,0x2066,0x2068, 0x0000,0x206a,0x206c,0x206e,0x2070,0x2072,0x2074,0x0000, 0x0000,0x2076,0x2078,0x207a,0x207c,0x207e,0x0000,0x2080, 0x2082,0x2084,0x2086,0x2088,0x208a,0x208c,0x208e,0x2090, 0x2092,0x2094,0x2096,0x2098,0x209a,0x209c,0x209e,0x20a0, 0x0000,0x0000,0x20a2,0x20a4,0x20a6,0x20a8,0x20aa,0x20ac, 0x20ae,0x20b0,0x20b2,0x20b4,0x20b6,0x20b8,0x20ba,0x20bc, 0x20be,0x20c0,0x20c2,0x20c4,0x20c6,0x20c8,0x0000,0x0000, 0x20ca,0x20cc,0x20ce,0x20d0,0x20d2,0x20d4,0x20d6,0x20d8, 0x20da,0x0000,0x20dc,0x20de,0x20e0,0x20e2,0x20e4,0x20e6, 0x0000,0x20e8,0x20ea,0x20ec,0x20ee,0x20f0,0x20f2,0x20f4, 0x20f6,0x0000,0x0000,0x20f8,0x20fa,0x20fc,0x20fe,0x2100, 0x2102,0x2104,0x0000,0x0000,0x2106,0x2108,0x210a,0x210c, 0x210e,0x2110,0x0000,0x0000,0x2112,0x2114,0x2116,0x2118, 0x211a,0x211c,0x211e,0x2120,0x2122,0x2124,0x2126,0x2128, 0x212a,0x212c,0x212e,0x2130,0x2132,0x2134,0x0000,0x0000, 0x2136,0x2138,0x213a,0x213c,0x213e,0x2140,0x2142,0x2144, 0x2146,0x2148,0x214a,0x214c,0x214e,0x2150,0x2152,0x2154, 0x2156,0x2158,0x215a,0x215c,0x215e,0x2160,0x2162,0x0164, 0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000, 0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000, 0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000, 0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000, 0x2165,0x2167,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000, 0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x2169, 0x216b,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000, 0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000, 0x0000,0x0000,0x0000,0x0000,0x216d,0x216f,0x2171,0x2173, 0x2175,0x2177,0x2179,0x217b,0x217d,0x217f,0x2181,0x2183, 0x2185,0x2187,0x2189,0x218b,0x218d,0x218f,0x2191,0x2193, 0x2195,0x2197,0x2199,0x219b,0x219d,0x0000,0x219f,0x21a1, 0x21a3,0x21a5,0x21a7,0x21a9,0x0000,0x0000,0x21ab,0x21ad, 0x21af,0x21b1,0x21b3,0x21b5,0x21b7,0x21b9,0x21bb,0x21bd, 0x21bf,0x21c1,0x21c3,0x21c5,0x21c7,0x21c9,0x0000,0x0000, 0x21cb,0x21cd,0x21cf,0x21d1,0x21d3,0x21d5,0x21d7,0x21d9, 0x21db,0x21dd,0x21df,0x21e1,0x21e3,0x21e5,0x21e7,0x21e9, 0x21eb,0x21ed,0x21ef,0x21f1,0x21f3,0x21f5,0x21f7,0x21f9, 0x21fb,0x21fd,0x21ff,0x2201,0x2203,0x2205,0x2207,0x2209, 0x220b,0x220d,0x220f,0x2211,0x0000,0x0000,0x2213,0x2215, 0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x2217,0x2219, 0x221b,0x221d,0x221f,0x2221,0x2223,0x2225,0x2227,0x2229, 0x222b,0x222d,0x222f,0x2231,0x0000,0x0000,0x0000,0x0000, 0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000, 0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000, 0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000, 0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000, 0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000, 0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000, 0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000, 0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000, 0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000, 0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000, 0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000, 0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000, 0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000, 0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000, 0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000, 0x0233,0x0234,0x0235,0x0236,0x0237,0x0238,0x0239,0x023a, 0x023b,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000, 0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000, 0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000, 0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000, 0x223c,0x223e,0x2240,0x2242,0x2244,0x2246,0x0000,0x0000, 0x0248,0x0249,0x024a,0x024b,0x024c,0x0000,0x0000,0x0000, 0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000, 0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000, 0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000, 0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000, 0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000, 0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000, 0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000, 0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000, 0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000, 0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000, 0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000, 0x024d,0x024e,0x0000,0x024f,0x2250,0x0000,0x0000,0x0000, 0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000, 0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000, 0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000, 0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000, 0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000, 0x0000,0x0000,0x0000,0x0000,0x0252,0x0000,0x0000,0x0000, 0x0000,0x0000,0x2253,0x0000,0x0000,0x0000,0x0255,0x0000, 0x0000,0x0000,0x0000,0x0000,0x2256,0x2258,0x225a,0x025c, 0x225d,0x225f,0x2261,0x0000,0x2263,0x0000,0x2265,0x2267, 0x2269,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000, 0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000, 0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000, 0x0000,0x0000,0x226b,0x226d,0x226f,0x2271,0x2273,0x2275, 0x2277,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000, 0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000, 0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000, 0x0000,0x0000,0x2279,0x227b,0x227d,0x227f,0x2281,0x0000, 0x0283,0x0284,0x0285,0x2286,0x2288,0x028a,0x028b,0x0000, 0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000, 0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000, 0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000, 0x028c,0x028d,0x028e,0x0000,0x028f,0x0290,0x0000,0x0000, 0x0000,0x0291,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000, 0x2292,0x2294,0x0000,0x2296,0x0000,0x0000,0x0000,0x2298, 0x0000,0x0000,0x0000,0x0000,0x229a,0x229c,0x229e,0x0000, 0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000, 0x0000,0x22a0,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000, 0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000, 0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000, 0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000, 0x0000,0x22a2,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000, 0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000, 0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000, 0x22a4,0x22a6,0x0000,0x22a8,0x0000,0x0000,0x0000,0x22aa, 0x0000,0x0000,0x0000,0x0000,0x22ac,0x22ae,0x22b0,0x0000, 0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000, 0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000, 0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x22b2,0x22b4, 0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000, 0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000, 0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000, 0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000, 0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000, 0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000, 0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000, 0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000, 0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000, 0x0000,0x22b6,0x22b8,0x0000,0x0000,0x0000,0x0000,0x0000, 0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000, 0x22ba,0x22bc,0x22be,0x22c0,0x0000,0x0000,0x22c2,0x22c4, 0x0000,0x0000,0x22c6,0x22c8,0x22ca,0x22cc,0x22ce,0x22d0, 0x0000,0x0000,0x22d2,0x22d4,0x22d6,0x22d8,0x22da,0x22dc, 0x0000,0x0000,0x22de,0x22e0,0x22e2,0x22e4,0x22e6,0x22e8, 0x22ea,0x22ec,0x22ee,0x22f0,0x22f2,0x22f4,0x0000,0x0000, 0x22f6,0x22f8,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000, 0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000, 0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000, 0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000, 0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000, 0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000, 0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000, 0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000, 0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000, 0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000, 0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000, 0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000, 0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000, 0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000, 0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000, 0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000, 0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000, 0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x22fa, 0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000, 0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000, 0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000, 0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000, 0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000, 0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000, 0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000, 0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000, 0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000, 0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000, 0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000, 0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000, 0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000, 0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000, 0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000, 0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000, 0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000, 0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000, 0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000, 0x0000,0x0000,0x22fc,0x22fe,0x2300,0x2302,0x2304,0x0000, 0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000, 0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000, 0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000, 0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000, 0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000, 0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000, 0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000, 0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000, 0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000, 0x0000,0x0000,0x0000,0x0000,0x0000,0x2306,0x2308,0x230a, 0x230c,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000, 0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000, 0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000, 0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000, 0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000, 0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000, 0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000, 0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000, 0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000, 0x230e,0x0000,0x2310,0x0000,0x0000,0x0000,0x0000,0x0000, 0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000, 0x0000,0x0000,0x0000,0x2312,0x0000,0x0000,0x0000,0x0000, 0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000, 0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000, 0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000, 0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000, 0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000, 0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000, 0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000, 0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000, 0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000, 0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000, 0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000, 0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000, 0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000, 0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000, 0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000, 0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000, 0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000, 0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000, 0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000, 0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000, 0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000, 0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000, 0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000, 0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000, 0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000, 0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000, 0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000, 0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000, 0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000, 0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000, 0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000, 0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000, 0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000, 0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000, 0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000, 0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000, 0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000, 0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000, 0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000, 0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000, 0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000, 0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000, 0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000, 0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000, 0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000, 0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000, 0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000, 0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000, 0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000, 0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000, 0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000, 0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000, 0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000, 0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000, 0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000, 0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000, 0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000, 0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000, 0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000, 0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000, 0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000, 0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000, 0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000, 0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000, 0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000, 0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000, 0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000, 0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000, 0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000, 0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000, 0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000, 0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000, 0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000, 0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000, 0x0000,0x2314,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000, 0x0000,0x2316,0x0000,0x0000,0x2318,0x0000,0x0000,0x0000, 0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000, 0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000, 0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000, 0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000, 0x231a,0x231c,0x231e,0x2320,0x2322,0x2324,0x2326,0x2328, 0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000, 0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000, 0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000, 0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000, 0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000, 0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000, 0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000, 0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000, 0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000, 0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000, 0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000, 0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000, 0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000, 0x0000,0x0000,0x0000,0x232a,0x232c,0x0000,0x0000,0x0000, 0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000, 0x0000,0x0000,0x0000,0x0000,0x232e,0x2330,0x0000,0x2332, 0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000, 0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000, 0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000, 0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000, 0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000, 0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000, 0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000, 0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000, 0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000, 0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000, 0x0000,0x0000,0x0000,0x2334,0x0000,0x0000,0x2336,0x0000, 0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000, 0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000, 0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000, 0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000, 0x0000,0x2338,0x233a,0x233c,0x0000,0x0000,0x233e,0x0000, 0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000, 0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000, 0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000, 0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000, 0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000, 0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000, 0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000, 0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000, 0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000, 0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000, 0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000, 0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000, 0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000, 0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000, 0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000, 0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000, 0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000, 0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000, 0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000, 0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000, 0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000, 0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000, 0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000, 0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000, 0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000, 0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000, 0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000, 0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000, 0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000, 0x2340,0x0000,0x0000,0x2342,0x2344,0x0000,0x0000,0x0000, 0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000, 0x0000,0x0000,0x0000,0x0000,0x2346,0x2348,0x0000,0x0000, 0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000, 0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000, 0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000, 0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000, 0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000, 0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000, 0x0000,0x0000,0x0000,0x0000,0x234a,0x0000,0x0000,0x0000, 0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000, 0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000, 0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000, 0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000, 0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000, 0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000, 0x0000,0x0000,0x234c,0x234e,0x2350,0x0000,0x0000,0x0000, 0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000, 0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000, 0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000, 0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000, 0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000, 0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000, 0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000, 0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000, 0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000, 0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000, 0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000, 0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000, 0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000, 0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000, 0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000, 0x2352,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000, 0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000, 0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000, 0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000, 0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000, 0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000, 0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000, 0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000, 0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000, 0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000, 0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000, 0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000, 0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000, 0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000, 0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000, 0x2354,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x2356, 0x2358,0x0000,0x235a,0x235c,0x0000,0x0000,0x0000,0x0000, 0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000, 0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000, 0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000, 0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000, 0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000, 0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000, 0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000, 0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000, 0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000, 0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000, 0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000, 0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000, 0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000, 0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000, 0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000, 0x0000,0x0000,0x235e,0x2360,0x2362,0x0000,0x0000,0x0000, 0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000, 0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000, 0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000, 0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000, 0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000, 0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000, 0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000, 0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000, 0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000, 0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000, 0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000, 0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000, 0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000, 0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000, 0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000, 0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000, 0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000, 0x0000,0x0000,0x2364,0x0000,0x2366,0x2368,0x236a,0x0000, 0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000, 0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000, 0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000, 0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000, 0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000, 0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000, 0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000, 0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000, 0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000, 0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000, 0x0000,0x0000,0x0000,0x236c,0x0000,0x0000,0x0000,0x0000, 0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000, 0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000, 0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000, 0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000, 0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000, 0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000, 0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000, 0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000, 0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000, 0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000, 0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000, 0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000, 0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000, 0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000, 0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000, 0x0000,0x0000,0x0000,0x236e,0x0000,0x0000,0x0000,0x0000, 0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000, 0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000, 0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000, 0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000, 0x0000,0x0000,0x0000,0x0000,0x2370,0x2372,0x0000,0x0000, 0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000, 0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000, 0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000, 0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000, 0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000, 0x0000,0x0000,0x0000,0x0000,0x0374,0x0000,0x0000,0x0000, 0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000, 0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000, 0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000, 0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000, 0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000, 0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000, 0x0000,0x0000,0x0000,0x2375,0x0000,0x0000,0x0000,0x0000, 0x0000,0x0000,0x0000,0x0000,0x0000,0x2377,0x0000,0x0000, 0x0000,0x0000,0x2379,0x0000,0x0000,0x0000,0x0000,0x237b, 0x0000,0x0000,0x0000,0x0000,0x237d,0x0000,0x0000,0x0000, 0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000, 0x0000,0x237f,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000, 0x0000,0x0000,0x0000,0x2381,0x0000,0x2383,0x2385,0x2387, 0x2389,0x238b,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000, 0x0000,0x238d,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000, 0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000, 0x0000,0x0000,0x0000,0x238f,0x0000,0x0000,0x0000,0x0000, 0x0000,0x0000,0x0000,0x0000,0x0000,0x2391,0x0000,0x0000, 0x0000,0x0000,0x2393,0x0000,0x0000,0x0000,0x0000,0x2395, 0x0000,0x0000,0x0000,0x0000,0x2397,0x0000,0x0000,0x0000, 0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000, 0x0000,0x2399,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000, 0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000, 0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000, 0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000, 0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000, 0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000, 0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000, 0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000, 0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000, 0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000, 0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000, 0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000, 0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000, 0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x239b,0x0000, 0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000, 0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000, 0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000, 0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000, 0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000, 0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000, 0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000, 0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000, 0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000, 0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000, 0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000, 0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000, 0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000, 0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000, 0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000, 0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000, 0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000, 0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000, 0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000, 0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000, 0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000, 0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000, 0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000, 0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000, 0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000, 0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000, 0x0000,0x0000,0x0000,0x0000,0x039d,0x0000,0x0000,0x0000, 0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000, 0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000, 0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000, 0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000, 0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000, 0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000, 0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000, 0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000, 0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000, 0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000, 0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000, 0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000, 0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000, 0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000, 0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000, 0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000, 0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000, 0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000, 0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000, 0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000, 0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000, 0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000, 0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000, 0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000, 0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000, 0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000, 0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000, 0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000, 0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000, 0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000, 0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000, 0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000, 0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000, 0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000, 0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000, 0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000, 0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000, 0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000, 0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000, 0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000, 0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000, 0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000, 0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000, 0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000, 0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000, 0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000, 0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000, 0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000, 0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000, 0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000, 0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000, 0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000, 0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000, 0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000, 0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000, 0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000, 0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000, 0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000, 0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000, 0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000, 0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000, 0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000, 0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000, 0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000, 0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000, 0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000, 0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000, 0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000, 0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000, 0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000, 0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000, 0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000, 0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000, 0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000, 0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000, 0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000, 0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000, 0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000, 0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000, 0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000, 0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000, 0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000, 0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000, 0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000, 0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000, 0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000, 0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000, 0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000, 0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000, 0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000, 0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000, 0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000, 0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000, 0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000, 0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000, 0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000, 0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000, 0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000, 0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000, 0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000, 0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000, 0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000, 0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000, 0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000, 0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000, 0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000, 0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000, 0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000, 0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000, 0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000, 0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000, 0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000, 0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000, 0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000, 0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000, 0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000, 0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000, 0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000, 0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000, 0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000, 0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000, 0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000, 0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000, 0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000, 0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000, 0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000, 0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000, 0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000, 0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000, 0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000, 0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000, 0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000, 0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000, 0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000, 0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000, 0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000, 0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000, 0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000, 0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000, 0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000, 0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000, 0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000, 0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000, 0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000, 0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000, 0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000, 0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000, 0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000, 0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000, 0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000, 0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000, 0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000, 0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000, 0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000, 0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000, 0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000, 0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000, 0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000, 0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000, 0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000, 0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000, 0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000, 0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000, 0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000, 0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000, 0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000, 0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000, 0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000, 0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000, 0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000, 0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000, 0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000, 0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000, 0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000, 0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000, 0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000, 0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000, 0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000, 0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000, 0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000, 0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000, 0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000, 0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000, 0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000, 0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000, 0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000, 0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000, 0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000, 0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000, 0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000, 0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000, 0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000, 0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000, 0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000, 0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000, 0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000, 0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000, 0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000, 0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000, 0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000, 0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000, 0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000, 0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000, 0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000, 0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000, 0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000, 0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000, 0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000, 0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000, 0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000, 0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000, 0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000, 0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000, 0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000, 0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000, 0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000, 0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000, 0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000, 0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000, 0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000, 0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000, 0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000, 0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000, 0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000, 0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000, 0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000, 0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000, 0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000, 0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000, 0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000, 0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000, 0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000, 0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000, 0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000, 0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000, 0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000, 0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000, 0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000, 0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000, 0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000, 0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000, 0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000, 0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000, 0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000, 0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000, 0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000, 0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000, 0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000, 0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000, 0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000, 0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000, 0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000, 0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000, 0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000, 0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000, 0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000, 0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000, 0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000, 0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000, 0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000, 0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000, 0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000, 0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000, 0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000, 0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000, 0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000, 0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000, 0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000, 0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000, 0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000, 0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000, 0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000, 0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000, 0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000, 0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000, 0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000, 0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000, 0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000, 0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000, 0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000, 0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000, 0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000, 0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000, 0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000, 0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000, 0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000, 0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000, 0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000, 0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000, 0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000, 0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000, 0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000, 0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000, 0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000, 0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000, 0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000, 0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000, 0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000, 0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000, 0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000, 0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000, 0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000, 0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000, 0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000, 0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000, 0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000, 0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000, 0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000, 0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000, 0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000, 0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000, 0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000, 0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000, 0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000, 0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000, 0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000, 0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000, 0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000, 0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000, 0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000, 0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x239e,0x0000, 0x23a0,0x0000,0x23a2,0x0000,0x23a4,0x0000,0x23a6,0x0000, 0x0000,0x0000,0x23a8,0x0000,0x0000,0x0000,0x0000,0x0000, 0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000, 0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000, 0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000, 0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000, 0x0000,0x0000,0x0000,0x23aa,0x0000,0x23ac,0x0000,0x0000, 0x23ae,0x23b0,0x0000,0x23b2,0x0000,0x0000,0x0000,0x0000, 0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000, 0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000, 0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000, 0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000, 0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000, 0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000, 0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000, 0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000, 0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000, 0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000, 0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000, 0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000, 0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000, 0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000, 0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000, 0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000, 0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000, 0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000, 0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000, 0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000, 0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000, 0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000, 0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000, 0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000, 0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000, 0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000, 0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000, 0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000, 0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000, 0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000, 0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000, 0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000, 0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000, 0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000, 0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000, 0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000, 0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000, 0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000, 0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000, 0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000, 0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000, 0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000, 0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000, 0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000, 0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000, 0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000, 0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000, 0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000, 0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000, 0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000, 0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000, 0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000, 0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000, 0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000, 0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000, 0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000, 0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000, 0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000, 0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000, 0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000, 0x0000,0x0000,0x0000,0x0000,0x03b4,0x03b5,0x03b6,0x0000, 0x03b7,0x03b8,0x03b9,0x03ba,0x03bb,0x03bc,0x03bd,0x03be, 0x03bf,0x03c0,0x03c1,0x0000,0x03c2,0x03c3,0x03c4,0x03c5, 0x03c6,0x03c7,0x03c8,0x03c9,0x03ca,0x03cb,0x03cc,0x03cd, 0x03ce,0x03cf,0x03d0,0x03d1,0x03d2,0x03d3,0x0000,0x03d4, 0x03d5,0x03d6,0x03d7,0x03d8,0x03d9,0x03da,0x03db,0x03dc, 0x03dd,0x03de,0x03df,0x03e0,0x03e1,0x03e2,0x03e3,0x03e4, 0x03e5,0x03e6,0x03e7,0x03e8,0x03e9,0x03ea,0x03eb,0x03ec, 0x03ed,0x03ee,0x03ef,0x0000,0x0000,0x0000,0x0000,0x0000, 0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000, 0x03f0,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000, 0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000, 0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000, 0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000, 0x0000,0x0000,0x0000,0x03f1,0x03f2,0x03f3,0x03f4,0x03f5, 0x03f6,0x03f7,0x03f8,0x03f9,0x03fa,0x03fb,0x03fc,0x03fd, 0x03fe,0x03ff,0x0400,0x0401,0x0402,0x0403,0x0404,0x0405, 0x0406,0x0407,0x0408,0x0409,0x040a,0x040b,0x040c,0x040d, 0x040e,0x040f,0x0410,0x0411,0x0412,0x0413,0x0414,0x0415, 0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000, 0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000, 0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000, 0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000, 0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000, 0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000, 0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000, 0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000, 0x2416,0x2418,0x241a,0x241c,0x241e,0x2420,0x2422,0x2424, 0x2426,0x2428,0x242a,0x242c,0x242e,0x2430,0x2432,0x2434, 0x2436,0x2438,0x243a,0x243c,0x243e,0x2440,0x2442,0x2444, 0x2446,0x2448,0x244a,0x244c,0x244e,0x2450,0x2452,0x2454, 0x2456,0x2458,0x245a,0x245c,0x245e,0x2460,0x2462,0x2464, 0x2466,0x2468,0x246a,0x246c,0x246e,0x2470,0x2472,0x2474, 0x2476,0x2478,0x247a,0x247c,0x247e,0x2480,0x2482,0x2484, 0x2486,0x2488,0x248a,0x248c,0x248e,0x2490,0x2492,0x2494, 0x2496,0x2498,0x249a,0x249c,0x249e,0x24a0,0x24a2,0x24a4, 0x24a6,0x24a8,0x24aa,0x24ac,0x24ae,0x24b0,0x24b2,0x24b4, 0x24b6,0x24b8,0x24ba,0x24bc,0x24be,0x24c0,0x24c2,0x24c4, 0x24c6,0x24c8,0x24ca,0x24cc,0x24ce,0x24d0,0x24d2,0x24d4, 0x24d6,0x24d8,0x24da,0x24dc,0x24de,0x24e0,0x24e2,0x24e4, 0x24e6,0x24e8,0x24ea,0x24ec,0x24ee,0x24f0,0x24f2,0x24f4, 0x24f6,0x24f8,0x24fa,0x24fc,0x24fe,0x2500,0x2502,0x2504, 0x2506,0x2508,0x250a,0x250c,0x250e,0x2510,0x2512,0x2514, 0x2516,0x2518,0x251a,0x251c,0x251e,0x2520,0x2522,0x2524, 0x2526,0x2528,0x252a,0x252c,0x252e,0x2530,0x2532,0x2534, 0x2536,0x2538,0x253a,0x253c,0x253e,0x2540,0x2542,0x2544, 0x2546,0x2548,0x254a,0x254c,0x0000,0x0000,0x0000,0x0000, 0x254e,0x2550,0x2552,0x2554,0x2556,0x2558,0x255a,0x255c, 0x255e,0x2560,0x2562,0x2564,0x2566,0x2568,0x256a,0x256c, 0x256e,0x2570,0x2572,0x2574,0x2576,0x2578,0x257a,0x257c, 0x257e,0x2580,0x2582,0x2584,0x2586,0x2588,0x258a,0x258c, 0x258e,0x2590,0x2592,0x2594,0x2596,0x2598,0x259a,0x259c, 0x259e,0x25a0,0x25a2,0x25a4,0x25a6,0x25a8,0x25aa,0x25ac, 0x25ae,0x25b0,0x25b2,0x25b4,0x25b6,0x25b8,0x25ba,0x25bc, 0x25be,0x25c0,0x25c2,0x25c4,0x25c6,0x25c8,0x25ca,0x25cc, 0x25ce,0x25d0,0x25d2,0x25d4,0x25d6,0x25d8,0x25da,0x25dc, 0x25de,0x25e0,0x25e2,0x25e4,0x25e6,0x25e8,0x25ea,0x25ec, 0x25ee,0x25f0,0x25f2,0x25f4,0x25f6,0x25f8,0x25fa,0x25fc, 0x25fe,0x2600,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000, 0x2602,0x2604,0x2606,0x2608,0x260a,0x260c,0x260e,0x2610, 0x2612,0x2614,0x2616,0x2618,0x261a,0x261c,0x261e,0x2620, 0x2622,0x2624,0x2626,0x2628,0x262a,0x262c,0x0000,0x0000, 0x262e,0x2630,0x2632,0x2634,0x2636,0x2638,0x0000,0x0000, 0x263a,0x263c,0x263e,0x2640,0x2642,0x2644,0x2646,0x2648, 0x264a,0x264c,0x264e,0x2650,0x2652,0x2654,0x2656,0x2658, 0x265a,0x265c,0x265e,0x2660,0x2662,0x2664,0x2666,0x2668, 0x266a,0x266c,0x266e,0x2670,0x2672,0x2674,0x2676,0x2678, 0x267a,0x267c,0x267e,0x2680,0x2682,0x2684,0x0000,0x0000, 0x2686,0x2688,0x268a,0x268c,0x268e,0x2690,0x0000,0x0000, 0x2692,0x2694,0x2696,0x2698,0x269a,0x269c,0x269e,0x26a0, 0x0000,0x26a2,0x0000,0x26a4,0x0000,0x26a6,0x0000,0x26a8, 0x26aa,0x26ac,0x26ae,0x26b0,0x26b2,0x26b4,0x26b6,0x26b8, 0x26ba,0x26bc,0x26be,0x26c0,0x26c2,0x26c4,0x26c6,0x26c8, 0x26ca,0x06cc,0x26cd,0x06cf,0x26d0,0x06d2,0x26d3,0x06d5, 0x26d6,0x06d8,0x26d9,0x06db,0x26dc,0x06de,0x0000,0x0000, 0x26df,0x26e1,0x26e3,0x26e5,0x26e7,0x26e9,0x26eb,0x26ed, 0x26ef,0x26f1,0x26f3,0x26f5,0x26f7,0x26f9,0x26fb,0x26fd, 0x26ff,0x2701,0x2703,0x2705,0x2707,0x2709,0x270b,0x270d, 0x270f,0x2711,0x2713,0x2715,0x2717,0x2719,0x271b,0x271d, 0x271f,0x2721,0x2723,0x2725,0x2727,0x2729,0x272b,0x272d, 0x272f,0x2731,0x2733,0x2735,0x2737,0x2739,0x273b,0x273d, 0x273f,0x2741,0x2743,0x2745,0x2747,0x0000,0x2749,0x274b, 0x274d,0x274f,0x2751,0x0753,0x2754,0x2756,0x0758,0x2759, 0x275b,0x275d,0x275f,0x2761,0x2763,0x0000,0x2765,0x2767, 0x2769,0x076b,0x276c,0x076e,0x276f,0x2771,0x2773,0x2775, 0x2777,0x2779,0x277b,0x077d,0x0000,0x0000,0x277e,0x2780, 0x2782,0x2784,0x2786,0x0788,0x0000,0x2789,0x278b,0x278d, 0x278f,0x2791,0x2793,0x0795,0x2796,0x2798,0x279a,0x279c, 0x279e,0x27a0,0x27a2,0x07a4,0x27a5,0x27a7,0x07a9,0x07aa, 0x0000,0x0000,0x27ab,0x27ad,0x27af,0x0000,0x27b1,0x27b3, 0x27b5,0x07b7,0x27b8,0x07ba,0x27bb,0x07bd,0x27be,0x0000, 0x07c0,0x07c1,0x07c2,0x07c3,0x07c4,0x07c5,0x07c6,0x07c7, 0x07c8,0x07c9,0x07ca,0x0000,0x0000,0x0000,0x0000,0x0000, 0x0000,0x07cb,0x0000,0x0000,0x0000,0x0000,0x0000,0x27cc, 0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000, 0x0000,0x0000,0x0000,0x0000,0x07ce,0x27cf,0x47d1,0x0000, 0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x07d4, 0x0000,0x0000,0x0000,0x27d5,0x47d7,0x0000,0x27da,0x47dc, 0x0000,0x0000,0x0000,0x0000,0x27df,0x0000,0x27e1,0x0000, 0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x27e3, 0x27e5,0x27e7,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000, 0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x67e9, 0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x07ed, 0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000, 0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000, 0x07ee,0x07ef,0x0000,0x0000,0x07f0,0x07f1,0x07f2,0x07f3, 0x07f4,0x07f5,0x07f6,0x07f7,0x07f8,0x07f9,0x07fa,0x07fb, 0x07fc,0x07fd,0x07fe,0x07ff,0x0800,0x0801,0x0802,0x0803, 0x0804,0x0805,0x0806,0x0807,0x0808,0x0809,0x080a,0x0000, 0x080b,0x080c,0x080d,0x080e,0x080f,0x0000,0x0000,0x0000, 0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000, 0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000, 0x2810,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000, 0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000, 0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000, 0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000, 0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000, 0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000, 0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000, 0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000, 0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000, 0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000, 0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000, 0x4812,0x4815,0x0818,0x2819,0x0000,0x481b,0x481e,0x0821, 0x0000,0x2822,0x0824,0x0825,0x0826,0x0827,0x0828,0x0829, 0x082a,0x082b,0x082c,0x082d,0x0000,0x082e,0x282f,0x0000, 0x0000,0x0831,0x0832,0x0833,0x0834,0x0835,0x0000,0x0000, 0x2836,0x4838,0x283b,0x0000,0x083d,0x0000,0x083e,0x0000, 0x083f,0x0000,0x0840,0x0841,0x0842,0x0843,0x0000,0x0844, 0x0845,0x0846,0x0000,0x0847,0x0848,0x0849,0x084a,0x084b, 0x084c,0x084d,0x0000,0x484e,0x0851,0x0852,0x0853,0x0854, 0x0855,0x0000,0x0000,0x0000,0x0000,0x0856,0x0857,0x0858, 0x0859,0x085a,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000, 0x0000,0x0000,0x0000,0x485b,0x485e,0x4861,0x4864,0x4867, 0x486a,0x486d,0x4870,0x4873,0x4876,0x4879,0x487c,0x287f, 0x0881,0x2882,0x4884,0x2887,0x0889,0x288a,0x488c,0x688f, 0x2893,0x0895,0x2896,0x4898,0x089b,0x089c,0x089d,0x089e, 0x089f,0x28a0,0x48a2,0x28a5,0x08a7,0x28a8,0x48aa,0x68ad, 0x28b1,0x08b3,0x28b4,0x48b6,0x08b9,0x08ba,0x08bb,0x08bc, 0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000, 0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000, 0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000, 0x0000,0x0000,0x28bd,0x28bf,0x0000,0x0000,0x0000,0x0000, 0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000, 0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x28c1,0x0000, 0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000, 0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000, 0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000, 0x0000,0x0000,0x0000,0x0000,0x0000,0x28c3,0x28c5,0x28c7, 0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000, 0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000, 0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000, 0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000, 0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000, 0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000, 0x0000,0x0000,0x0000,0x0000,0x28c9,0x0000,0x0000,0x0000, 0x0000,0x28cb,0x0000,0x0000,0x28cd,0x0000,0x0000,0x0000, 0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000, 0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000, 0x0000,0x0000,0x0000,0x0000,0x28cf,0x0000,0x28d1,0x0000, 0x0000,0x0000,0x0000,0x0000,0x28d3,0x48d5,0x0000,0x28d8, 0x48da,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000, 0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000, 0x0000,0x28dd,0x0000,0x0000,0x28df,0x0000,0x0000,0x28e1, 0x0000,0x28e3,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000, 0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000, 0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000, 0x28e5,0x0000,0x28e7,0x0000,0x0000,0x0000,0x0000,0x0000, 0x0000,0x0000,0x0000,0x0000,0x0000,0x28e9,0x28eb,0x28ed, 0x28ef,0x28f1,0x0000,0x0000,0x28f3,0x28f5,0x0000,0x0000, 0x28f7,0x28f9,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000, 0x28fb,0x28fd,0x0000,0x0000,0x28ff,0x2901,0x0000,0x0000, 0x2903,0x2905,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000, 0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000, 0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000, 0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000, 0x0000,0x0000,0x0000,0x0000,0x2907,0x2909,0x290b,0x290d, 0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000, 0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000, 0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000, 0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000, 0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000, 0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000, 0x290f,0x2911,0x2913,0x2915,0x0000,0x0000,0x0000,0x0000, 0x0000,0x0000,0x2917,0x2919,0x291b,0x291d,0x0000,0x0000, 0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000, 0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000, 0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000, 0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000, 0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000, 0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000, 0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000, 0x0000,0x091f,0x0920,0x0000,0x0000,0x0000,0x0000,0x0000, 0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000, 0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000, 0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000, 0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000, 0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000, 0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000, 0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000, 0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000, 0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000, 0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000, 0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000, 0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000, 0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000, 0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000, 0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000, 0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000, 0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000, 0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000, 0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000, 0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000, 0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000, 0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000, 0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000, 0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000, 0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000, 0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000, 0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000, 0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000, 0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000, 0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000, 0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000, 0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000, 0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000, 0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000, 0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000, 0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000, 0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000, 0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000, 0x0921,0x0922,0x0923,0x0924,0x0925,0x0926,0x0927,0x0928, 0x0929,0x292a,0x292c,0x292e,0x2930,0x2932,0x2934,0x2936, 0x2938,0x293a,0x293c,0x293e,0x4940,0x4943,0x4946,0x4949, 0x494c,0x494f,0x4952,0x4955,0x4958,0x695b,0x695f,0x6963, 0x6967,0x696b,0x696f,0x6973,0x6977,0x697b,0x697f,0x6983, 0x2987,0x2989,0x298b,0x298d,0x298f,0x2991,0x2993,0x2995, 0x2997,0x4999,0x499c,0x499f,0x49a2,0x49a5,0x49a8,0x49ab, 0x49ae,0x49b1,0x49b4,0x49b7,0x49ba,0x49bd,0x49c0,0x49c3, 0x49c6,0x49c9,0x49cc,0x49cf,0x49d2,0x49d5,0x49d8,0x49db, 0x49de,0x49e1,0x49e4,0x49e7,0x49ea,0x49ed,0x49f0,0x49f3, 0x49f6,0x49f9,0x49fc,0x49ff,0x4a02,0x4a05,0x0a08,0x0a09, 0x0a0a,0x0a0b,0x0a0c,0x0a0d,0x0a0e,0x0a0f,0x0a10,0x0a11, 0x0a12,0x0a13,0x0a14,0x0a15,0x0a16,0x0a17,0x0a18,0x0a19, 0x0a1a,0x0a1b,0x0a1c,0x0a1d,0x0a1e,0x0a1f,0x0a20,0x0a21, 0x0a22,0x0a23,0x0a24,0x0a25,0x0a26,0x0a27,0x0a28,0x0a29, 0x0a2a,0x0a2b,0x0a2c,0x0a2d,0x0a2e,0x0a2f,0x0a30,0x0a31, 0x0a32,0x0a33,0x0a34,0x0a35,0x0a36,0x0a37,0x0a38,0x0a39, 0x0a3a,0x0a3b,0x0a3c,0x0000,0x0000,0x0000,0x0000,0x0000, 0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000, 0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000, 0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000, 0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000, 0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000, 0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000, 0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000, 0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000, 0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000, 0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000, 0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000, 0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000, 0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000, 0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000, 0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000, 0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000, 0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000, 0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000, 0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000, 0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000, 0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000, 0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000, 0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000, 0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000, 0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000, 0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000, 0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000, 0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000, 0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000, 0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000, 0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000, 0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000, 0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000, 0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000, 0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000, 0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000, 0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000, 0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000, 0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000, 0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000, 0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000, 0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000, 0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000, 0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000, 0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000, 0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000, 0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000, 0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000, 0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000, 0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000, 0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000, 0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000, 0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000, 0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000, 0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000, 0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000, 0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000, 0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000, 0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000, 0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000, 0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000, 0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000, 0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000, 0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000, 0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000, 0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000, 0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000, 0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000, 0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000, 0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000, 0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000, 0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000, 0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000, 0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000, 0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000, 0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000, 0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000, 0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000, 0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000, 0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000, 0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000, 0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000, 0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000, 0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000, 0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000, 0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000, 0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000, 0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000, 0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000, 0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000, 0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000, 0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000, 0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000, 0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000, 0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000, 0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000, 0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000, 0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000, 0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000, 0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000, 0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000, 0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000, 0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000, 0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000, 0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000, 0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000, 0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000, 0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000, 0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000, 0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000, 0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000, 0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000, 0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000, 0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000, 0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000, 0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000, 0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000, 0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000, 0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000, 0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000, 0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000, 0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000, 0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000, 0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000, 0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000, 0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000, 0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000, 0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000, 0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000, 0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000, 0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000, 0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000, 0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000, 0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000, 0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000, 0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000, 0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000, 0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000, 0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000, 0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000, 0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000, 0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000, 0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000, 0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000, 0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000, 0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000, 0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000, 0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000, 0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000, 0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000, 0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000, 0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000, 0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000, 0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000, 0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000, 0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000, 0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000, 0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000, 0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000, 0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000, 0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000, 0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000, 0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000, 0x0000,0x0000,0x0000,0x0000,0x6a3d,0x0000,0x0000,0x0000, 0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000, 0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000, 0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000, 0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000, 0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000, 0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000, 0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000, 0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000, 0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000, 0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000, 0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000, 0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000, 0x0000,0x0000,0x0000,0x0000,0x4a41,0x2a44,0x4a46,0x0000, 0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000, 0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000, 0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000, 0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000, 0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000, 0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000, 0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000, 0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000, 0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000, 0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000, 0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000, 0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000, 0x0000,0x0000,0x0000,0x0000,0x2a49,0x0000,0x0000,0x0000, 0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000, 0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000, 0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000, 0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000, 0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000, 0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000, 0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000, 0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000, 0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000, 0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000, 0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000, 0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000, 0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000, 0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000, 0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000, 0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000, 0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000, 0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000, 0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000, 0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000, 0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000, 0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000, 0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000, 0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000, 0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000, 0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000, 0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000, 0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000, 0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000, 0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000, 0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000, 0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000, 0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000, 0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000, 0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000, 0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000, 0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000, 0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000, 0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000, 0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000, 0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000, 0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000, 0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000, 0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000, 0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000, 0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000, 0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000, 0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000, 0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000, 0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000, 0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000, 0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000, 0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000, 0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000, 0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000, 0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000, 0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000, 0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000, 0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000, 0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000, 0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000, 0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000, 0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000, 0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000, 0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000, 0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000, 0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000, 0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000, 0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000, 0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000, 0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000, 0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000, 0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000, 0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000, 0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000, 0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000, 0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000, 0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000, 0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000, 0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000, 0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000, 0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0a4b, 0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000, 0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000, 0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000, 0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000, 0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000, 0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000, 0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000, 0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000, 0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000, 0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000, 0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000, 0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000, 0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000, 0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000, 0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000, 0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000, 0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000, 0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000, 0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000, 0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000, 0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000, 0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000, 0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000, 0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000, 0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000, 0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000, 0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000, 0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000, 0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000, 0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000, 0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000, 0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000, 0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000, 0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000, 0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000, 0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000, 0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000, 0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0a4c, 0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000, 0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000, 0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000, 0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000, 0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000, 0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000, 0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000, 0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000, 0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000, 0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000, 0x0000,0x0000,0x0000,0x0a4d,0x0000,0x0000,0x0000,0x0000, 0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000, 0x0a4e,0x0a4f,0x0a50,0x0a51,0x0a52,0x0a53,0x0a54,0x0a55, 0x0a56,0x0a57,0x0a58,0x0a59,0x0a5a,0x0a5b,0x0a5c,0x0a5d, 0x0a5e,0x0a5f,0x0a60,0x0a61,0x0a62,0x0a63,0x0a64,0x0a65, 0x0a66,0x0a67,0x0a68,0x0a69,0x0a6a,0x0a6b,0x0a6c,0x0a6d, 0x0a6e,0x0a6f,0x0a70,0x0a71,0x0a72,0x0a73,0x0a74,0x0a75, 0x0a76,0x0a77,0x0a78,0x0a79,0x0a7a,0x0a7b,0x0a7c,0x0a7d, 0x0a7e,0x0a7f,0x0a80,0x0a81,0x0a82,0x0a83,0x0a84,0x0a85, 0x0a86,0x0a87,0x0a88,0x0a89,0x0a8a,0x0a8b,0x0a8c,0x0a8d, 0x0a8e,0x0a8f,0x0a90,0x0a91,0x0a92,0x0a93,0x0a94,0x0a95, 0x0a96,0x0a97,0x0a98,0x0a99,0x0a9a,0x0a9b,0x0a9c,0x0a9d, 0x0a9e,0x0a9f,0x0aa0,0x0aa1,0x0aa2,0x0aa3,0x0aa4,0x0aa5, 0x0aa6,0x0aa7,0x0aa8,0x0aa9,0x0aaa,0x0aab,0x0aac,0x0aad, 0x0aae,0x0aaf,0x0ab0,0x0ab1,0x0ab2,0x0ab3,0x0ab4,0x0ab5, 0x0ab6,0x0ab7,0x0ab8,0x0ab9,0x0aba,0x0abb,0x0abc,0x0abd, 0x0abe,0x0abf,0x0ac0,0x0ac1,0x0ac2,0x0ac3,0x0ac4,0x0ac5, 0x0ac6,0x0ac7,0x0ac8,0x0ac9,0x0aca,0x0acb,0x0acc,0x0acd, 0x0ace,0x0acf,0x0ad0,0x0ad1,0x0ad2,0x0ad3,0x0ad4,0x0ad5, 0x0ad6,0x0ad7,0x0ad8,0x0ad9,0x0ada,0x0adb,0x0adc,0x0add, 0x0ade,0x0adf,0x0ae0,0x0ae1,0x0ae2,0x0ae3,0x0ae4,0x0ae5, 0x0ae6,0x0ae7,0x0ae8,0x0ae9,0x0aea,0x0aeb,0x0aec,0x0aed, 0x0aee,0x0aef,0x0af0,0x0af1,0x0af2,0x0af3,0x0af4,0x0af5, 0x0af6,0x0af7,0x0af8,0x0af9,0x0afa,0x0afb,0x0afc,0x0afd, 0x0afe,0x0aff,0x0b00,0x0b01,0x0b02,0x0b03,0x0b04,0x0b05, 0x0b06,0x0b07,0x0b08,0x0b09,0x0b0a,0x0b0b,0x0b0c,0x0b0d, 0x0b0e,0x0b0f,0x0b10,0x0b11,0x0b12,0x0b13,0x0b14,0x0b15, 0x0b16,0x0b17,0x0b18,0x0b19,0x0b1a,0x0b1b,0x0b1c,0x0b1d, 0x0b1e,0x0b1f,0x0b20,0x0b21,0x0b22,0x0b23,0x0000,0x0000, 0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000, 0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000, 0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000, 0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000, 0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000, 0x0b24,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000, 0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000, 0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000, 0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000, 0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000, 0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000, 0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0b25,0x0000, 0x0b26,0x0b27,0x0b28,0x0000,0x0000,0x0000,0x0000,0x0000, 0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000, 0x0000,0x0000,0x0000,0x0000,0x2b29,0x0000,0x2b2b,0x0000, 0x2b2d,0x0000,0x2b2f,0x0000,0x2b31,0x0000,0x2b33,0x0000, 0x2b35,0x0000,0x2b37,0x0000,0x2b39,0x0000,0x2b3b,0x0000, 0x2b3d,0x0000,0x2b3f,0x0000,0x0000,0x2b41,0x0000,0x2b43, 0x0000,0x2b45,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000, 0x2b47,0x2b49,0x0000,0x2b4b,0x2b4d,0x0000,0x2b4f,0x2b51, 0x0000,0x2b53,0x2b55,0x0000,0x2b57,0x2b59,0x0000,0x0000, 0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000, 0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000, 0x0000,0x0000,0x0000,0x0000,0x2b5b,0x0000,0x0000,0x0000, 0x0000,0x0000,0x0000,0x2b5d,0x2b5f,0x0000,0x2b61,0x2b63, 0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000, 0x0000,0x0000,0x0000,0x0000,0x2b65,0x0000,0x2b67,0x0000, 0x2b69,0x0000,0x2b6b,0x0000,0x2b6d,0x0000,0x2b6f,0x0000, 0x2b71,0x0000,0x2b73,0x0000,0x2b75,0x0000,0x2b77,0x0000, 0x2b79,0x0000,0x2b7b,0x0000,0x0000,0x2b7d,0x0000,0x2b7f, 0x0000,0x2b81,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000, 0x2b83,0x2b85,0x0000,0x2b87,0x2b89,0x0000,0x2b8b,0x2b8d, 0x0000,0x2b8f,0x2b91,0x0000,0x2b93,0x2b95,0x0000,0x0000, 0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000, 0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000, 0x0000,0x0000,0x0000,0x0000,0x2b97,0x0000,0x0000,0x2b99, 0x2b9b,0x2b9d,0x2b9f,0x0000,0x0000,0x0000,0x2ba1,0x2ba3, 0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000, 0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000, 0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000, 0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000, 0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000, 0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000, 0x0000,0x0ba5,0x0ba6,0x0ba7,0x0ba8,0x0ba9,0x0baa,0x0bab, 0x0bac,0x0bad,0x0bae,0x0baf,0x0bb0,0x0bb1,0x0bb2,0x0bb3, 0x0bb4,0x0bb5,0x0bb6,0x0bb7,0x0bb8,0x0bb9,0x0bba,0x0bbb, 0x0bbc,0x0bbd,0x0bbe,0x0bbf,0x0bc0,0x0bc1,0x0bc2,0x0bc3, 0x0bc4,0x0bc5,0x0bc6,0x0bc7,0x0bc8,0x0bc9,0x0bca,0x0bcb, 0x0bcc,0x0bcd,0x0bce,0x0bcf,0x0bd0,0x0bd1,0x0bd2,0x0bd3, 0x0bd4,0x0bd5,0x0bd6,0x0bd7,0x0bd8,0x0bd9,0x0bda,0x0bdb, 0x0bdc,0x0bdd,0x0bde,0x0bdf,0x0be0,0x0be1,0x0be2,0x0be3, 0x0be4,0x0be5,0x0be6,0x0be7,0x0be8,0x0be9,0x0bea,0x0beb, 0x0bec,0x0bed,0x0bee,0x0bef,0x0bf0,0x0bf1,0x0bf2,0x0bf3, 0x0bf4,0x0bf5,0x0bf6,0x0bf7,0x0bf8,0x0bf9,0x0bfa,0x0bfb, 0x0bfc,0x0bfd,0x0bfe,0x0bff,0x0c00,0x0c01,0x0c02,0x0000, 0x0000,0x0000,0x0c03,0x0c04,0x0c05,0x0c06,0x0c07,0x0c08, 0x0c09,0x0c0a,0x0c0b,0x0c0c,0x0c0d,0x0c0e,0x0c0f,0x0c10, 0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000, 0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000, 0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000, 0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000, 0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000, 0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000, 0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000, 0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000, 0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000, 0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000, 0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000, 0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000, 0x4c11,0x4c14,0x4c17,0x4c1a,0x4c1d,0x4c20,0x4c23,0x4c26, 0x4c29,0x4c2c,0x4c2f,0x4c32,0x4c35,0x4c38,0x6c3b,0x6c3f, 0x6c43,0x6c47,0x6c4b,0x6c4f,0x6c53,0x6c57,0x6c5b,0x6c5f, 0x6c63,0x6c67,0x6c6b,0x6c6f,0x6c73,0xcc77,0xac7e,0x0000, 0x4c84,0x4c87,0x4c8a,0x4c8d,0x4c90,0x4c93,0x4c96,0x4c99, 0x4c9c,0x4c9f,0x4ca2,0x4ca5,0x4ca8,0x4cab,0x4cae,0x4cb1, 0x4cb4,0x4cb7,0x4cba,0x4cbd,0x4cc0,0x4cc3,0x4cc6,0x4cc9, 0x4ccc,0x4ccf,0x4cd2,0x4cd5,0x4cd8,0x4cdb,0x4cde,0x4ce1, 0x4ce4,0x4ce7,0x4cea,0x4ced,0x0000,0x0000,0x0000,0x0000, 0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000, 0x4cf0,0x2cf3,0x2cf5,0x2cf7,0x2cf9,0x2cfb,0x2cfd,0x2cff, 0x2d01,0x2d03,0x2d05,0x2d07,0x2d09,0x2d0b,0x2d0d,0x2d0f, 0x0d11,0x0d12,0x0d13,0x0d14,0x0d15,0x0d16,0x0d17,0x0d18, 0x0d19,0x0d1a,0x0d1b,0x0d1c,0x0d1d,0x0d1e,0x2d1f,0x2d21, 0x2d23,0x2d25,0x2d27,0x2d29,0x2d2b,0x2d2d,0x2d2f,0x2d31, 0x2d33,0x2d35,0x2d37,0x2d39,0x8d3b,0x6d40,0x2d44,0x0000, 0x0d46,0x0d47,0x0d48,0x0d49,0x0d4a,0x0d4b,0x0d4c,0x0d4d, 0x0d4e,0x0d4f,0x0d50,0x0d51,0x0d52,0x0d53,0x0d54,0x0d55, 0x0d56,0x0d57,0x0d58,0x0d59,0x0d5a,0x0d5b,0x0d5c,0x0d5d, 0x0d5e,0x0d5f,0x0d60,0x0d61,0x0d62,0x0d63,0x0d64,0x0d65, 0x0d66,0x0d67,0x0d68,0x0d69,0x0d6a,0x0d6b,0x0d6c,0x0d6d, 0x0d6e,0x0d6f,0x0d70,0x0d71,0x0d72,0x0d73,0x0d74,0x0d75, 0x0d76,0x2d77,0x2d79,0x2d7b,0x2d7d,0x2d7f,0x2d81,0x2d83, 0x2d85,0x2d87,0x2d89,0x2d8b,0x2d8d,0x2d8f,0x2d91,0x2d93, 0x2d95,0x2d97,0x2d99,0x2d9b,0x2d9d,0x2d9f,0x2da1,0x2da3, 0x2da5,0x4da7,0x4daa,0x4dad,0x2db0,0x4db2,0x2db5,0x4db7, 0x0dba,0x0dbb,0x0dbc,0x0dbd,0x0dbe,0x0dbf,0x0dc0,0x0dc1, 0x0dc2,0x0dc3,0x0dc4,0x0dc5,0x0dc6,0x0dc7,0x0dc8,0x0dc9, 0x0dca,0x0dcb,0x0dcc,0x0dcd,0x0dce,0x0dcf,0x0dd0,0x0dd1, 0x0dd2,0x0dd3,0x0dd4,0x0dd5,0x0dd6,0x0dd7,0x0dd8,0x0dd9, 0x0dda,0x0ddb,0x0ddc,0x0ddd,0x0dde,0x0ddf,0x0de0,0x0de1, 0x0de2,0x0de3,0x0de4,0x0de5,0x0de6,0x0de7,0x0de8,0x0000, 0x6de9,0x6ded,0x6df1,0x4df5,0x6df8,0x4dfc,0x4dff,0x8e02, 0x6e07,0x4e0b,0x4e0e,0x4e11,0x6e14,0x6e18,0x4e1c,0x4e1f, 0x2e22,0x4e24,0x6e27,0x6e2b,0x2e2f,0x8e31,0xae36,0x8e3c, 0x4e41,0x8e44,0x8e49,0x6e4e,0x4e52,0x4e55,0x4e58,0x6e5b, 0x8e5f,0x6e64,0x4e68,0x4e6b,0x4e6e,0x2e71,0x2e73,0x2e75, 0x2e77,0x4e79,0x4e7c,0x8e7f,0x4e84,0x6e87,0x8e8b,0x4e90, 0x2e93,0x2e95,0x8e97,0x6e9c,0x8ea0,0x4ea5,0x8ea8,0x2ead, 0x4eaf,0x4eb2,0x4eb5,0x4eb8,0x4ebb,0x6ebe,0x4ec2,0x2ec5, 0x4ec7,0x4eca,0x4ecd,0x6ed0,0x4ed4,0x4ed7,0x4eda,0x8edd, 0x6ee2,0x2ee6,0x8ee8,0x2eed,0x6eef,0x6ef3,0x4ef7,0x4efa, 0x4efd,0x6f00,0x2f04,0x4f06,0x6f09,0x2f0d,0x8f0f,0x4f14, 0x2f17,0x2f19,0x2f1b,0x2f1d,0x2f1f,0x2f21,0x2f23,0x2f25, 0x2f27,0x2f29,0x4f2b,0x4f2e,0x4f31,0x4f34,0x4f37,0x4f3a, 0x4f3d,0x4f40,0x4f43,0x4f46,0x4f49,0x4f4c,0x4f4f,0x4f52, 0x4f55,0x4f58,0x2f5b,0x2f5d,0x4f5f,0x2f62,0x2f64,0x2f66, 0x4f68,0x4f6b,0x2f6e,0x2f70,0x2f72,0x2f74,0x2f76,0x6f78, 0x2f7c,0x2f7e,0x2f80,0x2f82,0x2f84,0x2f86,0x2f88,0x2f8a, 0x4f8c,0x6f8f,0x2f93,0x2f95,0x2f97,0x2f99,0x2f9b,0x2f9d, 0x2f9f,0x4fa1,0x4fa4,0x4fa7,0x4faa,0x2fad,0x2faf,0x2fb1, 0x2fb3,0x2fb5,0x2fb7,0x2fb9,0x2fbb,0x2fbd,0x2fbf,0x4fc1, 0x4fc4,0x2fc7,0x4fc9,0x4fcc,0x4fcf,0x2fd2,0x4fd4,0x4fd7, 0x6fda,0x2fde,0x4fe0,0x4fe3,0x4fe6,0x4fe9,0x8fec,0xaff1, 0x2ff7,0x2ff9,0x2ffb,0x2ffd,0x2fff,0x3001,0x3003,0x3005, 0x3007,0x3009,0x300b,0x300d,0x300f,0x3011,0x3013,0x3015, 0x3017,0x3019,0x701b,0x301f,0x3021,0x3023,0x7025,0x5029, 0x302c,0x302e,0x3030,0x3032,0x3034,0x3036,0x3038,0x303a, 0x303c,0x303e,0x5040,0x3043,0x3045,0x5047,0x504a,0x304d, 0x704f,0x5053,0x3056,0x3058,0x305a,0x305c,0x505e,0x5061, 0x3064,0x3066,0x3068,0x306a,0x306c,0x306e,0x3070,0x3072, 0x3074,0x5076,0x5079,0x507c,0x507f,0x5082,0x5085,0x5088, 0x508b,0x508e,0x5091,0x5094,0x5097,0x509a,0x509d,0x50a0, 0x50a3,0x50a6,0x50a9,0x50ac,0x50af,0x50b2,0x50b5,0x50b8, }; /* BMP low decompositions */ static unsigned short ucs4_dbmplotab[4283] = { 0x0020,0x0020,0x0308,0x0061,0x0020,0x0304,0x0032,0x0033, 0x0020,0x0301,0x03bc,0x0020,0x0327,0x0031,0x006f,0x0031, 0x2044,0x0034,0x0031,0x2044,0x0032,0x0033,0x2044,0x0034, 0x0041,0x0300,0x0041,0x0301,0x0041,0x0302,0x0041,0x0303, 0x0041,0x0308,0x0041,0x030a,0x0043,0x0327,0x0045,0x0300, 0x0045,0x0301,0x0045,0x0302,0x0045,0x0308,0x0049,0x0300, 0x0049,0x0301,0x0049,0x0302,0x0049,0x0308,0x004e,0x0303, 0x004f,0x0300,0x004f,0x0301,0x004f,0x0302,0x004f,0x0303, 0x004f,0x0308,0x0055,0x0300,0x0055,0x0301,0x0055,0x0302, 0x0055,0x0308,0x0059,0x0301,0x0061,0x0300,0x0061,0x0301, 0x0061,0x0302,0x0061,0x0303,0x0061,0x0308,0x0061,0x030a, 0x0063,0x0327,0x0065,0x0300,0x0065,0x0301,0x0065,0x0302, 0x0065,0x0308,0x0069,0x0300,0x0069,0x0301,0x0069,0x0302, 0x0069,0x0308,0x006e,0x0303,0x006f,0x0300,0x006f,0x0301, 0x006f,0x0302,0x006f,0x0303,0x006f,0x0308,0x0075,0x0300, 0x0075,0x0301,0x0075,0x0302,0x0075,0x0308,0x0079,0x0301, 0x0079,0x0308,0x0041,0x0304,0x0061,0x0304,0x0041,0x0306, 0x0061,0x0306,0x0041,0x0328,0x0061,0x0328,0x0043,0x0301, 0x0063,0x0301,0x0043,0x0302,0x0063,0x0302,0x0043,0x0307, 0x0063,0x0307,0x0043,0x030c,0x0063,0x030c,0x0044,0x030c, 0x0064,0x030c,0x0045,0x0304,0x0065,0x0304,0x0045,0x0306, 0x0065,0x0306,0x0045,0x0307,0x0065,0x0307,0x0045,0x0328, 0x0065,0x0328,0x0045,0x030c,0x0065,0x030c,0x0047,0x0302, 0x0067,0x0302,0x0047,0x0306,0x0067,0x0306,0x0047,0x0307, 0x0067,0x0307,0x0047,0x0327,0x0067,0x0327,0x0048,0x0302, 0x0068,0x0302,0x0049,0x0303,0x0069,0x0303,0x0049,0x0304, 0x0069,0x0304,0x0049,0x0306,0x0069,0x0306,0x0049,0x0328, 0x0069,0x0328,0x0049,0x0307,0x0049,0x004a,0x0069,0x006a, 0x004a,0x0302,0x006a,0x0302,0x004b,0x0327,0x006b,0x0327, 0x004c,0x0301,0x006c,0x0301,0x004c,0x0327,0x006c,0x0327, 0x004c,0x030c,0x006c,0x030c,0x004c,0x00b7,0x006c,0x00b7, 0x004e,0x0301,0x006e,0x0301,0x004e,0x0327,0x006e,0x0327, 0x004e,0x030c,0x006e,0x030c,0x02bc,0x006e,0x004f,0x0304, 0x006f,0x0304,0x004f,0x0306,0x006f,0x0306,0x004f,0x030b, 0x006f,0x030b,0x0052,0x0301,0x0072,0x0301,0x0052,0x0327, 0x0072,0x0327,0x0052,0x030c,0x0072,0x030c,0x0053,0x0301, 0x0073,0x0301,0x0053,0x0302,0x0073,0x0302,0x0053,0x0327, 0x0073,0x0327,0x0053,0x030c,0x0073,0x030c,0x0054,0x0327, 0x0074,0x0327,0x0054,0x030c,0x0074,0x030c,0x0055,0x0303, 0x0075,0x0303,0x0055,0x0304,0x0075,0x0304,0x0055,0x0306, 0x0075,0x0306,0x0055,0x030a,0x0075,0x030a,0x0055,0x030b, 0x0075,0x030b,0x0055,0x0328,0x0075,0x0328,0x0057,0x0302, 0x0077,0x0302,0x0059,0x0302,0x0079,0x0302,0x0059,0x0308, 0x005a,0x0301,0x007a,0x0301,0x005a,0x0307,0x007a,0x0307, 0x005a,0x030c,0x007a,0x030c,0x0073,0x004f,0x031b,0x006f, 0x031b,0x0055,0x031b,0x0075,0x031b,0x0044,0x017d,0x0044, 0x017e,0x0064,0x017e,0x004c,0x004a,0x004c,0x006a,0x006c, 0x006a,0x004e,0x004a,0x004e,0x006a,0x006e,0x006a,0x0041, 0x030c,0x0061,0x030c,0x0049,0x030c,0x0069,0x030c,0x004f, 0x030c,0x006f,0x030c,0x0055,0x030c,0x0075,0x030c,0x00dc, 0x0304,0x00fc,0x0304,0x00dc,0x0301,0x00fc,0x0301,0x00dc, 0x030c,0x00fc,0x030c,0x00dc,0x0300,0x00fc,0x0300,0x00c4, 0x0304,0x00e4,0x0304,0x0226,0x0304,0x0227,0x0304,0x00c6, 0x0304,0x00e6,0x0304,0x0047,0x030c,0x0067,0x030c,0x004b, 0x030c,0x006b,0x030c,0x004f,0x0328,0x006f,0x0328,0x01ea, 0x0304,0x01eb,0x0304,0x01b7,0x030c,0x0292,0x030c,0x006a, 0x030c,0x0044,0x005a,0x0044,0x007a,0x0064,0x007a,0x0047, 0x0301,0x0067,0x0301,0x004e,0x0300,0x006e,0x0300,0x00c5, 0x0301,0x00e5,0x0301,0x00c6,0x0301,0x00e6,0x0301,0x00d8, 0x0301,0x00f8,0x0301,0x0041,0x030f,0x0061,0x030f,0x0041, 0x0311,0x0061,0x0311,0x0045,0x030f,0x0065,0x030f,0x0045, 0x0311,0x0065,0x0311,0x0049,0x030f,0x0069,0x030f,0x0049, 0x0311,0x0069,0x0311,0x004f,0x030f,0x006f,0x030f,0x004f, 0x0311,0x006f,0x0311,0x0052,0x030f,0x0072,0x030f,0x0052, 0x0311,0x0072,0x0311,0x0055,0x030f,0x0075,0x030f,0x0055, 0x0311,0x0075,0x0311,0x0053,0x0326,0x0073,0x0326,0x0054, 0x0326,0x0074,0x0326,0x0048,0x030c,0x0068,0x030c,0x0041, 0x0307,0x0061,0x0307,0x0045,0x0327,0x0065,0x0327,0x00d6, 0x0304,0x00f6,0x0304,0x00d5,0x0304,0x00f5,0x0304,0x004f, 0x0307,0x006f,0x0307,0x022e,0x0304,0x022f,0x0304,0x0059, 0x0304,0x0079,0x0304,0x0068,0x0266,0x006a,0x0072,0x0279, 0x027b,0x0281,0x0077,0x0079,0x0020,0x0306,0x0020,0x0307, 0x0020,0x030a,0x0020,0x0328,0x0020,0x0303,0x0020,0x030b, 0x0263,0x006c,0x0073,0x0078,0x0295,0x0300,0x0301,0x0313, 0x0308,0x0301,0x02b9,0x0020,0x0345,0x003b,0x0020,0x0301, 0x00a8,0x0301,0x0391,0x0301,0x00b7,0x0395,0x0301,0x0397, 0x0301,0x0399,0x0301,0x039f,0x0301,0x03a5,0x0301,0x03a9, 0x0301,0x03ca,0x0301,0x0399,0x0308,0x03a5,0x0308,0x03b1, 0x0301,0x03b5,0x0301,0x03b7,0x0301,0x03b9,0x0301,0x03cb, 0x0301,0x03b9,0x0308,0x03c5,0x0308,0x03bf,0x0301,0x03c5, 0x0301,0x03c9,0x0301,0x03b2,0x03b8,0x03a5,0x03d2,0x0301, 0x03d2,0x0308,0x03c6,0x03c0,0x03ba,0x03c1,0x03c2,0x0398, 0x03b5,0x03a3,0x0415,0x0300,0x0415,0x0308,0x0413,0x0301, 0x0406,0x0308,0x041a,0x0301,0x0418,0x0300,0x0423,0x0306, 0x0418,0x0306,0x0438,0x0306,0x0435,0x0300,0x0435,0x0308, 0x0433,0x0301,0x0456,0x0308,0x043a,0x0301,0x0438,0x0300, 0x0443,0x0306,0x0474,0x030f,0x0475,0x030f,0x0416,0x0306, 0x0436,0x0306,0x0410,0x0306,0x0430,0x0306,0x0410,0x0308, 0x0430,0x0308,0x0415,0x0306,0x0435,0x0306,0x04d8,0x0308, 0x04d9,0x0308,0x0416,0x0308,0x0436,0x0308,0x0417,0x0308, 0x0437,0x0308,0x0418,0x0304,0x0438,0x0304,0x0418,0x0308, 0x0438,0x0308,0x041e,0x0308,0x043e,0x0308,0x04e8,0x0308, 0x04e9,0x0308,0x042d,0x0308,0x044d,0x0308,0x0423,0x0304, 0x0443,0x0304,0x0423,0x0308,0x0443,0x0308,0x0423,0x030b, 0x0443,0x030b,0x0427,0x0308,0x0447,0x0308,0x042b,0x0308, 0x044b,0x0308,0x0565,0x0582,0x0627,0x0653,0x0627,0x0654, 0x0648,0x0654,0x0627,0x0655,0x064a,0x0654,0x0627,0x0674, 0x0648,0x0674,0x06c7,0x0674,0x064a,0x0674,0x06d5,0x0654, 0x06c1,0x0654,0x06d2,0x0654,0x0928,0x093c,0x0930,0x093c, 0x0933,0x093c,0x0915,0x093c,0x0916,0x093c,0x0917,0x093c, 0x091c,0x093c,0x0921,0x093c,0x0922,0x093c,0x092b,0x093c, 0x092f,0x093c,0x09c7,0x09be,0x09c7,0x09d7,0x09a1,0x09bc, 0x09a2,0x09bc,0x09af,0x09bc,0x0a32,0x0a3c,0x0a38,0x0a3c, 0x0a16,0x0a3c,0x0a17,0x0a3c,0x0a1c,0x0a3c,0x0a2b,0x0a3c, 0x0b47,0x0b56,0x0b47,0x0b3e,0x0b47,0x0b57,0x0b21,0x0b3c, 0x0b22,0x0b3c,0x0b92,0x0bd7,0x0bc6,0x0bbe,0x0bc7,0x0bbe, 0x0bc6,0x0bd7,0x0c46,0x0c56,0x0cbf,0x0cd5,0x0cc6,0x0cd5, 0x0cc6,0x0cd6,0x0cc6,0x0cc2,0x0cca,0x0cd5,0x0d46,0x0d3e, 0x0d47,0x0d3e,0x0d46,0x0d57,0x0dd9,0x0dca,0x0dd9,0x0dcf, 0x0ddc,0x0dca,0x0dd9,0x0ddf,0x0e4d,0x0e32,0x0ecd,0x0eb2, 0x0eab,0x0e99,0x0eab,0x0ea1,0x0f0b,0x0f42,0x0fb7,0x0f4c, 0x0fb7,0x0f51,0x0fb7,0x0f56,0x0fb7,0x0f5b,0x0fb7,0x0f40, 0x0fb5,0x0f71,0x0f72,0x0f71,0x0f74,0x0fb2,0x0f80,0x0fb2, 0x0f81,0x0fb3,0x0f80,0x0fb3,0x0f81,0x0f71,0x0f80,0x0f92, 0x0fb7,0x0f9c,0x0fb7,0x0fa1,0x0fb7,0x0fa6,0x0fb7,0x0fab, 0x0fb7,0x0f90,0x0fb5,0x1025,0x102e,0x10dc,0x1b05,0x1b35, 0x1b07,0x1b35,0x1b09,0x1b35,0x1b0b,0x1b35,0x1b0d,0x1b35, 0x1b11,0x1b35,0x1b3a,0x1b35,0x1b3c,0x1b35,0x1b3e,0x1b35, 0x1b3f,0x1b35,0x1b42,0x1b35,0x0041,0x00c6,0x0042,0x0044, 0x0045,0x018e,0x0047,0x0048,0x0049,0x004a,0x004b,0x004c, 0x004d,0x004e,0x004f,0x0222,0x0050,0x0052,0x0054,0x0055, 0x0057,0x0061,0x0250,0x0251,0x1d02,0x0062,0x0064,0x0065, 0x0259,0x025b,0x025c,0x0067,0x006b,0x006d,0x014b,0x006f, 0x0254,0x1d16,0x1d17,0x0070,0x0074,0x0075,0x1d1d,0x026f, 0x0076,0x1d25,0x03b2,0x03b3,0x03b4,0x03c6,0x03c7,0x0069, 0x0072,0x0075,0x0076,0x03b2,0x03b3,0x03c1,0x03c6,0x03c7, 0x043d,0x0252,0x0063,0x0255,0x00f0,0x025c,0x0066,0x025f, 0x0261,0x0265,0x0268,0x0269,0x026a,0x1d7b,0x029d,0x026d, 0x1d85,0x029f,0x0271,0x0270,0x0272,0x0273,0x0274,0x0275, 0x0278,0x0282,0x0283,0x01ab,0x0289,0x028a,0x1d1c,0x028b, 0x028c,0x007a,0x0290,0x0291,0x0292,0x03b8,0x0041,0x0325, 0x0061,0x0325,0x0042,0x0307,0x0062,0x0307,0x0042,0x0323, 0x0062,0x0323,0x0042,0x0331,0x0062,0x0331,0x00c7,0x0301, 0x00e7,0x0301,0x0044,0x0307,0x0064,0x0307,0x0044,0x0323, 0x0064,0x0323,0x0044,0x0331,0x0064,0x0331,0x0044,0x0327, 0x0064,0x0327,0x0044,0x032d,0x0064,0x032d,0x0112,0x0300, 0x0113,0x0300,0x0112,0x0301,0x0113,0x0301,0x0045,0x032d, 0x0065,0x032d,0x0045,0x0330,0x0065,0x0330,0x0228,0x0306, 0x0229,0x0306,0x0046,0x0307,0x0066,0x0307,0x0047,0x0304, 0x0067,0x0304,0x0048,0x0307,0x0068,0x0307,0x0048,0x0323, 0x0068,0x0323,0x0048,0x0308,0x0068,0x0308,0x0048,0x0327, 0x0068,0x0327,0x0048,0x032e,0x0068,0x032e,0x0049,0x0330, 0x0069,0x0330,0x00cf,0x0301,0x00ef,0x0301,0x004b,0x0301, 0x006b,0x0301,0x004b,0x0323,0x006b,0x0323,0x004b,0x0331, 0x006b,0x0331,0x004c,0x0323,0x006c,0x0323,0x1e36,0x0304, 0x1e37,0x0304,0x004c,0x0331,0x006c,0x0331,0x004c,0x032d, 0x006c,0x032d,0x004d,0x0301,0x006d,0x0301,0x004d,0x0307, 0x006d,0x0307,0x004d,0x0323,0x006d,0x0323,0x004e,0x0307, 0x006e,0x0307,0x004e,0x0323,0x006e,0x0323,0x004e,0x0331, 0x006e,0x0331,0x004e,0x032d,0x006e,0x032d,0x00d5,0x0301, 0x00f5,0x0301,0x00d5,0x0308,0x00f5,0x0308,0x014c,0x0300, 0x014d,0x0300,0x014c,0x0301,0x014d,0x0301,0x0050,0x0301, 0x0070,0x0301,0x0050,0x0307,0x0070,0x0307,0x0052,0x0307, 0x0072,0x0307,0x0052,0x0323,0x0072,0x0323,0x1e5a,0x0304, 0x1e5b,0x0304,0x0052,0x0331,0x0072,0x0331,0x0053,0x0307, 0x0073,0x0307,0x0053,0x0323,0x0073,0x0323,0x015a,0x0307, 0x015b,0x0307,0x0160,0x0307,0x0161,0x0307,0x1e62,0x0307, 0x1e63,0x0307,0x0054,0x0307,0x0074,0x0307,0x0054,0x0323, 0x0074,0x0323,0x0054,0x0331,0x0074,0x0331,0x0054,0x032d, 0x0074,0x032d,0x0055,0x0324,0x0075,0x0324,0x0055,0x0330, 0x0075,0x0330,0x0055,0x032d,0x0075,0x032d,0x0168,0x0301, 0x0169,0x0301,0x016a,0x0308,0x016b,0x0308,0x0056,0x0303, 0x0076,0x0303,0x0056,0x0323,0x0076,0x0323,0x0057,0x0300, 0x0077,0x0300,0x0057,0x0301,0x0077,0x0301,0x0057,0x0308, 0x0077,0x0308,0x0057,0x0307,0x0077,0x0307,0x0057,0x0323, 0x0077,0x0323,0x0058,0x0307,0x0078,0x0307,0x0058,0x0308, 0x0078,0x0308,0x0059,0x0307,0x0079,0x0307,0x005a,0x0302, 0x007a,0x0302,0x005a,0x0323,0x007a,0x0323,0x005a,0x0331, 0x007a,0x0331,0x0068,0x0331,0x0074,0x0308,0x0077,0x030a, 0x0079,0x030a,0x0061,0x02be,0x017f,0x0307,0x0041,0x0323, 0x0061,0x0323,0x0041,0x0309,0x0061,0x0309,0x00c2,0x0301, 0x00e2,0x0301,0x00c2,0x0300,0x00e2,0x0300,0x00c2,0x0309, 0x00e2,0x0309,0x00c2,0x0303,0x00e2,0x0303,0x1ea0,0x0302, 0x1ea1,0x0302,0x0102,0x0301,0x0103,0x0301,0x0102,0x0300, 0x0103,0x0300,0x0102,0x0309,0x0103,0x0309,0x0102,0x0303, 0x0103,0x0303,0x1ea0,0x0306,0x1ea1,0x0306,0x0045,0x0323, 0x0065,0x0323,0x0045,0x0309,0x0065,0x0309,0x0045,0x0303, 0x0065,0x0303,0x00ca,0x0301,0x00ea,0x0301,0x00ca,0x0300, 0x00ea,0x0300,0x00ca,0x0309,0x00ea,0x0309,0x00ca,0x0303, 0x00ea,0x0303,0x1eb8,0x0302,0x1eb9,0x0302,0x0049,0x0309, 0x0069,0x0309,0x0049,0x0323,0x0069,0x0323,0x004f,0x0323, 0x006f,0x0323,0x004f,0x0309,0x006f,0x0309,0x00d4,0x0301, 0x00f4,0x0301,0x00d4,0x0300,0x00f4,0x0300,0x00d4,0x0309, 0x00f4,0x0309,0x00d4,0x0303,0x00f4,0x0303,0x1ecc,0x0302, 0x1ecd,0x0302,0x01a0,0x0301,0x01a1,0x0301,0x01a0,0x0300, 0x01a1,0x0300,0x01a0,0x0309,0x01a1,0x0309,0x01a0,0x0303, 0x01a1,0x0303,0x01a0,0x0323,0x01a1,0x0323,0x0055,0x0323, 0x0075,0x0323,0x0055,0x0309,0x0075,0x0309,0x01af,0x0301, 0x01b0,0x0301,0x01af,0x0300,0x01b0,0x0300,0x01af,0x0309, 0x01b0,0x0309,0x01af,0x0303,0x01b0,0x0303,0x01af,0x0323, 0x01b0,0x0323,0x0059,0x0300,0x0079,0x0300,0x0059,0x0323, 0x0079,0x0323,0x0059,0x0309,0x0079,0x0309,0x0059,0x0303, 0x0079,0x0303,0x03b1,0x0313,0x03b1,0x0314,0x1f00,0x0300, 0x1f01,0x0300,0x1f00,0x0301,0x1f01,0x0301,0x1f00,0x0342, 0x1f01,0x0342,0x0391,0x0313,0x0391,0x0314,0x1f08,0x0300, 0x1f09,0x0300,0x1f08,0x0301,0x1f09,0x0301,0x1f08,0x0342, 0x1f09,0x0342,0x03b5,0x0313,0x03b5,0x0314,0x1f10,0x0300, 0x1f11,0x0300,0x1f10,0x0301,0x1f11,0x0301,0x0395,0x0313, 0x0395,0x0314,0x1f18,0x0300,0x1f19,0x0300,0x1f18,0x0301, 0x1f19,0x0301,0x03b7,0x0313,0x03b7,0x0314,0x1f20,0x0300, 0x1f21,0x0300,0x1f20,0x0301,0x1f21,0x0301,0x1f20,0x0342, 0x1f21,0x0342,0x0397,0x0313,0x0397,0x0314,0x1f28,0x0300, 0x1f29,0x0300,0x1f28,0x0301,0x1f29,0x0301,0x1f28,0x0342, 0x1f29,0x0342,0x03b9,0x0313,0x03b9,0x0314,0x1f30,0x0300, 0x1f31,0x0300,0x1f30,0x0301,0x1f31,0x0301,0x1f30,0x0342, 0x1f31,0x0342,0x0399,0x0313,0x0399,0x0314,0x1f38,0x0300, 0x1f39,0x0300,0x1f38,0x0301,0x1f39,0x0301,0x1f38,0x0342, 0x1f39,0x0342,0x03bf,0x0313,0x03bf,0x0314,0x1f40,0x0300, 0x1f41,0x0300,0x1f40,0x0301,0x1f41,0x0301,0x039f,0x0313, 0x039f,0x0314,0x1f48,0x0300,0x1f49,0x0300,0x1f48,0x0301, 0x1f49,0x0301,0x03c5,0x0313,0x03c5,0x0314,0x1f50,0x0300, 0x1f51,0x0300,0x1f50,0x0301,0x1f51,0x0301,0x1f50,0x0342, 0x1f51,0x0342,0x03a5,0x0314,0x1f59,0x0300,0x1f59,0x0301, 0x1f59,0x0342,0x03c9,0x0313,0x03c9,0x0314,0x1f60,0x0300, 0x1f61,0x0300,0x1f60,0x0301,0x1f61,0x0301,0x1f60,0x0342, 0x1f61,0x0342,0x03a9,0x0313,0x03a9,0x0314,0x1f68,0x0300, 0x1f69,0x0300,0x1f68,0x0301,0x1f69,0x0301,0x1f68,0x0342, 0x1f69,0x0342,0x03b1,0x0300,0x03ac,0x03b5,0x0300,0x03ad, 0x03b7,0x0300,0x03ae,0x03b9,0x0300,0x03af,0x03bf,0x0300, 0x03cc,0x03c5,0x0300,0x03cd,0x03c9,0x0300,0x03ce,0x1f00, 0x0345,0x1f01,0x0345,0x1f02,0x0345,0x1f03,0x0345,0x1f04, 0x0345,0x1f05,0x0345,0x1f06,0x0345,0x1f07,0x0345,0x1f08, 0x0345,0x1f09,0x0345,0x1f0a,0x0345,0x1f0b,0x0345,0x1f0c, 0x0345,0x1f0d,0x0345,0x1f0e,0x0345,0x1f0f,0x0345,0x1f20, 0x0345,0x1f21,0x0345,0x1f22,0x0345,0x1f23,0x0345,0x1f24, 0x0345,0x1f25,0x0345,0x1f26,0x0345,0x1f27,0x0345,0x1f28, 0x0345,0x1f29,0x0345,0x1f2a,0x0345,0x1f2b,0x0345,0x1f2c, 0x0345,0x1f2d,0x0345,0x1f2e,0x0345,0x1f2f,0x0345,0x1f60, 0x0345,0x1f61,0x0345,0x1f62,0x0345,0x1f63,0x0345,0x1f64, 0x0345,0x1f65,0x0345,0x1f66,0x0345,0x1f67,0x0345,0x1f68, 0x0345,0x1f69,0x0345,0x1f6a,0x0345,0x1f6b,0x0345,0x1f6c, 0x0345,0x1f6d,0x0345,0x1f6e,0x0345,0x1f6f,0x0345,0x03b1, 0x0306,0x03b1,0x0304,0x1f70,0x0345,0x03b1,0x0345,0x03ac, 0x0345,0x03b1,0x0342,0x1fb6,0x0345,0x0391,0x0306,0x0391, 0x0304,0x0391,0x0300,0x0386,0x0391,0x0345,0x0020,0x0313, 0x03b9,0x0020,0x0313,0x0020,0x0342,0x00a8,0x0342,0x1f74, 0x0345,0x03b7,0x0345,0x03ae,0x0345,0x03b7,0x0342,0x1fc6, 0x0345,0x0395,0x0300,0x0388,0x0397,0x0300,0x0389,0x0397, 0x0345,0x1fbf,0x0300,0x1fbf,0x0301,0x1fbf,0x0342,0x03b9, 0x0306,0x03b9,0x0304,0x03ca,0x0300,0x0390,0x03b9,0x0342, 0x03ca,0x0342,0x0399,0x0306,0x0399,0x0304,0x0399,0x0300, 0x038a,0x1ffe,0x0300,0x1ffe,0x0301,0x1ffe,0x0342,0x03c5, 0x0306,0x03c5,0x0304,0x03cb,0x0300,0x03b0,0x03c1,0x0313, 0x03c1,0x0314,0x03c5,0x0342,0x03cb,0x0342,0x03a5,0x0306, 0x03a5,0x0304,0x03a5,0x0300,0x038e,0x03a1,0x0314,0x00a8, 0x0300,0x0385,0x0060,0x1f7c,0x0345,0x03c9,0x0345,0x03ce, 0x0345,0x03c9,0x0342,0x1ff6,0x0345,0x039f,0x0300,0x038c, 0x03a9,0x0300,0x038f,0x03a9,0x0345,0x00b4,0x0020,0x0314, 0x2002,0x2003,0x0020,0x0020,0x0020,0x0020,0x0020,0x0020, 0x0020,0x0020,0x0020,0x2010,0x0020,0x0333,0x002e,0x002e, 0x002e,0x002e,0x002e,0x002e,0x0020,0x2032,0x2032,0x2032, 0x2032,0x2032,0x2035,0x2035,0x2035,0x2035,0x2035,0x0021, 0x0021,0x0020,0x0305,0x003f,0x003f,0x003f,0x0021,0x0021, 0x003f,0x2032,0x2032,0x2032,0x2032,0x0020,0x0030,0x0069, 0x0034,0x0035,0x0036,0x0037,0x0038,0x0039,0x002b,0x2212, 0x003d,0x0028,0x0029,0x006e,0x0030,0x0031,0x0032,0x0033, 0x0034,0x0035,0x0036,0x0037,0x0038,0x0039,0x002b,0x2212, 0x003d,0x0028,0x0029,0x0061,0x0065,0x006f,0x0078,0x0259, 0x0052,0x0073,0x0061,0x002f,0x0063,0x0061,0x002f,0x0073, 0x0043,0x00b0,0x0043,0x0063,0x002f,0x006f,0x0063,0x002f, 0x0075,0x0190,0x00b0,0x0046,0x0067,0x0048,0x0048,0x0048, 0x0068,0x0127,0x0049,0x0049,0x004c,0x006c,0x004e,0x004e, 0x006f,0x0050,0x0051,0x0052,0x0052,0x0052,0x0053,0x004d, 0x0054,0x0045,0x004c,0x0054,0x004d,0x005a,0x03a9,0x005a, 0x004b,0x00c5,0x0042,0x0043,0x0065,0x0045,0x0046,0x004d, 0x006f,0x05d0,0x05d1,0x05d2,0x05d3,0x0069,0x0046,0x0041, 0x0058,0x03c0,0x03b3,0x0393,0x03a0,0x2211,0x0044,0x0064, 0x0065,0x0069,0x006a,0x0031,0x2044,0x0033,0x0032,0x2044, 0x0033,0x0031,0x2044,0x0035,0x0032,0x2044,0x0035,0x0033, 0x2044,0x0035,0x0034,0x2044,0x0035,0x0031,0x2044,0x0036, 0x0035,0x2044,0x0036,0x0031,0x2044,0x0038,0x0033,0x2044, 0x0038,0x0035,0x2044,0x0038,0x0037,0x2044,0x0038,0x0031, 0x2044,0x0049,0x0049,0x0049,0x0049,0x0049,0x0049,0x0049, 0x0056,0x0056,0x0056,0x0049,0x0056,0x0049,0x0049,0x0056, 0x0049,0x0049,0x0049,0x0049,0x0058,0x0058,0x0058,0x0049, 0x0058,0x0049,0x0049,0x004c,0x0043,0x0044,0x004d,0x0069, 0x0069,0x0069,0x0069,0x0069,0x0069,0x0069,0x0076,0x0076, 0x0076,0x0069,0x0076,0x0069,0x0069,0x0076,0x0069,0x0069, 0x0069,0x0069,0x0078,0x0078,0x0078,0x0069,0x0078,0x0069, 0x0069,0x006c,0x0063,0x0064,0x006d,0x2190,0x0338,0x2192, 0x0338,0x2194,0x0338,0x21d0,0x0338,0x21d4,0x0338,0x21d2, 0x0338,0x2203,0x0338,0x2208,0x0338,0x220b,0x0338,0x2223, 0x0338,0x2225,0x0338,0x222b,0x222b,0x222b,0x222b,0x222b, 0x222e,0x222e,0x222e,0x222e,0x222e,0x223c,0x0338,0x2243, 0x0338,0x2245,0x0338,0x2248,0x0338,0x003d,0x0338,0x2261, 0x0338,0x224d,0x0338,0x003c,0x0338,0x003e,0x0338,0x2264, 0x0338,0x2265,0x0338,0x2272,0x0338,0x2273,0x0338,0x2276, 0x0338,0x2277,0x0338,0x227a,0x0338,0x227b,0x0338,0x2282, 0x0338,0x2283,0x0338,0x2286,0x0338,0x2287,0x0338,0x22a2, 0x0338,0x22a8,0x0338,0x22a9,0x0338,0x22ab,0x0338,0x227c, 0x0338,0x227d,0x0338,0x2291,0x0338,0x2292,0x0338,0x22b2, 0x0338,0x22b3,0x0338,0x22b4,0x0338,0x22b5,0x0338,0x3008, 0x3009,0x0031,0x0032,0x0033,0x0034,0x0035,0x0036,0x0037, 0x0038,0x0039,0x0031,0x0030,0x0031,0x0031,0x0031,0x0032, 0x0031,0x0033,0x0031,0x0034,0x0031,0x0035,0x0031,0x0036, 0x0031,0x0037,0x0031,0x0038,0x0031,0x0039,0x0032,0x0030, 0x0028,0x0031,0x0029,0x0028,0x0032,0x0029,0x0028,0x0033, 0x0029,0x0028,0x0034,0x0029,0x0028,0x0035,0x0029,0x0028, 0x0036,0x0029,0x0028,0x0037,0x0029,0x0028,0x0038,0x0029, 0x0028,0x0039,0x0029,0x0028,0x0031,0x0030,0x0029,0x0028, 0x0031,0x0031,0x0029,0x0028,0x0031,0x0032,0x0029,0x0028, 0x0031,0x0033,0x0029,0x0028,0x0031,0x0034,0x0029,0x0028, 0x0031,0x0035,0x0029,0x0028,0x0031,0x0036,0x0029,0x0028, 0x0031,0x0037,0x0029,0x0028,0x0031,0x0038,0x0029,0x0028, 0x0031,0x0039,0x0029,0x0028,0x0032,0x0030,0x0029,0x0031, 0x002e,0x0032,0x002e,0x0033,0x002e,0x0034,0x002e,0x0035, 0x002e,0x0036,0x002e,0x0037,0x002e,0x0038,0x002e,0x0039, 0x002e,0x0031,0x0030,0x002e,0x0031,0x0031,0x002e,0x0031, 0x0032,0x002e,0x0031,0x0033,0x002e,0x0031,0x0034,0x002e, 0x0031,0x0035,0x002e,0x0031,0x0036,0x002e,0x0031,0x0037, 0x002e,0x0031,0x0038,0x002e,0x0031,0x0039,0x002e,0x0032, 0x0030,0x002e,0x0028,0x0061,0x0029,0x0028,0x0062,0x0029, 0x0028,0x0063,0x0029,0x0028,0x0064,0x0029,0x0028,0x0065, 0x0029,0x0028,0x0066,0x0029,0x0028,0x0067,0x0029,0x0028, 0x0068,0x0029,0x0028,0x0069,0x0029,0x0028,0x006a,0x0029, 0x0028,0x006b,0x0029,0x0028,0x006c,0x0029,0x0028,0x006d, 0x0029,0x0028,0x006e,0x0029,0x0028,0x006f,0x0029,0x0028, 0x0070,0x0029,0x0028,0x0071,0x0029,0x0028,0x0072,0x0029, 0x0028,0x0073,0x0029,0x0028,0x0074,0x0029,0x0028,0x0075, 0x0029,0x0028,0x0076,0x0029,0x0028,0x0077,0x0029,0x0028, 0x0078,0x0029,0x0028,0x0079,0x0029,0x0028,0x007a,0x0029, 0x0041,0x0042,0x0043,0x0044,0x0045,0x0046,0x0047,0x0048, 0x0049,0x004a,0x004b,0x004c,0x004d,0x004e,0x004f,0x0050, 0x0051,0x0052,0x0053,0x0054,0x0055,0x0056,0x0057,0x0058, 0x0059,0x005a,0x0061,0x0062,0x0063,0x0064,0x0065,0x0066, 0x0067,0x0068,0x0069,0x006a,0x006b,0x006c,0x006d,0x006e, 0x006f,0x0070,0x0071,0x0072,0x0073,0x0074,0x0075,0x0076, 0x0077,0x0078,0x0079,0x007a,0x0030,0x222b,0x222b,0x222b, 0x222b,0x003a,0x003a,0x003d,0x003d,0x003d,0x003d,0x003d, 0x003d,0x2add,0x0338,0x2d61,0x6bcd,0x9f9f,0x4e00,0x4e28, 0x4e36,0x4e3f,0x4e59,0x4e85,0x4e8c,0x4ea0,0x4eba,0x513f, 0x5165,0x516b,0x5182,0x5196,0x51ab,0x51e0,0x51f5,0x5200, 0x529b,0x52f9,0x5315,0x531a,0x5338,0x5341,0x535c,0x5369, 0x5382,0x53b6,0x53c8,0x53e3,0x56d7,0x571f,0x58eb,0x5902, 0x590a,0x5915,0x5927,0x5973,0x5b50,0x5b80,0x5bf8,0x5c0f, 0x5c22,0x5c38,0x5c6e,0x5c71,0x5ddb,0x5de5,0x5df1,0x5dfe, 0x5e72,0x5e7a,0x5e7f,0x5ef4,0x5efe,0x5f0b,0x5f13,0x5f50, 0x5f61,0x5f73,0x5fc3,0x6208,0x6236,0x624b,0x652f,0x6534, 0x6587,0x6597,0x65a4,0x65b9,0x65e0,0x65e5,0x66f0,0x6708, 0x6728,0x6b20,0x6b62,0x6b79,0x6bb3,0x6bcb,0x6bd4,0x6bdb, 0x6c0f,0x6c14,0x6c34,0x706b,0x722a,0x7236,0x723b,0x723f, 0x7247,0x7259,0x725b,0x72ac,0x7384,0x7389,0x74dc,0x74e6, 0x7518,0x751f,0x7528,0x7530,0x758b,0x7592,0x7676,0x767d, 0x76ae,0x76bf,0x76ee,0x77db,0x77e2,0x77f3,0x793a,0x79b8, 0x79be,0x7a74,0x7acb,0x7af9,0x7c73,0x7cf8,0x7f36,0x7f51, 0x7f8a,0x7fbd,0x8001,0x800c,0x8012,0x8033,0x807f,0x8089, 0x81e3,0x81ea,0x81f3,0x81fc,0x820c,0x821b,0x821f,0x826e, 0x8272,0x8278,0x864d,0x866b,0x8840,0x884c,0x8863,0x897e, 0x898b,0x89d2,0x8a00,0x8c37,0x8c46,0x8c55,0x8c78,0x8c9d, 0x8d64,0x8d70,0x8db3,0x8eab,0x8eca,0x8f9b,0x8fb0,0x8fb5, 0x9091,0x9149,0x91c6,0x91cc,0x91d1,0x9577,0x9580,0x961c, 0x96b6,0x96b9,0x96e8,0x9751,0x975e,0x9762,0x9769,0x97cb, 0x97ed,0x97f3,0x9801,0x98a8,0x98db,0x98df,0x9996,0x9999, 0x99ac,0x9aa8,0x9ad8,0x9adf,0x9b25,0x9b2f,0x9b32,0x9b3c, 0x9b5a,0x9ce5,0x9e75,0x9e7f,0x9ea5,0x9ebb,0x9ec3,0x9ecd, 0x9ed1,0x9ef9,0x9efd,0x9f0e,0x9f13,0x9f20,0x9f3b,0x9f4a, 0x9f52,0x9f8d,0x9f9c,0x9fa0,0x0020,0x3012,0x5341,0x5344, 0x5345,0x304b,0x3099,0x304d,0x3099,0x304f,0x3099,0x3051, 0x3099,0x3053,0x3099,0x3055,0x3099,0x3057,0x3099,0x3059, 0x3099,0x305b,0x3099,0x305d,0x3099,0x305f,0x3099,0x3061, 0x3099,0x3064,0x3099,0x3066,0x3099,0x3068,0x3099,0x306f, 0x3099,0x306f,0x309a,0x3072,0x3099,0x3072,0x309a,0x3075, 0x3099,0x3075,0x309a,0x3078,0x3099,0x3078,0x309a,0x307b, 0x3099,0x307b,0x309a,0x3046,0x3099,0x0020,0x3099,0x0020, 0x309a,0x309d,0x3099,0x3088,0x308a,0x30ab,0x3099,0x30ad, 0x3099,0x30af,0x3099,0x30b1,0x3099,0x30b3,0x3099,0x30b5, 0x3099,0x30b7,0x3099,0x30b9,0x3099,0x30bb,0x3099,0x30bd, 0x3099,0x30bf,0x3099,0x30c1,0x3099,0x30c4,0x3099,0x30c6, 0x3099,0x30c8,0x3099,0x30cf,0x3099,0x30cf,0x309a,0x30d2, 0x3099,0x30d2,0x309a,0x30d5,0x3099,0x30d5,0x309a,0x30d8, 0x3099,0x30d8,0x309a,0x30db,0x3099,0x30db,0x309a,0x30a6, 0x3099,0x30ef,0x3099,0x30f0,0x3099,0x30f1,0x3099,0x30f2, 0x3099,0x30fd,0x3099,0x30b3,0x30c8,0x1100,0x1101,0x11aa, 0x1102,0x11ac,0x11ad,0x1103,0x1104,0x1105,0x11b0,0x11b1, 0x11b2,0x11b3,0x11b4,0x11b5,0x111a,0x1106,0x1107,0x1108, 0x1121,0x1109,0x110a,0x110b,0x110c,0x110d,0x110e,0x110f, 0x1110,0x1111,0x1112,0x1161,0x1162,0x1163,0x1164,0x1165, 0x1166,0x1167,0x1168,0x1169,0x116a,0x116b,0x116c,0x116d, 0x116e,0x116f,0x1170,0x1171,0x1172,0x1173,0x1174,0x1175, 0x1160,0x1114,0x1115,0x11c7,0x11c8,0x11cc,0x11ce,0x11d3, 0x11d7,0x11d9,0x111c,0x11dd,0x11df,0x111d,0x111e,0x1120, 0x1122,0x1123,0x1127,0x1129,0x112b,0x112c,0x112d,0x112e, 0x112f,0x1132,0x1136,0x1140,0x1147,0x114c,0x11f1,0x11f2, 0x1157,0x1158,0x1159,0x1184,0x1185,0x1188,0x1191,0x1192, 0x1194,0x119e,0x11a1,0x4e00,0x4e8c,0x4e09,0x56db,0x4e0a, 0x4e2d,0x4e0b,0x7532,0x4e59,0x4e19,0x4e01,0x5929,0x5730, 0x4eba,0x0028,0x1100,0x0029,0x0028,0x1102,0x0029,0x0028, 0x1103,0x0029,0x0028,0x1105,0x0029,0x0028,0x1106,0x0029, 0x0028,0x1107,0x0029,0x0028,0x1109,0x0029,0x0028,0x110b, 0x0029,0x0028,0x110c,0x0029,0x0028,0x110e,0x0029,0x0028, 0x110f,0x0029,0x0028,0x1110,0x0029,0x0028,0x1111,0x0029, 0x0028,0x1112,0x0029,0x0028,0x1100,0x1161,0x0029,0x0028, 0x1102,0x1161,0x0029,0x0028,0x1103,0x1161,0x0029,0x0028, 0x1105,0x1161,0x0029,0x0028,0x1106,0x1161,0x0029,0x0028, 0x1107,0x1161,0x0029,0x0028,0x1109,0x1161,0x0029,0x0028, 0x110b,0x1161,0x0029,0x0028,0x110c,0x1161,0x0029,0x0028, 0x110e,0x1161,0x0029,0x0028,0x110f,0x1161,0x0029,0x0028, 0x1110,0x1161,0x0029,0x0028,0x1111,0x1161,0x0029,0x0028, 0x1112,0x1161,0x0029,0x0028,0x110c,0x116e,0x0029,0x0028, 0x110b,0x1169,0x110c,0x1165,0x11ab,0x0029,0x0028,0x110b, 0x1169,0x1112,0x116e,0x0029,0x0028,0x4e00,0x0029,0x0028, 0x4e8c,0x0029,0x0028,0x4e09,0x0029,0x0028,0x56db,0x0029, 0x0028,0x4e94,0x0029,0x0028,0x516d,0x0029,0x0028,0x4e03, 0x0029,0x0028,0x516b,0x0029,0x0028,0x4e5d,0x0029,0x0028, 0x5341,0x0029,0x0028,0x6708,0x0029,0x0028,0x706b,0x0029, 0x0028,0x6c34,0x0029,0x0028,0x6728,0x0029,0x0028,0x91d1, 0x0029,0x0028,0x571f,0x0029,0x0028,0x65e5,0x0029,0x0028, 0x682a,0x0029,0x0028,0x6709,0x0029,0x0028,0x793e,0x0029, 0x0028,0x540d,0x0029,0x0028,0x7279,0x0029,0x0028,0x8ca1, 0x0029,0x0028,0x795d,0x0029,0x0028,0x52b4,0x0029,0x0028, 0x4ee3,0x0029,0x0028,0x547c,0x0029,0x0028,0x5b66,0x0029, 0x0028,0x76e3,0x0029,0x0028,0x4f01,0x0029,0x0028,0x8cc7, 0x0029,0x0028,0x5354,0x0029,0x0028,0x796d,0x0029,0x0028, 0x4f11,0x0029,0x0028,0x81ea,0x0029,0x0028,0x81f3,0x0029, 0x0050,0x0054,0x0045,0x0032,0x0031,0x0032,0x0032,0x0032, 0x0033,0x0032,0x0034,0x0032,0x0035,0x0032,0x0036,0x0032, 0x0037,0x0032,0x0038,0x0032,0x0039,0x0033,0x0030,0x0033, 0x0031,0x0033,0x0032,0x0033,0x0033,0x0033,0x0034,0x0033, 0x0035,0x1100,0x1102,0x1103,0x1105,0x1106,0x1107,0x1109, 0x110b,0x110c,0x110e,0x110f,0x1110,0x1111,0x1112,0x1100, 0x1161,0x1102,0x1161,0x1103,0x1161,0x1105,0x1161,0x1106, 0x1161,0x1107,0x1161,0x1109,0x1161,0x110b,0x1161,0x110c, 0x1161,0x110e,0x1161,0x110f,0x1161,0x1110,0x1161,0x1111, 0x1161,0x1112,0x1161,0x110e,0x1161,0x11b7,0x1100,0x1169, 0x110c,0x116e,0x110b,0x1174,0x110b,0x116e,0x4e00,0x4e8c, 0x4e09,0x56db,0x4e94,0x516d,0x4e03,0x516b,0x4e5d,0x5341, 0x6708,0x706b,0x6c34,0x6728,0x91d1,0x571f,0x65e5,0x682a, 0x6709,0x793e,0x540d,0x7279,0x8ca1,0x795d,0x52b4,0x79d8, 0x7537,0x5973,0x9069,0x512a,0x5370,0x6ce8,0x9805,0x4f11, 0x5199,0x6b63,0x4e0a,0x4e2d,0x4e0b,0x5de6,0x53f3,0x533b, 0x5b97,0x5b66,0x76e3,0x4f01,0x8cc7,0x5354,0x591c,0x0033, 0x0036,0x0033,0x0037,0x0033,0x0038,0x0033,0x0039,0x0034, 0x0030,0x0034,0x0031,0x0034,0x0032,0x0034,0x0033,0x0034, 0x0034,0x0034,0x0035,0x0034,0x0036,0x0034,0x0037,0x0034, 0x0038,0x0034,0x0039,0x0035,0x0030,0x0031,0x6708,0x0032, 0x6708,0x0033,0x6708,0x0034,0x6708,0x0035,0x6708,0x0036, 0x6708,0x0037,0x6708,0x0038,0x6708,0x0039,0x6708,0x0031, 0x0030,0x6708,0x0031,0x0031,0x6708,0x0031,0x0032,0x6708, 0x0048,0x0067,0x0065,0x0072,0x0067,0x0065,0x0056,0x004c, 0x0054,0x0044,0x30a2,0x30a4,0x30a6,0x30a8,0x30aa,0x30ab, 0x30ad,0x30af,0x30b1,0x30b3,0x30b5,0x30b7,0x30b9,0x30bb, 0x30bd,0x30bf,0x30c1,0x30c4,0x30c6,0x30c8,0x30ca,0x30cb, 0x30cc,0x30cd,0x30ce,0x30cf,0x30d2,0x30d5,0x30d8,0x30db, 0x30de,0x30df,0x30e0,0x30e1,0x30e2,0x30e4,0x30e6,0x30e8, 0x30e9,0x30ea,0x30eb,0x30ec,0x30ed,0x30ef,0x30f0,0x30f1, 0x30f2,0x30a2,0x30d1,0x30fc,0x30c8,0x30a2,0x30eb,0x30d5, 0x30a1,0x30a2,0x30f3,0x30da,0x30a2,0x30a2,0x30fc,0x30eb, 0x30a4,0x30cb,0x30f3,0x30b0,0x30a4,0x30f3,0x30c1,0x30a6, 0x30a9,0x30f3,0x30a8,0x30b9,0x30af,0x30fc,0x30c9,0x30a8, 0x30fc,0x30ab,0x30fc,0x30aa,0x30f3,0x30b9,0x30aa,0x30fc, 0x30e0,0x30ab,0x30a4,0x30ea,0x30ab,0x30e9,0x30c3,0x30c8, 0x30ab,0x30ed,0x30ea,0x30fc,0x30ac,0x30ed,0x30f3,0x30ac, 0x30f3,0x30de,0x30ae,0x30ac,0x30ae,0x30cb,0x30fc,0x30ad, 0x30e5,0x30ea,0x30fc,0x30ae,0x30eb,0x30c0,0x30fc,0x30ad, 0x30ed,0x30ad,0x30ed,0x30b0,0x30e9,0x30e0,0x30ad,0x30ed, 0x30e1,0x30fc,0x30c8,0x30eb,0x30ad,0x30ed,0x30ef,0x30c3, 0x30c8,0x30b0,0x30e9,0x30e0,0x30b0,0x30e9,0x30e0,0x30c8, 0x30f3,0x30af,0x30eb,0x30bc,0x30a4,0x30ed,0x30af,0x30ed, 0x30fc,0x30cd,0x30b1,0x30fc,0x30b9,0x30b3,0x30eb,0x30ca, 0x30b3,0x30fc,0x30dd,0x30b5,0x30a4,0x30af,0x30eb,0x30b5, 0x30f3,0x30c1,0x30fc,0x30e0,0x30b7,0x30ea,0x30f3,0x30b0, 0x30bb,0x30f3,0x30c1,0x30bb,0x30f3,0x30c8,0x30c0,0x30fc, 0x30b9,0x30c7,0x30b7,0x30c9,0x30eb,0x30c8,0x30f3,0x30ca, 0x30ce,0x30ce,0x30c3,0x30c8,0x30cf,0x30a4,0x30c4,0x30d1, 0x30fc,0x30bb,0x30f3,0x30c8,0x30d1,0x30fc,0x30c4,0x30d0, 0x30fc,0x30ec,0x30eb,0x30d4,0x30a2,0x30b9,0x30c8,0x30eb, 0x30d4,0x30af,0x30eb,0x30d4,0x30b3,0x30d3,0x30eb,0x30d5, 0x30a1,0x30e9,0x30c3,0x30c9,0x30d5,0x30a3,0x30fc,0x30c8, 0x30d6,0x30c3,0x30b7,0x30a7,0x30eb,0x30d5,0x30e9,0x30f3, 0x30d8,0x30af,0x30bf,0x30fc,0x30eb,0x30da,0x30bd,0x30da, 0x30cb,0x30d2,0x30d8,0x30eb,0x30c4,0x30da,0x30f3,0x30b9, 0x30da,0x30fc,0x30b8,0x30d9,0x30fc,0x30bf,0x30dd,0x30a4, 0x30f3,0x30c8,0x30dc,0x30eb,0x30c8,0x30db,0x30f3,0x30dd, 0x30f3,0x30c9,0x30db,0x30fc,0x30eb,0x30db,0x30fc,0x30f3, 0x30de,0x30a4,0x30af,0x30ed,0x30de,0x30a4,0x30eb,0x30de, 0x30c3,0x30cf,0x30de,0x30eb,0x30af,0x30de,0x30f3,0x30b7, 0x30e7,0x30f3,0x30df,0x30af,0x30ed,0x30f3,0x30df,0x30ea, 0x30df,0x30ea,0x30d0,0x30fc,0x30eb,0x30e1,0x30ac,0x30e1, 0x30ac,0x30c8,0x30f3,0x30e1,0x30fc,0x30c8,0x30eb,0x30e4, 0x30fc,0x30c9,0x30e4,0x30fc,0x30eb,0x30e6,0x30a2,0x30f3, 0x30ea,0x30c3,0x30c8,0x30eb,0x30ea,0x30e9,0x30eb,0x30d4, 0x30fc,0x30eb,0x30fc,0x30d6,0x30eb,0x30ec,0x30e0,0x30ec, 0x30f3,0x30c8,0x30b2,0x30f3,0x30ef,0x30c3,0x30c8,0x0030, 0x70b9,0x0031,0x70b9,0x0032,0x70b9,0x0033,0x70b9,0x0034, 0x70b9,0x0035,0x70b9,0x0036,0x70b9,0x0037,0x70b9,0x0038, 0x70b9,0x0039,0x70b9,0x0031,0x0030,0x70b9,0x0031,0x0031, 0x70b9,0x0031,0x0032,0x70b9,0x0031,0x0033,0x70b9,0x0031, 0x0034,0x70b9,0x0031,0x0035,0x70b9,0x0031,0x0036,0x70b9, 0x0031,0x0037,0x70b9,0x0031,0x0038,0x70b9,0x0031,0x0039, 0x70b9,0x0032,0x0030,0x70b9,0x0032,0x0031,0x70b9,0x0032, 0x0032,0x70b9,0x0032,0x0033,0x70b9,0x0032,0x0034,0x70b9, 0x0068,0x0050,0x0061,0x0064,0x0061,0x0041,0x0055,0x0062, 0x0061,0x0072,0x006f,0x0056,0x0070,0x0063,0x0064,0x006d, 0x0064,0x006d,0x00b2,0x0064,0x006d,0x00b3,0x0049,0x0055, 0x5e73,0x6210,0x662d,0x548c,0x5927,0x6b63,0x660e,0x6cbb, 0x682a,0x5f0f,0x4f1a,0x793e,0x0070,0x0041,0x006e,0x0041, 0x03bc,0x0041,0x006d,0x0041,0x006b,0x0041,0x004b,0x0042, 0x004d,0x0042,0x0047,0x0042,0x0063,0x0061,0x006c,0x006b, 0x0063,0x0061,0x006c,0x0070,0x0046,0x006e,0x0046,0x03bc, 0x0046,0x03bc,0x0067,0x006d,0x0067,0x006b,0x0067,0x0048, 0x007a,0x006b,0x0048,0x007a,0x004d,0x0048,0x007a,0x0047, 0x0048,0x007a,0x0054,0x0048,0x007a,0x03bc,0x2113,0x006d, 0x2113,0x0064,0x2113,0x006b,0x2113,0x0066,0x006d,0x006e, 0x006d,0x03bc,0x006d,0x006d,0x006d,0x0063,0x006d,0x006b, 0x006d,0x006d,0x006d,0x00b2,0x0063,0x006d,0x00b2,0x006d, 0x00b2,0x006b,0x006d,0x00b2,0x006d,0x006d,0x00b3,0x0063, 0x006d,0x00b3,0x006d,0x00b3,0x006b,0x006d,0x00b3,0x006d, 0x2215,0x0073,0x006d,0x2215,0x0073,0x00b2,0x0050,0x0061, 0x006b,0x0050,0x0061,0x004d,0x0050,0x0061,0x0047,0x0050, 0x0061,0x0072,0x0061,0x0064,0x0072,0x0061,0x0064,0x2215, 0x0073,0x0072,0x0061,0x0064,0x2215,0x0073,0x00b2,0x0070, 0x0073,0x006e,0x0073,0x03bc,0x0073,0x006d,0x0073,0x0070, 0x0056,0x006e,0x0056,0x03bc,0x0056,0x006d,0x0056,0x006b, 0x0056,0x004d,0x0056,0x0070,0x0057,0x006e,0x0057,0x03bc, 0x0057,0x006d,0x0057,0x006b,0x0057,0x004d,0x0057,0x006b, 0x03a9,0x004d,0x03a9,0x0061,0x002e,0x006d,0x002e,0x0042, 0x0071,0x0063,0x0063,0x0063,0x0064,0x0043,0x2215,0x006b, 0x0067,0x0043,0x006f,0x002e,0x0064,0x0042,0x0047,0x0079, 0x0068,0x0061,0x0048,0x0050,0x0069,0x006e,0x004b,0x004b, 0x004b,0x004d,0x006b,0x0074,0x006c,0x006d,0x006c,0x006e, 0x006c,0x006f,0x0067,0x006c,0x0078,0x006d,0x0062,0x006d, 0x0069,0x006c,0x006d,0x006f,0x006c,0x0050,0x0048,0x0070, 0x002e,0x006d,0x002e,0x0050,0x0050,0x004d,0x0050,0x0052, 0x0073,0x0072,0x0053,0x0076,0x0057,0x0062,0x0056,0x2215, 0x006d,0x0041,0x2215,0x006d,0x0031,0x65e5,0x0032,0x65e5, 0x0033,0x65e5,0x0034,0x65e5,0x0035,0x65e5,0x0036,0x65e5, 0x0037,0x65e5,0x0038,0x65e5,0x0039,0x65e5,0x0031,0x0030, 0x65e5,0x0031,0x0031,0x65e5,0x0031,0x0032,0x65e5,0x0031, 0x0033,0x65e5,0x0031,0x0034,0x65e5,0x0031,0x0035,0x65e5, 0x0031,0x0036,0x65e5,0x0031,0x0037,0x65e5,0x0031,0x0038, 0x65e5,0x0031,0x0039,0x65e5,0x0032,0x0030,0x65e5,0x0032, 0x0031,0x65e5,0x0032,0x0032,0x65e5,0x0032,0x0033,0x65e5, 0x0032,0x0034,0x65e5,0x0032,0x0035,0x65e5,0x0032,0x0036, 0x65e5,0x0032,0x0037,0x65e5,0x0032,0x0038,0x65e5,0x0032, 0x0039,0x65e5,0x0033,0x0030,0x65e5,0x0033,0x0031,0x65e5, 0x0067,0x0061,0x006c }; #define UCS4_BMPCJKMIN 0xf900 #define UCS4_BMPCJKMAX 0xface /* CJK Compatibility - 0 means hole (no decomposition) */ static const unsigned short ucs4_bmpcjk1decomptab[463] = { 0x8c48,0x66f4,0x8eca,0x8cc8,0x6ed1,0x4e32,0x53e5,0x9f9c, 0x9f9c,0x5951,0x91d1,0x5587,0x5948,0x61f6,0x7669,0x7f85, 0x863f,0x87ba,0x88f8,0x908f,0x6a02,0x6d1b,0x70d9,0x73de, 0x843d,0x916a,0x99f1,0x4e82,0x5375,0x6b04,0x721b,0x862d, 0x9e1e,0x5d50,0x6feb,0x85cd,0x8964,0x62c9,0x81d8,0x881f, 0x5eca,0x6717,0x6d6a,0x72fc,0x90ce,0x4f86,0x51b7,0x52de, 0x64c4,0x6ad3,0x7210,0x76e7,0x8001,0x8606,0x865c,0x8def, 0x9732,0x9b6f,0x9dfa,0x788c,0x797f,0x7da0,0x83c9,0x9304, 0x9e7f,0x8ad6,0x58df,0x5f04,0x7c60,0x807e,0x7262,0x78ca, 0x8cc2,0x96f7,0x58d8,0x5c62,0x6a13,0x6dda,0x6f0f,0x7d2f, 0x7e37,0x964b,0x52d2,0x808b,0x51dc,0x51cc,0x7a1c,0x7dbe, 0x83f1,0x9675,0x8b80,0x62cf,0x6a02,0x8afe,0x4e39,0x5be7, 0x6012,0x7387,0x7570,0x5317,0x78fb,0x4fbf,0x5fa9,0x4e0d, 0x6ccc,0x6578,0x7d22,0x53c3,0x585e,0x7701,0x8449,0x8aaa, 0x6bba,0x8fb0,0x6c88,0x62fe,0x82e5,0x63a0,0x7565,0x4eae, 0x5169,0x51c9,0x6881,0x7ce7,0x826f,0x8ad2,0x91cf,0x52f5, 0x5442,0x5973,0x5eec,0x65c5,0x6ffe,0x792a,0x95ad,0x9a6a, 0x9e97,0x9ece,0x529b,0x66c6,0x6b77,0x8f62,0x5e74,0x6190, 0x6200,0x649a,0x6f23,0x7149,0x7489,0x79ca,0x7df4,0x806f, 0x8f26,0x84ee,0x9023,0x934a,0x5217,0x52a3,0x54bd,0x70c8, 0x88c2,0x8aaa,0x5ec9,0x5ff5,0x637b,0x6bae,0x7c3e,0x7375, 0x4ee4,0x56f9,0x5be7,0x5dba,0x601c,0x73b2,0x7469,0x7f9a, 0x8046,0x9234,0x96f6,0x9748,0x9818,0x4f8b,0x79ae,0x91b4, 0x96b8,0x60e1,0x4e86,0x50da,0x5bee,0x5c3f,0x6599,0x6a02, 0x71ce,0x7642,0x84fc,0x907c,0x9f8d,0x6688,0x962e,0x5289, 0x677b,0x67f3,0x6d41,0x6e9c,0x7409,0x7559,0x786b,0x7d10, 0x985e,0x516d,0x622e,0x9678,0x502b,0x5d19,0x6dea,0x8f2a, 0x5f8b,0x6144,0x6817,0x7387,0x9686,0x5229,0x540f,0x5c65, 0x6613,0x674e,0x68a8,0x6ce5,0x7406,0x75e2,0x7f79,0x88cf, 0x88e1,0x91cc,0x96e2,0x533f,0x6eba,0x541d,0x71d0,0x7498, 0x85fa,0x96a3,0x9c57,0x9e9f,0x6797,0x6dcb,0x81e8,0x7acb, 0x7b20,0x7c92,0x72c0,0x7099,0x8b58,0x4ec0,0x8336,0x523a, 0x5207,0x5ea6,0x62d3,0x7cd6,0x5b85,0x6d1e,0x66b4,0x8f3b, 0x884c,0x964d,0x898b,0x5ed3,0x5140,0x55c0,0x0000,0x0000, 0x585a,0x0000,0x6674,0x0000,0x0000,0x51de,0x732a,0x76ca, 0x793c,0x795e,0x7965,0x798f,0x9756,0x7cbe,0x7fbd,0x0000, 0x8612,0x0000,0x8af8,0x0000,0x0000,0x9038,0x90fd,0x0000, 0x0000,0x0000,0x98ef,0x98fc,0x9928,0x9db4,0x0000,0x0000, 0x4fae,0x50e7,0x514d,0x52c9,0x52e4,0x5351,0x559d,0x5606, 0x5668,0x5840,0x58a8,0x5c64,0x5c6e,0x6094,0x6168,0x618e, 0x61f2,0x654f,0x65e2,0x6691,0x6885,0x6d77,0x6e1a,0x6f22, 0x716e,0x722b,0x7422,0x7891,0x793e,0x7949,0x7948,0x7950, 0x7956,0x795d,0x798d,0x798e,0x7a40,0x7a81,0x7bc0,0x7df4, 0x7e09,0x7e41,0x7f72,0x8005,0x81ed,0x8279,0x8279,0x8457, 0x8910,0x8996,0x8b01,0x8b39,0x8cd3,0x8d08,0x8fb6,0x9038, 0x96e3,0x97ff,0x983b,0x0000,0x0000,0x0000,0x0000,0x0000, 0x4e26,0x51b5,0x5168,0x4f80,0x5145,0x5180,0x52c7,0x52fa, 0x559d,0x5555,0x5599,0x55e2,0x585a,0x58b3,0x5944,0x5954, 0x5a62,0x5b28,0x5ed2,0x5ed9,0x5f69,0x5fad,0x60d8,0x614e, 0x6108,0x618e,0x6160,0x61f2,0x6234,0x63c4,0x641c,0x6452, 0x6556,0x6674,0x6717,0x671b,0x6756,0x6b79,0x6bba,0x6d41, 0x6edb,0x6ecb,0x6f22,0x701e,0x716e,0x77a7,0x7235,0x72af, 0x732a,0x7471,0x7506,0x753b,0x761d,0x761f,0x76ca,0x76db, 0x76f4,0x774a,0x7740,0x78cc,0x7ab1,0x7bc0,0x7c7b,0x7d5b, 0x7df4,0x7f3e,0x8005,0x8352,0x83ef,0x8779,0x8941,0x8986, 0x8996,0x8abf,0x8af8,0x8acb,0x8b01,0x8afe,0x8aed,0x8b39, 0x8b8a,0x8d08,0x8f38,0x9072,0x9199,0x9276,0x967c,0x96e3, 0x9756,0x97db,0x97ff,0x980b,0x983b,0x9b12,0x9f9c }; #define UCS4_BMPCJK2MIN 0xfacf #define UCS4_BMPCJK2MAX 0xfad9 /* CJK Compatibility - some values not in BMP */ static const unsigned long ucs4_bmpcjk2decomptab[11] = { 0x2284a,0x22844,0x233d5, 0x3b9d, 0x4018, 0x4039, 0x25249,0x25cd0,0x27ed3, 0x9f43, 0x9f8e }; #define UCS4_BMPHIMIN 0xfb00 #define UCS4_BMPHIMAX 0xfefc #define UCS4_BMPHIIXMASK 0x7ff #define UCS4_BMPHISIZEMASK 0xf800 #define UCS4_BMPHISIZESHIFT 11 /* BMP hi decomposition indices - ssss siii iiii iiii */ static unsigned short ucs4_dbmphiixtab[1021] = { 0x0800,0x0802,0x0804,0x1006,0x1009,0x080c,0x080e,0x0000, 0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000, 0x0000,0x0000,0x0000,0x0810,0x0812,0x0814,0x0816,0x0818, 0x0000,0x0000,0x0000,0x0000,0x0000,0x081a,0x0000,0x081c, 0x001e,0x001f,0x0020,0x0021,0x0022,0x0023,0x0024,0x0025, 0x0026,0x0027,0x0828,0x082a,0x082c,0x082e,0x0830,0x0832, 0x0834,0x0836,0x0838,0x083a,0x083c,0x083e,0x0840,0x0000, 0x0842,0x0844,0x0846,0x0848,0x084a,0x0000,0x084c,0x0000, 0x084e,0x0850,0x0000,0x0852,0x0854,0x0000,0x0856,0x0858, 0x085a,0x085c,0x085e,0x0860,0x0862,0x0864,0x0866,0x0868, 0x006a,0x006b,0x006c,0x006d,0x006e,0x006f,0x0070,0x0071, 0x0072,0x0073,0x0074,0x0075,0x0076,0x0077,0x0078,0x0079, 0x007a,0x007b,0x007c,0x007d,0x007e,0x007f,0x0080,0x0081, 0x0082,0x0083,0x0084,0x0085,0x0086,0x0087,0x0088,0x0089, 0x008a,0x008b,0x008c,0x008d,0x008e,0x008f,0x0090,0x0091, 0x0092,0x0093,0x0094,0x0095,0x0096,0x0097,0x0098,0x0099, 0x009a,0x009b,0x009c,0x009d,0x009e,0x009f,0x00a0,0x00a1, 0x00a2,0x00a3,0x00a4,0x00a5,0x00a6,0x00a7,0x00a8,0x00a9, 0x00aa,0x00ab,0x00ac,0x00ad,0x00ae,0x00af,0x00b0,0x00b1, 0x00b2,0x00b3,0x00b4,0x00b5,0x00b6,0x00b7,0x00b8,0x00b9, 0x00ba,0x00bb,0x00bc,0x00bd,0x00be,0x00bf,0x00c0,0x00c1, 0x00c2,0x00c3,0x00c4,0x00c5,0x00c6,0x00c7,0x00c8,0x00c9, 0x00ca,0x00cb,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000, 0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000, 0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000, 0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000, 0x0000,0x0000,0x0000,0x00cc,0x00cd,0x00ce,0x00cf,0x00d0, 0x00d1,0x00d2,0x00d3,0x00d4,0x00d5,0x00d6,0x00d7,0x00d8, 0x00d9,0x00da,0x00db,0x00dc,0x00dd,0x00de,0x00df,0x00e0, 0x00e1,0x00e2,0x08e3,0x08e5,0x08e7,0x08e9,0x08eb,0x08ed, 0x08ef,0x08f1,0x08f3,0x08f5,0x08f7,0x08f9,0x08fb,0x08fd, 0x08ff,0x0901,0x0903,0x0905,0x0107,0x0108,0x0109,0x010a, 0x090b,0x090d,0x090f,0x0911,0x0913,0x0915,0x0917,0x0919, 0x091b,0x091d,0x091f,0x0921,0x0923,0x0925,0x0927,0x0929, 0x092b,0x092d,0x092f,0x0931,0x0933,0x0935,0x0937,0x0939, 0x093b,0x093d,0x093f,0x0941,0x0943,0x0945,0x0947,0x0949, 0x094b,0x094d,0x094f,0x0951,0x0953,0x0955,0x0957,0x0959, 0x095b,0x095d,0x095f,0x0961,0x0963,0x0965,0x0967,0x0969, 0x096b,0x096d,0x096f,0x0971,0x0973,0x0975,0x0977,0x0979, 0x097b,0x097d,0x097f,0x0981,0x0983,0x0985,0x0987,0x0989, 0x098b,0x098d,0x098f,0x0991,0x0993,0x0995,0x0997,0x0999, 0x099b,0x099d,0x099f,0x09a1,0x09a3,0x09a5,0x09a7,0x09a9, 0x09ab,0x09ad,0x09af,0x09b1,0x09b3,0x09b5,0x09b7,0x09b9, 0x09bb,0x09bd,0x09bf,0x09c1,0x09c3,0x09c5,0x11c7,0x11ca, 0x11cd,0x11d0,0x11d3,0x11d6,0x09d9,0x09db,0x09dd,0x09df, 0x09e1,0x09e3,0x09e5,0x09e7,0x09e9,0x09eb,0x09ed,0x09ef, 0x09f1,0x09f3,0x09f5,0x09f7,0x09f9,0x09fb,0x09fd,0x09ff, 0x0a01,0x0a03,0x0a05,0x0a07,0x0a09,0x0a0b,0x0a0d,0x0a0f, 0x0a11,0x0a13,0x0a15,0x0a17,0x0a19,0x0a1b,0x0a1d,0x0a1f, 0x0a21,0x0a23,0x0a25,0x0a27,0x0a29,0x0a2b,0x0a2d,0x0a2f, 0x0a31,0x0a33,0x0a35,0x0a37,0x0a39,0x0a3b,0x0a3d,0x0a3f, 0x0a41,0x0a43,0x0a45,0x0a47,0x0a49,0x0a4b,0x0a4d,0x0a4f, 0x0a51,0x0a53,0x0a55,0x0a57,0x0a59,0x0a5b,0x0a5d,0x0a5f, 0x0a61,0x0a63,0x0a65,0x0a67,0x0a69,0x0a6b,0x0a6d,0x0a6f, 0x0a71,0x0a73,0x0a75,0x0a77,0x0a79,0x0a7b,0x0a7d,0x0a7f, 0x0a81,0x0a83,0x0a85,0x0a87,0x0a89,0x0a8b,0x0a8d,0x0a8f, 0x0a91,0x0a93,0x0a95,0x0a97,0x0a99,0x0a9b,0x0a9d,0x0a9f, 0x0aa1,0x0aa3,0x0aa5,0x0aa7,0x0aa9,0x0aab,0x0aad,0x0aaf, 0x0ab1,0x0ab3,0x0ab5,0x0ab7,0x0ab9,0x0abb,0x0abd,0x0abf, 0x0ac1,0x0ac3,0x0ac5,0x0ac7,0x0ac9,0x0acb,0x0acd,0x0acf, 0x0ad1,0x0ad3,0x0ad5,0x0ad7,0x0ad9,0x0adb,0x0add,0x0adf, 0x0ae1,0x0ae3,0x0ae5,0x0ae7,0x0ae9,0x0aeb,0x0aed,0x0aef, 0x0af1,0x0af3,0x12f5,0x12f8,0x12fb,0x0afe,0x0b00,0x0b02, 0x0b04,0x0b06,0x0b08,0x0b0a,0x0b0c,0x0b0e,0x0b10,0x0b12, 0x0b14,0x0b16,0x0b18,0x0b1a,0x0b1c,0x0b1e,0x0b20,0x0b22, 0x0b24,0x0b26,0x0b28,0x0b2a,0x0b2c,0x0b2e,0x0b30,0x0b32, 0x0b34,0x0b36,0x0b38,0x0b3a,0x0b3c,0x0b3e,0x0b40,0x0b42, 0x0b44,0x0b46,0x0b48,0x0b4a,0x0b4c,0x0b4e,0x0b50,0x0b52, 0x0b54,0x0b56,0x0b58,0x0b5a,0x0b5c,0x0b5e,0x0b60,0x0b62, 0x0b64,0x0b66,0x0b68,0x0b6a,0x0b6c,0x0b6e,0x0b70,0x0b72, 0x0b74,0x0b76,0x0b78,0x0b7a,0x0b7c,0x0b7e,0x0b80,0x0b82, 0x0b84,0x0b86,0x0b88,0x0b8a,0x0b8c,0x0b8e,0x0000,0x0000, 0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000, 0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000, 0x1390,0x1393,0x1396,0x1399,0x139c,0x139f,0x13a2,0x13a5, 0x13a8,0x13ab,0x13ae,0x13b1,0x13b4,0x13b7,0x13ba,0x13bd, 0x13c0,0x13c3,0x13c6,0x13c9,0x13cc,0x13cf,0x13d2,0x13d5, 0x13d8,0x13db,0x13de,0x13e1,0x13e4,0x13e7,0x13ea,0x13ed, 0x13f0,0x13f3,0x13f6,0x13f9,0x13fc,0x13ff,0x1402,0x1405, 0x1408,0x140b,0x140e,0x1411,0x1414,0x1417,0x141a,0x141d, 0x1420,0x1423,0x1426,0x1429,0x142c,0x142f,0x1432,0x1435, 0x1438,0x143b,0x143e,0x1441,0x1444,0x1447,0x144a,0x144d, 0x0000,0x0000,0x1450,0x1453,0x1456,0x1459,0x145c,0x145f, 0x1462,0x1465,0x1468,0x146b,0x146e,0x1471,0x1474,0x1477, 0x147a,0x147d,0x1480,0x1483,0x1486,0x1489,0x148c,0x148f, 0x1492,0x1495,0x1498,0x149b,0x149e,0x14a1,0x14a4,0x14a7, 0x14aa,0x14ad,0x14b0,0x14b3,0x14b6,0x14b9,0x14bc,0x14bf, 0x14c2,0x14c5,0x14c8,0x14cb,0x14ce,0x14d1,0x14d4,0x14d7, 0x14da,0x14dd,0x14e0,0x14e3,0x14e6,0x14e9,0x14ec,0x14ef, 0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000, 0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000, 0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000, 0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000, 0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000, 0x14f2,0x14f5,0x1cf8,0x1cfc,0x1d00,0x1d04,0x1d08,0x1d0c, 0x1d10,0x1514,0x8d17,0x3d29,0x1d31,0x0000,0x0000,0x0000, 0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000, 0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000, 0x0535,0x0536,0x0537,0x0538,0x0539,0x053a,0x053b,0x053c, 0x053d,0x053e,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000, 0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000, 0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000, 0x053f,0x0540,0x0541,0x0542,0x0543,0x0544,0x0545,0x0546, 0x0547,0x0548,0x0549,0x054a,0x054b,0x054c,0x054d,0x054e, 0x054f,0x0550,0x0551,0x0552,0x0553,0x0000,0x0000,0x0554, 0x0555,0x0556,0x0557,0x0558,0x0559,0x055a,0x055b,0x055c, 0x055d,0x055e,0x055f,0x0000,0x0560,0x0561,0x0562,0x0563, 0x0564,0x0565,0x0566,0x0567,0x0568,0x0569,0x056a,0x056b, 0x056c,0x056d,0x056e,0x056f,0x0570,0x0571,0x0572,0x0000, 0x0573,0x0574,0x0575,0x0576,0x0000,0x0000,0x0000,0x0000, 0x0d77,0x0d79,0x0d7b,0x0000,0x0d7d,0x0000,0x0d7f,0x0d81, 0x0d83,0x0d85,0x0d87,0x0d89,0x0d8b,0x0d8d,0x0d8f,0x0d91, 0x0593,0x0594,0x0595,0x0596,0x0597,0x0598,0x0599,0x059a, 0x059b,0x059c,0x059d,0x059e,0x059f,0x05a0,0x05a1,0x05a2, 0x05a3,0x05a4,0x05a5,0x05a6,0x05a7,0x05a8,0x05a9,0x05aa, 0x05ab,0x05ac,0x05ad,0x05ae,0x05af,0x05b0,0x05b1,0x05b2, 0x05b3,0x05b4,0x05b5,0x05b6,0x05b7,0x05b8,0x05b9,0x05ba, 0x05bb,0x05bc,0x05bd,0x05be,0x05bf,0x05c0,0x05c1,0x05c2, 0x05c3,0x05c4,0x05c5,0x05c6,0x05c7,0x05c8,0x05c9,0x05ca, 0x05cb,0x05cc,0x05cd,0x05ce,0x05cf,0x05d0,0x05d1,0x05d2, 0x05d3,0x05d4,0x05d5,0x05d6,0x05d7,0x05d8,0x05d9,0x05da, 0x05db,0x05dc,0x05dd,0x05de,0x05df,0x05e0,0x05e1,0x05e2, 0x05e3,0x05e4,0x05e5,0x05e6,0x05e7,0x05e8,0x05e9,0x05ea, 0x05eb,0x05ec,0x05ed,0x05ee,0x05ef,0x05f0,0x05f1,0x05f2, 0x05f3,0x05f4,0x05f5,0x05f6,0x05f7,0x05f8,0x05f9,0x05fa, 0x05fb,0x05fc,0x05fd,0x05fe,0x05ff,0x0600,0x0601,0x0602, 0x0603,0x0604,0x0605,0x0606,0x0607,0x0e08,0x0e0a,0x0e0c, 0x0e0e,0x0e10,0x0e12,0x0e14,0x0e16 }; /* BMP high decompositions */ static unsigned short ucs4_dbmphitab[1560] = { 0x0066,0x0066,0x0066,0x0069,0x0066,0x006c,0x0066,0x0066, 0x0069,0x0066,0x0066,0x006c,0x017f,0x0074,0x0073,0x0074, 0x0574,0x0576,0x0574,0x0565,0x0574,0x056b,0x057e,0x0576, 0x0574,0x056d,0x05d9,0x05b4,0x05f2,0x05b7,0x05e2,0x05d0, 0x05d3,0x05d4,0x05db,0x05dc,0x05dd,0x05e8,0x05ea,0x002b, 0x05e9,0x05c1,0x05e9,0x05c2,0xfb49,0x05c1,0xfb49,0x05c2, 0x05d0,0x05b7,0x05d0,0x05b8,0x05d0,0x05bc,0x05d1,0x05bc, 0x05d2,0x05bc,0x05d3,0x05bc,0x05d4,0x05bc,0x05d5,0x05bc, 0x05d6,0x05bc,0x05d8,0x05bc,0x05d9,0x05bc,0x05da,0x05bc, 0x05db,0x05bc,0x05dc,0x05bc,0x05de,0x05bc,0x05e0,0x05bc, 0x05e1,0x05bc,0x05e3,0x05bc,0x05e4,0x05bc,0x05e6,0x05bc, 0x05e7,0x05bc,0x05e8,0x05bc,0x05e9,0x05bc,0x05ea,0x05bc, 0x05d5,0x05b9,0x05d1,0x05bf,0x05db,0x05bf,0x05e4,0x05bf, 0x05d0,0x05dc,0x0671,0x0671,0x067b,0x067b,0x067b,0x067b, 0x067e,0x067e,0x067e,0x067e,0x0680,0x0680,0x0680,0x0680, 0x067a,0x067a,0x067a,0x067a,0x067f,0x067f,0x067f,0x067f, 0x0679,0x0679,0x0679,0x0679,0x06a4,0x06a4,0x06a4,0x06a4, 0x06a6,0x06a6,0x06a6,0x06a6,0x0684,0x0684,0x0684,0x0684, 0x0683,0x0683,0x0683,0x0683,0x0686,0x0686,0x0686,0x0686, 0x0687,0x0687,0x0687,0x0687,0x068d,0x068d,0x068c,0x068c, 0x068e,0x068e,0x0688,0x0688,0x0698,0x0698,0x0691,0x0691, 0x06a9,0x06a9,0x06a9,0x06a9,0x06af,0x06af,0x06af,0x06af, 0x06b3,0x06b3,0x06b3,0x06b3,0x06b1,0x06b1,0x06b1,0x06b1, 0x06ba,0x06ba,0x06bb,0x06bb,0x06bb,0x06bb,0x06c0,0x06c0, 0x06c1,0x06c1,0x06c1,0x06c1,0x06be,0x06be,0x06be,0x06be, 0x06d2,0x06d2,0x06d3,0x06d3,0x06ad,0x06ad,0x06ad,0x06ad, 0x06c7,0x06c7,0x06c6,0x06c6,0x06c8,0x06c8,0x0677,0x06cb, 0x06cb,0x06c5,0x06c5,0x06c9,0x06c9,0x06d0,0x06d0,0x06d0, 0x06d0,0x0649,0x0649,0x0626,0x0627,0x0626,0x0627,0x0626, 0x06d5,0x0626,0x06d5,0x0626,0x0648,0x0626,0x0648,0x0626, 0x06c7,0x0626,0x06c7,0x0626,0x06c6,0x0626,0x06c6,0x0626, 0x06c8,0x0626,0x06c8,0x0626,0x06d0,0x0626,0x06d0,0x0626, 0x06d0,0x0626,0x0649,0x0626,0x0649,0x0626,0x0649,0x06cc, 0x06cc,0x06cc,0x06cc,0x0626,0x062c,0x0626,0x062d,0x0626, 0x0645,0x0626,0x0649,0x0626,0x064a,0x0628,0x062c,0x0628, 0x062d,0x0628,0x062e,0x0628,0x0645,0x0628,0x0649,0x0628, 0x064a,0x062a,0x062c,0x062a,0x062d,0x062a,0x062e,0x062a, 0x0645,0x062a,0x0649,0x062a,0x064a,0x062b,0x062c,0x062b, 0x0645,0x062b,0x0649,0x062b,0x064a,0x062c,0x062d,0x062c, 0x0645,0x062d,0x062c,0x062d,0x0645,0x062e,0x062c,0x062e, 0x062d,0x062e,0x0645,0x0633,0x062c,0x0633,0x062d,0x0633, 0x062e,0x0633,0x0645,0x0635,0x062d,0x0635,0x0645,0x0636, 0x062c,0x0636,0x062d,0x0636,0x062e,0x0636,0x0645,0x0637, 0x062d,0x0637,0x0645,0x0638,0x0645,0x0639,0x062c,0x0639, 0x0645,0x063a,0x062c,0x063a,0x0645,0x0641,0x062c,0x0641, 0x062d,0x0641,0x062e,0x0641,0x0645,0x0641,0x0649,0x0641, 0x064a,0x0642,0x062d,0x0642,0x0645,0x0642,0x0649,0x0642, 0x064a,0x0643,0x0627,0x0643,0x062c,0x0643,0x062d,0x0643, 0x062e,0x0643,0x0644,0x0643,0x0645,0x0643,0x0649,0x0643, 0x064a,0x0644,0x062c,0x0644,0x062d,0x0644,0x062e,0x0644, 0x0645,0x0644,0x0649,0x0644,0x064a,0x0645,0x062c,0x0645, 0x062d,0x0645,0x062e,0x0645,0x0645,0x0645,0x0649,0x0645, 0x064a,0x0646,0x062c,0x0646,0x062d,0x0646,0x062e,0x0646, 0x0645,0x0646,0x0649,0x0646,0x064a,0x0647,0x062c,0x0647, 0x0645,0x0647,0x0649,0x0647,0x064a,0x064a,0x062c,0x064a, 0x062d,0x064a,0x062e,0x064a,0x0645,0x064a,0x0649,0x064a, 0x064a,0x0630,0x0670,0x0631,0x0670,0x0649,0x0670,0x0020, 0x064c,0x0651,0x0020,0x064d,0x0651,0x0020,0x064e,0x0651, 0x0020,0x064f,0x0651,0x0020,0x0650,0x0651,0x0020,0x0651, 0x0670,0x0626,0x0631,0x0626,0x0632,0x0626,0x0645,0x0626, 0x0646,0x0626,0x0649,0x0626,0x064a,0x0628,0x0631,0x0628, 0x0632,0x0628,0x0645,0x0628,0x0646,0x0628,0x0649,0x0628, 0x064a,0x062a,0x0631,0x062a,0x0632,0x062a,0x0645,0x062a, 0x0646,0x062a,0x0649,0x062a,0x064a,0x062b,0x0631,0x062b, 0x0632,0x062b,0x0645,0x062b,0x0646,0x062b,0x0649,0x062b, 0x064a,0x0641,0x0649,0x0641,0x064a,0x0642,0x0649,0x0642, 0x064a,0x0643,0x0627,0x0643,0x0644,0x0643,0x0645,0x0643, 0x0649,0x0643,0x064a,0x0644,0x0645,0x0644,0x0649,0x0644, 0x064a,0x0645,0x0627,0x0645,0x0645,0x0646,0x0631,0x0646, 0x0632,0x0646,0x0645,0x0646,0x0646,0x0646,0x0649,0x0646, 0x064a,0x0649,0x0670,0x064a,0x0631,0x064a,0x0632,0x064a, 0x0645,0x064a,0x0646,0x064a,0x0649,0x064a,0x064a,0x0626, 0x062c,0x0626,0x062d,0x0626,0x062e,0x0626,0x0645,0x0626, 0x0647,0x0628,0x062c,0x0628,0x062d,0x0628,0x062e,0x0628, 0x0645,0x0628,0x0647,0x062a,0x062c,0x062a,0x062d,0x062a, 0x062e,0x062a,0x0645,0x062a,0x0647,0x062b,0x0645,0x062c, 0x062d,0x062c,0x0645,0x062d,0x062c,0x062d,0x0645,0x062e, 0x062c,0x062e,0x0645,0x0633,0x062c,0x0633,0x062d,0x0633, 0x062e,0x0633,0x0645,0x0635,0x062d,0x0635,0x062e,0x0635, 0x0645,0x0636,0x062c,0x0636,0x062d,0x0636,0x062e,0x0636, 0x0645,0x0637,0x062d,0x0638,0x0645,0x0639,0x062c,0x0639, 0x0645,0x063a,0x062c,0x063a,0x0645,0x0641,0x062c,0x0641, 0x062d,0x0641,0x062e,0x0641,0x0645,0x0642,0x062d,0x0642, 0x0645,0x0643,0x062c,0x0643,0x062d,0x0643,0x062e,0x0643, 0x0644,0x0643,0x0645,0x0644,0x062c,0x0644,0x062d,0x0644, 0x062e,0x0644,0x0645,0x0644,0x0647,0x0645,0x062c,0x0645, 0x062d,0x0645,0x062e,0x0645,0x0645,0x0646,0x062c,0x0646, 0x062d,0x0646,0x062e,0x0646,0x0645,0x0646,0x0647,0x0647, 0x062c,0x0647,0x0645,0x0647,0x0670,0x064a,0x062c,0x064a, 0x062d,0x064a,0x062e,0x064a,0x0645,0x064a,0x0647,0x0626, 0x0645,0x0626,0x0647,0x0628,0x0645,0x0628,0x0647,0x062a, 0x0645,0x062a,0x0647,0x062b,0x0645,0x062b,0x0647,0x0633, 0x0645,0x0633,0x0647,0x0634,0x0645,0x0634,0x0647,0x0643, 0x0644,0x0643,0x0645,0x0644,0x0645,0x0646,0x0645,0x0646, 0x0647,0x064a,0x0645,0x064a,0x0647,0x0640,0x064e,0x0651, 0x0640,0x064f,0x0651,0x0640,0x0650,0x0651,0x0637,0x0649, 0x0637,0x064a,0x0639,0x0649,0x0639,0x064a,0x063a,0x0649, 0x063a,0x064a,0x0633,0x0649,0x0633,0x064a,0x0634,0x0649, 0x0634,0x064a,0x062d,0x0649,0x062d,0x064a,0x062c,0x0649, 0x062c,0x064a,0x062e,0x0649,0x062e,0x064a,0x0635,0x0649, 0x0635,0x064a,0x0636,0x0649,0x0636,0x064a,0x0634,0x062c, 0x0634,0x062d,0x0634,0x062e,0x0634,0x0645,0x0634,0x0631, 0x0633,0x0631,0x0635,0x0631,0x0636,0x0631,0x0637,0x0649, 0x0637,0x064a,0x0639,0x0649,0x0639,0x064a,0x063a,0x0649, 0x063a,0x064a,0x0633,0x0649,0x0633,0x064a,0x0634,0x0649, 0x0634,0x064a,0x062d,0x0649,0x062d,0x064a,0x062c,0x0649, 0x062c,0x064a,0x062e,0x0649,0x062e,0x064a,0x0635,0x0649, 0x0635,0x064a,0x0636,0x0649,0x0636,0x064a,0x0634,0x062c, 0x0634,0x062d,0x0634,0x062e,0x0634,0x0645,0x0634,0x0631, 0x0633,0x0631,0x0635,0x0631,0x0636,0x0631,0x0634,0x062c, 0x0634,0x062d,0x0634,0x062e,0x0634,0x0645,0x0633,0x0647, 0x0634,0x0647,0x0637,0x0645,0x0633,0x062c,0x0633,0x062d, 0x0633,0x062e,0x0634,0x062c,0x0634,0x062d,0x0634,0x062e, 0x0637,0x0645,0x0638,0x0645,0x0627,0x064b,0x0627,0x064b, 0x062a,0x062c,0x0645,0x062a,0x062d,0x062c,0x062a,0x062d, 0x062c,0x062a,0x062d,0x0645,0x062a,0x062e,0x0645,0x062a, 0x0645,0x062c,0x062a,0x0645,0x062d,0x062a,0x0645,0x062e, 0x062c,0x0645,0x062d,0x062c,0x0645,0x062d,0x062d,0x0645, 0x064a,0x062d,0x0645,0x0649,0x0633,0x062d,0x062c,0x0633, 0x062c,0x062d,0x0633,0x062c,0x0649,0x0633,0x0645,0x062d, 0x0633,0x0645,0x062d,0x0633,0x0645,0x062c,0x0633,0x0645, 0x0645,0x0633,0x0645,0x0645,0x0635,0x062d,0x062d,0x0635, 0x062d,0x062d,0x0635,0x0645,0x0645,0x0634,0x062d,0x0645, 0x0634,0x062d,0x0645,0x0634,0x062c,0x064a,0x0634,0x0645, 0x062e,0x0634,0x0645,0x062e,0x0634,0x0645,0x0645,0x0634, 0x0645,0x0645,0x0636,0x062d,0x0649,0x0636,0x062e,0x0645, 0x0636,0x062e,0x0645,0x0637,0x0645,0x062d,0x0637,0x0645, 0x062d,0x0637,0x0645,0x0645,0x0637,0x0645,0x064a,0x0639, 0x062c,0x0645,0x0639,0x0645,0x0645,0x0639,0x0645,0x0645, 0x0639,0x0645,0x0649,0x063a,0x0645,0x0645,0x063a,0x0645, 0x064a,0x063a,0x0645,0x0649,0x0641,0x062e,0x0645,0x0641, 0x062e,0x0645,0x0642,0x0645,0x062d,0x0642,0x0645,0x0645, 0x0644,0x062d,0x0645,0x0644,0x062d,0x064a,0x0644,0x062d, 0x0649,0x0644,0x062c,0x062c,0x0644,0x062c,0x062c,0x0644, 0x062e,0x0645,0x0644,0x062e,0x0645,0x0644,0x0645,0x062d, 0x0644,0x0645,0x062d,0x0645,0x062d,0x062c,0x0645,0x062d, 0x0645,0x0645,0x062d,0x064a,0x0645,0x062c,0x062d,0x0645, 0x062c,0x0645,0x0645,0x062e,0x062c,0x0645,0x062e,0x0645, 0x0645,0x062c,0x062e,0x0647,0x0645,0x062c,0x0647,0x0645, 0x0645,0x0646,0x062d,0x0645,0x0646,0x062d,0x0649,0x0646, 0x062c,0x0645,0x0646,0x062c,0x0645,0x0646,0x062c,0x0649, 0x0646,0x0645,0x064a,0x0646,0x0645,0x0649,0x064a,0x0645, 0x0645,0x064a,0x0645,0x0645,0x0628,0x062e,0x064a,0x062a, 0x062c,0x064a,0x062a,0x062c,0x0649,0x062a,0x062e,0x064a, 0x062a,0x062e,0x0649,0x062a,0x0645,0x064a,0x062a,0x0645, 0x0649,0x062c,0x0645,0x064a,0x062c,0x062d,0x0649,0x062c, 0x0645,0x0649,0x0633,0x062e,0x0649,0x0635,0x062d,0x064a, 0x0634,0x062d,0x064a,0x0636,0x062d,0x064a,0x0644,0x062c, 0x064a,0x0644,0x0645,0x064a,0x064a,0x062d,0x064a,0x064a, 0x062c,0x064a,0x064a,0x0645,0x064a,0x0645,0x0645,0x064a, 0x0642,0x0645,0x064a,0x0646,0x062d,0x064a,0x0642,0x0645, 0x062d,0x0644,0x062d,0x0645,0x0639,0x0645,0x064a,0x0643, 0x0645,0x064a,0x0646,0x062c,0x062d,0x0645,0x062e,0x064a, 0x0644,0x062c,0x0645,0x0643,0x0645,0x0645,0x0644,0x062c, 0x0645,0x0646,0x062c,0x062d,0x062c,0x062d,0x064a,0x062d, 0x062c,0x064a,0x0645,0x062c,0x064a,0x0641,0x0645,0x064a, 0x0628,0x062d,0x064a,0x0643,0x0645,0x0645,0x0639,0x062c, 0x0645,0x0635,0x0645,0x0645,0x0633,0x062e,0x064a,0x0646, 0x062c,0x064a,0x0635,0x0644,0x06d2,0x0642,0x0644,0x06d2, 0x0627,0x0644,0x0644,0x0647,0x0627,0x0643,0x0628,0x0631, 0x0645,0x062d,0x0645,0x062f,0x0635,0x0644,0x0639,0x0645, 0x0631,0x0633,0x0648,0x0644,0x0639,0x0644,0x064a,0x0647, 0x0648,0x0633,0x0644,0x0645,0x0635,0x0644,0x0649,0x0635, 0x0644,0x0649,0x0020,0x0627,0x0644,0x0644,0x0647,0x0020, 0x0639,0x0644,0x064a,0x0647,0x0020,0x0648,0x0633,0x0644, 0x0645,0x062c,0x0644,0x0020,0x062c,0x0644,0x0627,0x0644, 0x0647,0x0631,0x06cc,0x0627,0x0644,0x002c,0x3001,0x3002, 0x003a,0x003b,0x0021,0x003f,0x3016,0x3017,0x2026,0x2025, 0x2014,0x2013,0x005f,0x005f,0x0028,0x0029,0x007b,0x007d, 0x3014,0x3015,0x3010,0x3011,0x300a,0x300b,0x3008,0x3009, 0x300c,0x300d,0x300e,0x300f,0x005b,0x005d,0x203e,0x203e, 0x203e,0x203e,0x005f,0x005f,0x005f,0x002c,0x3001,0x002e, 0x003b,0x003a,0x003f,0x0021,0x2014,0x0028,0x0029,0x007b, 0x007d,0x3014,0x3015,0x0023,0x0026,0x002a,0x002b,0x002d, 0x003c,0x003e,0x003d,0x005c,0x0024,0x0025,0x0040,0x0020, 0x064b,0x0640,0x064b,0x0020,0x064c,0x0020,0x064d,0x0020, 0x064e,0x0640,0x064e,0x0020,0x064f,0x0640,0x064f,0x0020, 0x0650,0x0640,0x0650,0x0020,0x0651,0x0640,0x0651,0x0020, 0x0652,0x0640,0x0652,0x0621,0x0622,0x0622,0x0623,0x0623, 0x0624,0x0624,0x0625,0x0625,0x0626,0x0626,0x0626,0x0626, 0x0627,0x0627,0x0628,0x0628,0x0628,0x0628,0x0629,0x0629, 0x062a,0x062a,0x062a,0x062a,0x062b,0x062b,0x062b,0x062b, 0x062c,0x062c,0x062c,0x062c,0x062d,0x062d,0x062d,0x062d, 0x062e,0x062e,0x062e,0x062e,0x062f,0x062f,0x0630,0x0630, 0x0631,0x0631,0x0632,0x0632,0x0633,0x0633,0x0633,0x0633, 0x0634,0x0634,0x0634,0x0634,0x0635,0x0635,0x0635,0x0635, 0x0636,0x0636,0x0636,0x0636,0x0637,0x0637,0x0637,0x0637, 0x0638,0x0638,0x0638,0x0638,0x0639,0x0639,0x0639,0x0639, 0x063a,0x063a,0x063a,0x063a,0x0641,0x0641,0x0641,0x0641, 0x0642,0x0642,0x0642,0x0642,0x0643,0x0643,0x0643,0x0643, 0x0644,0x0644,0x0644,0x0644,0x0645,0x0645,0x0645,0x0645, 0x0646,0x0646,0x0646,0x0646,0x0647,0x0647,0x0647,0x0647, 0x0648,0x0648,0x0649,0x0649,0x064a,0x064a,0x064a,0x064a, 0x0644,0x0622,0x0644,0x0622,0x0644,0x0623,0x0644,0x0623, 0x0644,0x0625,0x0644,0x0625,0x0644,0x0627,0x0644,0x0627, }; #define UCS4_BMPHALFFULLMIN 0xff00 #define UCS4_BMPHALFFULLMAX 0xffef static const unsigned short ucs4_bmphalffulldecomptab[240] = { 0x0000,0x0021,0x0022,0x0023,0x0024,0x0025,0x0026,0x0027, 0x0028,0x0029,0x002a,0x002b,0x002c,0x002d,0x002e,0x002f, 0x0030,0x0031,0x0032,0x0033,0x0034,0x0035,0x0036,0x0037, 0x0038,0x0039,0x003a,0x003b,0x003c,0x003d,0x003e,0x003f, 0x0040,0x0041,0x0042,0x0043,0x0044,0x0045,0x0046,0x0047, 0x0048,0x0049,0x004a,0x004b,0x004c,0x004d,0x004e,0x004f, 0x0050,0x0051,0x0052,0x0053,0x0054,0x0055,0x0056,0x0057, 0x0058,0x0059,0x005a,0x005b,0x005c,0x005d,0x005e,0x005f, 0x0060,0x0061,0x0062,0x0063,0x0064,0x0065,0x0066,0x0067, 0x0068,0x0069,0x006a,0x006b,0x006c,0x006d,0x006e,0x006f, 0x0070,0x0071,0x0072,0x0073,0x0074,0x0075,0x0076,0x0077, 0x0078,0x0079,0x007a,0x007b,0x007c,0x007d,0x007e,0x2985, 0x2986,0x3002,0x300c,0x300d,0x3001,0x30fb,0x30f2,0x30a1, 0x30a3,0x30a5,0x30a7,0x30a9,0x30e3,0x30e5,0x30e7,0x30c3, 0x30fc,0x30a2,0x30a4,0x30a6,0x30a8,0x30aa,0x30ab,0x30ad, 0x30af,0x30b1,0x30b3,0x30b5,0x30b7,0x30b9,0x30bb,0x30bd, 0x30bf,0x30c1,0x30c4,0x30c6,0x30c8,0x30ca,0x30cb,0x30cc, 0x30cd,0x30ce,0x30cf,0x30d2,0x30d5,0x30d8,0x30db,0x30de, 0x30df,0x30e0,0x30e1,0x30e2,0x30e4,0x30e6,0x30e8,0x30e9, 0x30ea,0x30eb,0x30ec,0x30ed,0x30ef,0x30f3,0x3099,0x309a, 0x3164,0x3131,0x3132,0x3133,0x3134,0x3135,0x3136,0x3137, 0x3138,0x3139,0x313a,0x313b,0x313c,0x313d,0x313e,0x313f, 0x3140,0x3141,0x3142,0x3143,0x3144,0x3145,0x3146,0x3147, 0x3148,0x3149,0x314a,0x314b,0x314c,0x314d,0x314e,0x0000, 0x0000,0x0000,0x314f,0x3150,0x3151,0x3152,0x3153,0x3154, 0x0000,0x0000,0x3155,0x3156,0x3157,0x3158,0x3159,0x315a, 0x0000,0x0000,0x315b,0x315c,0x315d,0x315e,0x315f,0x3160, 0x0000,0x0000,0x3161,0x3162,0x3163,0x0000,0x0000,0x0000, 0x00a2,0x00a3,0x00ac,0x00af,0x00a6,0x00a5,0x20a9,0x0000, 0x2502,0x2190,0x2191,0x2192,0x2193,0x25a0,0x25cb,0x0000 }; /* SMP decompositions */ /* Musical */ #define UCS4_SMPMUSIC1MIN 0x1d15e #define UCS4_SMPMUSIC1MAX 0x1d164 static const unsigned long ucs4_smpmusic1decomptab[7][2] = { {0x1d157,0x1d165},{0x1d158,0x1d165},{0x1d15f,0x1d16e},{0x1d15f,0x1d16f}, {0x1d15f,0x1d170},{0x1d15f,0x1d171},{0x1d15f,0x1d172} }; #define UCS4_SMPMUSIC2MIN 0x1d1bb #define UCS4_SMPMUSIC2MAX 0x1d1c0 static const unsigned long ucs4_smpmusic2decomptab[6][2] = { {0x1d1b9,0x1d165},{0x1d1ba,0x1d165},{0x1d1bb,0x1d16e}, {0x1d1bc,0x1d16e},{0x1d1bb,0x1d16f},{0x1d1bc,0x1d16f} }; #define UCS4_SMPMATHMIN 0x1d400 #define UCS4_SMPMATHMAX 0x1d7ff /* Mathematical - 0 means hole (no decomposition) */ static const unsigned short ucs4_smpmathdecomptab[1024] = { 0x0041,0x0042,0x0043,0x0044,0x0045,0x0046,0x0047,0x0048, 0x0049,0x004a,0x004b,0x004c,0x004d,0x004e,0x004f,0x0050, 0x0051,0x0052,0x0053,0x0054,0x0055,0x0056,0x0057,0x0058, 0x0059,0x005a,0x0061,0x0062,0x0063,0x0064,0x0065,0x0066, 0x0067,0x0068,0x0069,0x006a,0x006b,0x006c,0x006d,0x006e, 0x006f,0x0070,0x0071,0x0072,0x0073,0x0074,0x0075,0x0076, 0x0077,0x0078,0x0079,0x007a,0x0041,0x0042,0x0043,0x0044, 0x0045,0x0046,0x0047,0x0048,0x0049,0x004a,0x004b,0x004c, 0x004d,0x004e,0x004f,0x0050,0x0051,0x0052,0x0053,0x0054, 0x0055,0x0056,0x0057,0x0058,0x0059,0x005a,0x0061,0x0062, 0x0063,0x0064,0x0065,0x0066,0x0067,0x0000,0x0069,0x006a, 0x006b,0x006c,0x006d,0x006e,0x006f,0x0070,0x0071,0x0072, 0x0073,0x0074,0x0075,0x0076,0x0077,0x0078,0x0079,0x007a, 0x0041,0x0042,0x0043,0x0044,0x0045,0x0046,0x0047,0x0048, 0x0049,0x004a,0x004b,0x004c,0x004d,0x004e,0x004f,0x0050, 0x0051,0x0052,0x0053,0x0054,0x0055,0x0056,0x0057,0x0058, 0x0059,0x005a,0x0061,0x0062,0x0063,0x0064,0x0065,0x0066, 0x0067,0x0068,0x0069,0x006a,0x006b,0x006c,0x006d,0x006e, 0x006f,0x0070,0x0071,0x0072,0x0073,0x0074,0x0075,0x0076, 0x0077,0x0078,0x0079,0x007a,0x0041,0x0000,0x0043,0x0044, 0x0000,0x0000,0x0047,0x0000,0x004a,0x004b,0x0000,0x0000, 0x004e,0x004f,0x0050,0x0051,0x0000,0x0053,0x0054,0x0055, 0x0000,0x0056,0x0057,0x0058,0x0059,0x005a,0x0061,0x0062, 0x0063,0x0064,0x0000,0x0066,0x0000,0x0068,0x0069,0x006a, 0x006b,0x006c,0x006d,0x006e,0x0000,0x0070,0x0071,0x0072, 0x0073,0x0074,0x0075,0x0076,0x0077,0x0078,0x0079,0x007a, 0x0041,0x0042,0x0043,0x0044,0x0045,0x0046,0x0047,0x0048, 0x0049,0x004a,0x004b,0x004c,0x004d,0x004e,0x004f,0x0050, 0x0051,0x0052,0x0053,0x0054,0x0055,0x0056,0x0057,0x0058, 0x0059,0x005a,0x0061,0x0062,0x0063,0x0064,0x0065,0x0066, 0x0067,0x0068,0x0069,0x006a,0x006b,0x006c,0x006d,0x006e, 0x006f,0x0070,0x0071,0x0072,0x0073,0x0074,0x0075,0x0076, 0x0077,0x0078,0x0079,0x007a,0x0041,0x0042,0x0000,0x0044, 0x0045,0x0046,0x0047,0x0000,0x004a,0x004b,0x004c,0x004d, 0x0000,0x004e,0x004f,0x0050,0x0051,0x0000,0x0053,0x0054, 0x0055,0x0056,0x0057,0x0058,0x0059,0x0000,0x0061,0x0062, 0x0063,0x0064,0x0065,0x0066,0x0067,0x0068,0x0069,0x006a, 0x006b,0x006c,0x006d,0x006e,0x006f,0x0070,0x0071,0x0072, 0x0073,0x0074,0x0075,0x0076,0x0077,0x0078,0x0079,0x007a, 0x0041,0x0042,0x0000,0x0044,0x0045,0x0046,0x0047,0x0000, 0x0049,0x004a,0x004b,0x004c,0x004d,0x0000,0x004f,0x0000, 0x0000,0x0000,0x0053,0x0054,0x0055,0x0056,0x0057,0x0058, 0x0059,0x0000,0x0061,0x0062,0x0063,0x0064,0x0065,0x0066, 0x0067,0x0068,0x0069,0x006a,0x006b,0x006c,0x006d,0x006e, 0x006f,0x0070,0x0071,0x0072,0x0073,0x0074,0x0075,0x0076, 0x0077,0x0078,0x0079,0x007a,0x0041,0x0042,0x0043,0x0044, 0x0045,0x0046,0x0047,0x0048,0x0049,0x004a,0x004b,0x004c, 0x004d,0x004e,0x004f,0x0050,0x0051,0x0052,0x0053,0x0054, 0x0055,0x0056,0x0057,0x0058,0x0059,0x005a,0x0061,0x0062, 0x0063,0x0064,0x0065,0x0066,0x0067,0x0068,0x0069,0x006a, 0x006b,0x006c,0x006d,0x006e,0x006f,0x0070,0x0071,0x0072, 0x0073,0x0074,0x0075,0x0076,0x0077,0x0078,0x0079,0x007a, 0x0041,0x0042,0x0043,0x0044,0x0045,0x0046,0x0047,0x0048, 0x0049,0x004a,0x004b,0x004c,0x004d,0x004e,0x004f,0x0050, 0x0051,0x0052,0x0053,0x0054,0x0055,0x0056,0x0057,0x0058, 0x0059,0x005a,0x0061,0x0062,0x0063,0x0064,0x0065,0x0066, 0x0067,0x0068,0x0069,0x006a,0x006b,0x006c,0x006d,0x006e, 0x006f,0x0070,0x0071,0x0072,0x0073,0x0074,0x0075,0x0076, 0x0077,0x0078,0x0079,0x007a,0x0041,0x0042,0x0043,0x0044, 0x0045,0x0046,0x0047,0x0048,0x0049,0x004a,0x004b,0x004c, 0x004d,0x004e,0x004f,0x0050,0x0051,0x0052,0x0053,0x0054, 0x0055,0x0056,0x0057,0x0058,0x0059,0x005a,0x0061,0x0062, 0x0063,0x0064,0x0065,0x0066,0x0067,0x0068,0x0069,0x006a, 0x006b,0x006c,0x006d,0x006e,0x006f,0x0070,0x0071,0x0072, 0x0073,0x0074,0x0075,0x0076,0x0077,0x0078,0x0079,0x007a, 0x0041,0x0042,0x0043,0x0044,0x0045,0x0046,0x0047,0x0048, 0x0049,0x004a,0x004b,0x004c,0x004d,0x004e,0x004f,0x0050, 0x0051,0x0052,0x0053,0x0054,0x0055,0x0056,0x0057,0x0058, 0x0059,0x005a,0x0061,0x0062,0x0063,0x0064,0x0065,0x0066, 0x0067,0x0068,0x0069,0x006a,0x006b,0x006c,0x006d,0x006e, 0x006f,0x0070,0x0071,0x0072,0x0073,0x0074,0x0075,0x0076, 0x0077,0x0078,0x0079,0x007a,0x0041,0x0042,0x0043,0x0044, 0x0045,0x0046,0x0047,0x0048,0x0049,0x004a,0x004b,0x004c, 0x004d,0x004e,0x004f,0x0050,0x0051,0x0052,0x0053,0x0054, 0x0055,0x0056,0x0057,0x0058,0x0059,0x005a,0x0061,0x0062, 0x0063,0x0064,0x0065,0x0066,0x0067,0x0068,0x0069,0x006a, 0x006b,0x006c,0x006d,0x006e,0x006f,0x0070,0x0071,0x0072, 0x0073,0x0074,0x0075,0x0076,0x0077,0x0078,0x0079,0x007a, 0x0041,0x0042,0x0043,0x0044,0x0045,0x0046,0x0047,0x0048, 0x0049,0x004a,0x004b,0x004c,0x004d,0x004e,0x004f,0x0050, 0x0051,0x0052,0x0053,0x0054,0x0055,0x0056,0x0057,0x0058, 0x0059,0x005a,0x0061,0x0062,0x0063,0x0064,0x0065,0x0066, 0x0067,0x0068,0x0069,0x006a,0x006b,0x006c,0x006d,0x006e, 0x006f,0x0070,0x0071,0x0072,0x0073,0x0074,0x0075,0x0076, 0x0077,0x0078,0x0079,0x007a,0x0131,0x0237,0x0000,0x0000, 0x0391,0x0392,0x0393,0x0394,0x0395,0x0396,0x0397,0x0398, 0x0399,0x039a,0x039b,0x039c,0x039d,0x039e,0x039f,0x03a0, 0x03a1,0x03f4,0x03a3,0x03a4,0x03a5,0x03a6,0x03a7,0x03a8, 0x03a9,0x2207,0x03b1,0x03b2,0x03b3,0x03b4,0x03b5,0x03b6, 0x03b7,0x03b8,0x03b9,0x03ba,0x03bb,0x03bc,0x03bd,0x03be, 0x03bf,0x03c0,0x03c1,0x03c2,0x03c3,0x03c4,0x03c5,0x03c6, 0x03c7,0x03c8,0x03c9,0x2202,0x03f5,0x03d1,0x03f0,0x03d5, 0x03f1,0x03d6,0x0391,0x0392,0x0393,0x0394,0x0395,0x0396, 0x0397,0x0398,0x0399,0x039a,0x039b,0x039c,0x039d,0x039e, 0x039f,0x03a0,0x03a1,0x03f4,0x03a3,0x03a4,0x03a5,0x03a6, 0x03a7,0x03a8,0x03a9,0x2207,0x03b1,0x03b2,0x03b3,0x03b4, 0x03b5,0x03b6,0x03b7,0x03b8,0x03b9,0x03ba,0x03bb,0x03bc, 0x03bd,0x03be,0x03bf,0x03c0,0x03c1,0x03c2,0x03c3,0x03c4, 0x03c5,0x03c6,0x03c7,0x03c8,0x03c9,0x2202,0x03f5,0x03d1, 0x03f0,0x03d5,0x03f1,0x03d6,0x0391,0x0392,0x0393,0x0394, 0x0395,0x0396,0x0397,0x0398,0x0399,0x039a,0x039b,0x039c, 0x039d,0x039e,0x039f,0x03a0,0x03a1,0x03f4,0x03a3,0x03a4, 0x03a5,0x03a6,0x03a7,0x03a8,0x03a9,0x2207,0x03b1,0x03b2, 0x03b3,0x03b4,0x03b5,0x03b6,0x03b7,0x03b8,0x03b9,0x03ba, 0x03bb,0x03bc,0x03bd,0x03be,0x03bf,0x03c0,0x03c1,0x03c2, 0x03c3,0x03c4,0x03c5,0x03c6,0x03c7,0x03c8,0x03c9,0x2202, 0x03f5,0x03d1,0x03f0,0x03d5,0x03f1,0x03d6,0x0391,0x0392, 0x0393,0x0394,0x0395,0x0396,0x0397,0x0398,0x0399,0x039a, 0x039b,0x039c,0x039d,0x039e,0x039f,0x03a0,0x03a1,0x03f4, 0x03a3,0x03a4,0x03a5,0x03a6,0x03a7,0x03a8,0x03a9,0x2207, 0x03b1,0x03b2,0x03b3,0x03b4,0x03b5,0x03b6,0x03b7,0x03b8, 0x03b9,0x03ba,0x03bb,0x03bc,0x03bd,0x03be,0x03bf,0x03c0, 0x03c1,0x03c2,0x03c3,0x03c4,0x03c5,0x03c6,0x03c7,0x03c8, 0x03c9,0x2202,0x03f5,0x03d1,0x03f0,0x03d5,0x03f1,0x03d6, 0x0391,0x0392,0x0393,0x0394,0x0395,0x0396,0x0397,0x0398, 0x0399,0x039a,0x039b,0x039c,0x039d,0x039e,0x039f,0x03a0, 0x03a1,0x03f4,0x03a3,0x03a4,0x03a5,0x03a6,0x03a7,0x03a8, 0x03a9,0x2207,0x03b1,0x03b2,0x03b3,0x03b4,0x03b5,0x03b6, 0x03b7,0x03b8,0x03b9,0x03ba,0x03bb,0x03bc,0x03bd,0x03be, 0x03bf,0x03c0,0x03c1,0x03c2,0x03c3,0x03c4,0x03c5,0x03c6, 0x03c7,0x03c8,0x03c9,0x2202,0x03f5,0x03d1,0x03f0,0x03d5, 0x03f1,0x03d6,0x03dc,0x03dd,0x0000,0x0000,0x0030,0x0031, 0x0032,0x0033,0x0034,0x0035,0x0036,0x0037,0x0038,0x0039, 0x0030,0x0031,0x0032,0x0033,0x0034,0x0035,0x0036,0x0037, 0x0038,0x0039,0x0030,0x0031,0x0032,0x0033,0x0034,0x0035, 0x0036,0x0037,0x0038,0x0039,0x0030,0x0031,0x0032,0x0033, 0x0034,0x0035,0x0036,0x0037,0x0038,0x0039,0x0030,0x0031, 0x0032,0x0033,0x0034,0x0035,0x0036,0x0037,0x0038,0x0039 }; /* SIP decompositions */ #define UCS4_SIPMIN 0x2f800 #define UCS4_SIPMAX 0x2fa1d /* CJK compatibility ideographs - no holes */ static const unsigned long ucs4_sipdecomptab[542] = { 0x4e3d, 0x4e38, 0x4e41,0x20122, 0x4f60, 0x4fae, 0x4fbb, 0x5002, 0x507a, 0x5099, 0x50e7, 0x50cf, 0x349e,0x2063a, 0x514d, 0x5154, 0x5164, 0x5177,0x2051c, 0x34b9, 0x5167, 0x518d,0x2054b, 0x5197, 0x51a4, 0x4ecc, 0x51ac, 0x51b5,0x291df, 0x51f5, 0x5203, 0x34df, 0x523b, 0x5246, 0x5272, 0x5277, 0x3515, 0x52c7, 0x52c9, 0x52e4, 0x52fa, 0x5305, 0x5306, 0x5317, 0x5349, 0x5351, 0x535a, 0x5373, 0x537d, 0x537f, 0x537f, 0x537f,0x20a2c, 0x7070, 0x53ca, 0x53df, 0x20b63, 0x53eb, 0x53f1, 0x5406, 0x549e, 0x5438, 0x5448, 0x5468, 0x54a2, 0x54f6, 0x5510, 0x5553, 0x5563, 0x5584, 0x5584, 0x5599, 0x55ab, 0x55b3, 0x55c2, 0x5716, 0x5606, 0x5717, 0x5651, 0x5674, 0x5207, 0x58ee, 0x57ce, 0x57f4, 0x580d, 0x578b, 0x5832, 0x5831, 0x58ac,0x214e4, 0x58f2, 0x58f7, 0x5906, 0x591a, 0x5922, 0x5962, 0x216a8,0x216ea, 0x59ec, 0x5a1b, 0x5a27, 0x59d8, 0x5a66, 0x36ee, 0x36fc, 0x5b08, 0x5b3e, 0x5b3e,0x219c8, 0x5bc3, 0x5bd8, 0x5be7, 0x5bf3,0x21b18, 0x5bff, 0x5c06, 0x5f53, 0x5c22, 0x3781, 0x5c60, 0x5c6e, 0x5cc0, 0x5c8d,0x21de4, 0x5d43,0x21de6, 0x5d6e, 0x5d6b, 0x5d7c, 0x5de1, 0x5de2, 0x382f, 0x5dfd, 0x5e28, 0x5e3d, 0x5e69, 0x3862,0x22183, 0x387c, 0x5eb0, 0x5eb3, 0x5eb6, 0x5eca,0x2a392, 0x5efe,0x22331,0x22331, 0x8201, 0x5f22, 0x5f22, 0x38c7,0x232b8, 0x261da, 0x5f62, 0x5f6b, 0x38e3, 0x5f9a, 0x5fcd, 0x5fd7, 0x5ff9, 0x6081, 0x393a, 0x391c, 0x6094,0x226d4, 0x60c7, 0x6148, 0x614c, 0x614e, 0x614c, 0x617a, 0x618e, 0x61b2, 0x61a4, 0x61af, 0x61de, 0x61f2, 0x61f6, 0x6210, 0x621b, 0x625d, 0x62b1, 0x62d4, 0x6350, 0x22b0c, 0x633d, 0x62fc, 0x6368, 0x6383, 0x63e4,0x22bf1, 0x6422, 0x63c5, 0x63a9, 0x3a2e, 0x6469, 0x647e, 0x649d, 0x6477, 0x3a6c, 0x654f, 0x656c,0x2300a, 0x65e3, 0x66f8, 0x6649, 0x3b19, 0x6691, 0x3b08, 0x3ae4, 0x5192, 0x5195, 0x6700, 0x669c, 0x80ad, 0x43d9, 0x6717, 0x671b, 0x6721, 0x675e, 0x6753,0x233c3, 0x3b49, 0x67fa, 0x6785, 0x6852, 0x6885,0x2346d, 0x688e, 0x681f, 0x6914, 0x3b9d, 0x6942, 0x69a3, 0x69ea, 0x6aa8,0x236a3, 0x6adb, 0x3c18, 0x6b21, 0x238a7, 0x6b54, 0x3c4e, 0x6b72, 0x6b9f, 0x6bba, 0x6bbb,0x23a8d, 0x21d0b,0x23afa, 0x6c4e,0x23cbc, 0x6cbf, 0x6ccd, 0x6c67, 0x6d16, 0x6d3e, 0x6d77, 0x6d41, 0x6d69, 0x6d78, 0x6d85,0x23d1e, 0x6d34, 0x6e2f, 0x6e6e, 0x3d33, 0x6ecb, 0x6ec7,0x23ed1, 0x6df9, 0x6f6e, 0x23f5e,0x23f8e, 0x6fc6, 0x7039, 0x701e, 0x701b, 0x3d96, 0x704a, 0x707d, 0x7077, 0x70ad,0x20525, 0x7145,0x24263, 0x719c,0x243ab, 0x7228, 0x7235, 0x7250,0x24608, 0x7280, 0x7295,0x24735,0x24814, 0x737a, 0x738b, 0x3eac, 0x73a5, 0x3eb8, 0x3eb8, 0x7447, 0x745c, 0x7471, 0x7485, 0x74ca, 0x3f1b, 0x7524,0x24c36, 0x753e,0x24c92, 0x7570,0x2219f, 0x7610,0x24fa1,0x24fb8,0x25044, 0x3ffc, 0x4008, 0x76f4,0x250f3,0x250f2,0x25119,0x25133, 0x771e, 0x771f, 0x771f, 0x774a, 0x4039, 0x778b, 0x4046, 0x4096,0x2541d, 0x784e, 0x788c, 0x78cc, 0x40e3,0x25626, 0x7956,0x2569a,0x256c5, 0x798f, 0x79eb, 0x412f, 0x7a40, 0x7a4a, 0x7a4f,0x2597c,0x25aa7,0x25aa7, 0x7aee, 0x4202,0x25bab, 0x7bc6, 0x7bc9, 0x4227,0x25c80, 0x7cd2, 0x42a0, 0x7ce8, 0x7ce3, 0x7d00,0x25f86, 0x7d63, 0x4301, 0x7dc7, 0x7e02, 0x7e45, 0x4334,0x26228,0x26247, 0x4359,0x262d9, 0x7f7a,0x2633e, 0x7f95, 0x7ffa, 0x8005,0x264da,0x26523, 0x8060,0x265a8, 0x8070, 0x2335f, 0x43d5, 0x80b2, 0x8103, 0x440b, 0x813e, 0x5ab5,0x267a7, 0x267b5,0x23393,0x2339c, 0x8201, 0x8204, 0x8f9e, 0x446b, 0x8291, 0x828b, 0x829d, 0x52b3, 0x82b1, 0x82b3, 0x82bd, 0x82e6,0x26b3c, 0x82e5, 0x831d, 0x8363, 0x83ad, 0x8323, 0x83bd, 0x83e7, 0x8457, 0x8353, 0x83ca, 0x83cc, 0x83dc,0x26c36,0x26d6b,0x26cd5, 0x452b, 0x84f1, 0x84f3, 0x8516,0x273ca, 0x8564,0x26f2c, 0x455d, 0x4561, 0x26fb1,0x270d2, 0x456b, 0x8650, 0x865c, 0x8667, 0x8669, 0x86a9, 0x8688, 0x870e, 0x86e2, 0x8779, 0x8728, 0x876b, 0x8786, 0x45d7, 0x87e1, 0x8801, 0x45f9, 0x8860, 0x8863,0x27667, 0x88d7, 0x88de, 0x4635, 0x88fa, 0x34bb,0x278ae,0x27966, 0x46be, 0x46c7, 0x8aa0, 0x8aed, 0x8b8a, 0x8c55,0x27ca8, 0x8cab, 0x8cc1, 0x8d1b, 0x8d77, 0x27f2f,0x20804, 0x8dcb, 0x8dbc, 0x8df0,0x208de, 0x8ed4, 0x8f38, 0x285d2,0x285ed, 0x9094, 0x90f1, 0x9111,0x2872e, 0x911b, 0x9238, 0x92d7, 0x92d8, 0x927c, 0x93f9, 0x9415,0x28bfa, 0x958b, 0x4995, 0x95b7,0x28d77, 0x49e6, 0x96c3, 0x5db2, 0x9723,0x29145,0x2921a, 0x4a6e, 0x4a76, 0x97e0,0x2940a, 0x4ab2,0x29496, 0x980b, 0x980b, 0x9829,0x295b6, 0x98e2, 0x4b33, 0x9929, 0x99a7, 0x99c2, 0x99fe, 0x4bce,0x29b30, 0x9b12, 0x9c40, 0x9cfd, 0x4cce, 0x4ced, 0x9d67, 0x2a0ce, 0x4cf8,0x2a105,0x2a20e,0x2a291, 0x9ebb, 0x4d56, 0x9ef9, 0x9efe, 0x9f05, 0x9f0f, 0x9f16, 0x9f3b,0x2a600 }; alpine-2.10+dfsg/imap/src/charset/ksc_5601.c0000600000175000017500000054423711512502123022117 0ustar paulproteuspaulproteus/* ======================================================================== * Copyright 1988-2006 University of Washington * * Licensed under the Apache License, Version 2.0 (the "License"); * you may not use this file except in compliance with the License. * You may obtain a copy of the License at * * http://www.apache.org/licenses/LICENSE-2.0 * * * ======================================================================== */ /* * Program: KSC 5601 conversion table * * Author: Mark Crispin * Networks and Distributed Computing * Computing & Communications * University of Washington * Administration Building, AG-44 * Seattle, WA 98195 * Internet: MRC@CAC.Washington.EDU * * Date: 3 July 1997 * Last Edited: 30 August 2006 */ /* KSC 5601 is the national standard of the Republic of Korea (South Korea). * It is believed that it is also the de-facto standard of the Democratic * People's Republic of Korea (North Korea), although North Korea has its * own official national standard (KPS 9566-97). */ #define BASE_KSC5601_KU 0x81 #define BASE_KSC5601_TEN 0x41 #define MAX_KSC5601_KU 125 #define MAX_KSC5601_TEN 190 #define KSCTOUNICODE(c,c1,ku,ten) \ ((((ku = c - BASE_KSC5601_KU) < MAX_KSC5601_KU) && \ ((ten = c1 - BASE_KSC5601_TEN) < MAX_KSC5601_TEN)) ? \ ksc5601tab[ku][ten] : UBOGON) static const unsigned short ksc5601tab[MAX_KSC5601_KU][MAX_KSC5601_TEN] = { { /* ku 01 */ 0xac02,0xac03,0xac05,0xac06,0xac0b,0xac0c,0xac0d,0xac0e,0xac0f,0xac18, 0xac1e,0xac1f,0xac21,0xac22,0xac23,0xac25,0xac26,0xac27,0xac28,0xac29, 0xac2a,0xac2b,0xac2e,0xac32,0xac33,0xac34,UBOGON,UBOGON,UBOGON,UBOGON, UBOGON,UBOGON,0xac35,0xac36,0xac37,0xac3a,0xac3b,0xac3d,0xac3e,0xac3f, 0xac41,0xac42,0xac43,0xac44,0xac45,0xac46,0xac47,0xac48,0xac49,0xac4a, 0xac4c,0xac4e,0xac4f,0xac50,0xac51,0xac52,0xac53,0xac55,UBOGON,UBOGON, UBOGON,UBOGON,UBOGON,UBOGON,0xac56,0xac57,0xac59,0xac5a,0xac5b,0xac5d, 0xac5e,0xac5f,0xac60,0xac61,0xac62,0xac63,0xac64,0xac65,0xac66,0xac67, 0xac68,0xac69,0xac6a,0xac6b,0xac6c,0xac6d,0xac6e,0xac6f,0xac72,0xac73, 0xac75,0xac76,0xac79,0xac7b,0xac7c,0xac7d,0xac7e,0xac7f,0xac82,0xac87, 0xac88,0xac8d,0xac8e,0xac8f,0xac91,0xac92,0xac93,0xac95,0xac96,0xac97, 0xac98,0xac99,0xac9a,0xac9b,0xac9e,0xaca2,0xaca3,0xaca4,0xaca5,0xaca6, 0xaca7,0xacab,0xacad,0xacae,0xacb1,0xacb2,0xacb3,0xacb4,0xacb5,0xacb6, 0xacb7,0xacba,0xacbe,0xacbf,0xacc0,0xacc2,0xacc3,0xacc5,0xacc6,0xacc7, 0xacc9,0xacca,0xaccb,0xaccd,0xacce,0xaccf,0xacd0,0xacd1,0xacd2,0xacd3, 0xacd4,0xacd6,0xacd8,0xacd9,0xacda,0xacdb,0xacdc,0xacdd,0xacde,0xacdf, 0xace2,0xace3,0xace5,0xace6,0xace9,0xaceb,0xaced,0xacee,0xacf2,0xacf4, 0xacf7,0xacf8,0xacf9,0xacfa,0xacfb,0xacfe,0xacff,0xad01,0xad02,0xad03, 0xad05,0xad07,0xad08,0xad09,0xad0a,0xad0b,0xad0e,0xad10,0xad12,0xad13 }, { /* ku 02 */ 0xad14,0xad15,0xad16,0xad17,0xad19,0xad1a,0xad1b,0xad1d,0xad1e,0xad1f, 0xad21,0xad22,0xad23,0xad24,0xad25,0xad26,0xad27,0xad28,0xad2a,0xad2b, 0xad2e,0xad2f,0xad30,0xad31,0xad32,0xad33,UBOGON,UBOGON,UBOGON,UBOGON, UBOGON,UBOGON,0xad36,0xad37,0xad39,0xad3a,0xad3b,0xad3d,0xad3e,0xad3f, 0xad40,0xad41,0xad42,0xad43,0xad46,0xad48,0xad4a,0xad4b,0xad4c,0xad4d, 0xad4e,0xad4f,0xad51,0xad52,0xad53,0xad55,0xad56,0xad57,UBOGON,UBOGON, UBOGON,UBOGON,UBOGON,UBOGON,0xad59,0xad5a,0xad5b,0xad5c,0xad5d,0xad5e, 0xad5f,0xad60,0xad62,0xad64,0xad65,0xad66,0xad67,0xad68,0xad69,0xad6a, 0xad6b,0xad6e,0xad6f,0xad71,0xad72,0xad77,0xad78,0xad79,0xad7a,0xad7e, 0xad80,0xad83,0xad84,0xad85,0xad86,0xad87,0xad8a,0xad8b,0xad8d,0xad8e, 0xad8f,0xad91,0xad92,0xad93,0xad94,0xad95,0xad96,0xad97,0xad98,0xad99, 0xad9a,0xad9b,0xad9e,0xad9f,0xada0,0xada1,0xada2,0xada3,0xada5,0xada6, 0xada7,0xada8,0xada9,0xadaa,0xadab,0xadac,0xadad,0xadae,0xadaf,0xadb0, 0xadb1,0xadb2,0xadb3,0xadb4,0xadb5,0xadb6,0xadb8,0xadb9,0xadba,0xadbb, 0xadbc,0xadbd,0xadbe,0xadbf,0xadc2,0xadc3,0xadc5,0xadc6,0xadc7,0xadc9, 0xadca,0xadcb,0xadcc,0xadcd,0xadce,0xadcf,0xadd2,0xadd4,0xadd5,0xadd6, 0xadd7,0xadd8,0xadd9,0xadda,0xaddb,0xaddd,0xadde,0xaddf,0xade1,0xade2, 0xade3,0xade5,0xade6,0xade7,0xade8,0xade9,0xadea,0xadeb,0xadec,0xaded, 0xadee,0xadef,0xadf0,0xadf1,0xadf2,0xadf3,0xadf4,0xadf5,0xadf6,0xadf7 }, { /* ku 03 */ 0xadfa,0xadfb,0xadfd,0xadfe,0xae02,0xae03,0xae04,0xae05,0xae06,0xae07, 0xae0a,0xae0c,0xae0e,0xae0f,0xae10,0xae11,0xae12,0xae13,0xae15,0xae16, 0xae17,0xae18,0xae19,0xae1a,0xae1b,0xae1c,UBOGON,UBOGON,UBOGON,UBOGON, UBOGON,UBOGON,0xae1d,0xae1e,0xae1f,0xae20,0xae21,0xae22,0xae23,0xae24, 0xae25,0xae26,0xae27,0xae28,0xae29,0xae2a,0xae2b,0xae2c,0xae2d,0xae2e, 0xae2f,0xae32,0xae33,0xae35,0xae36,0xae39,0xae3b,0xae3c,UBOGON,UBOGON, UBOGON,UBOGON,UBOGON,UBOGON,0xae3d,0xae3e,0xae3f,0xae42,0xae44,0xae47, 0xae48,0xae49,0xae4b,0xae4f,0xae51,0xae52,0xae53,0xae55,0xae57,0xae58, 0xae59,0xae5a,0xae5b,0xae5e,0xae62,0xae63,0xae64,0xae66,0xae67,0xae6a, 0xae6b,0xae6d,0xae6e,0xae6f,0xae71,0xae72,0xae73,0xae74,0xae75,0xae76, 0xae77,0xae7a,0xae7e,0xae7f,0xae80,0xae81,0xae82,0xae83,0xae86,0xae87, 0xae88,0xae89,0xae8a,0xae8b,0xae8d,0xae8e,0xae8f,0xae90,0xae91,0xae92, 0xae93,0xae94,0xae95,0xae96,0xae97,0xae98,0xae99,0xae9a,0xae9b,0xae9c, 0xae9d,0xae9e,0xae9f,0xaea0,0xaea1,0xaea2,0xaea3,0xaea4,0xaea5,0xaea6, 0xaea7,0xaea8,0xaea9,0xaeaa,0xaeab,0xaeac,0xaead,0xaeae,0xaeaf,0xaeb0, 0xaeb1,0xaeb2,0xaeb3,0xaeb4,0xaeb5,0xaeb6,0xaeb7,0xaeb8,0xaeb9,0xaeba, 0xaebb,0xaebf,0xaec1,0xaec2,0xaec3,0xaec5,0xaec6,0xaec7,0xaec8,0xaec9, 0xaeca,0xaecb,0xaece,0xaed2,0xaed3,0xaed4,0xaed5,0xaed6,0xaed7,0xaeda, 0xaedb,0xaedd,0xaede,0xaedf,0xaee0,0xaee1,0xaee2,0xaee3,0xaee4,0xaee5 }, { /* ku 04 */ 0xaee6,0xaee7,0xaee9,0xaeea,0xaeec,0xaeee,0xaeef,0xaef0,0xaef1,0xaef2, 0xaef3,0xaef5,0xaef6,0xaef7,0xaef9,0xaefa,0xaefb,0xaefd,0xaefe,0xaeff, 0xaf00,0xaf01,0xaf02,0xaf03,0xaf04,0xaf05,UBOGON,UBOGON,UBOGON,UBOGON, UBOGON,UBOGON,0xaf06,0xaf09,0xaf0a,0xaf0b,0xaf0c,0xaf0e,0xaf0f,0xaf11, 0xaf12,0xaf13,0xaf14,0xaf15,0xaf16,0xaf17,0xaf18,0xaf19,0xaf1a,0xaf1b, 0xaf1c,0xaf1d,0xaf1e,0xaf1f,0xaf20,0xaf21,0xaf22,0xaf23,UBOGON,UBOGON, UBOGON,UBOGON,UBOGON,UBOGON,0xaf24,0xaf25,0xaf26,0xaf27,0xaf28,0xaf29, 0xaf2a,0xaf2b,0xaf2e,0xaf2f,0xaf31,0xaf33,0xaf35,0xaf36,0xaf37,0xaf38, 0xaf39,0xaf3a,0xaf3b,0xaf3e,0xaf40,0xaf44,0xaf45,0xaf46,0xaf47,0xaf4a, 0xaf4b,0xaf4c,0xaf4d,0xaf4e,0xaf4f,0xaf51,0xaf52,0xaf53,0xaf54,0xaf55, 0xaf56,0xaf57,0xaf58,0xaf59,0xaf5a,0xaf5b,0xaf5e,0xaf5f,0xaf60,0xaf61, 0xaf62,0xaf63,0xaf66,0xaf67,0xaf68,0xaf69,0xaf6a,0xaf6b,0xaf6c,0xaf6d, 0xaf6e,0xaf6f,0xaf70,0xaf71,0xaf72,0xaf73,0xaf74,0xaf75,0xaf76,0xaf77, 0xaf78,0xaf7a,0xaf7b,0xaf7c,0xaf7d,0xaf7e,0xaf7f,0xaf81,0xaf82,0xaf83, 0xaf85,0xaf86,0xaf87,0xaf89,0xaf8a,0xaf8b,0xaf8c,0xaf8d,0xaf8e,0xaf8f, 0xaf92,0xaf93,0xaf94,0xaf96,0xaf97,0xaf98,0xaf99,0xaf9a,0xaf9b,0xaf9d, 0xaf9e,0xaf9f,0xafa0,0xafa1,0xafa2,0xafa3,0xafa4,0xafa5,0xafa6,0xafa7, 0xafa8,0xafa9,0xafaa,0xafab,0xafac,0xafad,0xafae,0xafaf,0xafb0,0xafb1, 0xafb2,0xafb3,0xafb4,0xafb5,0xafb6,0xafb7,0xafba,0xafbb,0xafbd,0xafbe }, { /* ku 05 */ 0xafbf,0xafc1,0xafc2,0xafc3,0xafc4,0xafc5,0xafc6,0xafca,0xafcc,0xafcf, 0xafd0,0xafd1,0xafd2,0xafd3,0xafd5,0xafd6,0xafd7,0xafd8,0xafd9,0xafda, 0xafdb,0xafdd,0xafde,0xafdf,0xafe0,0xafe1,UBOGON,UBOGON,UBOGON,UBOGON, UBOGON,UBOGON,0xafe2,0xafe3,0xafe4,0xafe5,0xafe6,0xafe7,0xafea,0xafeb, 0xafec,0xafed,0xafee,0xafef,0xaff2,0xaff3,0xaff5,0xaff6,0xaff7,0xaff9, 0xaffa,0xaffb,0xaffc,0xaffd,0xaffe,0xafff,0xb002,0xb003,UBOGON,UBOGON, UBOGON,UBOGON,UBOGON,UBOGON,0xb005,0xb006,0xb007,0xb008,0xb009,0xb00a, 0xb00b,0xb00d,0xb00e,0xb00f,0xb011,0xb012,0xb013,0xb015,0xb016,0xb017, 0xb018,0xb019,0xb01a,0xb01b,0xb01e,0xb01f,0xb020,0xb021,0xb022,0xb023, 0xb024,0xb025,0xb026,0xb027,0xb029,0xb02a,0xb02b,0xb02c,0xb02d,0xb02e, 0xb02f,0xb030,0xb031,0xb032,0xb033,0xb034,0xb035,0xb036,0xb037,0xb038, 0xb039,0xb03a,0xb03b,0xb03c,0xb03d,0xb03e,0xb03f,0xb040,0xb041,0xb042, 0xb043,0xb046,0xb047,0xb049,0xb04b,0xb04d,0xb04f,0xb050,0xb051,0xb052, 0xb056,0xb058,0xb05a,0xb05b,0xb05c,0xb05e,0xb05f,0xb060,0xb061,0xb062, 0xb063,0xb064,0xb065,0xb066,0xb067,0xb068,0xb069,0xb06a,0xb06b,0xb06c, 0xb06d,0xb06e,0xb06f,0xb070,0xb071,0xb072,0xb073,0xb074,0xb075,0xb076, 0xb077,0xb078,0xb079,0xb07a,0xb07b,0xb07e,0xb07f,0xb081,0xb082,0xb083, 0xb085,0xb086,0xb087,0xb088,0xb089,0xb08a,0xb08b,0xb08e,0xb090,0xb092, 0xb093,0xb094,0xb095,0xb096,0xb097,0xb09b,0xb09d,0xb09e,0xb0a3,0xb0a4 }, { /* ku 06 */ 0xb0a5,0xb0a6,0xb0a7,0xb0aa,0xb0b0,0xb0b2,0xb0b6,0xb0b7,0xb0b9,0xb0ba, 0xb0bb,0xb0bd,0xb0be,0xb0bf,0xb0c0,0xb0c1,0xb0c2,0xb0c3,0xb0c6,0xb0ca, 0xb0cb,0xb0cc,0xb0cd,0xb0ce,0xb0cf,0xb0d2,UBOGON,UBOGON,UBOGON,UBOGON, UBOGON,UBOGON,0xb0d3,0xb0d5,0xb0d6,0xb0d7,0xb0d9,0xb0da,0xb0db,0xb0dc, 0xb0dd,0xb0de,0xb0df,0xb0e1,0xb0e2,0xb0e3,0xb0e4,0xb0e6,0xb0e7,0xb0e8, 0xb0e9,0xb0ea,0xb0eb,0xb0ec,0xb0ed,0xb0ee,0xb0ef,0xb0f0,UBOGON,UBOGON, UBOGON,UBOGON,UBOGON,UBOGON,0xb0f1,0xb0f2,0xb0f3,0xb0f4,0xb0f5,0xb0f6, 0xb0f7,0xb0f8,0xb0f9,0xb0fa,0xb0fb,0xb0fc,0xb0fd,0xb0fe,0xb0ff,0xb100, 0xb101,0xb102,0xb103,0xb104,0xb105,0xb106,0xb107,0xb10a,0xb10d,0xb10e, 0xb10f,0xb111,0xb114,0xb115,0xb116,0xb117,0xb11a,0xb11e,0xb11f,0xb120, 0xb121,0xb122,0xb126,0xb127,0xb129,0xb12a,0xb12b,0xb12d,0xb12e,0xb12f, 0xb130,0xb131,0xb132,0xb133,0xb136,0xb13a,0xb13b,0xb13c,0xb13d,0xb13e, 0xb13f,0xb142,0xb143,0xb145,0xb146,0xb147,0xb149,0xb14a,0xb14b,0xb14c, 0xb14d,0xb14e,0xb14f,0xb152,0xb153,0xb156,0xb157,0xb159,0xb15a,0xb15b, 0xb15d,0xb15e,0xb15f,0xb161,0xb162,0xb163,0xb164,0xb165,0xb166,0xb167, 0xb168,0xb169,0xb16a,0xb16b,0xb16c,0xb16d,0xb16e,0xb16f,0xb170,0xb171, 0xb172,0xb173,0xb174,0xb175,0xb176,0xb177,0xb17a,0xb17b,0xb17d,0xb17e, 0xb17f,0xb181,0xb183,0xb184,0xb185,0xb186,0xb187,0xb18a,0xb18c,0xb18e, 0xb18f,0xb190,0xb191,0xb195,0xb196,0xb197,0xb199,0xb19a,0xb19b,0xb19d }, { /* ku 07 */ 0xb19e,0xb19f,0xb1a0,0xb1a1,0xb1a2,0xb1a3,0xb1a4,0xb1a5,0xb1a6,0xb1a7, 0xb1a9,0xb1aa,0xb1ab,0xb1ac,0xb1ad,0xb1ae,0xb1af,0xb1b0,0xb1b1,0xb1b2, 0xb1b3,0xb1b4,0xb1b5,0xb1b6,0xb1b7,0xb1b8,UBOGON,UBOGON,UBOGON,UBOGON, UBOGON,UBOGON,0xb1b9,0xb1ba,0xb1bb,0xb1bc,0xb1bd,0xb1be,0xb1bf,0xb1c0, 0xb1c1,0xb1c2,0xb1c3,0xb1c4,0xb1c5,0xb1c6,0xb1c7,0xb1c8,0xb1c9,0xb1ca, 0xb1cb,0xb1cd,0xb1ce,0xb1cf,0xb1d1,0xb1d2,0xb1d3,0xb1d5,UBOGON,UBOGON, UBOGON,UBOGON,UBOGON,UBOGON,0xb1d6,0xb1d7,0xb1d8,0xb1d9,0xb1da,0xb1db, 0xb1de,0xb1e0,0xb1e1,0xb1e2,0xb1e3,0xb1e4,0xb1e5,0xb1e6,0xb1e7,0xb1ea, 0xb1eb,0xb1ed,0xb1ee,0xb1ef,0xb1f1,0xb1f2,0xb1f3,0xb1f4,0xb1f5,0xb1f6, 0xb1f7,0xb1f8,0xb1fa,0xb1fc,0xb1fe,0xb1ff,0xb200,0xb201,0xb202,0xb203, 0xb206,0xb207,0xb209,0xb20a,0xb20d,0xb20e,0xb20f,0xb210,0xb211,0xb212, 0xb213,0xb216,0xb218,0xb21a,0xb21b,0xb21c,0xb21d,0xb21e,0xb21f,0xb221, 0xb222,0xb223,0xb224,0xb225,0xb226,0xb227,0xb228,0xb229,0xb22a,0xb22b, 0xb22c,0xb22d,0xb22e,0xb22f,0xb230,0xb231,0xb232,0xb233,0xb235,0xb236, 0xb237,0xb238,0xb239,0xb23a,0xb23b,0xb23d,0xb23e,0xb23f,0xb240,0xb241, 0xb242,0xb243,0xb244,0xb245,0xb246,0xb247,0xb248,0xb249,0xb24a,0xb24b, 0xb24c,0xb24d,0xb24e,0xb24f,0xb250,0xb251,0xb252,0xb253,0xb254,0xb255, 0xb256,0xb257,0xb259,0xb25a,0xb25b,0xb25d,0xb25e,0xb25f,0xb261,0xb262, 0xb263,0xb264,0xb265,0xb266,0xb267,0xb26a,0xb26b,0xb26c,0xb26d,0xb26e }, { /* ku 08 */ 0xb26f,0xb270,0xb271,0xb272,0xb273,0xb276,0xb277,0xb278,0xb279,0xb27a, 0xb27b,0xb27d,0xb27e,0xb27f,0xb280,0xb281,0xb282,0xb283,0xb286,0xb287, 0xb288,0xb28a,0xb28b,0xb28c,0xb28d,0xb28e,UBOGON,UBOGON,UBOGON,UBOGON, UBOGON,UBOGON,0xb28f,0xb292,0xb293,0xb295,0xb296,0xb297,0xb29b,0xb29c, 0xb29d,0xb29e,0xb29f,0xb2a2,0xb2a4,0xb2a7,0xb2a8,0xb2a9,0xb2ab,0xb2ad, 0xb2ae,0xb2af,0xb2b1,0xb2b2,0xb2b3,0xb2b5,0xb2b6,0xb2b7,UBOGON,UBOGON, UBOGON,UBOGON,UBOGON,UBOGON,0xb2b8,0xb2b9,0xb2ba,0xb2bb,0xb2bc,0xb2bd, 0xb2be,0xb2bf,0xb2c0,0xb2c1,0xb2c2,0xb2c3,0xb2c4,0xb2c5,0xb2c6,0xb2c7, 0xb2ca,0xb2cb,0xb2cd,0xb2ce,0xb2cf,0xb2d1,0xb2d3,0xb2d4,0xb2d5,0xb2d6, 0xb2d7,0xb2da,0xb2dc,0xb2de,0xb2df,0xb2e0,0xb2e1,0xb2e3,0xb2e7,0xb2e9, 0xb2ea,0xb2f0,0xb2f1,0xb2f2,0xb2f6,0xb2fc,0xb2fd,0xb2fe,0xb302,0xb303, 0xb305,0xb306,0xb307,0xb309,0xb30a,0xb30b,0xb30c,0xb30d,0xb30e,0xb30f, 0xb312,0xb316,0xb317,0xb318,0xb319,0xb31a,0xb31b,0xb31d,0xb31e,0xb31f, 0xb320,0xb321,0xb322,0xb323,0xb324,0xb325,0xb326,0xb327,0xb328,0xb329, 0xb32a,0xb32b,0xb32c,0xb32d,0xb32e,0xb32f,0xb330,0xb331,0xb332,0xb333, 0xb334,0xb335,0xb336,0xb337,0xb338,0xb339,0xb33a,0xb33b,0xb33c,0xb33d, 0xb33e,0xb33f,0xb340,0xb341,0xb342,0xb343,0xb344,0xb345,0xb346,0xb347, 0xb348,0xb349,0xb34a,0xb34b,0xb34c,0xb34d,0xb34e,0xb34f,0xb350,0xb351, 0xb352,0xb353,0xb357,0xb359,0xb35a,0xb35d,0xb360,0xb361,0xb362,0xb363 }, { /* ku 09 */ 0xb366,0xb368,0xb36a,0xb36c,0xb36d,0xb36f,0xb372,0xb373,0xb375,0xb376, 0xb377,0xb379,0xb37a,0xb37b,0xb37c,0xb37d,0xb37e,0xb37f,0xb382,0xb386, 0xb387,0xb388,0xb389,0xb38a,0xb38b,0xb38d,UBOGON,UBOGON,UBOGON,UBOGON, UBOGON,UBOGON,0xb38e,0xb38f,0xb391,0xb392,0xb393,0xb395,0xb396,0xb397, 0xb398,0xb399,0xb39a,0xb39b,0xb39c,0xb39d,0xb39e,0xb39f,0xb3a2,0xb3a3, 0xb3a4,0xb3a5,0xb3a6,0xb3a7,0xb3a9,0xb3aa,0xb3ab,0xb3ad,UBOGON,UBOGON, UBOGON,UBOGON,UBOGON,UBOGON,0xb3ae,0xb3af,0xb3b0,0xb3b1,0xb3b2,0xb3b3, 0xb3b4,0xb3b5,0xb3b6,0xb3b7,0xb3b8,0xb3b9,0xb3ba,0xb3bb,0xb3bc,0xb3bd, 0xb3be,0xb3bf,0xb3c0,0xb3c1,0xb3c2,0xb3c3,0xb3c6,0xb3c7,0xb3c9,0xb3ca, 0xb3cd,0xb3cf,0xb3d1,0xb3d2,0xb3d3,0xb3d6,0xb3d8,0xb3da,0xb3dc,0xb3de, 0xb3df,0xb3e1,0xb3e2,0xb3e3,0xb3e5,0xb3e6,0xb3e7,0xb3e9,0xb3ea,0xb3eb, 0xb3ec,0xb3ed,0xb3ee,0xb3ef,0xb3f0,0xb3f1,0xb3f2,0xb3f3,0xb3f4,0xb3f5, 0xb3f6,0xb3f7,0xb3f8,0xb3f9,0xb3fa,0xb3fb,0xb3fd,0xb3fe,0xb3ff,0xb400, 0xb401,0xb402,0xb403,0xb404,0xb405,0xb406,0xb407,0xb408,0xb409,0xb40a, 0xb40b,0xb40c,0xb40d,0xb40e,0xb40f,0xb411,0xb412,0xb413,0xb414,0xb415, 0xb416,0xb417,0xb419,0xb41a,0xb41b,0xb41d,0xb41e,0xb41f,0xb421,0xb422, 0xb423,0xb424,0xb425,0xb426,0xb427,0xb42a,0xb42c,0xb42d,0xb42e,0xb42f, 0xb430,0xb431,0xb432,0xb433,0xb435,0xb436,0xb437,0xb438,0xb439,0xb43a, 0xb43b,0xb43c,0xb43d,0xb43e,0xb43f,0xb440,0xb441,0xb442,0xb443,0xb444 }, { /* ku 0a */ 0xb445,0xb446,0xb447,0xb448,0xb449,0xb44a,0xb44b,0xb44c,0xb44d,0xb44e, 0xb44f,0xb452,0xb453,0xb455,0xb456,0xb457,0xb459,0xb45a,0xb45b,0xb45c, 0xb45d,0xb45e,0xb45f,0xb462,0xb464,0xb466,UBOGON,UBOGON,UBOGON,UBOGON, UBOGON,UBOGON,0xb467,0xb468,0xb469,0xb46a,0xb46b,0xb46d,0xb46e,0xb46f, 0xb470,0xb471,0xb472,0xb473,0xb474,0xb475,0xb476,0xb477,0xb478,0xb479, 0xb47a,0xb47b,0xb47c,0xb47d,0xb47e,0xb47f,0xb481,0xb482,UBOGON,UBOGON, UBOGON,UBOGON,UBOGON,UBOGON,0xb483,0xb484,0xb485,0xb486,0xb487,0xb489, 0xb48a,0xb48b,0xb48c,0xb48d,0xb48e,0xb48f,0xb490,0xb491,0xb492,0xb493, 0xb494,0xb495,0xb496,0xb497,0xb498,0xb499,0xb49a,0xb49b,0xb49c,0xb49e, 0xb49f,0xb4a0,0xb4a1,0xb4a2,0xb4a3,0xb4a5,0xb4a6,0xb4a7,0xb4a9,0xb4aa, 0xb4ab,0xb4ad,0xb4ae,0xb4af,0xb4b0,0xb4b1,0xb4b2,0xb4b3,0xb4b4,0xb4b6, 0xb4b8,0xb4ba,0xb4bb,0xb4bc,0xb4bd,0xb4be,0xb4bf,0xb4c1,0xb4c2,0xb4c3, 0xb4c5,0xb4c6,0xb4c7,0xb4c9,0xb4ca,0xb4cb,0xb4cc,0xb4cd,0xb4ce,0xb4cf, 0xb4d1,0xb4d2,0xb4d3,0xb4d4,0xb4d6,0xb4d7,0xb4d8,0xb4d9,0xb4da,0xb4db, 0xb4de,0xb4df,0xb4e1,0xb4e2,0xb4e5,0xb4e7,0xb4e8,0xb4e9,0xb4ea,0xb4eb, 0xb4ee,0xb4f0,0xb4f2,0xb4f3,0xb4f4,0xb4f5,0xb4f6,0xb4f7,0xb4f9,0xb4fa, 0xb4fb,0xb4fc,0xb4fd,0xb4fe,0xb4ff,0xb500,0xb501,0xb502,0xb503,0xb504, 0xb505,0xb506,0xb507,0xb508,0xb509,0xb50a,0xb50b,0xb50c,0xb50d,0xb50e, 0xb50f,0xb510,0xb511,0xb512,0xb513,0xb516,0xb517,0xb519,0xb51a,0xb51d }, { /* ku 0b */ 0xb51e,0xb51f,0xb520,0xb521,0xb522,0xb523,0xb526,0xb52b,0xb52c,0xb52d, 0xb52e,0xb52f,0xb532,0xb533,0xb535,0xb536,0xb537,0xb539,0xb53a,0xb53b, 0xb53c,0xb53d,0xb53e,0xb53f,0xb542,0xb546,UBOGON,UBOGON,UBOGON,UBOGON, UBOGON,UBOGON,0xb547,0xb548,0xb549,0xb54a,0xb54e,0xb54f,0xb551,0xb552, 0xb553,0xb555,0xb556,0xb557,0xb558,0xb559,0xb55a,0xb55b,0xb55e,0xb562, 0xb563,0xb564,0xb565,0xb566,0xb567,0xb568,0xb569,0xb56a,UBOGON,UBOGON, UBOGON,UBOGON,UBOGON,UBOGON,0xb56b,0xb56c,0xb56d,0xb56e,0xb56f,0xb570, 0xb571,0xb572,0xb573,0xb574,0xb575,0xb576,0xb577,0xb578,0xb579,0xb57a, 0xb57b,0xb57c,0xb57d,0xb57e,0xb57f,0xb580,0xb581,0xb582,0xb583,0xb584, 0xb585,0xb586,0xb587,0xb588,0xb589,0xb58a,0xb58b,0xb58c,0xb58d,0xb58e, 0xb58f,0xb590,0xb591,0xb592,0xb593,0xb594,0xb595,0xb596,0xb597,0xb598, 0xb599,0xb59a,0xb59b,0xb59c,0xb59d,0xb59e,0xb59f,0xb5a2,0xb5a3,0xb5a5, 0xb5a6,0xb5a7,0xb5a9,0xb5ac,0xb5ad,0xb5ae,0xb5af,0xb5b2,0xb5b6,0xb5b7, 0xb5b8,0xb5b9,0xb5ba,0xb5be,0xb5bf,0xb5c1,0xb5c2,0xb5c3,0xb5c5,0xb5c6, 0xb5c7,0xb5c8,0xb5c9,0xb5ca,0xb5cb,0xb5ce,0xb5d2,0xb5d3,0xb5d4,0xb5d5, 0xb5d6,0xb5d7,0xb5d9,0xb5da,0xb5db,0xb5dc,0xb5dd,0xb5de,0xb5df,0xb5e0, 0xb5e1,0xb5e2,0xb5e3,0xb5e4,0xb5e5,0xb5e6,0xb5e7,0xb5e8,0xb5e9,0xb5ea, 0xb5eb,0xb5ed,0xb5ee,0xb5ef,0xb5f0,0xb5f1,0xb5f2,0xb5f3,0xb5f4,0xb5f5, 0xb5f6,0xb5f7,0xb5f8,0xb5f9,0xb5fa,0xb5fb,0xb5fc,0xb5fd,0xb5fe,0xb5ff }, { /* ku 0c */ 0xb600,0xb601,0xb602,0xb603,0xb604,0xb605,0xb606,0xb607,0xb608,0xb609, 0xb60a,0xb60b,0xb60c,0xb60d,0xb60e,0xb60f,0xb612,0xb613,0xb615,0xb616, 0xb617,0xb619,0xb61a,0xb61b,0xb61c,0xb61d,UBOGON,UBOGON,UBOGON,UBOGON, UBOGON,UBOGON,0xb61e,0xb61f,0xb620,0xb621,0xb622,0xb623,0xb624,0xb626, 0xb627,0xb628,0xb629,0xb62a,0xb62b,0xb62d,0xb62e,0xb62f,0xb630,0xb631, 0xb632,0xb633,0xb635,0xb636,0xb637,0xb638,0xb639,0xb63a,UBOGON,UBOGON, UBOGON,UBOGON,UBOGON,UBOGON,0xb63b,0xb63c,0xb63d,0xb63e,0xb63f,0xb640, 0xb641,0xb642,0xb643,0xb644,0xb645,0xb646,0xb647,0xb649,0xb64a,0xb64b, 0xb64c,0xb64d,0xb64e,0xb64f,0xb650,0xb651,0xb652,0xb653,0xb654,0xb655, 0xb656,0xb657,0xb658,0xb659,0xb65a,0xb65b,0xb65c,0xb65d,0xb65e,0xb65f, 0xb660,0xb661,0xb662,0xb663,0xb665,0xb666,0xb667,0xb669,0xb66a,0xb66b, 0xb66c,0xb66d,0xb66e,0xb66f,0xb670,0xb671,0xb672,0xb673,0xb674,0xb675, 0xb676,0xb677,0xb678,0xb679,0xb67a,0xb67b,0xb67c,0xb67d,0xb67e,0xb67f, 0xb680,0xb681,0xb682,0xb683,0xb684,0xb685,0xb686,0xb687,0xb688,0xb689, 0xb68a,0xb68b,0xb68c,0xb68d,0xb68e,0xb68f,0xb690,0xb691,0xb692,0xb693, 0xb694,0xb695,0xb696,0xb697,0xb698,0xb699,0xb69a,0xb69b,0xb69e,0xb69f, 0xb6a1,0xb6a2,0xb6a3,0xb6a5,0xb6a6,0xb6a7,0xb6a8,0xb6a9,0xb6aa,0xb6ad, 0xb6ae,0xb6af,0xb6b0,0xb6b2,0xb6b3,0xb6b4,0xb6b5,0xb6b6,0xb6b7,0xb6b8, 0xb6b9,0xb6ba,0xb6bb,0xb6bc,0xb6bd,0xb6be,0xb6bf,0xb6c0,0xb6c1,0xb6c2 }, { /* ku 0d */ 0xb6c3,0xb6c4,0xb6c5,0xb6c6,0xb6c7,0xb6c8,0xb6c9,0xb6ca,0xb6cb,0xb6cc, 0xb6cd,0xb6ce,0xb6cf,0xb6d0,0xb6d1,0xb6d2,0xb6d3,0xb6d5,0xb6d6,0xb6d7, 0xb6d8,0xb6d9,0xb6da,0xb6db,0xb6dc,0xb6dd,UBOGON,UBOGON,UBOGON,UBOGON, UBOGON,UBOGON,0xb6de,0xb6df,0xb6e0,0xb6e1,0xb6e2,0xb6e3,0xb6e4,0xb6e5, 0xb6e6,0xb6e7,0xb6e8,0xb6e9,0xb6ea,0xb6eb,0xb6ec,0xb6ed,0xb6ee,0xb6ef, 0xb6f1,0xb6f2,0xb6f3,0xb6f5,0xb6f6,0xb6f7,0xb6f9,0xb6fa,UBOGON,UBOGON, UBOGON,UBOGON,UBOGON,UBOGON,0xb6fb,0xb6fc,0xb6fd,0xb6fe,0xb6ff,0xb702, 0xb703,0xb704,0xb706,0xb707,0xb708,0xb709,0xb70a,0xb70b,0xb70c,0xb70d, 0xb70e,0xb70f,0xb710,0xb711,0xb712,0xb713,0xb714,0xb715,0xb716,0xb717, 0xb718,0xb719,0xb71a,0xb71b,0xb71c,0xb71d,0xb71e,0xb71f,0xb720,0xb721, 0xb722,0xb723,0xb724,0xb725,0xb726,0xb727,0xb72a,0xb72b,0xb72d,0xb72e, 0xb731,0xb732,0xb733,0xb734,0xb735,0xb736,0xb737,0xb73a,0xb73c,0xb73d, 0xb73e,0xb73f,0xb740,0xb741,0xb742,0xb743,0xb745,0xb746,0xb747,0xb749, 0xb74a,0xb74b,0xb74d,0xb74e,0xb74f,0xb750,0xb751,0xb752,0xb753,0xb756, 0xb757,0xb758,0xb759,0xb75a,0xb75b,0xb75c,0xb75d,0xb75e,0xb75f,0xb761, 0xb762,0xb763,0xb765,0xb766,0xb767,0xb769,0xb76a,0xb76b,0xb76c,0xb76d, 0xb76e,0xb76f,0xb772,0xb774,0xb776,0xb777,0xb778,0xb779,0xb77a,0xb77b, 0xb77e,0xb77f,0xb781,0xb782,0xb783,0xb785,0xb786,0xb787,0xb788,0xb789, 0xb78a,0xb78b,0xb78e,0xb793,0xb794,0xb795,0xb79a,0xb79b,0xb79d,0xb79e }, { /* ku 0e */ 0xb79f,0xb7a1,0xb7a2,0xb7a3,0xb7a4,0xb7a5,0xb7a6,0xb7a7,0xb7aa,0xb7ae, 0xb7af,0xb7b0,0xb7b1,0xb7b2,0xb7b3,0xb7b6,0xb7b7,0xb7b9,0xb7ba,0xb7bb, 0xb7bc,0xb7bd,0xb7be,0xb7bf,0xb7c0,0xb7c1,UBOGON,UBOGON,UBOGON,UBOGON, UBOGON,UBOGON,0xb7c2,0xb7c3,0xb7c4,0xb7c5,0xb7c6,0xb7c8,0xb7ca,0xb7cb, 0xb7cc,0xb7cd,0xb7ce,0xb7cf,0xb7d0,0xb7d1,0xb7d2,0xb7d3,0xb7d4,0xb7d5, 0xb7d6,0xb7d7,0xb7d8,0xb7d9,0xb7da,0xb7db,0xb7dc,0xb7dd,UBOGON,UBOGON, UBOGON,UBOGON,UBOGON,UBOGON,0xb7de,0xb7df,0xb7e0,0xb7e1,0xb7e2,0xb7e3, 0xb7e4,0xb7e5,0xb7e6,0xb7e7,0xb7e8,0xb7e9,0xb7ea,0xb7eb,0xb7ee,0xb7ef, 0xb7f1,0xb7f2,0xb7f3,0xb7f5,0xb7f6,0xb7f7,0xb7f8,0xb7f9,0xb7fa,0xb7fb, 0xb7fe,0xb802,0xb803,0xb804,0xb805,0xb806,0xb80a,0xb80b,0xb80d,0xb80e, 0xb80f,0xb811,0xb812,0xb813,0xb814,0xb815,0xb816,0xb817,0xb81a,0xb81c, 0xb81e,0xb81f,0xb820,0xb821,0xb822,0xb823,0xb826,0xb827,0xb829,0xb82a, 0xb82b,0xb82d,0xb82e,0xb82f,0xb830,0xb831,0xb832,0xb833,0xb836,0xb83a, 0xb83b,0xb83c,0xb83d,0xb83e,0xb83f,0xb841,0xb842,0xb843,0xb845,0xb846, 0xb847,0xb848,0xb849,0xb84a,0xb84b,0xb84c,0xb84d,0xb84e,0xb84f,0xb850, 0xb852,0xb854,0xb855,0xb856,0xb857,0xb858,0xb859,0xb85a,0xb85b,0xb85e, 0xb85f,0xb861,0xb862,0xb863,0xb865,0xb866,0xb867,0xb868,0xb869,0xb86a, 0xb86b,0xb86e,0xb870,0xb872,0xb873,0xb874,0xb875,0xb876,0xb877,0xb879, 0xb87a,0xb87b,0xb87d,0xb87e,0xb87f,0xb880,0xb881,0xb882,0xb883,0xb884 }, { /* ku 0f */ 0xb885,0xb886,0xb887,0xb888,0xb889,0xb88a,0xb88b,0xb88c,0xb88e,0xb88f, 0xb890,0xb891,0xb892,0xb893,0xb894,0xb895,0xb896,0xb897,0xb898,0xb899, 0xb89a,0xb89b,0xb89c,0xb89d,0xb89e,0xb89f,UBOGON,UBOGON,UBOGON,UBOGON, UBOGON,UBOGON,0xb8a0,0xb8a1,0xb8a2,0xb8a3,0xb8a4,0xb8a5,0xb8a6,0xb8a7, 0xb8a9,0xb8aa,0xb8ab,0xb8ac,0xb8ad,0xb8ae,0xb8af,0xb8b1,0xb8b2,0xb8b3, 0xb8b5,0xb8b6,0xb8b7,0xb8b9,0xb8ba,0xb8bb,0xb8bc,0xb8bd,UBOGON,UBOGON, UBOGON,UBOGON,UBOGON,UBOGON,0xb8be,0xb8bf,0xb8c2,0xb8c4,0xb8c6,0xb8c7, 0xb8c8,0xb8c9,0xb8ca,0xb8cb,0xb8cd,0xb8ce,0xb8cf,0xb8d1,0xb8d2,0xb8d3, 0xb8d5,0xb8d6,0xb8d7,0xb8d8,0xb8d9,0xb8da,0xb8db,0xb8dc,0xb8de,0xb8e0, 0xb8e2,0xb8e3,0xb8e4,0xb8e5,0xb8e6,0xb8e7,0xb8ea,0xb8eb,0xb8ed,0xb8ee, 0xb8ef,0xb8f1,0xb8f2,0xb8f3,0xb8f4,0xb8f5,0xb8f6,0xb8f7,0xb8fa,0xb8fc, 0xb8fe,0xb8ff,0xb900,0xb901,0xb902,0xb903,0xb905,0xb906,0xb907,0xb908, 0xb909,0xb90a,0xb90b,0xb90c,0xb90d,0xb90e,0xb90f,0xb910,0xb911,0xb912, 0xb913,0xb914,0xb915,0xb916,0xb917,0xb919,0xb91a,0xb91b,0xb91c,0xb91d, 0xb91e,0xb91f,0xb921,0xb922,0xb923,0xb924,0xb925,0xb926,0xb927,0xb928, 0xb929,0xb92a,0xb92b,0xb92c,0xb92d,0xb92e,0xb92f,0xb930,0xb931,0xb932, 0xb933,0xb934,0xb935,0xb936,0xb937,0xb938,0xb939,0xb93a,0xb93b,0xb93e, 0xb93f,0xb941,0xb942,0xb943,0xb945,0xb946,0xb947,0xb948,0xb949,0xb94a, 0xb94b,0xb94d,0xb94e,0xb950,0xb952,0xb953,0xb954,0xb955,0xb956,0xb957 }, { /* ku 10 */ 0xb95a,0xb95b,0xb95d,0xb95e,0xb95f,0xb961,0xb962,0xb963,0xb964,0xb965, 0xb966,0xb967,0xb96a,0xb96c,0xb96e,0xb96f,0xb970,0xb971,0xb972,0xb973, 0xb976,0xb977,0xb979,0xb97a,0xb97b,0xb97d,UBOGON,UBOGON,UBOGON,UBOGON, UBOGON,UBOGON,0xb97e,0xb97f,0xb980,0xb981,0xb982,0xb983,0xb986,0xb988, 0xb98b,0xb98c,0xb98f,0xb990,0xb991,0xb992,0xb993,0xb994,0xb995,0xb996, 0xb997,0xb998,0xb999,0xb99a,0xb99b,0xb99c,0xb99d,0xb99e,UBOGON,UBOGON, UBOGON,UBOGON,UBOGON,UBOGON,0xb99f,0xb9a0,0xb9a1,0xb9a2,0xb9a3,0xb9a4, 0xb9a5,0xb9a6,0xb9a7,0xb9a8,0xb9a9,0xb9aa,0xb9ab,0xb9ae,0xb9af,0xb9b1, 0xb9b2,0xb9b3,0xb9b5,0xb9b6,0xb9b7,0xb9b8,0xb9b9,0xb9ba,0xb9bb,0xb9be, 0xb9c0,0xb9c2,0xb9c3,0xb9c4,0xb9c5,0xb9c6,0xb9c7,0xb9ca,0xb9cb,0xb9cd, 0xb9d3,0xb9d4,0xb9d5,0xb9d6,0xb9d7,0xb9da,0xb9dc,0xb9df,0xb9e0,0xb9e2, 0xb9e6,0xb9e7,0xb9e9,0xb9ea,0xb9eb,0xb9ed,0xb9ee,0xb9ef,0xb9f0,0xb9f1, 0xb9f2,0xb9f3,0xb9f6,0xb9fb,0xb9fc,0xb9fd,0xb9fe,0xb9ff,0xba02,0xba03, 0xba04,0xba05,0xba06,0xba07,0xba09,0xba0a,0xba0b,0xba0c,0xba0d,0xba0e, 0xba0f,0xba10,0xba11,0xba12,0xba13,0xba14,0xba16,0xba17,0xba18,0xba19, 0xba1a,0xba1b,0xba1c,0xba1d,0xba1e,0xba1f,0xba20,0xba21,0xba22,0xba23, 0xba24,0xba25,0xba26,0xba27,0xba28,0xba29,0xba2a,0xba2b,0xba2c,0xba2d, 0xba2e,0xba2f,0xba30,0xba31,0xba32,0xba33,0xba34,0xba35,0xba36,0xba37, 0xba3a,0xba3b,0xba3d,0xba3e,0xba3f,0xba41,0xba43,0xba44,0xba45,0xba46 }, { /* ku 11 */ 0xba47,0xba4a,0xba4c,0xba4f,0xba50,0xba51,0xba52,0xba56,0xba57,0xba59, 0xba5a,0xba5b,0xba5d,0xba5e,0xba5f,0xba60,0xba61,0xba62,0xba63,0xba66, 0xba6a,0xba6b,0xba6c,0xba6d,0xba6e,0xba6f,UBOGON,UBOGON,UBOGON,UBOGON, UBOGON,UBOGON,0xba72,0xba73,0xba75,0xba76,0xba77,0xba79,0xba7a,0xba7b, 0xba7c,0xba7d,0xba7e,0xba7f,0xba80,0xba81,0xba82,0xba86,0xba88,0xba89, 0xba8a,0xba8b,0xba8d,0xba8e,0xba8f,0xba90,0xba91,0xba92,UBOGON,UBOGON, UBOGON,UBOGON,UBOGON,UBOGON,0xba93,0xba94,0xba95,0xba96,0xba97,0xba98, 0xba99,0xba9a,0xba9b,0xba9c,0xba9d,0xba9e,0xba9f,0xbaa0,0xbaa1,0xbaa2, 0xbaa3,0xbaa4,0xbaa5,0xbaa6,0xbaa7,0xbaaa,0xbaad,0xbaae,0xbaaf,0xbab1, 0xbab3,0xbab4,0xbab5,0xbab6,0xbab7,0xbaba,0xbabc,0xbabe,0xbabf,0xbac0, 0xbac1,0xbac2,0xbac3,0xbac5,0xbac6,0xbac7,0xbac9,0xbaca,0xbacb,0xbacc, 0xbacd,0xbace,0xbacf,0xbad0,0xbad1,0xbad2,0xbad3,0xbad4,0xbad5,0xbad6, 0xbad7,0xbada,0xbadb,0xbadc,0xbadd,0xbade,0xbadf,0xbae0,0xbae1,0xbae2, 0xbae3,0xbae4,0xbae5,0xbae6,0xbae7,0xbae8,0xbae9,0xbaea,0xbaeb,0xbaec, 0xbaed,0xbaee,0xbaef,0xbaf0,0xbaf1,0xbaf2,0xbaf3,0xbaf4,0xbaf5,0xbaf6, 0xbaf7,0xbaf8,0xbaf9,0xbafa,0xbafb,0xbafd,0xbafe,0xbaff,0xbb01,0xbb02, 0xbb03,0xbb05,0xbb06,0xbb07,0xbb08,0xbb09,0xbb0a,0xbb0b,0xbb0c,0xbb0e, 0xbb10,0xbb12,0xbb13,0xbb14,0xbb15,0xbb16,0xbb17,0xbb19,0xbb1a,0xbb1b, 0xbb1d,0xbb1e,0xbb1f,0xbb21,0xbb22,0xbb23,0xbb24,0xbb25,0xbb26,0xbb27 }, { /* ku 12 */ 0xbb28,0xbb2a,0xbb2c,0xbb2d,0xbb2e,0xbb2f,0xbb30,0xbb31,0xbb32,0xbb33, 0xbb37,0xbb39,0xbb3a,0xbb3f,0xbb40,0xbb41,0xbb42,0xbb43,0xbb46,0xbb48, 0xbb4a,0xbb4b,0xbb4c,0xbb4e,0xbb51,0xbb52,UBOGON,UBOGON,UBOGON,UBOGON, UBOGON,UBOGON,0xbb53,0xbb55,0xbb56,0xbb57,0xbb59,0xbb5a,0xbb5b,0xbb5c, 0xbb5d,0xbb5e,0xbb5f,0xbb60,0xbb62,0xbb64,0xbb65,0xbb66,0xbb67,0xbb68, 0xbb69,0xbb6a,0xbb6b,0xbb6d,0xbb6e,0xbb6f,0xbb70,0xbb71,UBOGON,UBOGON, UBOGON,UBOGON,UBOGON,UBOGON,0xbb72,0xbb73,0xbb74,0xbb75,0xbb76,0xbb77, 0xbb78,0xbb79,0xbb7a,0xbb7b,0xbb7c,0xbb7d,0xbb7e,0xbb7f,0xbb80,0xbb81, 0xbb82,0xbb83,0xbb84,0xbb85,0xbb86,0xbb87,0xbb89,0xbb8a,0xbb8b,0xbb8d, 0xbb8e,0xbb8f,0xbb91,0xbb92,0xbb93,0xbb94,0xbb95,0xbb96,0xbb97,0xbb98, 0xbb99,0xbb9a,0xbb9b,0xbb9c,0xbb9d,0xbb9e,0xbb9f,0xbba0,0xbba1,0xbba2, 0xbba3,0xbba5,0xbba6,0xbba7,0xbba9,0xbbaa,0xbbab,0xbbad,0xbbae,0xbbaf, 0xbbb0,0xbbb1,0xbbb2,0xbbb3,0xbbb5,0xbbb6,0xbbb8,0xbbb9,0xbbba,0xbbbb, 0xbbbc,0xbbbd,0xbbbe,0xbbbf,0xbbc1,0xbbc2,0xbbc3,0xbbc5,0xbbc6,0xbbc7, 0xbbc9,0xbbca,0xbbcb,0xbbcc,0xbbcd,0xbbce,0xbbcf,0xbbd1,0xbbd2,0xbbd4, 0xbbd5,0xbbd6,0xbbd7,0xbbd8,0xbbd9,0xbbda,0xbbdb,0xbbdc,0xbbdd,0xbbde, 0xbbdf,0xbbe0,0xbbe1,0xbbe2,0xbbe3,0xbbe4,0xbbe5,0xbbe6,0xbbe7,0xbbe8, 0xbbe9,0xbbea,0xbbeb,0xbbec,0xbbed,0xbbee,0xbbef,0xbbf0,0xbbf1,0xbbf2, 0xbbf3,0xbbf4,0xbbf5,0xbbf6,0xbbf7,0xbbfa,0xbbfb,0xbbfd,0xbbfe,0xbc01 }, { /* ku 13 */ 0xbc03,0xbc04,0xbc05,0xbc06,0xbc07,0xbc0a,0xbc0e,0xbc10,0xbc12,0xbc13, 0xbc19,0xbc1a,0xbc20,0xbc21,0xbc22,0xbc23,0xbc26,0xbc28,0xbc2a,0xbc2b, 0xbc2c,0xbc2e,0xbc2f,0xbc32,0xbc33,0xbc35,UBOGON,UBOGON,UBOGON,UBOGON, UBOGON,UBOGON,0xbc36,0xbc37,0xbc39,0xbc3a,0xbc3b,0xbc3c,0xbc3d,0xbc3e, 0xbc3f,0xbc42,0xbc46,0xbc47,0xbc48,0xbc4a,0xbc4b,0xbc4e,0xbc4f,0xbc51, 0xbc52,0xbc53,0xbc54,0xbc55,0xbc56,0xbc57,0xbc58,0xbc59,UBOGON,UBOGON, UBOGON,UBOGON,UBOGON,UBOGON,0xbc5a,0xbc5b,0xbc5c,0xbc5e,0xbc5f,0xbc60, 0xbc61,0xbc62,0xbc63,0xbc64,0xbc65,0xbc66,0xbc67,0xbc68,0xbc69,0xbc6a, 0xbc6b,0xbc6c,0xbc6d,0xbc6e,0xbc6f,0xbc70,0xbc71,0xbc72,0xbc73,0xbc74, 0xbc75,0xbc76,0xbc77,0xbc78,0xbc79,0xbc7a,0xbc7b,0xbc7c,0xbc7d,0xbc7e, 0xbc7f,0xbc80,0xbc81,0xbc82,0xbc83,0xbc86,0xbc87,0xbc89,0xbc8a,0xbc8d, 0xbc8f,0xbc90,0xbc91,0xbc92,0xbc93,0xbc96,0xbc98,0xbc9b,0xbc9c,0xbc9d, 0xbc9e,0xbc9f,0xbca2,0xbca3,0xbca5,0xbca6,0xbca9,0xbcaa,0xbcab,0xbcac, 0xbcad,0xbcae,0xbcaf,0xbcb2,0xbcb6,0xbcb7,0xbcb8,0xbcb9,0xbcba,0xbcbb, 0xbcbe,0xbcbf,0xbcc1,0xbcc2,0xbcc3,0xbcc5,0xbcc6,0xbcc7,0xbcc8,0xbcc9, 0xbcca,0xbccb,0xbccc,0xbcce,0xbcd2,0xbcd3,0xbcd4,0xbcd6,0xbcd7,0xbcd9, 0xbcda,0xbcdb,0xbcdd,0xbcde,0xbcdf,0xbce0,0xbce1,0xbce2,0xbce3,0xbce4, 0xbce5,0xbce6,0xbce7,0xbce8,0xbce9,0xbcea,0xbceb,0xbcec,0xbced,0xbcee, 0xbcef,0xbcf0,0xbcf1,0xbcf2,0xbcf3,0xbcf7,0xbcf9,0xbcfa,0xbcfb,0xbcfd }, { /* ku 14 */ 0xbcfe,0xbcff,0xbd00,0xbd01,0xbd02,0xbd03,0xbd06,0xbd08,0xbd0a,0xbd0b, 0xbd0c,0xbd0d,0xbd0e,0xbd0f,0xbd11,0xbd12,0xbd13,0xbd15,0xbd16,0xbd17, 0xbd18,0xbd19,0xbd1a,0xbd1b,0xbd1c,0xbd1d,UBOGON,UBOGON,UBOGON,UBOGON, UBOGON,UBOGON,0xbd1e,0xbd1f,0xbd20,0xbd21,0xbd22,0xbd23,0xbd25,0xbd26, 0xbd27,0xbd28,0xbd29,0xbd2a,0xbd2b,0xbd2d,0xbd2e,0xbd2f,0xbd30,0xbd31, 0xbd32,0xbd33,0xbd34,0xbd35,0xbd36,0xbd37,0xbd38,0xbd39,UBOGON,UBOGON, UBOGON,UBOGON,UBOGON,UBOGON,0xbd3a,0xbd3b,0xbd3c,0xbd3d,0xbd3e,0xbd3f, 0xbd41,0xbd42,0xbd43,0xbd44,0xbd45,0xbd46,0xbd47,0xbd4a,0xbd4b,0xbd4d, 0xbd4e,0xbd4f,0xbd51,0xbd52,0xbd53,0xbd54,0xbd55,0xbd56,0xbd57,0xbd5a, 0xbd5b,0xbd5c,0xbd5d,0xbd5e,0xbd5f,0xbd60,0xbd61,0xbd62,0xbd63,0xbd65, 0xbd66,0xbd67,0xbd69,0xbd6a,0xbd6b,0xbd6c,0xbd6d,0xbd6e,0xbd6f,0xbd70, 0xbd71,0xbd72,0xbd73,0xbd74,0xbd75,0xbd76,0xbd77,0xbd78,0xbd79,0xbd7a, 0xbd7b,0xbd7c,0xbd7d,0xbd7e,0xbd7f,0xbd82,0xbd83,0xbd85,0xbd86,0xbd8b, 0xbd8c,0xbd8d,0xbd8e,0xbd8f,0xbd92,0xbd94,0xbd96,0xbd97,0xbd98,0xbd9b, 0xbd9d,0xbd9e,0xbd9f,0xbda0,0xbda1,0xbda2,0xbda3,0xbda5,0xbda6,0xbda7, 0xbda8,0xbda9,0xbdaa,0xbdab,0xbdac,0xbdad,0xbdae,0xbdaf,0xbdb1,0xbdb2, 0xbdb3,0xbdb4,0xbdb5,0xbdb6,0xbdb7,0xbdb9,0xbdba,0xbdbb,0xbdbc,0xbdbd, 0xbdbe,0xbdbf,0xbdc0,0xbdc1,0xbdc2,0xbdc3,0xbdc4,0xbdc5,0xbdc6,0xbdc7, 0xbdc8,0xbdc9,0xbdca,0xbdcb,0xbdcc,0xbdcd,0xbdce,0xbdcf,0xbdd0,0xbdd1 }, { /* ku 15 */ 0xbdd2,0xbdd3,0xbdd6,0xbdd7,0xbdd9,0xbdda,0xbddb,0xbddd,0xbdde,0xbddf, 0xbde0,0xbde1,0xbde2,0xbde3,0xbde4,0xbde5,0xbde6,0xbde7,0xbde8,0xbdea, 0xbdeb,0xbdec,0xbded,0xbdee,0xbdef,0xbdf1,UBOGON,UBOGON,UBOGON,UBOGON, UBOGON,UBOGON,0xbdf2,0xbdf3,0xbdf5,0xbdf6,0xbdf7,0xbdf9,0xbdfa,0xbdfb, 0xbdfc,0xbdfd,0xbdfe,0xbdff,0xbe01,0xbe02,0xbe04,0xbe06,0xbe07,0xbe08, 0xbe09,0xbe0a,0xbe0b,0xbe0e,0xbe0f,0xbe11,0xbe12,0xbe13,UBOGON,UBOGON, UBOGON,UBOGON,UBOGON,UBOGON,0xbe15,0xbe16,0xbe17,0xbe18,0xbe19,0xbe1a, 0xbe1b,0xbe1e,0xbe20,0xbe21,0xbe22,0xbe23,0xbe24,0xbe25,0xbe26,0xbe27, 0xbe28,0xbe29,0xbe2a,0xbe2b,0xbe2c,0xbe2d,0xbe2e,0xbe2f,0xbe30,0xbe31, 0xbe32,0xbe33,0xbe34,0xbe35,0xbe36,0xbe37,0xbe38,0xbe39,0xbe3a,0xbe3b, 0xbe3c,0xbe3d,0xbe3e,0xbe3f,0xbe40,0xbe41,0xbe42,0xbe43,0xbe46,0xbe47, 0xbe49,0xbe4a,0xbe4b,0xbe4d,0xbe4f,0xbe50,0xbe51,0xbe52,0xbe53,0xbe56, 0xbe58,0xbe5c,0xbe5d,0xbe5e,0xbe5f,0xbe62,0xbe63,0xbe65,0xbe66,0xbe67, 0xbe69,0xbe6b,0xbe6c,0xbe6d,0xbe6e,0xbe6f,0xbe72,0xbe76,0xbe77,0xbe78, 0xbe79,0xbe7a,0xbe7e,0xbe7f,0xbe81,0xbe82,0xbe83,0xbe85,0xbe86,0xbe87, 0xbe88,0xbe89,0xbe8a,0xbe8b,0xbe8e,0xbe92,0xbe93,0xbe94,0xbe95,0xbe96, 0xbe97,0xbe9a,0xbe9b,0xbe9c,0xbe9d,0xbe9e,0xbe9f,0xbea0,0xbea1,0xbea2, 0xbea3,0xbea4,0xbea5,0xbea6,0xbea7,0xbea9,0xbeaa,0xbeab,0xbeac,0xbead, 0xbeae,0xbeaf,0xbeb0,0xbeb1,0xbeb2,0xbeb3,0xbeb4,0xbeb5,0xbeb6,0xbeb7 }, { /* ku 16 */ 0xbeb8,0xbeb9,0xbeba,0xbebb,0xbebc,0xbebd,0xbebe,0xbebf,0xbec0,0xbec1, 0xbec2,0xbec3,0xbec4,0xbec5,0xbec6,0xbec7,0xbec8,0xbec9,0xbeca,0xbecb, 0xbecc,0xbecd,0xbece,0xbecf,0xbed2,0xbed3,UBOGON,UBOGON,UBOGON,UBOGON, UBOGON,UBOGON,0xbed5,0xbed6,0xbed9,0xbeda,0xbedb,0xbedc,0xbedd,0xbede, 0xbedf,0xbee1,0xbee2,0xbee6,0xbee7,0xbee8,0xbee9,0xbeea,0xbeeb,0xbeed, 0xbeee,0xbeef,0xbef0,0xbef1,0xbef2,0xbef3,0xbef4,0xbef5,UBOGON,UBOGON, UBOGON,UBOGON,UBOGON,UBOGON,0xbef6,0xbef7,0xbef8,0xbef9,0xbefa,0xbefb, 0xbefc,0xbefd,0xbefe,0xbeff,0xbf00,0xbf02,0xbf03,0xbf04,0xbf05,0xbf06, 0xbf07,0xbf0a,0xbf0b,0xbf0c,0xbf0d,0xbf0e,0xbf0f,0xbf10,0xbf11,0xbf12, 0xbf13,0xbf14,0xbf15,0xbf16,0xbf17,0xbf1a,0xbf1e,0xbf1f,0xbf20,0xbf21, 0xbf22,0xbf23,0xbf24,0xbf25,0xbf26,0xbf27,0xbf28,0xbf29,0xbf2a,0xbf2b, 0xbf2c,0xbf2d,0xbf2e,0xbf2f,0xbf30,0xbf31,0xbf32,0xbf33,0xbf34,0xbf35, 0xbf36,0xbf37,0xbf38,0xbf39,0xbf3a,0xbf3b,0xbf3c,0xbf3d,0xbf3e,0xbf3f, 0xbf42,0xbf43,0xbf45,0xbf46,0xbf47,0xbf49,0xbf4a,0xbf4b,0xbf4c,0xbf4d, 0xbf4e,0xbf4f,0xbf52,0xbf53,0xbf54,0xbf56,0xbf57,0xbf58,0xbf59,0xbf5a, 0xbf5b,0xbf5c,0xbf5d,0xbf5e,0xbf5f,0xbf60,0xbf61,0xbf62,0xbf63,0xbf64, 0xbf65,0xbf66,0xbf67,0xbf68,0xbf69,0xbf6a,0xbf6b,0xbf6c,0xbf6d,0xbf6e, 0xbf6f,0xbf70,0xbf71,0xbf72,0xbf73,0xbf74,0xbf75,0xbf76,0xbf77,0xbf78, 0xbf79,0xbf7a,0xbf7b,0xbf7c,0xbf7d,0xbf7e,0xbf7f,0xbf80,0xbf81,0xbf82 }, { /* ku 17 */ 0xbf83,0xbf84,0xbf85,0xbf86,0xbf87,0xbf88,0xbf89,0xbf8a,0xbf8b,0xbf8c, 0xbf8d,0xbf8e,0xbf8f,0xbf90,0xbf91,0xbf92,0xbf93,0xbf95,0xbf96,0xbf97, 0xbf98,0xbf99,0xbf9a,0xbf9b,0xbf9c,0xbf9d,UBOGON,UBOGON,UBOGON,UBOGON, UBOGON,UBOGON,0xbf9e,0xbf9f,0xbfa0,0xbfa1,0xbfa2,0xbfa3,0xbfa4,0xbfa5, 0xbfa6,0xbfa7,0xbfa8,0xbfa9,0xbfaa,0xbfab,0xbfac,0xbfad,0xbfae,0xbfaf, 0xbfb1,0xbfb2,0xbfb3,0xbfb4,0xbfb5,0xbfb6,0xbfb7,0xbfb8,UBOGON,UBOGON, UBOGON,UBOGON,UBOGON,UBOGON,0xbfb9,0xbfba,0xbfbb,0xbfbc,0xbfbd,0xbfbe, 0xbfbf,0xbfc0,0xbfc1,0xbfc2,0xbfc3,0xbfc4,0xbfc6,0xbfc7,0xbfc8,0xbfc9, 0xbfca,0xbfcb,0xbfce,0xbfcf,0xbfd1,0xbfd2,0xbfd3,0xbfd5,0xbfd6,0xbfd7, 0xbfd8,0xbfd9,0xbfda,0xbfdb,0xbfdd,0xbfde,0xbfe0,0xbfe2,0xbfe3,0xbfe4, 0xbfe5,0xbfe6,0xbfe7,0xbfe8,0xbfe9,0xbfea,0xbfeb,0xbfec,0xbfed,0xbfee, 0xbfef,0xbff0,0xbff1,0xbff2,0xbff3,0xbff4,0xbff5,0xbff6,0xbff7,0xbff8, 0xbff9,0xbffa,0xbffb,0xbffc,0xbffd,0xbffe,0xbfff,0xc000,0xc001,0xc002, 0xc003,0xc004,0xc005,0xc006,0xc007,0xc008,0xc009,0xc00a,0xc00b,0xc00c, 0xc00d,0xc00e,0xc00f,0xc010,0xc011,0xc012,0xc013,0xc014,0xc015,0xc016, 0xc017,0xc018,0xc019,0xc01a,0xc01b,0xc01c,0xc01d,0xc01e,0xc01f,0xc020, 0xc021,0xc022,0xc023,0xc024,0xc025,0xc026,0xc027,0xc028,0xc029,0xc02a, 0xc02b,0xc02c,0xc02d,0xc02e,0xc02f,0xc030,0xc031,0xc032,0xc033,0xc034, 0xc035,0xc036,0xc037,0xc038,0xc039,0xc03a,0xc03b,0xc03d,0xc03e,0xc03f }, { /* ku 18 */ 0xc040,0xc041,0xc042,0xc043,0xc044,0xc045,0xc046,0xc047,0xc048,0xc049, 0xc04a,0xc04b,0xc04c,0xc04d,0xc04e,0xc04f,0xc050,0xc052,0xc053,0xc054, 0xc055,0xc056,0xc057,0xc059,0xc05a,0xc05b,UBOGON,UBOGON,UBOGON,UBOGON, UBOGON,UBOGON,0xc05d,0xc05e,0xc05f,0xc061,0xc062,0xc063,0xc064,0xc065, 0xc066,0xc067,0xc06a,0xc06b,0xc06c,0xc06d,0xc06e,0xc06f,0xc070,0xc071, 0xc072,0xc073,0xc074,0xc075,0xc076,0xc077,0xc078,0xc079,UBOGON,UBOGON, UBOGON,UBOGON,UBOGON,UBOGON,0xc07a,0xc07b,0xc07c,0xc07d,0xc07e,0xc07f, 0xc080,0xc081,0xc082,0xc083,0xc084,0xc085,0xc086,0xc087,0xc088,0xc089, 0xc08a,0xc08b,0xc08c,0xc08d,0xc08e,0xc08f,0xc092,0xc093,0xc095,0xc096, 0xc097,0xc099,0xc09a,0xc09b,0xc09c,0xc09d,0xc09e,0xc09f,0xc0a2,0xc0a4, 0xc0a6,0xc0a7,0xc0a8,0xc0a9,0xc0aa,0xc0ab,0xc0ae,0xc0b1,0xc0b2,0xc0b7, 0xc0b8,0xc0b9,0xc0ba,0xc0bb,0xc0be,0xc0c2,0xc0c3,0xc0c4,0xc0c6,0xc0c7, 0xc0ca,0xc0cb,0xc0cd,0xc0ce,0xc0cf,0xc0d1,0xc0d2,0xc0d3,0xc0d4,0xc0d5, 0xc0d6,0xc0d7,0xc0da,0xc0de,0xc0df,0xc0e0,0xc0e1,0xc0e2,0xc0e3,0xc0e6, 0xc0e7,0xc0e9,0xc0ea,0xc0eb,0xc0ed,0xc0ee,0xc0ef,0xc0f0,0xc0f1,0xc0f2, 0xc0f3,0xc0f6,0xc0f8,0xc0fa,0xc0fb,0xc0fc,0xc0fd,0xc0fe,0xc0ff,0xc101, 0xc102,0xc103,0xc105,0xc106,0xc107,0xc109,0xc10a,0xc10b,0xc10c,0xc10d, 0xc10e,0xc10f,0xc111,0xc112,0xc113,0xc114,0xc116,0xc117,0xc118,0xc119, 0xc11a,0xc11b,0xc121,0xc122,0xc125,0xc128,0xc129,0xc12a,0xc12b,0xc12e }, { /* ku 19 */ 0xc132,0xc133,0xc134,0xc135,0xc137,0xc13a,0xc13b,0xc13d,0xc13e,0xc13f, 0xc141,0xc142,0xc143,0xc144,0xc145,0xc146,0xc147,0xc14a,0xc14e,0xc14f, 0xc150,0xc151,0xc152,0xc153,0xc156,0xc157,UBOGON,UBOGON,UBOGON,UBOGON, UBOGON,UBOGON,0xc159,0xc15a,0xc15b,0xc15d,0xc15e,0xc15f,0xc160,0xc161, 0xc162,0xc163,0xc166,0xc16a,0xc16b,0xc16c,0xc16d,0xc16e,0xc16f,0xc171, 0xc172,0xc173,0xc175,0xc176,0xc177,0xc179,0xc17a,0xc17b,UBOGON,UBOGON, UBOGON,UBOGON,UBOGON,UBOGON,0xc17c,0xc17d,0xc17e,0xc17f,0xc180,0xc181, 0xc182,0xc183,0xc184,0xc186,0xc187,0xc188,0xc189,0xc18a,0xc18b,0xc18f, 0xc191,0xc192,0xc193,0xc195,0xc197,0xc198,0xc199,0xc19a,0xc19b,0xc19e, 0xc1a0,0xc1a2,0xc1a3,0xc1a4,0xc1a6,0xc1a7,0xc1aa,0xc1ab,0xc1ad,0xc1ae, 0xc1af,0xc1b1,0xc1b2,0xc1b3,0xc1b4,0xc1b5,0xc1b6,0xc1b7,0xc1b8,0xc1b9, 0xc1ba,0xc1bb,0xc1bc,0xc1be,0xc1bf,0xc1c0,0xc1c1,0xc1c2,0xc1c3,0xc1c5, 0xc1c6,0xc1c7,0xc1c9,0xc1ca,0xc1cb,0xc1cd,0xc1ce,0xc1cf,0xc1d0,0xc1d1, 0xc1d2,0xc1d3,0xc1d5,0xc1d6,0xc1d9,0xc1da,0xc1db,0xc1dc,0xc1dd,0xc1de, 0xc1df,0xc1e1,0xc1e2,0xc1e3,0xc1e5,0xc1e6,0xc1e7,0xc1e9,0xc1ea,0xc1eb, 0xc1ec,0xc1ed,0xc1ee,0xc1ef,0xc1f2,0xc1f4,0xc1f5,0xc1f6,0xc1f7,0xc1f8, 0xc1f9,0xc1fa,0xc1fb,0xc1fe,0xc1ff,0xc201,0xc202,0xc203,0xc205,0xc206, 0xc207,0xc208,0xc209,0xc20a,0xc20b,0xc20e,0xc210,0xc212,0xc213,0xc214, 0xc215,0xc216,0xc217,0xc21a,0xc21b,0xc21d,0xc21e,0xc221,0xc222,0xc223 }, { /* ku 1a */ 0xc224,0xc225,0xc226,0xc227,0xc22a,0xc22c,0xc22e,0xc230,0xc233,0xc235, 0xc236,0xc237,0xc238,0xc239,0xc23a,0xc23b,0xc23c,0xc23d,0xc23e,0xc23f, 0xc240,0xc241,0xc242,0xc243,0xc244,0xc245,UBOGON,UBOGON,UBOGON,UBOGON, UBOGON,UBOGON,0xc246,0xc247,0xc249,0xc24a,0xc24b,0xc24c,0xc24d,0xc24e, 0xc24f,0xc252,0xc253,0xc255,0xc256,0xc257,0xc259,0xc25a,0xc25b,0xc25c, 0xc25d,0xc25e,0xc25f,0xc261,0xc262,0xc263,0xc264,0xc266,UBOGON,UBOGON, UBOGON,UBOGON,UBOGON,UBOGON,0xc267,0xc268,0xc269,0xc26a,0xc26b,0xc26e, 0xc26f,0xc271,0xc272,0xc273,0xc275,0xc276,0xc277,0xc278,0xc279,0xc27a, 0xc27b,0xc27e,0xc280,0xc282,0xc283,0xc284,0xc285,0xc286,0xc287,0xc28a, 0xc28b,0xc28c,0xc28d,0xc28e,0xc28f,0xc291,0xc292,0xc293,0xc294,0xc295, 0xc296,0xc297,0xc299,0xc29a,0xc29c,0xc29e,0xc29f,0xc2a0,0xc2a1,0xc2a2, 0xc2a3,0xc2a6,0xc2a7,0xc2a9,0xc2aa,0xc2ab,0xc2ae,0xc2af,0xc2b0,0xc2b1, 0xc2b2,0xc2b3,0xc2b6,0xc2b8,0xc2ba,0xc2bb,0xc2bc,0xc2bd,0xc2be,0xc2bf, 0xc2c0,0xc2c1,0xc2c2,0xc2c3,0xc2c4,0xc2c5,0xc2c6,0xc2c7,0xc2c8,0xc2c9, 0xc2ca,0xc2cb,0xc2cc,0xc2cd,0xc2ce,0xc2cf,0xc2d0,0xc2d1,0xc2d2,0xc2d3, 0xc2d4,0xc2d5,0xc2d6,0xc2d7,0xc2d8,0xc2d9,0xc2da,0xc2db,0xc2de,0xc2df, 0xc2e1,0xc2e2,0xc2e5,0xc2e6,0xc2e7,0xc2e8,0xc2e9,0xc2ea,0xc2ee,0xc2f0, 0xc2f2,0xc2f3,0xc2f4,0xc2f5,0xc2f7,0xc2fa,0xc2fd,0xc2fe,0xc2ff,0xc301, 0xc302,0xc303,0xc304,0xc305,0xc306,0xc307,0xc30a,0xc30b,0xc30e,0xc30f }, { /* ku 1b */ 0xc310,0xc311,0xc312,0xc316,0xc317,0xc319,0xc31a,0xc31b,0xc31d,0xc31e, 0xc31f,0xc320,0xc321,0xc322,0xc323,0xc326,0xc327,0xc32a,0xc32b,0xc32c, 0xc32d,0xc32e,0xc32f,0xc330,0xc331,0xc332,UBOGON,UBOGON,UBOGON,UBOGON, UBOGON,UBOGON,0xc333,0xc334,0xc335,0xc336,0xc337,0xc338,0xc339,0xc33a, 0xc33b,0xc33c,0xc33d,0xc33e,0xc33f,0xc340,0xc341,0xc342,0xc343,0xc344, 0xc346,0xc347,0xc348,0xc349,0xc34a,0xc34b,0xc34c,0xc34d,UBOGON,UBOGON, UBOGON,UBOGON,UBOGON,UBOGON,0xc34e,0xc34f,0xc350,0xc351,0xc352,0xc353, 0xc354,0xc355,0xc356,0xc357,0xc358,0xc359,0xc35a,0xc35b,0xc35c,0xc35d, 0xc35e,0xc35f,0xc360,0xc361,0xc362,0xc363,0xc364,0xc365,0xc366,0xc367, 0xc36a,0xc36b,0xc36d,0xc36e,0xc36f,0xc371,0xc373,0xc374,0xc375,0xc376, 0xc377,0xc37a,0xc37b,0xc37e,0xc37f,0xc380,0xc381,0xc382,0xc383,0xc385, 0xc386,0xc387,0xc389,0xc38a,0xc38b,0xc38d,0xc38e,0xc38f,0xc390,0xc391, 0xc392,0xc393,0xc394,0xc395,0xc396,0xc397,0xc398,0xc399,0xc39a,0xc39b, 0xc39c,0xc39d,0xc39e,0xc39f,0xc3a0,0xc3a1,0xc3a2,0xc3a3,0xc3a4,0xc3a5, 0xc3a6,0xc3a7,0xc3a8,0xc3a9,0xc3aa,0xc3ab,0xc3ac,0xc3ad,0xc3ae,0xc3af, 0xc3b0,0xc3b1,0xc3b2,0xc3b3,0xc3b4,0xc3b5,0xc3b6,0xc3b7,0xc3b8,0xc3b9, 0xc3ba,0xc3bb,0xc3bc,0xc3bd,0xc3be,0xc3bf,0xc3c1,0xc3c2,0xc3c3,0xc3c4, 0xc3c5,0xc3c6,0xc3c7,0xc3c8,0xc3c9,0xc3ca,0xc3cb,0xc3cc,0xc3cd,0xc3ce, 0xc3cf,0xc3d0,0xc3d1,0xc3d2,0xc3d3,0xc3d4,0xc3d5,0xc3d6,0xc3d7,0xc3da }, { /* ku 1c */ 0xc3db,0xc3dd,0xc3de,0xc3e1,0xc3e3,0xc3e4,0xc3e5,0xc3e6,0xc3e7,0xc3ea, 0xc3eb,0xc3ec,0xc3ee,0xc3ef,0xc3f0,0xc3f1,0xc3f2,0xc3f3,0xc3f6,0xc3f7, 0xc3f9,0xc3fa,0xc3fb,0xc3fc,0xc3fd,0xc3fe,UBOGON,UBOGON,UBOGON,UBOGON, UBOGON,UBOGON,0xc3ff,0xc400,0xc401,0xc402,0xc403,0xc404,0xc405,0xc406, 0xc407,0xc409,0xc40a,0xc40b,0xc40c,0xc40d,0xc40e,0xc40f,0xc411,0xc412, 0xc413,0xc414,0xc415,0xc416,0xc417,0xc418,0xc419,0xc41a,UBOGON,UBOGON, UBOGON,UBOGON,UBOGON,UBOGON,0xc41b,0xc41c,0xc41d,0xc41e,0xc41f,0xc420, 0xc421,0xc422,0xc423,0xc425,0xc426,0xc427,0xc428,0xc429,0xc42a,0xc42b, 0xc42d,0xc42e,0xc42f,0xc431,0xc432,0xc433,0xc435,0xc436,0xc437,0xc438, 0xc439,0xc43a,0xc43b,0xc43e,0xc43f,0xc440,0xc441,0xc442,0xc443,0xc444, 0xc445,0xc446,0xc447,0xc449,0xc44a,0xc44b,0xc44c,0xc44d,0xc44e,0xc44f, 0xc450,0xc451,0xc452,0xc453,0xc454,0xc455,0xc456,0xc457,0xc458,0xc459, 0xc45a,0xc45b,0xc45c,0xc45d,0xc45e,0xc45f,0xc460,0xc461,0xc462,0xc463, 0xc466,0xc467,0xc469,0xc46a,0xc46b,0xc46d,0xc46e,0xc46f,0xc470,0xc471, 0xc472,0xc473,0xc476,0xc477,0xc478,0xc47a,0xc47b,0xc47c,0xc47d,0xc47e, 0xc47f,0xc481,0xc482,0xc483,0xc484,0xc485,0xc486,0xc487,0xc488,0xc489, 0xc48a,0xc48b,0xc48c,0xc48d,0xc48e,0xc48f,0xc490,0xc491,0xc492,0xc493, 0xc495,0xc496,0xc497,0xc498,0xc499,0xc49a,0xc49b,0xc49d,0xc49e,0xc49f, 0xc4a0,0xc4a1,0xc4a2,0xc4a3,0xc4a4,0xc4a5,0xc4a6,0xc4a7,0xc4a8,0xc4a9 }, { /* ku 1d */ 0xc4aa,0xc4ab,0xc4ac,0xc4ad,0xc4ae,0xc4af,0xc4b0,0xc4b1,0xc4b2,0xc4b3, 0xc4b4,0xc4b5,0xc4b6,0xc4b7,0xc4b9,0xc4ba,0xc4bb,0xc4bd,0xc4be,0xc4bf, 0xc4c0,0xc4c1,0xc4c2,0xc4c3,0xc4c4,0xc4c5,UBOGON,UBOGON,UBOGON,UBOGON, UBOGON,UBOGON,0xc4c6,0xc4c7,0xc4c8,0xc4c9,0xc4ca,0xc4cb,0xc4cc,0xc4cd, 0xc4ce,0xc4cf,0xc4d0,0xc4d1,0xc4d2,0xc4d3,0xc4d4,0xc4d5,0xc4d6,0xc4d7, 0xc4d8,0xc4d9,0xc4da,0xc4db,0xc4dc,0xc4dd,0xc4de,0xc4df,UBOGON,UBOGON, UBOGON,UBOGON,UBOGON,UBOGON,0xc4e0,0xc4e1,0xc4e2,0xc4e3,0xc4e4,0xc4e5, 0xc4e6,0xc4e7,0xc4e8,0xc4ea,0xc4eb,0xc4ec,0xc4ed,0xc4ee,0xc4ef,0xc4f2, 0xc4f3,0xc4f5,0xc4f6,0xc4f7,0xc4f9,0xc4fb,0xc4fc,0xc4fd,0xc4fe,0xc502, 0xc503,0xc504,0xc505,0xc506,0xc507,0xc508,0xc509,0xc50a,0xc50b,0xc50d, 0xc50e,0xc50f,0xc511,0xc512,0xc513,0xc515,0xc516,0xc517,0xc518,0xc519, 0xc51a,0xc51b,0xc51d,0xc51e,0xc51f,0xc520,0xc521,0xc522,0xc523,0xc524, 0xc525,0xc526,0xc527,0xc52a,0xc52b,0xc52d,0xc52e,0xc52f,0xc531,0xc532, 0xc533,0xc534,0xc535,0xc536,0xc537,0xc53a,0xc53c,0xc53e,0xc53f,0xc540, 0xc541,0xc542,0xc543,0xc546,0xc547,0xc54b,0xc54f,0xc550,0xc551,0xc552, 0xc556,0xc55a,0xc55b,0xc55c,0xc55f,0xc562,0xc563,0xc565,0xc566,0xc567, 0xc569,0xc56a,0xc56b,0xc56c,0xc56d,0xc56e,0xc56f,0xc572,0xc576,0xc577, 0xc578,0xc579,0xc57a,0xc57b,0xc57e,0xc57f,0xc581,0xc582,0xc583,0xc585, 0xc586,0xc588,0xc589,0xc58a,0xc58b,0xc58e,0xc590,0xc592,0xc593,0xc594 }, { /* ku 1e */ 0xc596,0xc599,0xc59a,0xc59b,0xc59d,0xc59e,0xc59f,0xc5a1,0xc5a2,0xc5a3, 0xc5a4,0xc5a5,0xc5a6,0xc5a7,0xc5a8,0xc5aa,0xc5ab,0xc5ac,0xc5ad,0xc5ae, 0xc5af,0xc5b0,0xc5b1,0xc5b2,0xc5b3,0xc5b6,UBOGON,UBOGON,UBOGON,UBOGON, UBOGON,UBOGON,0xc5b7,0xc5ba,0xc5bf,0xc5c0,0xc5c1,0xc5c2,0xc5c3,0xc5cb, 0xc5cd,0xc5cf,0xc5d2,0xc5d3,0xc5d5,0xc5d6,0xc5d7,0xc5d9,0xc5da,0xc5db, 0xc5dc,0xc5dd,0xc5de,0xc5df,0xc5e2,0xc5e4,0xc5e6,0xc5e7,UBOGON,UBOGON, UBOGON,UBOGON,UBOGON,UBOGON,0xc5e8,0xc5e9,0xc5ea,0xc5eb,0xc5ef,0xc5f1, 0xc5f2,0xc5f3,0xc5f5,0xc5f8,0xc5f9,0xc5fa,0xc5fb,0xc602,0xc603,0xc604, 0xc609,0xc60a,0xc60b,0xc60d,0xc60e,0xc60f,0xc611,0xc612,0xc613,0xc614, 0xc615,0xc616,0xc617,0xc61a,0xc61d,0xc61e,0xc61f,0xc620,0xc621,0xc622, 0xc623,0xc626,0xc627,0xc629,0xc62a,0xc62b,0xc62f,0xc631,0xc632,0xc636, 0xc638,0xc63a,0xc63c,0xc63d,0xc63e,0xc63f,0xc642,0xc643,0xc645,0xc646, 0xc647,0xc649,0xc64a,0xc64b,0xc64c,0xc64d,0xc64e,0xc64f,0xc652,0xc656, 0xc657,0xc658,0xc659,0xc65a,0xc65b,0xc65e,0xc65f,0xc661,0xc662,0xc663, 0xc664,0xc665,0xc666,0xc667,0xc668,0xc669,0xc66a,0xc66b,0xc66d,0xc66e, 0xc670,0xc672,0xc673,0xc674,0xc675,0xc676,0xc677,0xc67a,0xc67b,0xc67d, 0xc67e,0xc67f,0xc681,0xc682,0xc683,0xc684,0xc685,0xc686,0xc687,0xc68a, 0xc68c,0xc68e,0xc68f,0xc690,0xc691,0xc692,0xc693,0xc696,0xc697,0xc699, 0xc69a,0xc69b,0xc69d,0xc69e,0xc69f,0xc6a0,0xc6a1,0xc6a2,0xc6a3,0xc6a6 }, { /* ku 1f */ 0xc6a8,0xc6aa,0xc6ab,0xc6ac,0xc6ad,0xc6ae,0xc6af,0xc6b2,0xc6b3,0xc6b5, 0xc6b6,0xc6b7,0xc6bb,0xc6bc,0xc6bd,0xc6be,0xc6bf,0xc6c2,0xc6c4,0xc6c6, 0xc6c7,0xc6c8,0xc6c9,0xc6ca,0xc6cb,0xc6ce,UBOGON,UBOGON,UBOGON,UBOGON, UBOGON,UBOGON,0xc6cf,0xc6d1,0xc6d2,0xc6d3,0xc6d5,0xc6d6,0xc6d7,0xc6d8, 0xc6d9,0xc6da,0xc6db,0xc6de,0xc6df,0xc6e2,0xc6e3,0xc6e4,0xc6e5,0xc6e6, 0xc6e7,0xc6ea,0xc6eb,0xc6ed,0xc6ee,0xc6ef,0xc6f1,0xc6f2,UBOGON,UBOGON, UBOGON,UBOGON,UBOGON,UBOGON,0xc6f3,0xc6f4,0xc6f5,0xc6f6,0xc6f7,0xc6fa, 0xc6fb,0xc6fc,0xc6fe,0xc6ff,0xc700,0xc701,0xc702,0xc703,0xc706,0xc707, 0xc709,0xc70a,0xc70b,0xc70d,0xc70e,0xc70f,0xc710,0xc711,0xc712,0xc713, 0xc716,0xc718,0xc71a,0xc71b,0xc71c,0xc71d,0xc71e,0xc71f,0xc722,0xc723, 0xc725,0xc726,0xc727,0xc729,0xc72a,0xc72b,0xc72c,0xc72d,0xc72e,0xc72f, 0xc732,0xc734,0xc736,0xc738,0xc739,0xc73a,0xc73b,0xc73e,0xc73f,0xc741, 0xc742,0xc743,0xc745,0xc746,0xc747,0xc748,0xc749,0xc74b,0xc74e,0xc750, 0xc759,0xc75a,0xc75b,0xc75d,0xc75e,0xc75f,0xc761,0xc762,0xc763,0xc764, 0xc765,0xc766,0xc767,0xc769,0xc76a,0xc76c,0xc76d,0xc76e,0xc76f,0xc770, 0xc771,0xc772,0xc773,0xc776,0xc777,0xc779,0xc77a,0xc77b,0xc77f,0xc780, 0xc781,0xc782,0xc786,0xc78b,0xc78c,0xc78d,0xc78f,0xc792,0xc793,0xc795, 0xc799,0xc79b,0xc79c,0xc79d,0xc79e,0xc79f,0xc7a2,0xc7a7,0xc7a8,0xc7a9, 0xc7aa,0xc7ab,0xc7ae,0xc7af,0xc7b1,0xc7b2,0xc7b3,0xc7b5,0xc7b6,0xc7b7 }, { /* ku 20 */ 0xc7b8,0xc7b9,0xc7ba,0xc7bb,0xc7be,0xc7c2,0xc7c3,0xc7c4,0xc7c5,0xc7c6, 0xc7c7,0xc7ca,0xc7cb,0xc7cd,0xc7cf,0xc7d1,0xc7d2,0xc7d3,0xc7d4,0xc7d5, 0xc7d6,0xc7d7,0xc7d9,0xc7da,0xc7db,0xc7dc,UBOGON,UBOGON,UBOGON,UBOGON, UBOGON,UBOGON,0xc7de,0xc7df,0xc7e0,0xc7e1,0xc7e2,0xc7e3,0xc7e5,0xc7e6, 0xc7e7,0xc7e9,0xc7ea,0xc7eb,0xc7ed,0xc7ee,0xc7ef,0xc7f0,0xc7f1,0xc7f2, 0xc7f3,0xc7f4,0xc7f5,0xc7f6,0xc7f7,0xc7f8,0xc7f9,0xc7fa,UBOGON,UBOGON, UBOGON,UBOGON,UBOGON,UBOGON,0xc7fb,0xc7fc,0xc7fd,0xc7fe,0xc7ff,0xc802, 0xc803,0xc805,0xc806,0xc807,0xc809,0xc80b,0xc80c,0xc80d,0xc80e,0xc80f, 0xc812,0xc814,0xc817,0xc818,0xc819,0xc81a,0xc81b,0xc81e,0xc81f,0xc821, 0xc822,0xc823,0xc825,0xc826,0xc827,0xc828,0xc829,0xc82a,0xc82b,0xc82e, 0xc830,0xc832,0xc833,0xc834,0xc835,0xc836,0xc837,0xc839,0xc83a,0xc83b, 0xc83d,0xc83e,0xc83f,0xc841,0xc842,0xc843,0xc844,0xc845,0xc846,0xc847, 0xc84a,0xc84b,0xc84e,0xc84f,0xc850,0xc851,0xc852,0xc853,0xc855,0xc856, 0xc857,0xc858,0xc859,0xc85a,0xc85b,0xc85c,0xc85d,0xc85e,0xc85f,0xc860, 0xc861,0xc862,0xc863,0xc864,0xc865,0xc866,0xc867,0xc868,0xc869,0xc86a, 0xc86b,0xc86c,0xc86d,0xc86e,0xc86f,0xc872,0xc873,0xc875,0xc876,0xc877, 0xc879,0xc87b,0xc87c,0xc87d,0xc87e,0xc87f,0xc882,0xc884,0xc888,0xc889, 0xc88a,0xc88e,0xc88f,0xc890,0xc891,0xc892,0xc893,0xc895,0xc896,0xc897, 0xc898,0xc899,0xc89a,0xc89b,0xc89c,0xc89e,0xc8a0,0xc8a2,0xc8a3,0xc8a4 }, { /* ku 21 */ 0xc8a5,0xc8a6,0xc8a7,0xc8a9,0xc8aa,0xc8ab,0xc8ac,0xc8ad,0xc8ae,0xc8af, 0xc8b0,0xc8b1,0xc8b2,0xc8b3,0xc8b4,0xc8b5,0xc8b6,0xc8b7,0xc8b8,0xc8b9, 0xc8ba,0xc8bb,0xc8be,0xc8bf,0xc8c0,0xc8c1,UBOGON,UBOGON,UBOGON,UBOGON, UBOGON,UBOGON,0xc8c2,0xc8c3,0xc8c5,0xc8c6,0xc8c7,0xc8c9,0xc8ca,0xc8cb, 0xc8cd,0xc8ce,0xc8cf,0xc8d0,0xc8d1,0xc8d2,0xc8d3,0xc8d6,0xc8d8,0xc8da, 0xc8db,0xc8dc,0xc8dd,0xc8de,0xc8df,0xc8e2,0xc8e3,0xc8e5,UBOGON,UBOGON, UBOGON,UBOGON,UBOGON,UBOGON,0xc8e6,0xc8e7,0xc8e8,0xc8e9,0xc8ea,0xc8eb, 0xc8ec,0xc8ed,0xc8ee,0xc8ef,0xc8f0,0xc8f1,0xc8f2,0xc8f3,0xc8f4,0xc8f6, 0xc8f7,0xc8f8,0xc8f9,0xc8fa,0xc8fb,0xc8fe,0xc8ff,0xc901,0xc902,0xc903, 0xc907,0xc908,0xc909,0xc90a,0xc90b,0xc90e,0x3000,0x3001,0x3002,0x00b7, 0x2025,0x2026,0x00a8,0x3003,0x00ad,0x2015,0x2225,0xff3c,0x223c,0x2018, 0x2019,0x201c,0x201d,0x3014,0x3015,0x3008,0x3009,0x300a,0x300b,0x300c, 0x300d,0x300e,0x300f,0x3010,0x3011,0x00b1,0x00d7,0x00f7,0x2260,0x2264, 0x2265,0x221e,0x2234,0x00b0,0x2032,0x2033,0x2103,0x212b,0xffe0,0xffe1, 0xffe5,0x2642,0x2640,0x2220,0x22a5,0x2312,0x2202,0x2207,0x2261,0x2252, 0x00a7,0x203b,0x2606,0x2605,0x25cb,0x25cf,0x25ce,0x25c7,0x25c6,0x25a1, 0x25a0,0x25b3,0x25b2,0x25bd,0x25bc,0x2192,0x2190,0x2191,0x2193,0x2194, 0x3013,0x226a,0x226b,0x221a,0x223d,0x221d,0x2235,0x222b,0x222c,0x2208, 0x220b,0x2286,0x2287,0x2282,0x2283,0x222a,0x2229,0x2227,0x2228,0xffe2 }, { /* ku 22 */ 0xc910,0xc912,0xc913,0xc914,0xc915,0xc916,0xc917,0xc919,0xc91a,0xc91b, 0xc91c,0xc91d,0xc91e,0xc91f,0xc920,0xc921,0xc922,0xc923,0xc924,0xc925, 0xc926,0xc927,0xc928,0xc929,0xc92a,0xc92b,UBOGON,UBOGON,UBOGON,UBOGON, UBOGON,UBOGON,0xc92d,0xc92e,0xc92f,0xc930,0xc931,0xc932,0xc933,0xc935, 0xc936,0xc937,0xc938,0xc939,0xc93a,0xc93b,0xc93c,0xc93d,0xc93e,0xc93f, 0xc940,0xc941,0xc942,0xc943,0xc944,0xc945,0xc946,0xc947,UBOGON,UBOGON, UBOGON,UBOGON,UBOGON,UBOGON,0xc948,0xc949,0xc94a,0xc94b,0xc94c,0xc94d, 0xc94e,0xc94f,0xc952,0xc953,0xc955,0xc956,0xc957,0xc959,0xc95a,0xc95b, 0xc95c,0xc95d,0xc95e,0xc95f,0xc962,0xc964,0xc965,0xc966,0xc967,0xc968, 0xc969,0xc96a,0xc96b,0xc96d,0xc96e,0xc96f,0x21d2,0x21d4,0x2200,0x2203, 0x00b4,0xff5e,0x02c7,0x02d8,0x02dd,0x02da,0x02d9,0x00b8,0x02db,0x00a1, 0x00bf,0x02d0,0x222e,0x2211,0x220f,0x00a4,0x2109,0x2030,0x25c1,0x25c0, 0x25b7,0x25b6,0x2664,0x2660,0x2661,0x2665,0x2667,0x2663,0x2299,0x25c8, 0x25a3,0x25d0,0x25d1,0x2592,0x25a4,0x25a5,0x25a8,0x25a7,0x25a6,0x25a9, 0x2668,0x260f,0x260e,0x261c,0x261e,0x00b6,0x2020,0x2021,0x2195,0x2197, 0x2199,0x2196,0x2198,0x266d,0x2669,0x266a,0x266c,0x327f,0x321c,0x2116, 0x33c7,0x2122,0x33c2,0x33d8,0x2121,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON, UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON, UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON }, { /* ku 23 */ 0xc971,0xc972,0xc973,0xc975,0xc976,0xc977,0xc978,0xc979,0xc97a,0xc97b, 0xc97d,0xc97e,0xc97f,0xc980,0xc981,0xc982,0xc983,0xc984,0xc985,0xc986, 0xc987,0xc98a,0xc98b,0xc98d,0xc98e,0xc98f,UBOGON,UBOGON,UBOGON,UBOGON, UBOGON,UBOGON,0xc991,0xc992,0xc993,0xc994,0xc995,0xc996,0xc997,0xc99a, 0xc99c,0xc99e,0xc99f,0xc9a0,0xc9a1,0xc9a2,0xc9a3,0xc9a4,0xc9a5,0xc9a6, 0xc9a7,0xc9a8,0xc9a9,0xc9aa,0xc9ab,0xc9ac,0xc9ad,0xc9ae,UBOGON,UBOGON, UBOGON,UBOGON,UBOGON,UBOGON,0xc9af,0xc9b0,0xc9b1,0xc9b2,0xc9b3,0xc9b4, 0xc9b5,0xc9b6,0xc9b7,0xc9b8,0xc9b9,0xc9ba,0xc9bb,0xc9bc,0xc9bd,0xc9be, 0xc9bf,0xc9c2,0xc9c3,0xc9c5,0xc9c6,0xc9c9,0xc9cb,0xc9cc,0xc9cd,0xc9ce, 0xc9cf,0xc9d2,0xc9d4,0xc9d7,0xc9d8,0xc9db,0xff01,0xff02,0xff03,0xff04, 0xff05,0xff06,0xff07,0xff08,0xff09,0xff0a,0xff0b,0xff0c,0xff0d,0xff0e, 0xff0f,0xff10,0xff11,0xff12,0xff13,0xff14,0xff15,0xff16,0xff17,0xff18, 0xff19,0xff1a,0xff1b,0xff1c,0xff1d,0xff1e,0xff1f,0xff20,0xff21,0xff22, 0xff23,0xff24,0xff25,0xff26,0xff27,0xff28,0xff29,0xff2a,0xff2b,0xff2c, 0xff2d,0xff2e,0xff2f,0xff30,0xff31,0xff32,0xff33,0xff34,0xff35,0xff36, 0xff37,0xff38,0xff39,0xff3a,0xff3b,0xffe6,0xff3d,0xff3e,0xff3f,0xff40, 0xff41,0xff42,0xff43,0xff44,0xff45,0xff46,0xff47,0xff48,0xff49,0xff4a, 0xff4b,0xff4c,0xff4d,0xff4e,0xff4f,0xff50,0xff51,0xff52,0xff53,0xff54, 0xff55,0xff56,0xff57,0xff58,0xff59,0xff5a,0xff5b,0xff5c,0xff5d,0xffe3 }, { /* ku 24 */ 0xc9de,0xc9df,0xc9e1,0xc9e3,0xc9e5,0xc9e6,0xc9e8,0xc9e9,0xc9ea,0xc9eb, 0xc9ee,0xc9f2,0xc9f3,0xc9f4,0xc9f5,0xc9f6,0xc9f7,0xc9fa,0xc9fb,0xc9fd, 0xc9fe,0xc9ff,0xca01,0xca02,0xca03,0xca04,UBOGON,UBOGON,UBOGON,UBOGON, UBOGON,UBOGON,0xca05,0xca06,0xca07,0xca0a,0xca0e,0xca0f,0xca10,0xca11, 0xca12,0xca13,0xca15,0xca16,0xca17,0xca19,0xca1a,0xca1b,0xca1c,0xca1d, 0xca1e,0xca1f,0xca20,0xca21,0xca22,0xca23,0xca24,0xca25,UBOGON,UBOGON, UBOGON,UBOGON,UBOGON,UBOGON,0xca26,0xca27,0xca28,0xca2a,0xca2b,0xca2c, 0xca2d,0xca2e,0xca2f,0xca30,0xca31,0xca32,0xca33,0xca34,0xca35,0xca36, 0xca37,0xca38,0xca39,0xca3a,0xca3b,0xca3c,0xca3d,0xca3e,0xca3f,0xca40, 0xca41,0xca42,0xca43,0xca44,0xca45,0xca46,0x3131,0x3132,0x3133,0x3134, 0x3135,0x3136,0x3137,0x3138,0x3139,0x313a,0x313b,0x313c,0x313d,0x313e, 0x313f,0x3140,0x3141,0x3142,0x3143,0x3144,0x3145,0x3146,0x3147,0x3148, 0x3149,0x314a,0x314b,0x314c,0x314d,0x314e,0x314f,0x3150,0x3151,0x3152, 0x3153,0x3154,0x3155,0x3156,0x3157,0x3158,0x3159,0x315a,0x315b,0x315c, 0x315d,0x315e,0x315f,0x3160,0x3161,0x3162,0x3163,0x3164,0x3165,0x3166, 0x3167,0x3168,0x3169,0x316a,0x316b,0x316c,0x316d,0x316e,0x316f,0x3170, 0x3171,0x3172,0x3173,0x3174,0x3175,0x3176,0x3177,0x3178,0x3179,0x317a, 0x317b,0x317c,0x317d,0x317e,0x317f,0x3180,0x3181,0x3182,0x3183,0x3184, 0x3185,0x3186,0x3187,0x3188,0x3189,0x318a,0x318b,0x318c,0x318d,0x318e }, { /* ku 25 */ 0xca47,0xca48,0xca49,0xca4a,0xca4b,0xca4e,0xca4f,0xca51,0xca52,0xca53, 0xca55,0xca56,0xca57,0xca58,0xca59,0xca5a,0xca5b,0xca5e,0xca62,0xca63, 0xca64,0xca65,0xca66,0xca67,0xca69,0xca6a,UBOGON,UBOGON,UBOGON,UBOGON, UBOGON,UBOGON,0xca6b,0xca6c,0xca6d,0xca6e,0xca6f,0xca70,0xca71,0xca72, 0xca73,0xca74,0xca75,0xca76,0xca77,0xca78,0xca79,0xca7a,0xca7b,0xca7c, 0xca7e,0xca7f,0xca80,0xca81,0xca82,0xca83,0xca85,0xca86,UBOGON,UBOGON, UBOGON,UBOGON,UBOGON,UBOGON,0xca87,0xca88,0xca89,0xca8a,0xca8b,0xca8c, 0xca8d,0xca8e,0xca8f,0xca90,0xca91,0xca92,0xca93,0xca94,0xca95,0xca96, 0xca97,0xca99,0xca9a,0xca9b,0xca9c,0xca9d,0xca9e,0xca9f,0xcaa0,0xcaa1, 0xcaa2,0xcaa3,0xcaa4,0xcaa5,0xcaa6,0xcaa7,0x2170,0x2171,0x2172,0x2173, 0x2174,0x2175,0x2176,0x2177,0x2178,0x2179,UBOGON,UBOGON,UBOGON,UBOGON, UBOGON,0x2160,0x2161,0x2162,0x2163,0x2164,0x2165,0x2166,0x2167,0x2168, 0x2169,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,0x0391,0x0392, 0x0393,0x0394,0x0395,0x0396,0x0397,0x0398,0x0399,0x039a,0x039b,0x039c, 0x039d,0x039e,0x039f,0x03a0,0x03a1,0x03a3,0x03a4,0x03a5,0x03a6,0x03a7, 0x03a8,0x03a9,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON, 0x03b1,0x03b2,0x03b3,0x03b4,0x03b5,0x03b6,0x03b7,0x03b8,0x03b9,0x03ba, 0x03bb,0x03bc,0x03bd,0x03be,0x03bf,0x03c0,0x03c1,0x03c3,0x03c4,0x03c5, 0x03c6,0x03c7,0x03c8,0x03c9,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON }, { /* ku 26 */ 0xcaa8,0xcaa9,0xcaaa,0xcaab,0xcaac,0xcaad,0xcaae,0xcaaf,0xcab0,0xcab1, 0xcab2,0xcab3,0xcab4,0xcab5,0xcab6,0xcab7,0xcab8,0xcab9,0xcaba,0xcabb, 0xcabe,0xcabf,0xcac1,0xcac2,0xcac3,0xcac5,UBOGON,UBOGON,UBOGON,UBOGON, UBOGON,UBOGON,0xcac6,0xcac7,0xcac8,0xcac9,0xcaca,0xcacb,0xcace,0xcad0, 0xcad2,0xcad4,0xcad5,0xcad6,0xcad7,0xcada,0xcadb,0xcadc,0xcadd,0xcade, 0xcadf,0xcae1,0xcae2,0xcae3,0xcae4,0xcae5,0xcae6,0xcae7,UBOGON,UBOGON, UBOGON,UBOGON,UBOGON,UBOGON,0xcae8,0xcae9,0xcaea,0xcaeb,0xcaed,0xcaee, 0xcaef,0xcaf0,0xcaf1,0xcaf2,0xcaf3,0xcaf5,0xcaf6,0xcaf7,0xcaf8,0xcaf9, 0xcafa,0xcafb,0xcafc,0xcafd,0xcafe,0xcaff,0xcb00,0xcb01,0xcb02,0xcb03, 0xcb04,0xcb05,0xcb06,0xcb07,0xcb09,0xcb0a,0x2500,0x2502,0x250c,0x2510, 0x2518,0x2514,0x251c,0x252c,0x2524,0x2534,0x253c,0x2501,0x2503,0x250f, 0x2513,0x251b,0x2517,0x2523,0x2533,0x252b,0x253b,0x254b,0x2520,0x252f, 0x2528,0x2537,0x253f,0x251d,0x2530,0x2525,0x2538,0x2542,0x2512,0x2511, 0x251a,0x2519,0x2516,0x2515,0x250e,0x250d,0x251e,0x251f,0x2521,0x2522, 0x2526,0x2527,0x2529,0x252a,0x252d,0x252e,0x2531,0x2532,0x2535,0x2536, 0x2539,0x253a,0x253d,0x253e,0x2540,0x2541,0x2543,0x2544,0x2545,0x2546, 0x2547,0x2548,0x2549,0x254a,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON, UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON, UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON }, { /* ku 27 */ 0xcb0b,0xcb0c,0xcb0d,0xcb0e,0xcb0f,0xcb11,0xcb12,0xcb13,0xcb15,0xcb16, 0xcb17,0xcb19,0xcb1a,0xcb1b,0xcb1c,0xcb1d,0xcb1e,0xcb1f,0xcb22,0xcb23, 0xcb24,0xcb25,0xcb26,0xcb27,0xcb28,0xcb29,UBOGON,UBOGON,UBOGON,UBOGON, UBOGON,UBOGON,0xcb2a,0xcb2b,0xcb2c,0xcb2d,0xcb2e,0xcb2f,0xcb30,0xcb31, 0xcb32,0xcb33,0xcb34,0xcb35,0xcb36,0xcb37,0xcb38,0xcb39,0xcb3a,0xcb3b, 0xcb3c,0xcb3d,0xcb3e,0xcb3f,0xcb40,0xcb42,0xcb43,0xcb44,UBOGON,UBOGON, UBOGON,UBOGON,UBOGON,UBOGON,0xcb45,0xcb46,0xcb47,0xcb4a,0xcb4b,0xcb4d, 0xcb4e,0xcb4f,0xcb51,0xcb52,0xcb53,0xcb54,0xcb55,0xcb56,0xcb57,0xcb5a, 0xcb5b,0xcb5c,0xcb5e,0xcb5f,0xcb60,0xcb61,0xcb62,0xcb63,0xcb65,0xcb66, 0xcb67,0xcb68,0xcb69,0xcb6a,0xcb6b,0xcb6c,0x3395,0x3396,0x3397,0x2113, 0x3398,0x33c4,0x33a3,0x33a4,0x33a5,0x33a6,0x3399,0x339a,0x339b,0x339c, 0x339d,0x339e,0x339f,0x33a0,0x33a1,0x33a2,0x33ca,0x338d,0x338e,0x338f, 0x33cf,0x3388,0x3389,0x33c8,0x33a7,0x33a8,0x33b0,0x33b1,0x33b2,0x33b3, 0x33b4,0x33b5,0x33b6,0x33b7,0x33b8,0x33b9,0x3380,0x3381,0x3382,0x3383, 0x3384,0x33ba,0x33bb,0x33bc,0x33bd,0x33be,0x33bf,0x3390,0x3391,0x3392, 0x3393,0x3394,0x2126,0x33c0,0x33c1,0x338a,0x338b,0x338c,0x33d6,0x33c5, 0x33ad,0x33ae,0x33af,0x33db,0x33a9,0x33aa,0x33ab,0x33ac,0x33dd,0x33d0, 0x33d3,0x33c3,0x33c9,0x33dc,0x33c6,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON, UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON }, { /* ku 28 */ 0xcb6d,0xcb6e,0xcb6f,0xcb70,0xcb71,0xcb72,0xcb73,0xcb74,0xcb75,0xcb76, 0xcb77,0xcb7a,0xcb7b,0xcb7c,0xcb7d,0xcb7e,0xcb7f,0xcb80,0xcb81,0xcb82, 0xcb83,0xcb84,0xcb85,0xcb86,0xcb87,0xcb88,UBOGON,UBOGON,UBOGON,UBOGON, UBOGON,UBOGON,0xcb89,0xcb8a,0xcb8b,0xcb8c,0xcb8d,0xcb8e,0xcb8f,0xcb90, 0xcb91,0xcb92,0xcb93,0xcb94,0xcb95,0xcb96,0xcb97,0xcb98,0xcb99,0xcb9a, 0xcb9b,0xcb9d,0xcb9e,0xcb9f,0xcba0,0xcba1,0xcba2,0xcba3,UBOGON,UBOGON, UBOGON,UBOGON,UBOGON,UBOGON,0xcba4,0xcba5,0xcba6,0xcba7,0xcba8,0xcba9, 0xcbaa,0xcbab,0xcbac,0xcbad,0xcbae,0xcbaf,0xcbb0,0xcbb1,0xcbb2,0xcbb3, 0xcbb4,0xcbb5,0xcbb6,0xcbb7,0xcbb9,0xcbba,0xcbbb,0xcbbc,0xcbbd,0xcbbe, 0xcbbf,0xcbc0,0xcbc1,0xcbc2,0xcbc3,0xcbc4,0x00c6,0x00d0,0x00aa,0x0126, UBOGON,0x0132,UBOGON,0x013f,0x0141,0x00d8,0x0152,0x00ba,0x00de,0x0166, 0x014a,UBOGON,0x3260,0x3261,0x3262,0x3263,0x3264,0x3265,0x3266,0x3267, 0x3268,0x3269,0x326a,0x326b,0x326c,0x326d,0x326e,0x326f,0x3270,0x3271, 0x3272,0x3273,0x3274,0x3275,0x3276,0x3277,0x3278,0x3279,0x327a,0x327b, 0x24d0,0x24d1,0x24d2,0x24d3,0x24d4,0x24d5,0x24d6,0x24d7,0x24d8,0x24d9, 0x24da,0x24db,0x24dc,0x24dd,0x24de,0x24df,0x24e0,0x24e1,0x24e2,0x24e3, 0x24e4,0x24e5,0x24e6,0x24e7,0x24e8,0x24e9,0x2460,0x2461,0x2462,0x2463, 0x2464,0x2465,0x2466,0x2467,0x2468,0x2469,0x246a,0x246b,0x246c,0x246d, 0x246e,0x00bd,0x2153,0x2154,0x00bc,0x00be,0x215b,0x215c,0x215d,0x215e }, { /* ku 29 */ 0xcbc5,0xcbc6,0xcbc7,0xcbc8,0xcbc9,0xcbca,0xcbcb,0xcbcc,0xcbcd,0xcbce, 0xcbcf,0xcbd0,0xcbd1,0xcbd2,0xcbd3,0xcbd5,0xcbd6,0xcbd7,0xcbd8,0xcbd9, 0xcbda,0xcbdb,0xcbdc,0xcbdd,0xcbde,0xcbdf,UBOGON,UBOGON,UBOGON,UBOGON, UBOGON,UBOGON,0xcbe0,0xcbe1,0xcbe2,0xcbe3,0xcbe5,0xcbe6,0xcbe8,0xcbea, 0xcbeb,0xcbec,0xcbed,0xcbee,0xcbef,0xcbf0,0xcbf1,0xcbf2,0xcbf3,0xcbf4, 0xcbf5,0xcbf6,0xcbf7,0xcbf8,0xcbf9,0xcbfa,0xcbfb,0xcbfc,UBOGON,UBOGON, UBOGON,UBOGON,UBOGON,UBOGON,0xcbfd,0xcbfe,0xcbff,0xcc00,0xcc01,0xcc02, 0xcc03,0xcc04,0xcc05,0xcc06,0xcc07,0xcc08,0xcc09,0xcc0a,0xcc0b,0xcc0e, 0xcc0f,0xcc11,0xcc12,0xcc13,0xcc15,0xcc16,0xcc17,0xcc18,0xcc19,0xcc1a, 0xcc1b,0xcc1e,0xcc1f,0xcc20,0xcc23,0xcc24,0x00e6,0x0111,0x00f0,0x0127, 0x0131,0x0133,0x0138,0x0140,0x0142,0x00f8,0x0153,0x00df,0x00fe,0x0167, 0x014b,0x0149,0x3200,0x3201,0x3202,0x3203,0x3204,0x3205,0x3206,0x3207, 0x3208,0x3209,0x320a,0x320b,0x320c,0x320d,0x320e,0x320f,0x3210,0x3211, 0x3212,0x3213,0x3214,0x3215,0x3216,0x3217,0x3218,0x3219,0x321a,0x321b, 0x249c,0x249d,0x249e,0x249f,0x24a0,0x24a1,0x24a2,0x24a3,0x24a4,0x24a5, 0x24a6,0x24a7,0x24a8,0x24a9,0x24aa,0x24ab,0x24ac,0x24ad,0x24ae,0x24af, 0x24b0,0x24b1,0x24b2,0x24b3,0x24b4,0x24b5,0x2474,0x2475,0x2476,0x2477, 0x2478,0x2479,0x247a,0x247b,0x247c,0x247d,0x247e,0x247f,0x2480,0x2481, 0x2482,0x00b9,0x00b2,0x00b3,0x2074,0x207f,0x2081,0x2082,0x2083,0x2084 }, { /* ku 2a */ 0xcc25,0xcc26,0xcc2a,0xcc2b,0xcc2d,0xcc2f,0xcc31,0xcc32,0xcc33,0xcc34, 0xcc35,0xcc36,0xcc37,0xcc3a,0xcc3f,0xcc40,0xcc41,0xcc42,0xcc43,0xcc46, 0xcc47,0xcc49,0xcc4a,0xcc4b,0xcc4d,0xcc4e,UBOGON,UBOGON,UBOGON,UBOGON, UBOGON,UBOGON,0xcc4f,0xcc50,0xcc51,0xcc52,0xcc53,0xcc56,0xcc5a,0xcc5b, 0xcc5c,0xcc5d,0xcc5e,0xcc5f,0xcc61,0xcc62,0xcc63,0xcc65,0xcc67,0xcc69, 0xcc6a,0xcc6b,0xcc6c,0xcc6d,0xcc6e,0xcc6f,0xcc71,0xcc72,UBOGON,UBOGON, UBOGON,UBOGON,UBOGON,UBOGON,0xcc73,0xcc74,0xcc76,0xcc77,0xcc78,0xcc79, 0xcc7a,0xcc7b,0xcc7c,0xcc7d,0xcc7e,0xcc7f,0xcc80,0xcc81,0xcc82,0xcc83, 0xcc84,0xcc85,0xcc86,0xcc87,0xcc88,0xcc89,0xcc8a,0xcc8b,0xcc8c,0xcc8d, 0xcc8e,0xcc8f,0xcc90,0xcc91,0xcc92,0xcc93,0x3041,0x3042,0x3043,0x3044, 0x3045,0x3046,0x3047,0x3048,0x3049,0x304a,0x304b,0x304c,0x304d,0x304e, 0x304f,0x3050,0x3051,0x3052,0x3053,0x3054,0x3055,0x3056,0x3057,0x3058, 0x3059,0x305a,0x305b,0x305c,0x305d,0x305e,0x305f,0x3060,0x3061,0x3062, 0x3063,0x3064,0x3065,0x3066,0x3067,0x3068,0x3069,0x306a,0x306b,0x306c, 0x306d,0x306e,0x306f,0x3070,0x3071,0x3072,0x3073,0x3074,0x3075,0x3076, 0x3077,0x3078,0x3079,0x307a,0x307b,0x307c,0x307d,0x307e,0x307f,0x3080, 0x3081,0x3082,0x3083,0x3084,0x3085,0x3086,0x3087,0x3088,0x3089,0x308a, 0x308b,0x308c,0x308d,0x308e,0x308f,0x3090,0x3091,0x3092,0x3093,UBOGON, UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON }, { /* ku 2b */ 0xcc94,0xcc95,0xcc96,0xcc97,0xcc9a,0xcc9b,0xcc9d,0xcc9e,0xcc9f,0xcca1, 0xcca2,0xcca3,0xcca4,0xcca5,0xcca6,0xcca7,0xccaa,0xccae,0xccaf,0xccb0, 0xccb1,0xccb2,0xccb3,0xccb6,0xccb7,0xccb9,UBOGON,UBOGON,UBOGON,UBOGON, UBOGON,UBOGON,0xccba,0xccbb,0xccbd,0xccbe,0xccbf,0xccc0,0xccc1,0xccc2, 0xccc3,0xccc6,0xccc8,0xccca,0xcccb,0xcccc,0xcccd,0xccce,0xcccf,0xccd1, 0xccd2,0xccd3,0xccd5,0xccd6,0xccd7,0xccd8,0xccd9,0xccda,UBOGON,UBOGON, UBOGON,UBOGON,UBOGON,UBOGON,0xccdb,0xccdc,0xccdd,0xccde,0xccdf,0xcce0, 0xcce1,0xcce2,0xcce3,0xcce5,0xcce6,0xcce7,0xcce8,0xcce9,0xccea,0xcceb, 0xcced,0xccee,0xccef,0xccf1,0xccf2,0xccf3,0xccf4,0xccf5,0xccf6,0xccf7, 0xccf8,0xccf9,0xccfa,0xccfb,0xccfc,0xccfd,0x30a1,0x30a2,0x30a3,0x30a4, 0x30a5,0x30a6,0x30a7,0x30a8,0x30a9,0x30aa,0x30ab,0x30ac,0x30ad,0x30ae, 0x30af,0x30b0,0x30b1,0x30b2,0x30b3,0x30b4,0x30b5,0x30b6,0x30b7,0x30b8, 0x30b9,0x30ba,0x30bb,0x30bc,0x30bd,0x30be,0x30bf,0x30c0,0x30c1,0x30c2, 0x30c3,0x30c4,0x30c5,0x30c6,0x30c7,0x30c8,0x30c9,0x30ca,0x30cb,0x30cc, 0x30cd,0x30ce,0x30cf,0x30d0,0x30d1,0x30d2,0x30d3,0x30d4,0x30d5,0x30d6, 0x30d7,0x30d8,0x30d9,0x30da,0x30db,0x30dc,0x30dd,0x30de,0x30df,0x30e0, 0x30e1,0x30e2,0x30e3,0x30e4,0x30e5,0x30e6,0x30e7,0x30e8,0x30e9,0x30ea, 0x30eb,0x30ec,0x30ed,0x30ee,0x30ef,0x30f0,0x30f1,0x30f2,0x30f3,0x30f4, 0x30f5,0x30f6,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON }, { /* ku 2c */ 0xccfe,0xccff,0xcd00,0xcd02,0xcd03,0xcd04,0xcd05,0xcd06,0xcd07,0xcd0a, 0xcd0b,0xcd0d,0xcd0e,0xcd0f,0xcd11,0xcd12,0xcd13,0xcd14,0xcd15,0xcd16, 0xcd17,0xcd1a,0xcd1c,0xcd1e,0xcd1f,0xcd20,UBOGON,UBOGON,UBOGON,UBOGON, UBOGON,UBOGON,0xcd21,0xcd22,0xcd23,0xcd25,0xcd26,0xcd27,0xcd29,0xcd2a, 0xcd2b,0xcd2d,0xcd2e,0xcd2f,0xcd30,0xcd31,0xcd32,0xcd33,0xcd34,0xcd35, 0xcd36,0xcd37,0xcd38,0xcd3a,0xcd3b,0xcd3c,0xcd3d,0xcd3e,UBOGON,UBOGON, UBOGON,UBOGON,UBOGON,UBOGON,0xcd3f,0xcd40,0xcd41,0xcd42,0xcd43,0xcd44, 0xcd45,0xcd46,0xcd47,0xcd48,0xcd49,0xcd4a,0xcd4b,0xcd4c,0xcd4d,0xcd4e, 0xcd4f,0xcd50,0xcd51,0xcd52,0xcd53,0xcd54,0xcd55,0xcd56,0xcd57,0xcd58, 0xcd59,0xcd5a,0xcd5b,0xcd5d,0xcd5e,0xcd5f,0x0410,0x0411,0x0412,0x0413, 0x0414,0x0415,0x0401,0x0416,0x0417,0x0418,0x0419,0x041a,0x041b,0x041c, 0x041d,0x041e,0x041f,0x0420,0x0421,0x0422,0x0423,0x0424,0x0425,0x0426, 0x0427,0x0428,0x0429,0x042a,0x042b,0x042c,0x042d,0x042e,0x042f,UBOGON, UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON, UBOGON,UBOGON,UBOGON,UBOGON,0x0430,0x0431,0x0432,0x0433,0x0434,0x0435, 0x0451,0x0436,0x0437,0x0438,0x0439,0x043a,0x043b,0x043c,0x043d,0x043e, 0x043f,0x0440,0x0441,0x0442,0x0443,0x0444,0x0445,0x0446,0x0447,0x0448, 0x0449,0x044a,0x044b,0x044c,0x044d,0x044e,0x044f,UBOGON,UBOGON,UBOGON, UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON }, { /* ku 2d */ 0xcd61,0xcd62,0xcd63,0xcd65,0xcd66,0xcd67,0xcd68,0xcd69,0xcd6a,0xcd6b, 0xcd6e,0xcd70,0xcd72,0xcd73,0xcd74,0xcd75,0xcd76,0xcd77,0xcd79,0xcd7a, 0xcd7b,0xcd7c,0xcd7d,0xcd7e,0xcd7f,0xcd80,UBOGON,UBOGON,UBOGON,UBOGON, UBOGON,UBOGON,0xcd81,0xcd82,0xcd83,0xcd84,0xcd85,0xcd86,0xcd87,0xcd89, 0xcd8a,0xcd8b,0xcd8c,0xcd8d,0xcd8e,0xcd8f,0xcd90,0xcd91,0xcd92,0xcd93, 0xcd96,0xcd97,0xcd99,0xcd9a,0xcd9b,0xcd9d,0xcd9e,0xcd9f,UBOGON,UBOGON, UBOGON,UBOGON,UBOGON,UBOGON,0xcda0,0xcda1,0xcda2,0xcda3,0xcda6,0xcda8, 0xcdaa,0xcdab,0xcdac,0xcdad,0xcdae,0xcdaf,0xcdb1,0xcdb2,0xcdb3,0xcdb4, 0xcdb5,0xcdb6,0xcdb7,0xcdb8,0xcdb9,0xcdba,0xcdbb,0xcdbc,0xcdbd,0xcdbe, 0xcdbf,0xcdc0,0xcdc1,0xcdc2,0xcdc3,0xcdc5,UBOGON,UBOGON,UBOGON,UBOGON, UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON, UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON, UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON, UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON, UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON, UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON, UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON, UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON, UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON }, { /* ku 2e */ 0xcdc6,0xcdc7,0xcdc8,0xcdc9,0xcdca,0xcdcb,0xcdcd,0xcdce,0xcdcf,0xcdd1, 0xcdd2,0xcdd3,0xcdd4,0xcdd5,0xcdd6,0xcdd7,0xcdd8,0xcdd9,0xcdda,0xcddb, 0xcddc,0xcddd,0xcdde,0xcddf,0xcde0,0xcde1,UBOGON,UBOGON,UBOGON,UBOGON, UBOGON,UBOGON,0xcde2,0xcde3,0xcde4,0xcde5,0xcde6,0xcde7,0xcde9,0xcdea, 0xcdeb,0xcded,0xcdee,0xcdef,0xcdf1,0xcdf2,0xcdf3,0xcdf4,0xcdf5,0xcdf6, 0xcdf7,0xcdfa,0xcdfc,0xcdfe,0xcdff,0xce00,0xce01,0xce02,UBOGON,UBOGON, UBOGON,UBOGON,UBOGON,UBOGON,0xce03,0xce05,0xce06,0xce07,0xce09,0xce0a, 0xce0b,0xce0d,0xce0e,0xce0f,0xce10,0xce11,0xce12,0xce13,0xce15,0xce16, 0xce17,0xce18,0xce1a,0xce1b,0xce1c,0xce1d,0xce1e,0xce1f,0xce22,0xce23, 0xce25,0xce26,0xce27,0xce29,0xce2a,0xce2b,UBOGON,UBOGON,UBOGON,UBOGON, UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON, UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON, UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON, UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON, UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON, UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON, UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON, UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON, UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON }, { /* ku 2f */ 0xce2c,0xce2d,0xce2e,0xce2f,0xce32,0xce34,0xce36,0xce37,0xce38,0xce39, 0xce3a,0xce3b,0xce3c,0xce3d,0xce3e,0xce3f,0xce40,0xce41,0xce42,0xce43, 0xce44,0xce45,0xce46,0xce47,0xce48,0xce49,UBOGON,UBOGON,UBOGON,UBOGON, UBOGON,UBOGON,0xce4a,0xce4b,0xce4c,0xce4d,0xce4e,0xce4f,0xce50,0xce51, 0xce52,0xce53,0xce54,0xce55,0xce56,0xce57,0xce5a,0xce5b,0xce5d,0xce5e, 0xce62,0xce63,0xce64,0xce65,0xce66,0xce67,0xce6a,0xce6c,UBOGON,UBOGON, UBOGON,UBOGON,UBOGON,UBOGON,0xce6e,0xce6f,0xce70,0xce71,0xce72,0xce73, 0xce76,0xce77,0xce79,0xce7a,0xce7b,0xce7d,0xce7e,0xce7f,0xce80,0xce81, 0xce82,0xce83,0xce86,0xce88,0xce8a,0xce8b,0xce8c,0xce8d,0xce8e,0xce8f, 0xce92,0xce93,0xce95,0xce96,0xce97,0xce99,UBOGON,UBOGON,UBOGON,UBOGON, UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON, UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON, UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON, UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON, UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON, UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON, UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON, UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON, UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON }, { /* ku 30 */ 0xce9a,0xce9b,0xce9c,0xce9d,0xce9e,0xce9f,0xcea2,0xcea6,0xcea7,0xcea8, 0xcea9,0xceaa,0xceab,0xceae,0xceaf,0xceb0,0xceb1,0xceb2,0xceb3,0xceb4, 0xceb5,0xceb6,0xceb7,0xceb8,0xceb9,0xceba,UBOGON,UBOGON,UBOGON,UBOGON, UBOGON,UBOGON,0xcebb,0xcebc,0xcebd,0xcebe,0xcebf,0xcec0,0xcec2,0xcec3, 0xcec4,0xcec5,0xcec6,0xcec7,0xcec8,0xcec9,0xceca,0xcecb,0xcecc,0xcecd, 0xcece,0xcecf,0xced0,0xced1,0xced2,0xced3,0xced4,0xced5,UBOGON,UBOGON, UBOGON,UBOGON,UBOGON,UBOGON,0xced6,0xced7,0xced8,0xced9,0xceda,0xcedb, 0xcedc,0xcedd,0xcede,0xcedf,0xcee0,0xcee1,0xcee2,0xcee3,0xcee6,0xcee7, 0xcee9,0xceea,0xceed,0xceee,0xceef,0xcef0,0xcef1,0xcef2,0xcef3,0xcef6, 0xcefa,0xcefb,0xcefc,0xcefd,0xcefe,0xceff,0xac00,0xac01,0xac04,0xac07, 0xac08,0xac09,0xac0a,0xac10,0xac11,0xac12,0xac13,0xac14,0xac15,0xac16, 0xac17,0xac19,0xac1a,0xac1b,0xac1c,0xac1d,0xac20,0xac24,0xac2c,0xac2d, 0xac2f,0xac30,0xac31,0xac38,0xac39,0xac3c,0xac40,0xac4b,0xac4d,0xac54, 0xac58,0xac5c,0xac70,0xac71,0xac74,0xac77,0xac78,0xac7a,0xac80,0xac81, 0xac83,0xac84,0xac85,0xac86,0xac89,0xac8a,0xac8b,0xac8c,0xac90,0xac94, 0xac9c,0xac9d,0xac9f,0xaca0,0xaca1,0xaca8,0xaca9,0xacaa,0xacac,0xacaf, 0xacb0,0xacb8,0xacb9,0xacbb,0xacbc,0xacbd,0xacc1,0xacc4,0xacc8,0xaccc, 0xacd5,0xacd7,0xace0,0xace1,0xace4,0xace7,0xace8,0xacea,0xacec,0xacef, 0xacf0,0xacf1,0xacf3,0xacf5,0xacf6,0xacfc,0xacfd,0xad00,0xad04,0xad06 }, { /* ku 31 */ 0xcf02,0xcf03,0xcf05,0xcf06,0xcf07,0xcf09,0xcf0a,0xcf0b,0xcf0c,0xcf0d, 0xcf0e,0xcf0f,0xcf12,0xcf14,0xcf16,0xcf17,0xcf18,0xcf19,0xcf1a,0xcf1b, 0xcf1d,0xcf1e,0xcf1f,0xcf21,0xcf22,0xcf23,UBOGON,UBOGON,UBOGON,UBOGON, UBOGON,UBOGON,0xcf25,0xcf26,0xcf27,0xcf28,0xcf29,0xcf2a,0xcf2b,0xcf2e, 0xcf32,0xcf33,0xcf34,0xcf35,0xcf36,0xcf37,0xcf39,0xcf3a,0xcf3b,0xcf3c, 0xcf3d,0xcf3e,0xcf3f,0xcf40,0xcf41,0xcf42,0xcf43,0xcf44,UBOGON,UBOGON, UBOGON,UBOGON,UBOGON,UBOGON,0xcf45,0xcf46,0xcf47,0xcf48,0xcf49,0xcf4a, 0xcf4b,0xcf4c,0xcf4d,0xcf4e,0xcf4f,0xcf50,0xcf51,0xcf52,0xcf53,0xcf56, 0xcf57,0xcf59,0xcf5a,0xcf5b,0xcf5d,0xcf5e,0xcf5f,0xcf60,0xcf61,0xcf62, 0xcf63,0xcf66,0xcf68,0xcf6a,0xcf6b,0xcf6c,0xad0c,0xad0d,0xad0f,0xad11, 0xad18,0xad1c,0xad20,0xad29,0xad2c,0xad2d,0xad34,0xad35,0xad38,0xad3c, 0xad44,0xad45,0xad47,0xad49,0xad50,0xad54,0xad58,0xad61,0xad63,0xad6c, 0xad6d,0xad70,0xad73,0xad74,0xad75,0xad76,0xad7b,0xad7c,0xad7d,0xad7f, 0xad81,0xad82,0xad88,0xad89,0xad8c,0xad90,0xad9c,0xad9d,0xada4,0xadb7, 0xadc0,0xadc1,0xadc4,0xadc8,0xadd0,0xadd1,0xadd3,0xaddc,0xade0,0xade4, 0xadf8,0xadf9,0xadfc,0xadff,0xae00,0xae01,0xae08,0xae09,0xae0b,0xae0d, 0xae14,0xae30,0xae31,0xae34,0xae37,0xae38,0xae3a,0xae40,0xae41,0xae43, 0xae45,0xae46,0xae4a,0xae4c,0xae4d,0xae4e,0xae50,0xae54,0xae56,0xae5c, 0xae5d,0xae5f,0xae60,0xae61,0xae65,0xae68,0xae69,0xae6c,0xae70,0xae78 }, { /* ku 32 */ 0xcf6d,0xcf6e,0xcf6f,0xcf72,0xcf73,0xcf75,0xcf76,0xcf77,0xcf79,0xcf7a, 0xcf7b,0xcf7c,0xcf7d,0xcf7e,0xcf7f,0xcf81,0xcf82,0xcf83,0xcf84,0xcf86, 0xcf87,0xcf88,0xcf89,0xcf8a,0xcf8b,0xcf8d,UBOGON,UBOGON,UBOGON,UBOGON, UBOGON,UBOGON,0xcf8e,0xcf8f,0xcf90,0xcf91,0xcf92,0xcf93,0xcf94,0xcf95, 0xcf96,0xcf97,0xcf98,0xcf99,0xcf9a,0xcf9b,0xcf9c,0xcf9d,0xcf9e,0xcf9f, 0xcfa0,0xcfa2,0xcfa3,0xcfa4,0xcfa5,0xcfa6,0xcfa7,0xcfa9,UBOGON,UBOGON, UBOGON,UBOGON,UBOGON,UBOGON,0xcfaa,0xcfab,0xcfac,0xcfad,0xcfae,0xcfaf, 0xcfb1,0xcfb2,0xcfb3,0xcfb4,0xcfb5,0xcfb6,0xcfb7,0xcfb8,0xcfb9,0xcfba, 0xcfbb,0xcfbc,0xcfbd,0xcfbe,0xcfbf,0xcfc0,0xcfc1,0xcfc2,0xcfc3,0xcfc5, 0xcfc6,0xcfc7,0xcfc8,0xcfc9,0xcfca,0xcfcb,0xae79,0xae7b,0xae7c,0xae7d, 0xae84,0xae85,0xae8c,0xaebc,0xaebd,0xaebe,0xaec0,0xaec4,0xaecc,0xaecd, 0xaecf,0xaed0,0xaed1,0xaed8,0xaed9,0xaedc,0xaee8,0xaeeb,0xaeed,0xaef4, 0xaef8,0xaefc,0xaf07,0xaf08,0xaf0d,0xaf10,0xaf2c,0xaf2d,0xaf30,0xaf32, 0xaf34,0xaf3c,0xaf3d,0xaf3f,0xaf41,0xaf42,0xaf43,0xaf48,0xaf49,0xaf50, 0xaf5c,0xaf5d,0xaf64,0xaf65,0xaf79,0xaf80,0xaf84,0xaf88,0xaf90,0xaf91, 0xaf95,0xaf9c,0xafb8,0xafb9,0xafbc,0xafc0,0xafc7,0xafc8,0xafc9,0xafcb, 0xafcd,0xafce,0xafd4,0xafdc,0xafe8,0xafe9,0xaff0,0xaff1,0xaff4,0xaff8, 0xb000,0xb001,0xb004,0xb00c,0xb010,0xb014,0xb01c,0xb01d,0xb028,0xb044, 0xb045,0xb048,0xb04a,0xb04c,0xb04e,0xb053,0xb054,0xb055,0xb057,0xb059 }, { /* ku 33 */ 0xcfcc,0xcfcd,0xcfce,0xcfcf,0xcfd0,0xcfd1,0xcfd2,0xcfd3,0xcfd4,0xcfd5, 0xcfd6,0xcfd7,0xcfd8,0xcfd9,0xcfda,0xcfdb,0xcfdc,0xcfdd,0xcfde,0xcfdf, 0xcfe2,0xcfe3,0xcfe5,0xcfe6,0xcfe7,0xcfe9,UBOGON,UBOGON,UBOGON,UBOGON, UBOGON,UBOGON,0xcfea,0xcfeb,0xcfec,0xcfed,0xcfee,0xcfef,0xcff2,0xcff4, 0xcff6,0xcff7,0xcff8,0xcff9,0xcffa,0xcffb,0xcffd,0xcffe,0xcfff,0xd001, 0xd002,0xd003,0xd005,0xd006,0xd007,0xd008,0xd009,0xd00a,UBOGON,UBOGON, UBOGON,UBOGON,UBOGON,UBOGON,0xd00b,0xd00c,0xd00d,0xd00e,0xd00f,0xd010, 0xd012,0xd013,0xd014,0xd015,0xd016,0xd017,0xd019,0xd01a,0xd01b,0xd01c, 0xd01d,0xd01e,0xd01f,0xd020,0xd021,0xd022,0xd023,0xd024,0xd025,0xd026, 0xd027,0xd028,0xd029,0xd02a,0xd02b,0xd02c,0xb05d,0xb07c,0xb07d,0xb080, 0xb084,0xb08c,0xb08d,0xb08f,0xb091,0xb098,0xb099,0xb09a,0xb09c,0xb09f, 0xb0a0,0xb0a1,0xb0a2,0xb0a8,0xb0a9,0xb0ab,0xb0ac,0xb0ad,0xb0ae,0xb0af, 0xb0b1,0xb0b3,0xb0b4,0xb0b5,0xb0b8,0xb0bc,0xb0c4,0xb0c5,0xb0c7,0xb0c8, 0xb0c9,0xb0d0,0xb0d1,0xb0d4,0xb0d8,0xb0e0,0xb0e5,0xb108,0xb109,0xb10b, 0xb10c,0xb110,0xb112,0xb113,0xb118,0xb119,0xb11b,0xb11c,0xb11d,0xb123, 0xb124,0xb125,0xb128,0xb12c,0xb134,0xb135,0xb137,0xb138,0xb139,0xb140, 0xb141,0xb144,0xb148,0xb150,0xb151,0xb154,0xb155,0xb158,0xb15c,0xb160, 0xb178,0xb179,0xb17c,0xb180,0xb182,0xb188,0xb189,0xb18b,0xb18d,0xb192, 0xb193,0xb194,0xb198,0xb19c,0xb1a8,0xb1cc,0xb1d0,0xb1d4,0xb1dc,0xb1dd }, { /* ku 34 */ 0xd02e,0xd02f,0xd030,0xd031,0xd032,0xd033,0xd036,0xd037,0xd039,0xd03a, 0xd03b,0xd03d,0xd03e,0xd03f,0xd040,0xd041,0xd042,0xd043,0xd046,0xd048, 0xd04a,0xd04b,0xd04c,0xd04d,0xd04e,0xd04f,UBOGON,UBOGON,UBOGON,UBOGON, UBOGON,UBOGON,0xd051,0xd052,0xd053,0xd055,0xd056,0xd057,0xd059,0xd05a, 0xd05b,0xd05c,0xd05d,0xd05e,0xd05f,0xd061,0xd062,0xd063,0xd064,0xd065, 0xd066,0xd067,0xd068,0xd069,0xd06a,0xd06b,0xd06e,0xd06f,UBOGON,UBOGON, UBOGON,UBOGON,UBOGON,UBOGON,0xd071,0xd072,0xd073,0xd075,0xd076,0xd077, 0xd078,0xd079,0xd07a,0xd07b,0xd07e,0xd07f,0xd080,0xd082,0xd083,0xd084, 0xd085,0xd086,0xd087,0xd088,0xd089,0xd08a,0xd08b,0xd08c,0xd08d,0xd08e, 0xd08f,0xd090,0xd091,0xd092,0xd093,0xd094,0xb1df,0xb1e8,0xb1e9,0xb1ec, 0xb1f0,0xb1f9,0xb1fb,0xb1fd,0xb204,0xb205,0xb208,0xb20b,0xb20c,0xb214, 0xb215,0xb217,0xb219,0xb220,0xb234,0xb23c,0xb258,0xb25c,0xb260,0xb268, 0xb269,0xb274,0xb275,0xb27c,0xb284,0xb285,0xb289,0xb290,0xb291,0xb294, 0xb298,0xb299,0xb29a,0xb2a0,0xb2a1,0xb2a3,0xb2a5,0xb2a6,0xb2aa,0xb2ac, 0xb2b0,0xb2b4,0xb2c8,0xb2c9,0xb2cc,0xb2d0,0xb2d2,0xb2d8,0xb2d9,0xb2db, 0xb2dd,0xb2e2,0xb2e4,0xb2e5,0xb2e6,0xb2e8,0xb2eb,0xb2ec,0xb2ed,0xb2ee, 0xb2ef,0xb2f3,0xb2f4,0xb2f5,0xb2f7,0xb2f8,0xb2f9,0xb2fa,0xb2fb,0xb2ff, 0xb300,0xb301,0xb304,0xb308,0xb310,0xb311,0xb313,0xb314,0xb315,0xb31c, 0xb354,0xb355,0xb356,0xb358,0xb35b,0xb35c,0xb35e,0xb35f,0xb364,0xb365 }, { /* ku 35 */ 0xd095,0xd096,0xd097,0xd098,0xd099,0xd09a,0xd09b,0xd09c,0xd09d,0xd09e, 0xd09f,0xd0a0,0xd0a1,0xd0a2,0xd0a3,0xd0a6,0xd0a7,0xd0a9,0xd0aa,0xd0ab, 0xd0ad,0xd0ae,0xd0af,0xd0b0,0xd0b1,0xd0b2,UBOGON,UBOGON,UBOGON,UBOGON, UBOGON,UBOGON,0xd0b3,0xd0b6,0xd0b8,0xd0ba,0xd0bb,0xd0bc,0xd0bd,0xd0be, 0xd0bf,0xd0c2,0xd0c3,0xd0c5,0xd0c6,0xd0c7,0xd0ca,0xd0cb,0xd0cc,0xd0cd, 0xd0ce,0xd0cf,0xd0d2,0xd0d6,0xd0d7,0xd0d8,0xd0d9,0xd0da,UBOGON,UBOGON, UBOGON,UBOGON,UBOGON,UBOGON,0xd0db,0xd0de,0xd0df,0xd0e1,0xd0e2,0xd0e3, 0xd0e5,0xd0e6,0xd0e7,0xd0e8,0xd0e9,0xd0ea,0xd0eb,0xd0ee,0xd0f2,0xd0f3, 0xd0f4,0xd0f5,0xd0f6,0xd0f7,0xd0f9,0xd0fa,0xd0fb,0xd0fc,0xd0fd,0xd0fe, 0xd0ff,0xd100,0xd101,0xd102,0xd103,0xd104,0xb367,0xb369,0xb36b,0xb36e, 0xb370,0xb371,0xb374,0xb378,0xb380,0xb381,0xb383,0xb384,0xb385,0xb38c, 0xb390,0xb394,0xb3a0,0xb3a1,0xb3a8,0xb3ac,0xb3c4,0xb3c5,0xb3c8,0xb3cb, 0xb3cc,0xb3ce,0xb3d0,0xb3d4,0xb3d5,0xb3d7,0xb3d9,0xb3db,0xb3dd,0xb3e0, 0xb3e4,0xb3e8,0xb3fc,0xb410,0xb418,0xb41c,0xb420,0xb428,0xb429,0xb42b, 0xb434,0xb450,0xb451,0xb454,0xb458,0xb460,0xb461,0xb463,0xb465,0xb46c, 0xb480,0xb488,0xb49d,0xb4a4,0xb4a8,0xb4ac,0xb4b5,0xb4b7,0xb4b9,0xb4c0, 0xb4c4,0xb4c8,0xb4d0,0xb4d5,0xb4dc,0xb4dd,0xb4e0,0xb4e3,0xb4e4,0xb4e6, 0xb4ec,0xb4ed,0xb4ef,0xb4f1,0xb4f8,0xb514,0xb515,0xb518,0xb51b,0xb51c, 0xb524,0xb525,0xb527,0xb528,0xb529,0xb52a,0xb530,0xb531,0xb534,0xb538 }, { /* ku 36 */ 0xd105,0xd106,0xd107,0xd108,0xd109,0xd10a,0xd10b,0xd10c,0xd10e,0xd10f, 0xd110,0xd111,0xd112,0xd113,0xd114,0xd115,0xd116,0xd117,0xd118,0xd119, 0xd11a,0xd11b,0xd11c,0xd11d,0xd11e,0xd11f,UBOGON,UBOGON,UBOGON,UBOGON, UBOGON,UBOGON,0xd120,0xd121,0xd122,0xd123,0xd124,0xd125,0xd126,0xd127, 0xd128,0xd129,0xd12a,0xd12b,0xd12c,0xd12d,0xd12e,0xd12f,0xd132,0xd133, 0xd135,0xd136,0xd137,0xd139,0xd13b,0xd13c,0xd13d,0xd13e,UBOGON,UBOGON, UBOGON,UBOGON,UBOGON,UBOGON,0xd13f,0xd142,0xd146,0xd147,0xd148,0xd149, 0xd14a,0xd14b,0xd14e,0xd14f,0xd151,0xd152,0xd153,0xd155,0xd156,0xd157, 0xd158,0xd159,0xd15a,0xd15b,0xd15e,0xd160,0xd162,0xd163,0xd164,0xd165, 0xd166,0xd167,0xd169,0xd16a,0xd16b,0xd16d,0xb540,0xb541,0xb543,0xb544, 0xb545,0xb54b,0xb54c,0xb54d,0xb550,0xb554,0xb55c,0xb55d,0xb55f,0xb560, 0xb561,0xb5a0,0xb5a1,0xb5a4,0xb5a8,0xb5aa,0xb5ab,0xb5b0,0xb5b1,0xb5b3, 0xb5b4,0xb5b5,0xb5bb,0xb5bc,0xb5bd,0xb5c0,0xb5c4,0xb5cc,0xb5cd,0xb5cf, 0xb5d0,0xb5d1,0xb5d8,0xb5ec,0xb610,0xb611,0xb614,0xb618,0xb625,0xb62c, 0xb634,0xb648,0xb664,0xb668,0xb69c,0xb69d,0xb6a0,0xb6a4,0xb6ab,0xb6ac, 0xb6b1,0xb6d4,0xb6f0,0xb6f4,0xb6f8,0xb700,0xb701,0xb705,0xb728,0xb729, 0xb72c,0xb72f,0xb730,0xb738,0xb739,0xb73b,0xb744,0xb748,0xb74c,0xb754, 0xb755,0xb760,0xb764,0xb768,0xb770,0xb771,0xb773,0xb775,0xb77c,0xb77d, 0xb780,0xb784,0xb78c,0xb78d,0xb78f,0xb790,0xb791,0xb792,0xb796,0xb797 }, { /* ku 37 */ 0xd16e,0xd16f,0xd170,0xd171,0xd172,0xd173,0xd174,0xd175,0xd176,0xd177, 0xd178,0xd179,0xd17a,0xd17b,0xd17d,0xd17e,0xd17f,0xd180,0xd181,0xd182, 0xd183,0xd185,0xd186,0xd187,0xd189,0xd18a,UBOGON,UBOGON,UBOGON,UBOGON, UBOGON,UBOGON,0xd18b,0xd18c,0xd18d,0xd18e,0xd18f,0xd190,0xd191,0xd192, 0xd193,0xd194,0xd195,0xd196,0xd197,0xd198,0xd199,0xd19a,0xd19b,0xd19c, 0xd19d,0xd19e,0xd19f,0xd1a2,0xd1a3,0xd1a5,0xd1a6,0xd1a7,UBOGON,UBOGON, UBOGON,UBOGON,UBOGON,UBOGON,0xd1a9,0xd1aa,0xd1ab,0xd1ac,0xd1ad,0xd1ae, 0xd1af,0xd1b2,0xd1b4,0xd1b6,0xd1b7,0xd1b8,0xd1b9,0xd1bb,0xd1bd,0xd1be, 0xd1bf,0xd1c1,0xd1c2,0xd1c3,0xd1c4,0xd1c5,0xd1c6,0xd1c7,0xd1c8,0xd1c9, 0xd1ca,0xd1cb,0xd1cc,0xd1cd,0xd1ce,0xd1cf,0xb798,0xb799,0xb79c,0xb7a0, 0xb7a8,0xb7a9,0xb7ab,0xb7ac,0xb7ad,0xb7b4,0xb7b5,0xb7b8,0xb7c7,0xb7c9, 0xb7ec,0xb7ed,0xb7f0,0xb7f4,0xb7fc,0xb7fd,0xb7ff,0xb800,0xb801,0xb807, 0xb808,0xb809,0xb80c,0xb810,0xb818,0xb819,0xb81b,0xb81d,0xb824,0xb825, 0xb828,0xb82c,0xb834,0xb835,0xb837,0xb838,0xb839,0xb840,0xb844,0xb851, 0xb853,0xb85c,0xb85d,0xb860,0xb864,0xb86c,0xb86d,0xb86f,0xb871,0xb878, 0xb87c,0xb88d,0xb8a8,0xb8b0,0xb8b4,0xb8b8,0xb8c0,0xb8c1,0xb8c3,0xb8c5, 0xb8cc,0xb8d0,0xb8d4,0xb8dd,0xb8df,0xb8e1,0xb8e8,0xb8e9,0xb8ec,0xb8f0, 0xb8f8,0xb8f9,0xb8fb,0xb8fd,0xb904,0xb918,0xb920,0xb93c,0xb93d,0xb940, 0xb944,0xb94c,0xb94f,0xb951,0xb958,0xb959,0xb95c,0xb960,0xb968,0xb969 }, { /* ku 38 */ 0xd1d0,0xd1d1,0xd1d2,0xd1d3,0xd1d4,0xd1d5,0xd1d6,0xd1d7,0xd1d9,0xd1da, 0xd1db,0xd1dc,0xd1dd,0xd1de,0xd1df,0xd1e0,0xd1e1,0xd1e2,0xd1e3,0xd1e4, 0xd1e5,0xd1e6,0xd1e7,0xd1e8,0xd1e9,0xd1ea,UBOGON,UBOGON,UBOGON,UBOGON, UBOGON,UBOGON,0xd1eb,0xd1ec,0xd1ed,0xd1ee,0xd1ef,0xd1f0,0xd1f1,0xd1f2, 0xd1f3,0xd1f5,0xd1f6,0xd1f7,0xd1f9,0xd1fa,0xd1fb,0xd1fc,0xd1fd,0xd1fe, 0xd1ff,0xd200,0xd201,0xd202,0xd203,0xd204,0xd205,0xd206,UBOGON,UBOGON, UBOGON,UBOGON,UBOGON,UBOGON,0xd208,0xd20a,0xd20b,0xd20c,0xd20d,0xd20e, 0xd20f,0xd211,0xd212,0xd213,0xd214,0xd215,0xd216,0xd217,0xd218,0xd219, 0xd21a,0xd21b,0xd21c,0xd21d,0xd21e,0xd21f,0xd220,0xd221,0xd222,0xd223, 0xd224,0xd225,0xd226,0xd227,0xd228,0xd229,0xb96b,0xb96d,0xb974,0xb975, 0xb978,0xb97c,0xb984,0xb985,0xb987,0xb989,0xb98a,0xb98d,0xb98e,0xb9ac, 0xb9ad,0xb9b0,0xb9b4,0xb9bc,0xb9bd,0xb9bf,0xb9c1,0xb9c8,0xb9c9,0xb9cc, 0xb9ce,0xb9cf,0xb9d0,0xb9d1,0xb9d2,0xb9d8,0xb9d9,0xb9db,0xb9dd,0xb9de, 0xb9e1,0xb9e3,0xb9e4,0xb9e5,0xb9e8,0xb9ec,0xb9f4,0xb9f5,0xb9f7,0xb9f8, 0xb9f9,0xb9fa,0xba00,0xba01,0xba08,0xba15,0xba38,0xba39,0xba3c,0xba40, 0xba42,0xba48,0xba49,0xba4b,0xba4d,0xba4e,0xba53,0xba54,0xba55,0xba58, 0xba5c,0xba64,0xba65,0xba67,0xba68,0xba69,0xba70,0xba71,0xba74,0xba78, 0xba83,0xba84,0xba85,0xba87,0xba8c,0xbaa8,0xbaa9,0xbaab,0xbaac,0xbab0, 0xbab2,0xbab8,0xbab9,0xbabb,0xbabd,0xbac4,0xbac8,0xbad8,0xbad9,0xbafc }, { /* ku 39 */ 0xd22a,0xd22b,0xd22e,0xd22f,0xd231,0xd232,0xd233,0xd235,0xd236,0xd237, 0xd238,0xd239,0xd23a,0xd23b,0xd23e,0xd240,0xd242,0xd243,0xd244,0xd245, 0xd246,0xd247,0xd249,0xd24a,0xd24b,0xd24c,UBOGON,UBOGON,UBOGON,UBOGON, UBOGON,UBOGON,0xd24d,0xd24e,0xd24f,0xd250,0xd251,0xd252,0xd253,0xd254, 0xd255,0xd256,0xd257,0xd258,0xd259,0xd25a,0xd25b,0xd25d,0xd25e,0xd25f, 0xd260,0xd261,0xd262,0xd263,0xd265,0xd266,0xd267,0xd268,UBOGON,UBOGON, UBOGON,UBOGON,UBOGON,UBOGON,0xd269,0xd26a,0xd26b,0xd26c,0xd26d,0xd26e, 0xd26f,0xd270,0xd271,0xd272,0xd273,0xd274,0xd275,0xd276,0xd277,0xd278, 0xd279,0xd27a,0xd27b,0xd27c,0xd27d,0xd27e,0xd27f,0xd282,0xd283,0xd285, 0xd286,0xd287,0xd289,0xd28a,0xd28b,0xd28c,0xbb00,0xbb04,0xbb0d,0xbb0f, 0xbb11,0xbb18,0xbb1c,0xbb20,0xbb29,0xbb2b,0xbb34,0xbb35,0xbb36,0xbb38, 0xbb3b,0xbb3c,0xbb3d,0xbb3e,0xbb44,0xbb45,0xbb47,0xbb49,0xbb4d,0xbb4f, 0xbb50,0xbb54,0xbb58,0xbb61,0xbb63,0xbb6c,0xbb88,0xbb8c,0xbb90,0xbba4, 0xbba8,0xbbac,0xbbb4,0xbbb7,0xbbc0,0xbbc4,0xbbc8,0xbbd0,0xbbd3,0xbbf8, 0xbbf9,0xbbfc,0xbbff,0xbc00,0xbc02,0xbc08,0xbc09,0xbc0b,0xbc0c,0xbc0d, 0xbc0f,0xbc11,0xbc14,0xbc15,0xbc16,0xbc17,0xbc18,0xbc1b,0xbc1c,0xbc1d, 0xbc1e,0xbc1f,0xbc24,0xbc25,0xbc27,0xbc29,0xbc2d,0xbc30,0xbc31,0xbc34, 0xbc38,0xbc40,0xbc41,0xbc43,0xbc44,0xbc45,0xbc49,0xbc4c,0xbc4d,0xbc50, 0xbc5d,0xbc84,0xbc85,0xbc88,0xbc8b,0xbc8c,0xbc8e,0xbc94,0xbc95,0xbc97 }, { /* ku 3a */ 0xd28d,0xd28e,0xd28f,0xd292,0xd293,0xd294,0xd296,0xd297,0xd298,0xd299, 0xd29a,0xd29b,0xd29d,0xd29e,0xd29f,0xd2a1,0xd2a2,0xd2a3,0xd2a5,0xd2a6, 0xd2a7,0xd2a8,0xd2a9,0xd2aa,0xd2ab,0xd2ad,UBOGON,UBOGON,UBOGON,UBOGON, UBOGON,UBOGON,0xd2ae,0xd2af,0xd2b0,0xd2b2,0xd2b3,0xd2b4,0xd2b5,0xd2b6, 0xd2b7,0xd2ba,0xd2bb,0xd2bd,0xd2be,0xd2c1,0xd2c3,0xd2c4,0xd2c5,0xd2c6, 0xd2c7,0xd2ca,0xd2cc,0xd2cd,0xd2ce,0xd2cf,0xd2d0,0xd2d1,UBOGON,UBOGON, UBOGON,UBOGON,UBOGON,UBOGON,0xd2d2,0xd2d3,0xd2d5,0xd2d6,0xd2d7,0xd2d9, 0xd2da,0xd2db,0xd2dd,0xd2de,0xd2df,0xd2e0,0xd2e1,0xd2e2,0xd2e3,0xd2e6, 0xd2e7,0xd2e8,0xd2e9,0xd2ea,0xd2eb,0xd2ec,0xd2ed,0xd2ee,0xd2ef,0xd2f2, 0xd2f3,0xd2f5,0xd2f6,0xd2f7,0xd2f9,0xd2fa,0xbc99,0xbc9a,0xbca0,0xbca1, 0xbca4,0xbca7,0xbca8,0xbcb0,0xbcb1,0xbcb3,0xbcb4,0xbcb5,0xbcbc,0xbcbd, 0xbcc0,0xbcc4,0xbccd,0xbccf,0xbcd0,0xbcd1,0xbcd5,0xbcd8,0xbcdc,0xbcf4, 0xbcf5,0xbcf6,0xbcf8,0xbcfc,0xbd04,0xbd05,0xbd07,0xbd09,0xbd10,0xbd14, 0xbd24,0xbd2c,0xbd40,0xbd48,0xbd49,0xbd4c,0xbd50,0xbd58,0xbd59,0xbd64, 0xbd68,0xbd80,0xbd81,0xbd84,0xbd87,0xbd88,0xbd89,0xbd8a,0xbd90,0xbd91, 0xbd93,0xbd95,0xbd99,0xbd9a,0xbd9c,0xbda4,0xbdb0,0xbdb8,0xbdd4,0xbdd5, 0xbdd8,0xbddc,0xbde9,0xbdf0,0xbdf4,0xbdf8,0xbe00,0xbe03,0xbe05,0xbe0c, 0xbe0d,0xbe10,0xbe14,0xbe1c,0xbe1d,0xbe1f,0xbe44,0xbe45,0xbe48,0xbe4c, 0xbe4e,0xbe54,0xbe55,0xbe57,0xbe59,0xbe5a,0xbe5b,0xbe60,0xbe61,0xbe64 }, { /* ku 3b */ 0xd2fb,0xd2fc,0xd2fd,0xd2fe,0xd2ff,0xd302,0xd304,0xd306,0xd307,0xd308, 0xd309,0xd30a,0xd30b,0xd30f,0xd311,0xd312,0xd313,0xd315,0xd317,0xd318, 0xd319,0xd31a,0xd31b,0xd31e,0xd322,0xd323,UBOGON,UBOGON,UBOGON,UBOGON, UBOGON,UBOGON,0xd324,0xd326,0xd327,0xd32a,0xd32b,0xd32d,0xd32e,0xd32f, 0xd331,0xd332,0xd333,0xd334,0xd335,0xd336,0xd337,0xd33a,0xd33e,0xd33f, 0xd340,0xd341,0xd342,0xd343,0xd346,0xd347,0xd348,0xd349,UBOGON,UBOGON, UBOGON,UBOGON,UBOGON,UBOGON,0xd34a,0xd34b,0xd34c,0xd34d,0xd34e,0xd34f, 0xd350,0xd351,0xd352,0xd353,0xd354,0xd355,0xd356,0xd357,0xd358,0xd359, 0xd35a,0xd35b,0xd35c,0xd35d,0xd35e,0xd35f,0xd360,0xd361,0xd362,0xd363, 0xd364,0xd365,0xd366,0xd367,0xd368,0xd369,0xbe68,0xbe6a,0xbe70,0xbe71, 0xbe73,0xbe74,0xbe75,0xbe7b,0xbe7c,0xbe7d,0xbe80,0xbe84,0xbe8c,0xbe8d, 0xbe8f,0xbe90,0xbe91,0xbe98,0xbe99,0xbea8,0xbed0,0xbed1,0xbed4,0xbed7, 0xbed8,0xbee0,0xbee3,0xbee4,0xbee5,0xbeec,0xbf01,0xbf08,0xbf09,0xbf18, 0xbf19,0xbf1b,0xbf1c,0xbf1d,0xbf40,0xbf41,0xbf44,0xbf48,0xbf50,0xbf51, 0xbf55,0xbf94,0xbfb0,0xbfc5,0xbfcc,0xbfcd,0xbfd0,0xbfd4,0xbfdc,0xbfdf, 0xbfe1,0xc03c,0xc051,0xc058,0xc05c,0xc060,0xc068,0xc069,0xc090,0xc091, 0xc094,0xc098,0xc0a0,0xc0a1,0xc0a3,0xc0a5,0xc0ac,0xc0ad,0xc0af,0xc0b0, 0xc0b3,0xc0b4,0xc0b5,0xc0b6,0xc0bc,0xc0bd,0xc0bf,0xc0c0,0xc0c1,0xc0c5, 0xc0c8,0xc0c9,0xc0cc,0xc0d0,0xc0d8,0xc0d9,0xc0db,0xc0dc,0xc0dd,0xc0e4 }, { /* ku 3c */ 0xd36a,0xd36b,0xd36c,0xd36d,0xd36e,0xd36f,0xd370,0xd371,0xd372,0xd373, 0xd374,0xd375,0xd376,0xd377,0xd378,0xd379,0xd37a,0xd37b,0xd37e,0xd37f, 0xd381,0xd382,0xd383,0xd385,0xd386,0xd387,UBOGON,UBOGON,UBOGON,UBOGON, UBOGON,UBOGON,0xd388,0xd389,0xd38a,0xd38b,0xd38e,0xd392,0xd393,0xd394, 0xd395,0xd396,0xd397,0xd39a,0xd39b,0xd39d,0xd39e,0xd39f,0xd3a1,0xd3a2, 0xd3a3,0xd3a4,0xd3a5,0xd3a6,0xd3a7,0xd3aa,0xd3ac,0xd3ae,UBOGON,UBOGON, UBOGON,UBOGON,UBOGON,UBOGON,0xd3af,0xd3b0,0xd3b1,0xd3b2,0xd3b3,0xd3b5, 0xd3b6,0xd3b7,0xd3b9,0xd3ba,0xd3bb,0xd3bd,0xd3be,0xd3bf,0xd3c0,0xd3c1, 0xd3c2,0xd3c3,0xd3c6,0xd3c7,0xd3ca,0xd3cb,0xd3cc,0xd3cd,0xd3ce,0xd3cf, 0xd3d1,0xd3d2,0xd3d3,0xd3d4,0xd3d5,0xd3d6,0xc0e5,0xc0e8,0xc0ec,0xc0f4, 0xc0f5,0xc0f7,0xc0f9,0xc100,0xc104,0xc108,0xc110,0xc115,0xc11c,0xc11d, 0xc11e,0xc11f,0xc120,0xc123,0xc124,0xc126,0xc127,0xc12c,0xc12d,0xc12f, 0xc130,0xc131,0xc136,0xc138,0xc139,0xc13c,0xc140,0xc148,0xc149,0xc14b, 0xc14c,0xc14d,0xc154,0xc155,0xc158,0xc15c,0xc164,0xc165,0xc167,0xc168, 0xc169,0xc170,0xc174,0xc178,0xc185,0xc18c,0xc18d,0xc18e,0xc190,0xc194, 0xc196,0xc19c,0xc19d,0xc19f,0xc1a1,0xc1a5,0xc1a8,0xc1a9,0xc1ac,0xc1b0, 0xc1bd,0xc1c4,0xc1c8,0xc1cc,0xc1d4,0xc1d7,0xc1d8,0xc1e0,0xc1e4,0xc1e8, 0xc1f0,0xc1f1,0xc1f3,0xc1fc,0xc1fd,0xc200,0xc204,0xc20c,0xc20d,0xc20f, 0xc211,0xc218,0xc219,0xc21c,0xc21f,0xc220,0xc228,0xc229,0xc22b,0xc22d }, { /* ku 3d */ 0xd3d7,0xd3d9,0xd3da,0xd3db,0xd3dc,0xd3dd,0xd3de,0xd3df,0xd3e0,0xd3e2, 0xd3e4,0xd3e5,0xd3e6,0xd3e7,0xd3e8,0xd3e9,0xd3ea,0xd3eb,0xd3ee,0xd3ef, 0xd3f1,0xd3f2,0xd3f3,0xd3f5,0xd3f6,0xd3f7,UBOGON,UBOGON,UBOGON,UBOGON, UBOGON,UBOGON,0xd3f8,0xd3f9,0xd3fa,0xd3fb,0xd3fe,0xd400,0xd402,0xd403, 0xd404,0xd405,0xd406,0xd407,0xd409,0xd40a,0xd40b,0xd40c,0xd40d,0xd40e, 0xd40f,0xd410,0xd411,0xd412,0xd413,0xd414,0xd415,0xd416,UBOGON,UBOGON, UBOGON,UBOGON,UBOGON,UBOGON,0xd417,0xd418,0xd419,0xd41a,0xd41b,0xd41c, 0xd41e,0xd41f,0xd420,0xd421,0xd422,0xd423,0xd424,0xd425,0xd426,0xd427, 0xd428,0xd429,0xd42a,0xd42b,0xd42c,0xd42d,0xd42e,0xd42f,0xd430,0xd431, 0xd432,0xd433,0xd434,0xd435,0xd436,0xd437,0xc22f,0xc231,0xc232,0xc234, 0xc248,0xc250,0xc251,0xc254,0xc258,0xc260,0xc265,0xc26c,0xc26d,0xc270, 0xc274,0xc27c,0xc27d,0xc27f,0xc281,0xc288,0xc289,0xc290,0xc298,0xc29b, 0xc29d,0xc2a4,0xc2a5,0xc2a8,0xc2ac,0xc2ad,0xc2b4,0xc2b5,0xc2b7,0xc2b9, 0xc2dc,0xc2dd,0xc2e0,0xc2e3,0xc2e4,0xc2eb,0xc2ec,0xc2ed,0xc2ef,0xc2f1, 0xc2f6,0xc2f8,0xc2f9,0xc2fb,0xc2fc,0xc300,0xc308,0xc309,0xc30c,0xc30d, 0xc313,0xc314,0xc315,0xc318,0xc31c,0xc324,0xc325,0xc328,0xc329,0xc345, 0xc368,0xc369,0xc36c,0xc370,0xc372,0xc378,0xc379,0xc37c,0xc37d,0xc384, 0xc388,0xc38c,0xc3c0,0xc3d8,0xc3d9,0xc3dc,0xc3df,0xc3e0,0xc3e2,0xc3e8, 0xc3e9,0xc3ed,0xc3f4,0xc3f5,0xc3f8,0xc408,0xc410,0xc424,0xc42c,0xc430 }, { /* ku 3e */ 0xd438,0xd439,0xd43a,0xd43b,0xd43c,0xd43d,0xd43e,0xd43f,0xd441,0xd442, 0xd443,0xd445,0xd446,0xd447,0xd448,0xd449,0xd44a,0xd44b,0xd44c,0xd44d, 0xd44e,0xd44f,0xd450,0xd451,0xd452,0xd453,UBOGON,UBOGON,UBOGON,UBOGON, UBOGON,UBOGON,0xd454,0xd455,0xd456,0xd457,0xd458,0xd459,0xd45a,0xd45b, 0xd45d,0xd45e,0xd45f,0xd461,0xd462,0xd463,0xd465,0xd466,0xd467,0xd468, 0xd469,0xd46a,0xd46b,0xd46c,0xd46e,0xd470,0xd471,0xd472,UBOGON,UBOGON, UBOGON,UBOGON,UBOGON,UBOGON,0xd473,0xd474,0xd475,0xd476,0xd477,0xd47a, 0xd47b,0xd47d,0xd47e,0xd481,0xd483,0xd484,0xd485,0xd486,0xd487,0xd48a, 0xd48c,0xd48e,0xd48f,0xd490,0xd491,0xd492,0xd493,0xd495,0xd496,0xd497, 0xd498,0xd499,0xd49a,0xd49b,0xd49c,0xd49d,0xc434,0xc43c,0xc43d,0xc448, 0xc464,0xc465,0xc468,0xc46c,0xc474,0xc475,0xc479,0xc480,0xc494,0xc49c, 0xc4b8,0xc4bc,0xc4e9,0xc4f0,0xc4f1,0xc4f4,0xc4f8,0xc4fa,0xc4ff,0xc500, 0xc501,0xc50c,0xc510,0xc514,0xc51c,0xc528,0xc529,0xc52c,0xc530,0xc538, 0xc539,0xc53b,0xc53d,0xc544,0xc545,0xc548,0xc549,0xc54a,0xc54c,0xc54d, 0xc54e,0xc553,0xc554,0xc555,0xc557,0xc558,0xc559,0xc55d,0xc55e,0xc560, 0xc561,0xc564,0xc568,0xc570,0xc571,0xc573,0xc574,0xc575,0xc57c,0xc57d, 0xc580,0xc584,0xc587,0xc58c,0xc58d,0xc58f,0xc591,0xc595,0xc597,0xc598, 0xc59c,0xc5a0,0xc5a9,0xc5b4,0xc5b5,0xc5b8,0xc5b9,0xc5bb,0xc5bc,0xc5bd, 0xc5be,0xc5c4,0xc5c5,0xc5c6,0xc5c7,0xc5c8,0xc5c9,0xc5ca,0xc5cc,0xc5ce }, { /* ku 3f */ 0xd49e,0xd49f,0xd4a0,0xd4a1,0xd4a2,0xd4a3,0xd4a4,0xd4a5,0xd4a6,0xd4a7, 0xd4a8,0xd4aa,0xd4ab,0xd4ac,0xd4ad,0xd4ae,0xd4af,0xd4b0,0xd4b1,0xd4b2, 0xd4b3,0xd4b4,0xd4b5,0xd4b6,0xd4b7,0xd4b8,UBOGON,UBOGON,UBOGON,UBOGON, UBOGON,UBOGON,0xd4b9,0xd4ba,0xd4bb,0xd4bc,0xd4bd,0xd4be,0xd4bf,0xd4c0, 0xd4c1,0xd4c2,0xd4c3,0xd4c4,0xd4c5,0xd4c6,0xd4c7,0xd4c8,0xd4c9,0xd4ca, 0xd4cb,0xd4cd,0xd4ce,0xd4cf,0xd4d1,0xd4d2,0xd4d3,0xd4d5,UBOGON,UBOGON, UBOGON,UBOGON,UBOGON,UBOGON,0xd4d6,0xd4d7,0xd4d8,0xd4d9,0xd4da,0xd4db, 0xd4dd,0xd4de,0xd4e0,0xd4e1,0xd4e2,0xd4e3,0xd4e4,0xd4e5,0xd4e6,0xd4e7, 0xd4e9,0xd4ea,0xd4eb,0xd4ed,0xd4ee,0xd4ef,0xd4f1,0xd4f2,0xd4f3,0xd4f4, 0xd4f5,0xd4f6,0xd4f7,0xd4f9,0xd4fa,0xd4fc,0xc5d0,0xc5d1,0xc5d4,0xc5d8, 0xc5e0,0xc5e1,0xc5e3,0xc5e5,0xc5ec,0xc5ed,0xc5ee,0xc5f0,0xc5f4,0xc5f6, 0xc5f7,0xc5fc,0xc5fd,0xc5fe,0xc5ff,0xc600,0xc601,0xc605,0xc606,0xc607, 0xc608,0xc60c,0xc610,0xc618,0xc619,0xc61b,0xc61c,0xc624,0xc625,0xc628, 0xc62c,0xc62d,0xc62e,0xc630,0xc633,0xc634,0xc635,0xc637,0xc639,0xc63b, 0xc640,0xc641,0xc644,0xc648,0xc650,0xc651,0xc653,0xc654,0xc655,0xc65c, 0xc65d,0xc660,0xc66c,0xc66f,0xc671,0xc678,0xc679,0xc67c,0xc680,0xc688, 0xc689,0xc68b,0xc68d,0xc694,0xc695,0xc698,0xc69c,0xc6a4,0xc6a5,0xc6a7, 0xc6a9,0xc6b0,0xc6b1,0xc6b4,0xc6b8,0xc6b9,0xc6ba,0xc6c0,0xc6c1,0xc6c3, 0xc6c5,0xc6cc,0xc6cd,0xc6d0,0xc6d4,0xc6dc,0xc6dd,0xc6e0,0xc6e1,0xc6e8 }, { /* ku 40 */ 0xd4fe,0xd4ff,0xd500,0xd501,0xd502,0xd503,0xd505,0xd506,0xd507,0xd509, 0xd50a,0xd50b,0xd50d,0xd50e,0xd50f,0xd510,0xd511,0xd512,0xd513,0xd516, 0xd518,0xd519,0xd51a,0xd51b,0xd51c,0xd51d,UBOGON,UBOGON,UBOGON,UBOGON, UBOGON,UBOGON,0xd51e,0xd51f,0xd520,0xd521,0xd522,0xd523,0xd524,0xd525, 0xd526,0xd527,0xd528,0xd529,0xd52a,0xd52b,0xd52c,0xd52d,0xd52e,0xd52f, 0xd530,0xd531,0xd532,0xd533,0xd534,0xd535,0xd536,0xd537,UBOGON,UBOGON, UBOGON,UBOGON,UBOGON,UBOGON,0xd538,0xd539,0xd53a,0xd53b,0xd53e,0xd53f, 0xd541,0xd542,0xd543,0xd545,0xd546,0xd547,0xd548,0xd549,0xd54a,0xd54b, 0xd54e,0xd550,0xd552,0xd553,0xd554,0xd555,0xd556,0xd557,0xd55a,0xd55b, 0xd55d,0xd55e,0xd55f,0xd561,0xd562,0xd563,0xc6e9,0xc6ec,0xc6f0,0xc6f8, 0xc6f9,0xc6fd,0xc704,0xc705,0xc708,0xc70c,0xc714,0xc715,0xc717,0xc719, 0xc720,0xc721,0xc724,0xc728,0xc730,0xc731,0xc733,0xc735,0xc737,0xc73c, 0xc73d,0xc740,0xc744,0xc74a,0xc74c,0xc74d,0xc74f,0xc751,0xc752,0xc753, 0xc754,0xc755,0xc756,0xc757,0xc758,0xc75c,0xc760,0xc768,0xc76b,0xc774, 0xc775,0xc778,0xc77c,0xc77d,0xc77e,0xc783,0xc784,0xc785,0xc787,0xc788, 0xc789,0xc78a,0xc78e,0xc790,0xc791,0xc794,0xc796,0xc797,0xc798,0xc79a, 0xc7a0,0xc7a1,0xc7a3,0xc7a4,0xc7a5,0xc7a6,0xc7ac,0xc7ad,0xc7b0,0xc7b4, 0xc7bc,0xc7bd,0xc7bf,0xc7c0,0xc7c1,0xc7c8,0xc7c9,0xc7cc,0xc7ce,0xc7d0, 0xc7d8,0xc7dd,0xc7e4,0xc7e8,0xc7ec,0xc800,0xc801,0xc804,0xc808,0xc80a }, { /* ku 41 */ 0xd564,0xd566,0xd567,0xd56a,0xd56c,0xd56e,0xd56f,0xd570,0xd571,0xd572, 0xd573,0xd576,0xd577,0xd579,0xd57a,0xd57b,0xd57d,0xd57e,0xd57f,0xd580, 0xd581,0xd582,0xd583,0xd586,0xd58a,0xd58b,UBOGON,UBOGON,UBOGON,UBOGON, UBOGON,UBOGON,0xd58c,0xd58d,0xd58e,0xd58f,0xd591,0xd592,0xd593,0xd594, 0xd595,0xd596,0xd597,0xd598,0xd599,0xd59a,0xd59b,0xd59c,0xd59d,0xd59e, 0xd59f,0xd5a0,0xd5a1,0xd5a2,0xd5a3,0xd5a4,0xd5a6,0xd5a7,UBOGON,UBOGON, UBOGON,UBOGON,UBOGON,UBOGON,0xd5a8,0xd5a9,0xd5aa,0xd5ab,0xd5ac,0xd5ad, 0xd5ae,0xd5af,0xd5b0,0xd5b1,0xd5b2,0xd5b3,0xd5b4,0xd5b5,0xd5b6,0xd5b7, 0xd5b8,0xd5b9,0xd5ba,0xd5bb,0xd5bc,0xd5bd,0xd5be,0xd5bf,0xd5c0,0xd5c1, 0xd5c2,0xd5c3,0xd5c4,0xd5c5,0xd5c6,0xd5c7,0xc810,0xc811,0xc813,0xc815, 0xc816,0xc81c,0xc81d,0xc820,0xc824,0xc82c,0xc82d,0xc82f,0xc831,0xc838, 0xc83c,0xc840,0xc848,0xc849,0xc84c,0xc84d,0xc854,0xc870,0xc871,0xc874, 0xc878,0xc87a,0xc880,0xc881,0xc883,0xc885,0xc886,0xc887,0xc88b,0xc88c, 0xc88d,0xc894,0xc89d,0xc89f,0xc8a1,0xc8a8,0xc8bc,0xc8bd,0xc8c4,0xc8c8, 0xc8cc,0xc8d4,0xc8d5,0xc8d7,0xc8d9,0xc8e0,0xc8e1,0xc8e4,0xc8f5,0xc8fc, 0xc8fd,0xc900,0xc904,0xc905,0xc906,0xc90c,0xc90d,0xc90f,0xc911,0xc918, 0xc92c,0xc934,0xc950,0xc951,0xc954,0xc958,0xc960,0xc961,0xc963,0xc96c, 0xc970,0xc974,0xc97c,0xc988,0xc989,0xc98c,0xc990,0xc998,0xc999,0xc99b, 0xc99d,0xc9c0,0xc9c1,0xc9c4,0xc9c7,0xc9c8,0xc9ca,0xc9d0,0xc9d1,0xc9d3 }, { /* ku 42 */ 0xd5ca,0xd5cb,0xd5cd,0xd5ce,0xd5cf,0xd5d1,0xd5d3,0xd5d4,0xd5d5,0xd5d6, 0xd5d7,0xd5da,0xd5dc,0xd5de,0xd5df,0xd5e0,0xd5e1,0xd5e2,0xd5e3,0xd5e6, 0xd5e7,0xd5e9,0xd5ea,0xd5eb,0xd5ed,0xd5ee,UBOGON,UBOGON,UBOGON,UBOGON, UBOGON,UBOGON,0xd5ef,0xd5f0,0xd5f1,0xd5f2,0xd5f3,0xd5f6,0xd5f8,0xd5fa, 0xd5fb,0xd5fc,0xd5fd,0xd5fe,0xd5ff,0xd602,0xd603,0xd605,0xd606,0xd607, 0xd609,0xd60a,0xd60b,0xd60c,0xd60d,0xd60e,0xd60f,0xd612,UBOGON,UBOGON, UBOGON,UBOGON,UBOGON,UBOGON,0xd616,0xd617,0xd618,0xd619,0xd61a,0xd61b, 0xd61d,0xd61e,0xd61f,0xd621,0xd622,0xd623,0xd625,0xd626,0xd627,0xd628, 0xd629,0xd62a,0xd62b,0xd62c,0xd62e,0xd62f,0xd630,0xd631,0xd632,0xd633, 0xd634,0xd635,0xd636,0xd637,0xd63a,0xd63b,0xc9d5,0xc9d6,0xc9d9,0xc9da, 0xc9dc,0xc9dd,0xc9e0,0xc9e2,0xc9e4,0xc9e7,0xc9ec,0xc9ed,0xc9ef,0xc9f0, 0xc9f1,0xc9f8,0xc9f9,0xc9fc,0xca00,0xca08,0xca09,0xca0b,0xca0c,0xca0d, 0xca14,0xca18,0xca29,0xca4c,0xca4d,0xca50,0xca54,0xca5c,0xca5d,0xca5f, 0xca60,0xca61,0xca68,0xca7d,0xca84,0xca98,0xcabc,0xcabd,0xcac0,0xcac4, 0xcacc,0xcacd,0xcacf,0xcad1,0xcad3,0xcad8,0xcad9,0xcae0,0xcaec,0xcaf4, 0xcb08,0xcb10,0xcb14,0xcb18,0xcb20,0xcb21,0xcb41,0xcb48,0xcb49,0xcb4c, 0xcb50,0xcb58,0xcb59,0xcb5d,0xcb64,0xcb78,0xcb79,0xcb9c,0xcbb8,0xcbd4, 0xcbe4,0xcbe7,0xcbe9,0xcc0c,0xcc0d,0xcc10,0xcc14,0xcc1c,0xcc1d,0xcc21, 0xcc22,0xcc27,0xcc28,0xcc29,0xcc2c,0xcc2e,0xcc30,0xcc38,0xcc39,0xcc3b }, { /* ku 43 */ 0xd63d,0xd63e,0xd63f,0xd641,0xd642,0xd643,0xd644,0xd646,0xd647,0xd64a, 0xd64c,0xd64e,0xd64f,0xd650,0xd652,0xd653,0xd656,0xd657,0xd659,0xd65a, 0xd65b,0xd65d,0xd65e,0xd65f,0xd660,0xd661,UBOGON,UBOGON,UBOGON,UBOGON, UBOGON,UBOGON,0xd662,0xd663,0xd664,0xd665,0xd666,0xd668,0xd66a,0xd66b, 0xd66c,0xd66d,0xd66e,0xd66f,0xd672,0xd673,0xd675,0xd676,0xd677,0xd678, 0xd679,0xd67a,0xd67b,0xd67c,0xd67d,0xd67e,0xd67f,0xd680,UBOGON,UBOGON, UBOGON,UBOGON,UBOGON,UBOGON,0xd681,0xd682,0xd684,0xd686,0xd687,0xd688, 0xd689,0xd68a,0xd68b,0xd68e,0xd68f,0xd691,0xd692,0xd693,0xd695,0xd696, 0xd697,0xd698,0xd699,0xd69a,0xd69b,0xd69c,0xd69e,0xd6a0,0xd6a2,0xd6a3, 0xd6a4,0xd6a5,0xd6a6,0xd6a7,0xd6a9,0xd6aa,0xcc3c,0xcc3d,0xcc3e,0xcc44, 0xcc45,0xcc48,0xcc4c,0xcc54,0xcc55,0xcc57,0xcc58,0xcc59,0xcc60,0xcc64, 0xcc66,0xcc68,0xcc70,0xcc75,0xcc98,0xcc99,0xcc9c,0xcca0,0xcca8,0xcca9, 0xccab,0xccac,0xccad,0xccb4,0xccb5,0xccb8,0xccbc,0xccc4,0xccc5,0xccc7, 0xccc9,0xccd0,0xccd4,0xcce4,0xccec,0xccf0,0xcd01,0xcd08,0xcd09,0xcd0c, 0xcd10,0xcd18,0xcd19,0xcd1b,0xcd1d,0xcd24,0xcd28,0xcd2c,0xcd39,0xcd5c, 0xcd60,0xcd64,0xcd6c,0xcd6d,0xcd6f,0xcd71,0xcd78,0xcd88,0xcd94,0xcd95, 0xcd98,0xcd9c,0xcda4,0xcda5,0xcda7,0xcda9,0xcdb0,0xcdc4,0xcdcc,0xcdd0, 0xcde8,0xcdec,0xcdf0,0xcdf8,0xcdf9,0xcdfb,0xcdfd,0xce04,0xce08,0xce0c, 0xce14,0xce19,0xce20,0xce21,0xce24,0xce28,0xce30,0xce31,0xce33,0xce35 }, { /* ku 44 */ 0xd6ab,0xd6ad,0xd6ae,0xd6af,0xd6b1,0xd6b2,0xd6b3,0xd6b4,0xd6b5,0xd6b6, 0xd6b7,0xd6b8,0xd6ba,0xd6bc,0xd6bd,0xd6be,0xd6bf,0xd6c0,0xd6c1,0xd6c2, 0xd6c3,0xd6c6,0xd6c7,0xd6c9,0xd6ca,0xd6cb,UBOGON,UBOGON,UBOGON,UBOGON, UBOGON,UBOGON,0xd6cd,0xd6ce,0xd6cf,0xd6d0,0xd6d2,0xd6d3,0xd6d5,0xd6d6, 0xd6d8,0xd6da,0xd6db,0xd6dc,0xd6dd,0xd6de,0xd6df,0xd6e1,0xd6e2,0xd6e3, 0xd6e5,0xd6e6,0xd6e7,0xd6e9,0xd6ea,0xd6eb,0xd6ec,0xd6ed,UBOGON,UBOGON, UBOGON,UBOGON,UBOGON,UBOGON,0xd6ee,0xd6ef,0xd6f1,0xd6f2,0xd6f3,0xd6f4, 0xd6f6,0xd6f7,0xd6f8,0xd6f9,0xd6fa,0xd6fb,0xd6fe,0xd6ff,0xd701,0xd702, 0xd703,0xd705,0xd706,0xd707,0xd708,0xd709,0xd70a,0xd70b,0xd70c,0xd70d, 0xd70e,0xd70f,0xd710,0xd712,0xd713,0xd714,0xce58,0xce59,0xce5c,0xce5f, 0xce60,0xce61,0xce68,0xce69,0xce6b,0xce6d,0xce74,0xce75,0xce78,0xce7c, 0xce84,0xce85,0xce87,0xce89,0xce90,0xce91,0xce94,0xce98,0xcea0,0xcea1, 0xcea3,0xcea4,0xcea5,0xceac,0xcead,0xcec1,0xcee4,0xcee5,0xcee8,0xceeb, 0xceec,0xcef4,0xcef5,0xcef7,0xcef8,0xcef9,0xcf00,0xcf01,0xcf04,0xcf08, 0xcf10,0xcf11,0xcf13,0xcf15,0xcf1c,0xcf20,0xcf24,0xcf2c,0xcf2d,0xcf2f, 0xcf30,0xcf31,0xcf38,0xcf54,0xcf55,0xcf58,0xcf5c,0xcf64,0xcf65,0xcf67, 0xcf69,0xcf70,0xcf71,0xcf74,0xcf78,0xcf80,0xcf85,0xcf8c,0xcfa1,0xcfa8, 0xcfb0,0xcfc4,0xcfe0,0xcfe1,0xcfe4,0xcfe8,0xcff0,0xcff1,0xcff3,0xcff5, 0xcffc,0xd000,0xd004,0xd011,0xd018,0xd02d,0xd034,0xd035,0xd038,0xd03c }, { /* ku 45 */ 0xd715,0xd716,0xd717,0xd71a,0xd71b,0xd71d,0xd71e,0xd71f,0xd721,0xd722, 0xd723,0xd724,0xd725,0xd726,0xd727,0xd72a,0xd72c,0xd72e,0xd72f,0xd730, 0xd731,0xd732,0xd733,0xd736,0xd737,0xd739,UBOGON,UBOGON,UBOGON,UBOGON, UBOGON,UBOGON,0xd73a,0xd73b,0xd73d,0xd73e,0xd73f,0xd740,0xd741,0xd742, 0xd743,0xd745,0xd746,0xd748,0xd74a,0xd74b,0xd74c,0xd74d,0xd74e,0xd74f, 0xd752,0xd753,0xd755,0xd75a,0xd75b,0xd75c,0xd75d,0xd75e,UBOGON,UBOGON, UBOGON,UBOGON,UBOGON,UBOGON,0xd75f,0xd762,0xd764,0xd766,0xd767,0xd768, 0xd76a,0xd76b,0xd76d,0xd76e,0xd76f,0xd771,0xd772,0xd773,0xd775,0xd776, 0xd777,0xd778,0xd779,0xd77a,0xd77b,0xd77e,0xd77f,0xd780,0xd782,0xd783, 0xd784,0xd785,0xd786,0xd787,0xd78a,0xd78b,0xd044,0xd045,0xd047,0xd049, 0xd050,0xd054,0xd058,0xd060,0xd06c,0xd06d,0xd070,0xd074,0xd07c,0xd07d, 0xd081,0xd0a4,0xd0a5,0xd0a8,0xd0ac,0xd0b4,0xd0b5,0xd0b7,0xd0b9,0xd0c0, 0xd0c1,0xd0c4,0xd0c8,0xd0c9,0xd0d0,0xd0d1,0xd0d3,0xd0d4,0xd0d5,0xd0dc, 0xd0dd,0xd0e0,0xd0e4,0xd0ec,0xd0ed,0xd0ef,0xd0f0,0xd0f1,0xd0f8,0xd10d, 0xd130,0xd131,0xd134,0xd138,0xd13a,0xd140,0xd141,0xd143,0xd144,0xd145, 0xd14c,0xd14d,0xd150,0xd154,0xd15c,0xd15d,0xd15f,0xd161,0xd168,0xd16c, 0xd17c,0xd184,0xd188,0xd1a0,0xd1a1,0xd1a4,0xd1a8,0xd1b0,0xd1b1,0xd1b3, 0xd1b5,0xd1ba,0xd1bc,0xd1c0,0xd1d8,0xd1f4,0xd1f8,0xd207,0xd209,0xd210, 0xd22c,0xd22d,0xd230,0xd234,0xd23c,0xd23d,0xd23f,0xd241,0xd248,0xd25c }, { /* ku 46 */ 0xd78d,0xd78e,0xd78f,0xd791,0xd792,0xd793,0xd794,0xd795,0xd796,0xd797, 0xd79a,0xd79c,0xd79e,0xd79f,0xd7a0,0xd7a1,0xd7a2,0xd7a3,UBOGON,UBOGON, UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON, UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON, UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON, UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON, UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON, UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON, UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON, UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,0xd264,0xd280,0xd281,0xd284, 0xd288,0xd290,0xd291,0xd295,0xd29c,0xd2a0,0xd2a4,0xd2ac,0xd2b1,0xd2b8, 0xd2b9,0xd2bc,0xd2bf,0xd2c0,0xd2c2,0xd2c8,0xd2c9,0xd2cb,0xd2d4,0xd2d8, 0xd2dc,0xd2e4,0xd2e5,0xd2f0,0xd2f1,0xd2f4,0xd2f8,0xd300,0xd301,0xd303, 0xd305,0xd30c,0xd30d,0xd30e,0xd310,0xd314,0xd316,0xd31c,0xd31d,0xd31f, 0xd320,0xd321,0xd325,0xd328,0xd329,0xd32c,0xd330,0xd338,0xd339,0xd33b, 0xd33c,0xd33d,0xd344,0xd345,0xd37c,0xd37d,0xd380,0xd384,0xd38c,0xd38d, 0xd38f,0xd390,0xd391,0xd398,0xd399,0xd39c,0xd3a0,0xd3a8,0xd3a9,0xd3ab, 0xd3ad,0xd3b4,0xd3b8,0xd3bc,0xd3c4,0xd3c5,0xd3c8,0xd3c9,0xd3d0,0xd3d8, 0xd3e1,0xd3e3,0xd3ec,0xd3ed,0xd3f0,0xd3f4,0xd3fc,0xd3fd,0xd3ff,0xd401 }, { /* ku 47 */ UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON, UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON, UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON, UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON, UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON, UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON, UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON, UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON, UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON, UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,0xd408,0xd41d,0xd440,0xd444, 0xd45c,0xd460,0xd464,0xd46d,0xd46f,0xd478,0xd479,0xd47c,0xd47f,0xd480, 0xd482,0xd488,0xd489,0xd48b,0xd48d,0xd494,0xd4a9,0xd4cc,0xd4d0,0xd4d4, 0xd4dc,0xd4df,0xd4e8,0xd4ec,0xd4f0,0xd4f8,0xd4fb,0xd4fd,0xd504,0xd508, 0xd50c,0xd514,0xd515,0xd517,0xd53c,0xd53d,0xd540,0xd544,0xd54c,0xd54d, 0xd54f,0xd551,0xd558,0xd559,0xd55c,0xd560,0xd565,0xd568,0xd569,0xd56b, 0xd56d,0xd574,0xd575,0xd578,0xd57c,0xd584,0xd585,0xd587,0xd588,0xd589, 0xd590,0xd5a5,0xd5c8,0xd5c9,0xd5cc,0xd5d0,0xd5d2,0xd5d8,0xd5d9,0xd5db, 0xd5dd,0xd5e4,0xd5e5,0xd5e8,0xd5ec,0xd5f4,0xd5f5,0xd5f7,0xd5f9,0xd600, 0xd601,0xd604,0xd608,0xd610,0xd611,0xd613,0xd614,0xd615,0xd61c,0xd620 }, { /* ku 48 */ UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON, UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON, UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON, UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON, UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON, UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON, UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON, UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON, UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON, UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,0xd624,0xd62d,0xd638,0xd639, 0xd63c,0xd640,0xd645,0xd648,0xd649,0xd64b,0xd64d,0xd651,0xd654,0xd655, 0xd658,0xd65c,0xd667,0xd669,0xd670,0xd671,0xd674,0xd683,0xd685,0xd68c, 0xd68d,0xd690,0xd694,0xd69d,0xd69f,0xd6a1,0xd6a8,0xd6ac,0xd6b0,0xd6b9, 0xd6bb,0xd6c4,0xd6c5,0xd6c8,0xd6cc,0xd6d1,0xd6d4,0xd6d7,0xd6d9,0xd6e0, 0xd6e4,0xd6e8,0xd6f0,0xd6f5,0xd6fc,0xd6fd,0xd700,0xd704,0xd711,0xd718, 0xd719,0xd71c,0xd720,0xd728,0xd729,0xd72b,0xd72d,0xd734,0xd735,0xd738, 0xd73c,0xd744,0xd747,0xd749,0xd750,0xd751,0xd754,0xd756,0xd757,0xd758, 0xd759,0xd760,0xd761,0xd763,0xd765,0xd769,0xd76c,0xd770,0xd774,0xd77c, 0xd77d,0xd781,0xd788,0xd789,0xd78c,0xd790,0xd798,0xd799,0xd79b,0xd79d }, { /* ku 49 */ UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON, UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON, UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON, UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON, UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON, UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON, UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON, UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON, UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON, UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON, UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON, UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON, UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON, UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON, UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON, UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON, UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON, UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON, UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON }, { /* ku 4a */ UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON, UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON, UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON, UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON, UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON, UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON, UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON, UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON, UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON, UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,0x4f3d,0x4f73,0x5047,0x50f9, 0x52a0,0x53ef,0x5475,0x54e5,0x5609,0x5ac1,0x5bb6,0x6687,0x67b6,0x67b7, 0x67ef,0x6b4c,0x73c2,0x75c2,0x7a3c,0x82db,0x8304,0x8857,0x8888,0x8a36, 0x8cc8,0x8dcf,0x8efb,0x8fe6,0x99d5,0x523b,0x5374,0x5404,0x606a,0x6164, 0x6bbc,0x73cf,0x811a,0x89ba,0x89d2,0x95a3,0x4f83,0x520a,0x58be,0x5978, 0x59e6,0x5e72,0x5e79,0x61c7,0x63c0,0x6746,0x67ec,0x687f,0x6f97,0x764e, 0x770b,0x78f5,0x7a08,0x7aff,0x7c21,0x809d,0x826e,0x8271,0x8aeb,0x9593, 0x4e6b,0x559d,0x66f7,0x6e34,0x78a3,0x7aed,0x845b,0x8910,0x874e,0x97a8, 0x52d8,0x574e,0x582a,0x5d4c,0x611f,0x61be,0x6221,0x6562,0x67d1,0x6a44, 0x6e1b,0x7518,0x75b3,0x76e3,0x77b0,0x7d3a,0x90af,0x9451,0x9452,0x9f95 }, { /* ku 4b */ UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON, UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON, UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON, UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON, UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON, UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON, UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON, UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON, UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON, UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,0x5323,0x5cac,0x7532,0x80db, 0x9240,0x9598,0x525b,0x5808,0x59dc,0x5ca1,0x5d17,0x5eb7,0x5f3a,0x5f4a, 0x6177,0x6c5f,0x757a,0x7586,0x7ce0,0x7d73,0x7db1,0x7f8c,0x8154,0x8221, 0x8591,0x8941,0x8b1b,0x92fc,0x964d,0x9c47,0x4ecb,0x4ef7,0x500b,0x51f1, 0x584f,0x6137,0x613e,0x6168,0x6539,0x69ea,0x6f11,0x75a5,0x7686,0x76d6, 0x7b87,0x82a5,0x84cb,0xf900,0x93a7,0x958b,0x5580,0x5ba2,0x5751,0xf901, 0x7cb3,0x7fb9,0x91b5,0x5028,0x53bb,0x5c45,0x5de8,0x62d2,0x636e,0x64da, 0x64e7,0x6e20,0x70ac,0x795b,0x8ddd,0x8e1e,0xf902,0x907d,0x9245,0x92f8, 0x4e7e,0x4ef6,0x5065,0x5dfe,0x5efa,0x6106,0x6957,0x8171,0x8654,0x8e47, 0x9375,0x9a2b,0x4e5e,0x5091,0x6770,0x6840,0x5109,0x528d,0x5292,0x6aa2 }, { /* ku 4c */ UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON, UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON, UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON, UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON, UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON, UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON, UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON, UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON, UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON, UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,0x77bc,0x9210,0x9ed4,0x52ab, 0x602f,0x8ff2,0x5048,0x61a9,0x63ed,0x64ca,0x683c,0x6a84,0x6fc0,0x8188, 0x89a1,0x9694,0x5805,0x727d,0x72ac,0x7504,0x7d79,0x7e6d,0x80a9,0x898b, 0x8b74,0x9063,0x9d51,0x6289,0x6c7a,0x6f54,0x7d50,0x7f3a,0x8a23,0x517c, 0x614a,0x7b9d,0x8b19,0x9257,0x938c,0x4eac,0x4fd3,0x501e,0x50be,0x5106, 0x52c1,0x52cd,0x537f,0x5770,0x5883,0x5e9a,0x5f91,0x6176,0x61ac,0x64ce, 0x656c,0x666f,0x66bb,0x66f4,0x6897,0x6d87,0x7085,0x70f1,0x749f,0x74a5, 0x74ca,0x75d9,0x786c,0x78ec,0x7adf,0x7af6,0x7d45,0x7d93,0x8015,0x803f, 0x811b,0x8396,0x8b66,0x8f15,0x9015,0x93e1,0x9803,0x9838,0x9a5a,0x9be8, 0x4fc2,0x5553,0x583a,0x5951,0x5b63,0x5c46,0x60b8,0x6212,0x6842,0x68b0 }, { /* ku 4d */ UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON, UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON, UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON, UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON, UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON, UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON, UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON, UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON, UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON, UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,0x68e8,0x6eaa,0x754c,0x7678, 0x78ce,0x7a3d,0x7cfb,0x7e6b,0x7e7c,0x8a08,0x8aa1,0x8c3f,0x968e,0x9dc4, 0x53e4,0x53e9,0x544a,0x5471,0x56fa,0x59d1,0x5b64,0x5c3b,0x5eab,0x62f7, 0x6537,0x6545,0x6572,0x66a0,0x67af,0x69c1,0x6cbd,0x75fc,0x7690,0x777e, 0x7a3f,0x7f94,0x8003,0x80a1,0x818f,0x82e6,0x82fd,0x83f0,0x85c1,0x8831, 0x88b4,0x8aa5,0xf903,0x8f9c,0x932e,0x96c7,0x9867,0x9ad8,0x9f13,0x54ed, 0x659b,0x66f2,0x688f,0x7a40,0x8c37,0x9d60,0x56f0,0x5764,0x5d11,0x6606, 0x68b1,0x68cd,0x6efe,0x7428,0x889e,0x9be4,0x6c68,0xf904,0x9aa8,0x4f9b, 0x516c,0x5171,0x529f,0x5b54,0x5de5,0x6050,0x606d,0x62f1,0x63a7,0x653b, 0x73d9,0x7a7a,0x86a3,0x8ca2,0x978f,0x4e32,0x5be1,0x6208,0x679c,0x74dc }, { /* ku 4e */ UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON, UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON, UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON, UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON, UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON, UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON, UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON, UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON, UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON, UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,0x79d1,0x83d3,0x8a87,0x8ab2, 0x8de8,0x904e,0x934b,0x9846,0x5ed3,0x69e8,0x85ff,0x90ed,0xf905,0x51a0, 0x5b98,0x5bec,0x6163,0x68fa,0x6b3e,0x704c,0x742f,0x74d8,0x7ba1,0x7f50, 0x83c5,0x89c0,0x8cab,0x95dc,0x9928,0x522e,0x605d,0x62ec,0x9002,0x4f8a, 0x5149,0x5321,0x58d9,0x5ee3,0x66e0,0x6d38,0x709a,0x72c2,0x73d6,0x7b50, 0x80f1,0x945b,0x5366,0x639b,0x7f6b,0x4e56,0x5080,0x584a,0x58de,0x602a, 0x6127,0x62d0,0x69d0,0x9b41,0x5b8f,0x7d18,0x80b1,0x8f5f,0x4ea4,0x50d1, 0x54ac,0x55ac,0x5b0c,0x5da0,0x5de7,0x652a,0x654e,0x6821,0x6a4b,0x72e1, 0x768e,0x77ef,0x7d5e,0x7ff9,0x81a0,0x854e,0x86df,0x8f03,0x8f4e,0x90ca, 0x9903,0x9a55,0x9bab,0x4e18,0x4e45,0x4e5d,0x4ec7,0x4ff1,0x5177,0x52fe }, { /* ku 4f */ UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON, UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON, UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON, UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON, UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON, UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON, UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON, UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON, UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON, UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,0x5340,0x53e3,0x53e5,0x548e, 0x5614,0x5775,0x57a2,0x5bc7,0x5d87,0x5ed0,0x61fc,0x62d8,0x6551,0x67b8, 0x67e9,0x69cb,0x6b50,0x6bc6,0x6bec,0x6c42,0x6e9d,0x7078,0x72d7,0x7396, 0x7403,0x77bf,0x77e9,0x7a76,0x7d7f,0x8009,0x81fc,0x8205,0x820a,0x82df, 0x8862,0x8b33,0x8cfc,0x8ec0,0x9011,0x90b1,0x9264,0x92b6,0x99d2,0x9a45, 0x9ce9,0x9dd7,0x9f9c,0x570b,0x5c40,0x83ca,0x97a0,0x97ab,0x9eb4,0x541b, 0x7a98,0x7fa4,0x88d9,0x8ecd,0x90e1,0x5800,0x5c48,0x6398,0x7a9f,0x5bae, 0x5f13,0x7a79,0x7aae,0x828e,0x8eac,0x5026,0x5238,0x52f8,0x5377,0x5708, 0x62f3,0x6372,0x6b0a,0x6dc3,0x7737,0x53a5,0x7357,0x8568,0x8e76,0x95d5, 0x673a,0x6ac3,0x6f70,0x8a6d,0x8ecc,0x994b,0xf906,0x6677,0x6b78,0x8cb4 }, { /* ku 50 */ UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON, UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON, UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON, UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON, UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON, UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON, UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON, UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON, UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON, UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,0x9b3c,0xf907,0x53eb,0x572d, 0x594e,0x63c6,0x69fb,0x73ea,0x7845,0x7aba,0x7ac5,0x7cfe,0x8475,0x898f, 0x8d73,0x9035,0x95a8,0x52fb,0x5747,0x7547,0x7b60,0x83cc,0x921e,0xf908, 0x6a58,0x514b,0x524b,0x5287,0x621f,0x68d8,0x6975,0x9699,0x50c5,0x52a4, 0x52e4,0x61c3,0x65a4,0x6839,0x69ff,0x747e,0x7b4b,0x82b9,0x83eb,0x89b2, 0x8b39,0x8fd1,0x9949,0xf909,0x4eca,0x5997,0x64d2,0x6611,0x6a8e,0x7434, 0x7981,0x79bd,0x82a9,0x887e,0x887f,0x895f,0xf90a,0x9326,0x4f0b,0x53ca, 0x6025,0x6271,0x6c72,0x7d1a,0x7d66,0x4e98,0x5162,0x77dc,0x80af,0x4f01, 0x4f0e,0x5176,0x5180,0x55dc,0x5668,0x573b,0x57fa,0x57fc,0x5914,0x5947, 0x5993,0x5bc4,0x5c90,0x5d0e,0x5df1,0x5e7e,0x5fcc,0x6280,0x65d7,0x65e3 }, { /* ku 51 */ UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON, UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON, UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON, UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON, UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON, UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON, UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON, UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON, UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON, UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,0x671e,0x671f,0x675e,0x68cb, 0x68c4,0x6a5f,0x6b3a,0x6c23,0x6c7d,0x6c82,0x6dc7,0x7398,0x7426,0x742a, 0x7482,0x74a3,0x7578,0x757f,0x7881,0x78ef,0x7941,0x7947,0x7948,0x797a, 0x7b95,0x7d00,0x7dba,0x7f88,0x8006,0x802d,0x808c,0x8a18,0x8b4f,0x8c48, 0x8d77,0x9321,0x9324,0x98e2,0x9951,0x9a0e,0x9a0f,0x9a65,0x9e92,0x7dca, 0x4f76,0x5409,0x62ee,0x6854,0x91d1,0x55ab,0x513a,0xf90b,0xf90c,0x5a1c, 0x61e6,0xf90d,0x62cf,0x62ff,0xf90e,0xf90f,0xf910,0xf911,0xf912,0xf913, 0x90a3,0xf914,0xf915,0xf916,0xf917,0xf918,0x8afe,0xf919,0xf91a,0xf91b, 0xf91c,0x6696,0xf91d,0x7156,0xf91e,0xf91f,0x96e3,0xf920,0x634f,0x637a, 0x5357,0xf921,0x678f,0x6960,0x6e73,0xf922,0x7537,0xf923,0xf924,0xf925 }, { /* ku 52 */ UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON, UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON, UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON, UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON, UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON, UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON, UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON, UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON, UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON, UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,0x7d0d,0xf926,0xf927,0x8872, 0x56ca,0x5a18,0xf928,0xf929,0xf92a,0xf92b,0xf92c,0x4e43,0xf92d,0x5167, 0x5948,0x67f0,0x8010,0xf92e,0x5973,0x5e74,0x649a,0x79ca,0x5ff5,0x606c, 0x62c8,0x637b,0x5be7,0x5bd7,0x52aa,0xf92f,0x5974,0x5f29,0x6012,0xf930, 0xf931,0xf932,0x7459,0xf933,0xf934,0xf935,0xf936,0xf937,0xf938,0x99d1, 0xf939,0xf93a,0xf93b,0xf93c,0xf93d,0xf93e,0xf93f,0xf940,0xf941,0xf942, 0xf943,0x6fc3,0xf944,0xf945,0x81bf,0x8fb2,0x60f1,0xf946,0xf947,0x8166, 0xf948,0xf949,0x5c3f,0xf94a,0xf94b,0xf94c,0xf94d,0xf94e,0xf94f,0xf950, 0xf951,0x5ae9,0x8a25,0x677b,0x7d10,0xf952,0xf953,0xf954,0xf955,0xf956, 0xf957,0x80fd,0xf958,0xf959,0x5c3c,0x6ce5,0x533f,0x6eba,0x591a,0x8336 }, { /* ku 53 */ UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON, UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON, UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON, UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON, UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON, UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON, UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON, UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON, UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON, UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,0x4e39,0x4eb6,0x4f46,0x55ae, 0x5718,0x58c7,0x5f56,0x65b7,0x65e6,0x6a80,0x6bb5,0x6e4d,0x77ed,0x7aef, 0x7c1e,0x7dde,0x86cb,0x8892,0x9132,0x935b,0x64bb,0x6fbe,0x737a,0x75b8, 0x9054,0x5556,0x574d,0x61ba,0x64d4,0x66c7,0x6de1,0x6e5b,0x6f6d,0x6fb9, 0x75f0,0x8043,0x81bd,0x8541,0x8983,0x8ac7,0x8b5a,0x931f,0x6c93,0x7553, 0x7b54,0x8e0f,0x905d,0x5510,0x5802,0x5858,0x5e62,0x6207,0x649e,0x68e0, 0x7576,0x7cd6,0x87b3,0x9ee8,0x4ee3,0x5788,0x576e,0x5927,0x5c0d,0x5cb1, 0x5e36,0x5f85,0x6234,0x64e1,0x73b3,0x81fa,0x888b,0x8cb8,0x968a,0x9edb, 0x5b85,0x5fb7,0x60b3,0x5012,0x5200,0x5230,0x5716,0x5835,0x5857,0x5c0e, 0x5c60,0x5cf6,0x5d8b,0x5ea6,0x5f92,0x60bc,0x6311,0x6389,0x6417,0x6843 }, { /* ku 54 */ UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON, UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON, UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON, UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON, UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON, UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON, UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON, UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON, UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON, UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,0x68f9,0x6ac2,0x6dd8,0x6e21, 0x6ed4,0x6fe4,0x71fe,0x76dc,0x7779,0x79b1,0x7a3b,0x8404,0x89a9,0x8ced, 0x8df3,0x8e48,0x9003,0x9014,0x9053,0x90fd,0x934d,0x9676,0x97dc,0x6bd2, 0x7006,0x7258,0x72a2,0x7368,0x7763,0x79bf,0x7be4,0x7e9b,0x8b80,0x58a9, 0x60c7,0x6566,0x65fd,0x66be,0x6c8c,0x711e,0x71c9,0x8c5a,0x9813,0x4e6d, 0x7a81,0x4edd,0x51ac,0x51cd,0x52d5,0x540c,0x61a7,0x6771,0x6850,0x68df, 0x6d1e,0x6f7c,0x75bc,0x77b3,0x7ae5,0x80f4,0x8463,0x9285,0x515c,0x6597, 0x675c,0x6793,0x75d8,0x7ac7,0x8373,0xf95a,0x8c46,0x9017,0x982d,0x5c6f, 0x81c0,0x829a,0x9041,0x906f,0x920d,0x5f97,0x5d9d,0x6a59,0x71c8,0x767b, 0x7b49,0x85e4,0x8b04,0x9127,0x9a30,0x5587,0x61f6,0xf95b,0x7669,0x7f85 }, { /* ku 55 */ UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON, UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON, UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON, UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON, UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON, UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON, UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON, UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON, UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON, UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,0x863f,0x87ba,0x88f8,0x908f, 0xf95c,0x6d1b,0x70d9,0x73de,0x7d61,0x843d,0xf95d,0x916a,0x99f1,0xf95e, 0x4e82,0x5375,0x6b04,0x6b12,0x703e,0x721b,0x862d,0x9e1e,0x524c,0x8fa3, 0x5d50,0x64e5,0x652c,0x6b16,0x6feb,0x7c43,0x7e9c,0x85cd,0x8964,0x89bd, 0x62c9,0x81d8,0x881f,0x5eca,0x6717,0x6d6a,0x72fc,0x7405,0x746f,0x8782, 0x90de,0x4f86,0x5d0d,0x5fa0,0x840a,0x51b7,0x63a0,0x7565,0x4eae,0x5006, 0x5169,0x51c9,0x6881,0x6a11,0x7cae,0x7cb1,0x7ce7,0x826f,0x8ad2,0x8f1b, 0x91cf,0x4fb6,0x5137,0x52f5,0x5442,0x5eec,0x616e,0x623e,0x65c5,0x6ada, 0x6ffe,0x792a,0x85dc,0x8823,0x95ad,0x9a62,0x9a6a,0x9e97,0x9ece,0x529b, 0x66c6,0x6b77,0x701d,0x792b,0x8f62,0x9742,0x6190,0x6200,0x6523,0x6f23 }, { /* ku 56 */ UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON, UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON, UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON, UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON, UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON, UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON, UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON, UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON, UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON, UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,0x7149,0x7489,0x7df4,0x806f, 0x84ee,0x8f26,0x9023,0x934a,0x51bd,0x5217,0x52a3,0x6d0c,0x70c8,0x88c2, 0x5ec9,0x6582,0x6bae,0x6fc2,0x7c3e,0x7375,0x4ee4,0x4f36,0x56f9,0xf95f, 0x5cba,0x5dba,0x601c,0x73b2,0x7b2d,0x7f9a,0x7fce,0x8046,0x901e,0x9234, 0x96f6,0x9748,0x9818,0x9f61,0x4f8b,0x6fa7,0x79ae,0x91b4,0x96b7,0x52de, 0xf960,0x6488,0x64c4,0x6ad3,0x6f5e,0x7018,0x7210,0x76e7,0x8001,0x8606, 0x865c,0x8def,0x8f05,0x9732,0x9b6f,0x9dfa,0x9e75,0x788c,0x797f,0x7da0, 0x83c9,0x9304,0x9e7f,0x9e93,0x8ad6,0x58df,0x5f04,0x6727,0x7027,0x74cf, 0x7c60,0x807e,0x5121,0x7028,0x7262,0x78ca,0x8cc2,0x8cda,0x8cf4,0x96f7, 0x4e86,0x50da,0x5bee,0x5ed6,0x6599,0x71ce,0x7642,0x77ad,0x804a,0x84fc }, { /* ku 57 */ UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON, UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON, UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON, UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON, UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON, UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON, UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON, UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON, UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON, UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,0x907c,0x9b27,0x9f8d,0x58d8, 0x5a41,0x5c62,0x6a13,0x6dda,0x6f0f,0x763b,0x7d2f,0x7e37,0x851e,0x8938, 0x93e4,0x964b,0x5289,0x65d2,0x67f3,0x69b4,0x6d41,0x6e9c,0x700f,0x7409, 0x7460,0x7559,0x7624,0x786b,0x8b2c,0x985e,0x516d,0x622e,0x9678,0x4f96, 0x502b,0x5d19,0x6dea,0x7db8,0x8f2a,0x5f8b,0x6144,0x6817,0xf961,0x9686, 0x52d2,0x808b,0x51dc,0x51cc,0x695e,0x7a1c,0x7dbe,0x83f1,0x9675,0x4fda, 0x5229,0x5398,0x540f,0x550e,0x5c65,0x60a7,0x674e,0x68a8,0x6d6c,0x7281, 0x72f8,0x7406,0x7483,0xf962,0x75e2,0x7c6c,0x7f79,0x7fb8,0x8389,0x88cf, 0x88e1,0x91cc,0x91d0,0x96e2,0x9bc9,0x541d,0x6f7e,0x71d0,0x7498,0x85fa, 0x8eaa,0x96a3,0x9c57,0x9e9f,0x6797,0x6dcb,0x7433,0x81e8,0x9716,0x782c }, { /* ku 58 */ UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON, UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON, UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON, UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON, UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON, UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON, UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON, UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON, UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON, UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,0x7acb,0x7b20,0x7c92,0x6469, 0x746a,0x75f2,0x78bc,0x78e8,0x99ac,0x9b54,0x9ebb,0x5bde,0x5e55,0x6f20, 0x819c,0x83ab,0x9088,0x4e07,0x534d,0x5a29,0x5dd2,0x5f4e,0x6162,0x633d, 0x6669,0x66fc,0x6eff,0x6f2b,0x7063,0x779e,0x842c,0x8513,0x883b,0x8f13, 0x9945,0x9c3b,0x551c,0x62b9,0x672b,0x6cab,0x8309,0x896a,0x977a,0x4ea1, 0x5984,0x5fd8,0x5fd9,0x671b,0x7db2,0x7f54,0x8292,0x832b,0x83bd,0x8f1e, 0x9099,0x57cb,0x59b9,0x5a92,0x5bd0,0x6627,0x679a,0x6885,0x6bcf,0x7164, 0x7f75,0x8cb7,0x8ce3,0x9081,0x9b45,0x8108,0x8c8a,0x964c,0x9a40,0x9ea5, 0x5b5f,0x6c13,0x731b,0x76f2,0x76df,0x840c,0x51aa,0x8993,0x514d,0x5195, 0x52c9,0x68c9,0x6c94,0x7704,0x7720,0x7dbf,0x7dec,0x9762,0x9eb5,0x6ec5 }, { /* ku 59 */ UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON, UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON, UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON, UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON, UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON, UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON, UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON, UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON, UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON, UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,0x8511,0x51a5,0x540d,0x547d, 0x660e,0x669d,0x6927,0x6e9f,0x76bf,0x7791,0x8317,0x84c2,0x879f,0x9169, 0x9298,0x9cf4,0x8882,0x4fae,0x5192,0x52df,0x59c6,0x5e3d,0x6155,0x6478, 0x6479,0x66ae,0x67d0,0x6a21,0x6bcd,0x6bdb,0x725f,0x7261,0x7441,0x7738, 0x77db,0x8017,0x82bc,0x8305,0x8b00,0x8b28,0x8c8c,0x6728,0x6c90,0x7267, 0x76ee,0x7766,0x7a46,0x9da9,0x6b7f,0x6c92,0x5922,0x6726,0x8499,0x536f, 0x5893,0x5999,0x5edf,0x63cf,0x6634,0x6773,0x6e3a,0x732b,0x7ad7,0x82d7, 0x9328,0x52d9,0x5deb,0x61ae,0x61cb,0x620a,0x62c7,0x64ab,0x65e0,0x6959, 0x6b66,0x6bcb,0x7121,0x73f7,0x755d,0x7e46,0x821e,0x8302,0x856a,0x8aa3, 0x8cbf,0x9727,0x9d61,0x58a8,0x9ed8,0x5011,0x520e,0x543b,0x554f,0x6587 }, { /* ku 5a */ UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON, UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON, UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON, UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON, UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON, UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON, UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON, UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON, UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON, UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,0x6c76,0x7d0a,0x7d0b,0x805e, 0x868a,0x9580,0x96ef,0x52ff,0x6c95,0x7269,0x5473,0x5a9a,0x5c3e,0x5d4b, 0x5f4c,0x5fae,0x672a,0x68b6,0x6963,0x6e3c,0x6e44,0x7709,0x7c73,0x7f8e, 0x8587,0x8b0e,0x8ff7,0x9761,0x9ef4,0x5cb7,0x60b6,0x610d,0x61ab,0x654f, 0x65fb,0x65fc,0x6c11,0x6cef,0x739f,0x73c9,0x7de1,0x9594,0x5bc6,0x871c, 0x8b10,0x525d,0x535a,0x62cd,0x640f,0x64b2,0x6734,0x6a38,0x6cca,0x73c0, 0x749e,0x7b94,0x7c95,0x7e1b,0x818a,0x8236,0x8584,0x8feb,0x96f9,0x99c1, 0x4f34,0x534a,0x53cd,0x53db,0x62cc,0x642c,0x6500,0x6591,0x69c3,0x6cee, 0x6f58,0x73ed,0x7554,0x7622,0x76e4,0x76fc,0x78d0,0x78fb,0x792c,0x7d46, 0x822c,0x87e0,0x8fd4,0x9812,0x98ef,0x52c3,0x62d4,0x64a5,0x6e24,0x6f51 }, { /* ku 5b */ UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON, UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON, UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON, UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON, UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON, UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON, UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON, UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON, UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON, UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,0x767c,0x8dcb,0x91b1,0x9262, 0x9aee,0x9b43,0x5023,0x508d,0x574a,0x59a8,0x5c28,0x5e47,0x5f77,0x623f, 0x653e,0x65b9,0x65c1,0x6609,0x678b,0x699c,0x6ec2,0x78c5,0x7d21,0x80aa, 0x8180,0x822b,0x82b3,0x84a1,0x868c,0x8a2a,0x8b17,0x90a6,0x9632,0x9f90, 0x500d,0x4ff3,0xf963,0x57f9,0x5f98,0x62dc,0x6392,0x676f,0x6e43,0x7119, 0x76c3,0x80cc,0x80da,0x88f4,0x88f5,0x8919,0x8ce0,0x8f29,0x914d,0x966a, 0x4f2f,0x4f70,0x5e1b,0x67cf,0x6822,0x767d,0x767e,0x9b44,0x5e61,0x6a0a, 0x7169,0x71d4,0x756a,0xf964,0x7e41,0x8543,0x85e9,0x98dc,0x4f10,0x7b4f, 0x7f70,0x95a5,0x51e1,0x5e06,0x68b5,0x6c3e,0x6c4e,0x6cdb,0x72af,0x7bc4, 0x8303,0x6cd5,0x743a,0x50fb,0x5288,0x58c1,0x64d8,0x6a97,0x74a7,0x7656 }, { /* ku 5c */ UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON, UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON, UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON, UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON, UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON, UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON, UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON, UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON, UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON, UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,0x78a7,0x8617,0x95e2,0x9739, 0xf965,0x535e,0x5f01,0x8b8a,0x8fa8,0x8faf,0x908a,0x5225,0x77a5,0x9c49, 0x9f08,0x4e19,0x5002,0x5175,0x5c5b,0x5e77,0x661e,0x663a,0x67c4,0x68c5, 0x70b3,0x7501,0x75c5,0x79c9,0x7add,0x8f27,0x9920,0x9a08,0x4fdd,0x5821, 0x5831,0x5bf6,0x666e,0x6b65,0x6d11,0x6e7a,0x6f7d,0x73e4,0x752b,0x83e9, 0x88dc,0x8913,0x8b5c,0x8f14,0x4f0f,0x50d5,0x5310,0x535c,0x5b93,0x5fa9, 0x670d,0x798f,0x8179,0x832f,0x8514,0x8907,0x8986,0x8f39,0x8f3b,0x99a5, 0x9c12,0x672c,0x4e76,0x4ff8,0x5949,0x5c01,0x5cef,0x5cf0,0x6367,0x68d2, 0x70fd,0x71a2,0x742b,0x7e2b,0x84ec,0x8702,0x9022,0x92d2,0x9cf3,0x4e0d, 0x4ed8,0x4fef,0x5085,0x5256,0x526f,0x5426,0x5490,0x57e0,0x592b,0x5a66 }, { /* ku 5d */ UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON, UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON, UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON, UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON, UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON, UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON, UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON, UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON, UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON, UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,0x5b5a,0x5b75,0x5bcc,0x5e9c, 0xf966,0x6276,0x6577,0x65a7,0x6d6e,0x6ea5,0x7236,0x7b26,0x7c3f,0x7f36, 0x8150,0x8151,0x819a,0x8240,0x8299,0x83a9,0x8a03,0x8ca0,0x8ce6,0x8cfb, 0x8d74,0x8dba,0x90e8,0x91dc,0x961c,0x9644,0x99d9,0x9ce7,0x5317,0x5206, 0x5429,0x5674,0x58b3,0x5954,0x596e,0x5fff,0x61a4,0x626e,0x6610,0x6c7e, 0x711a,0x76c6,0x7c89,0x7cde,0x7d1b,0x82ac,0x8cc1,0x96f0,0xf967,0x4f5b, 0x5f17,0x5f7f,0x62c2,0x5d29,0x670b,0x68da,0x787c,0x7e43,0x9d6c,0x4e15, 0x5099,0x5315,0x532a,0x5351,0x5983,0x5a62,0x5e87,0x60b2,0x618a,0x6249, 0x6279,0x6590,0x6787,0x69a7,0x6bd4,0x6bd6,0x6bd7,0x6bd8,0x6cb8,0xf968, 0x7435,0x75fa,0x7812,0x7891,0x79d5,0x79d8,0x7c83,0x7dcb,0x7fe1,0x80a5 }, { /* ku 5e */ UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON, UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON, UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON, UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON, UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON, UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON, UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON, UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON, UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON, UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,0x813e,0x81c2,0x83f2,0x871a, 0x88e8,0x8ab9,0x8b6c,0x8cbb,0x9119,0x975e,0x98db,0x9f3b,0x56ac,0x5b2a, 0x5f6c,0x658c,0x6ab3,0x6baf,0x6d5c,0x6ff1,0x7015,0x725d,0x73ad,0x8ca7, 0x8cd3,0x983b,0x6191,0x6c37,0x8058,0x9a01,0x4e4d,0x4e8b,0x4e9b,0x4ed5, 0x4f3a,0x4f3c,0x4f7f,0x4fdf,0x50ff,0x53f2,0x53f8,0x5506,0x55e3,0x56db, 0x58eb,0x5962,0x5a11,0x5beb,0x5bfa,0x5c04,0x5df3,0x5e2b,0x5f99,0x601d, 0x6368,0x659c,0x65af,0x67f6,0x67fb,0x68ad,0x6b7b,0x6c99,0x6cd7,0x6e23, 0x7009,0x7345,0x7802,0x793e,0x7940,0x7960,0x79c1,0x7be9,0x7d17,0x7d72, 0x8086,0x820d,0x838e,0x84d1,0x86c7,0x88df,0x8a50,0x8a5e,0x8b1d,0x8cdc, 0x8d66,0x8fad,0x90aa,0x98fc,0x99df,0x9e9d,0x524a,0xf969,0x6714,0xf96a }, { /* ku 5f */ UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON, UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON, UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON, UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON, UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON, UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON, UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON, UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON, UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON, UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,0x5098,0x522a,0x5c71,0x6563, 0x6c55,0x73ca,0x7523,0x759d,0x7b97,0x849c,0x9178,0x9730,0x4e77,0x6492, 0x6bba,0x715e,0x85a9,0x4e09,0xf96b,0x6749,0x68ee,0x6e17,0x829f,0x8518, 0x886b,0x63f7,0x6f81,0x9212,0x98af,0x4e0a,0x50b7,0x50cf,0x511f,0x5546, 0x55aa,0x5617,0x5b40,0x5c19,0x5ce0,0x5e38,0x5e8a,0x5ea0,0x5ec2,0x60f3, 0x6851,0x6a61,0x6e58,0x723d,0x7240,0x72c0,0x76f8,0x7965,0x7bb1,0x7fd4, 0x88f3,0x89f4,0x8a73,0x8c61,0x8cde,0x971c,0x585e,0x74bd,0x8cfd,0x55c7, 0xf96c,0x7a61,0x7d22,0x8272,0x7272,0x751f,0x7525,0xf96d,0x7b19,0x5885, 0x58fb,0x5dbc,0x5e8f,0x5eb6,0x5f90,0x6055,0x6292,0x637f,0x654d,0x6691, 0x66d9,0x66f8,0x6816,0x68f2,0x7280,0x745e,0x7b6e,0x7d6e,0x7dd6,0x7f72 }, { /* ku 60 */ UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON, UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON, UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON, UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON, UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON, UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON, UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON, UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON, UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON, UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,0x80e5,0x8212,0x85af,0x897f, 0x8a93,0x901d,0x92e4,0x9ecd,0x9f20,0x5915,0x596d,0x5e2d,0x60dc,0x6614, 0x6673,0x6790,0x6c50,0x6dc5,0x6f5f,0x77f3,0x78a9,0x84c6,0x91cb,0x932b, 0x4ed9,0x50ca,0x5148,0x5584,0x5b0b,0x5ba3,0x6247,0x657e,0x65cb,0x6e32, 0x717d,0x7401,0x7444,0x7487,0x74bf,0x766c,0x79aa,0x7dda,0x7e55,0x7fa8, 0x817a,0x81b3,0x8239,0x861a,0x87ec,0x8a75,0x8de3,0x9078,0x9291,0x9425, 0x994d,0x9bae,0x5368,0x5c51,0x6954,0x6cc4,0x6d29,0x6e2b,0x820c,0x859b, 0x893b,0x8a2d,0x8aaa,0x96ea,0x9f67,0x5261,0x66b9,0x6bb2,0x7e96,0x87fe, 0x8d0d,0x9583,0x965d,0x651d,0x6d89,0x71ee,0xf96e,0x57ce,0x59d3,0x5bac, 0x6027,0x60fa,0x6210,0x661f,0x665f,0x7329,0x73f9,0x76db,0x7701,0x7b6c }, { /* ku 61 */ UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON, UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON, UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON, UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON, UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON, UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON, UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON, UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON, UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON, UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,0x8056,0x8072,0x8165,0x8aa0, 0x9192,0x4e16,0x52e2,0x6b72,0x6d17,0x7a05,0x7b39,0x7d30,0xf96f,0x8cb0, 0x53ec,0x562f,0x5851,0x5bb5,0x5c0f,0x5c11,0x5de2,0x6240,0x6383,0x6414, 0x662d,0x68b3,0x6cbc,0x6d88,0x6eaf,0x701f,0x70a4,0x71d2,0x7526,0x758f, 0x758e,0x7619,0x7b11,0x7be0,0x7c2b,0x7d20,0x7d39,0x852c,0x856d,0x8607, 0x8a34,0x900d,0x9061,0x90b5,0x92b7,0x97f6,0x9a37,0x4fd7,0x5c6c,0x675f, 0x6d91,0x7c9f,0x7e8c,0x8b16,0x8d16,0x901f,0x5b6b,0x5dfd,0x640d,0x84c0, 0x905c,0x98e1,0x7387,0x5b8b,0x609a,0x677e,0x6dde,0x8a1f,0x8aa6,0x9001, 0x980c,0x5237,0xf970,0x7051,0x788e,0x9396,0x8870,0x91d7,0x4fee,0x53d7, 0x55fd,0x56da,0x5782,0x58fd,0x5ac2,0x5b88,0x5cab,0x5cc0,0x5e25,0x6101 }, { /* ku 62 */ UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON, UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON, UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON, UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON, UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON, UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON, UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON, UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON, UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON, UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,0x620d,0x624b,0x6388,0x641c, 0x6536,0x6578,0x6a39,0x6b8a,0x6c34,0x6d19,0x6f31,0x71e7,0x72e9,0x7378, 0x7407,0x74b2,0x7626,0x7761,0x79c0,0x7a57,0x7aea,0x7cb9,0x7d8f,0x7dac, 0x7e61,0x7f9e,0x8129,0x8331,0x8490,0x84da,0x85ea,0x8896,0x8ab0,0x8b90, 0x8f38,0x9042,0x9083,0x916c,0x9296,0x92b9,0x968b,0x96a7,0x96a8,0x96d6, 0x9700,0x9808,0x9996,0x9ad3,0x9b1a,0x53d4,0x587e,0x5919,0x5b70,0x5bbf, 0x6dd1,0x6f5a,0x719f,0x7421,0x74b9,0x8085,0x83fd,0x5de1,0x5f87,0x5faa, 0x6042,0x65ec,0x6812,0x696f,0x6a53,0x6b89,0x6d35,0x6df3,0x73e3,0x76fe, 0x77ac,0x7b4d,0x7d14,0x8123,0x821c,0x8340,0x84f4,0x8563,0x8a62,0x8ac4, 0x9187,0x931e,0x9806,0x99b4,0x620c,0x8853,0x8ff0,0x9265,0x5d07,0x5d27 }, { /* ku 63 */ UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON, UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON, UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON, UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON, UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON, UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON, UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON, UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON, UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON, UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,0x5d69,0x745f,0x819d,0x8768, 0x6fd5,0x62fe,0x7fd2,0x8936,0x8972,0x4e1e,0x4e58,0x50e7,0x52dd,0x5347, 0x627f,0x6607,0x7e69,0x8805,0x965e,0x4f8d,0x5319,0x5636,0x59cb,0x5aa4, 0x5c38,0x5c4e,0x5c4d,0x5e02,0x5f11,0x6043,0x65bd,0x662f,0x6642,0x67be, 0x67f4,0x731c,0x77e2,0x793a,0x7fc5,0x8494,0x84cd,0x8996,0x8a66,0x8a69, 0x8ae1,0x8c55,0x8c7a,0x57f4,0x5bd4,0x5f0f,0x606f,0x62ed,0x690d,0x6b96, 0x6e5c,0x7184,0x7bd2,0x8755,0x8b58,0x8efe,0x98df,0x98fe,0x4f38,0x4f81, 0x4fe1,0x547b,0x5a20,0x5bb8,0x613c,0x65b0,0x6668,0x71fc,0x7533,0x795e, 0x7d33,0x814e,0x81e3,0x8398,0x85aa,0x85ce,0x8703,0x8a0a,0x8eab,0x8f9b, 0xf971,0x8fc5,0x5931,0x5ba4,0x5be6,0x6089,0x5be9,0x5c0b,0x5fc3,0x6c81 }, { /* ku 64 */ UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON, UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON, UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON, UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON, UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON, UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON, UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON, UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON, UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON, UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,0xf972,0x6df1,0x700b,0x751a, 0x82af,0x8af6,0x4ec0,0x5341,0xf973,0x96d9,0x6c0f,0x4e9e,0x4fc4,0x5152, 0x555e,0x5a25,0x5ce8,0x6211,0x7259,0x82bd,0x83aa,0x86fe,0x8859,0x8a1d, 0x963f,0x96c5,0x9913,0x9d09,0x9d5d,0x580a,0x5cb3,0x5dbd,0x5e44,0x60e1, 0x6115,0x63e1,0x6a02,0x6e25,0x9102,0x9354,0x984e,0x9c10,0x9f77,0x5b89, 0x5cb8,0x6309,0x664f,0x6848,0x773c,0x96c1,0x978d,0x9854,0x9b9f,0x65a1, 0x8b01,0x8ecb,0x95bc,0x5535,0x5ca9,0x5dd6,0x5eb5,0x6697,0x764c,0x83f4, 0x95c7,0x58d3,0x62bc,0x72ce,0x9d28,0x4ef0,0x592e,0x600f,0x663b,0x6b83, 0x79e7,0x9d26,0x5393,0x54c0,0x57c3,0x5d16,0x611b,0x66d6,0x6daf,0x788d, 0x827e,0x9698,0x9744,0x5384,0x627c,0x6396,0x6db2,0x7e0a,0x814b,0x984d }, { /* ku 65 */ UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON, UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON, UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON, UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON, UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON, UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON, UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON, UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON, UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON, UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,0x6afb,0x7f4c,0x9daf,0x9e1a, 0x4e5f,0x503b,0x51b6,0x591c,0x60f9,0x63f6,0x6930,0x723a,0x8036,0xf974, 0x91ce,0x5f31,0xf975,0xf976,0x7d04,0x82e5,0x846f,0x84bb,0x85e5,0x8e8d, 0xf977,0x4f6f,0xf978,0xf979,0x58e4,0x5b43,0x6059,0x63da,0x6518,0x656d, 0x6698,0xf97a,0x694a,0x6a23,0x6d0b,0x7001,0x716c,0x75d2,0x760d,0x79b3, 0x7a70,0xf97b,0x7f8a,0xf97c,0x8944,0xf97d,0x8b93,0x91c0,0x967d,0xf97e, 0x990a,0x5704,0x5fa1,0x65bc,0x6f01,0x7600,0x79a6,0x8a9e,0x99ad,0x9b5a, 0x9f6c,0x5104,0x61b6,0x6291,0x6a8d,0x81c6,0x5043,0x5830,0x5f66,0x7109, 0x8a00,0x8afa,0x5b7c,0x8616,0x4ffa,0x513c,0x56b4,0x5944,0x63a9,0x6df9, 0x5daa,0x696d,0x5186,0x4e88,0x4f59,0xf97f,0xf980,0xf981,0x5982,0xf982 }, { /* ku 66 */ UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON, UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON, UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON, UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON, UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON, UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON, UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON, UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON, UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON, UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,0xf983,0x6b5f,0x6c5d,0xf984, 0x74b5,0x7916,0xf985,0x8207,0x8245,0x8339,0x8f3f,0x8f5d,0xf986,0x9918, 0xf987,0xf988,0xf989,0x4ea6,0xf98a,0x57df,0x5f79,0x6613,0xf98b,0xf98c, 0x75ab,0x7e79,0x8b6f,0xf98d,0x9006,0x9a5b,0x56a5,0x5827,0x59f8,0x5a1f, 0x5bb4,0xf98e,0x5ef6,0xf98f,0xf990,0x6350,0x633b,0xf991,0x693d,0x6c87, 0x6cbf,0x6d8e,0x6d93,0x6df5,0x6f14,0xf992,0x70df,0x7136,0x7159,0xf993, 0x71c3,0x71d5,0xf994,0x784f,0x786f,0xf995,0x7b75,0x7de3,0xf996,0x7e2f, 0xf997,0x884d,0x8edf,0xf998,0xf999,0xf99a,0x925b,0xf99b,0x9cf6,0xf99c, 0xf99d,0xf99e,0x6085,0x6d85,0xf99f,0x71b1,0xf9a0,0xf9a1,0x95b1,0x53ad, 0xf9a2,0xf9a3,0xf9a4,0x67d3,0xf9a5,0x708e,0x7130,0x7430,0x8276,0x82d2 }, { /* ku 67 */ UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON, UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON, UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON, UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON, UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON, UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON, UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON, UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON, UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON, UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,0xf9a6,0x95bb,0x9ae5,0x9e7d, 0x66c4,0xf9a7,0x71c1,0x8449,0xf9a8,0xf9a9,0x584b,0xf9aa,0xf9ab,0x5db8, 0x5f71,0xf9ac,0x6620,0x668e,0x6979,0x69ae,0x6c38,0x6cf3,0x6e36,0x6f41, 0x6fda,0x701b,0x702f,0x7150,0x71df,0x7370,0xf9ad,0x745b,0xf9ae,0x74d4, 0x76c8,0x7a4e,0x7e93,0xf9af,0xf9b0,0x82f1,0x8a60,0x8fce,0xf9b1,0x9348, 0xf9b2,0x9719,0xf9b3,0xf9b4,0x4e42,0x502a,0xf9b5,0x5208,0x53e1,0x66f3, 0x6c6d,0x6fca,0x730a,0x777f,0x7a62,0x82ae,0x85dd,0x8602,0xf9b6,0x88d4, 0x8a63,0x8b7d,0x8c6b,0xf9b7,0x92b3,0xf9b8,0x9713,0x9810,0x4e94,0x4f0d, 0x4fc9,0x50b2,0x5348,0x543e,0x5433,0x55da,0x5862,0x58ba,0x5967,0x5a1b, 0x5be4,0x609f,0xf9b9,0x61ca,0x6556,0x65ff,0x6664,0x68a7,0x6c5a,0x6fb3 }, { /* ku 68 */ UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON, UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON, UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON, UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON, UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON, UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON, UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON, UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON, UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON, UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,0x70cf,0x71ac,0x7352,0x7b7d, 0x8708,0x8aa4,0x9c32,0x9f07,0x5c4b,0x6c83,0x7344,0x7389,0x923a,0x6eab, 0x7465,0x761f,0x7a69,0x7e15,0x860a,0x5140,0x58c5,0x64c1,0x74ee,0x7515, 0x7670,0x7fc1,0x9095,0x96cd,0x9954,0x6e26,0x74e6,0x7aa9,0x7aaa,0x81e5, 0x86d9,0x8778,0x8a1b,0x5a49,0x5b8c,0x5b9b,0x68a1,0x6900,0x6d63,0x73a9, 0x7413,0x742c,0x7897,0x7de9,0x7feb,0x8118,0x8155,0x839e,0x8c4c,0x962e, 0x9811,0x66f0,0x5f80,0x65fa,0x6789,0x6c6a,0x738b,0x502d,0x5a03,0x6b6a, 0x77ee,0x5916,0x5d6c,0x5dcd,0x7325,0x754f,0xf9ba,0xf9bb,0x50e5,0x51f9, 0x582f,0x592d,0x5996,0x59da,0x5be5,0xf9bc,0xf9bd,0x5da2,0x62d7,0x6416, 0x6493,0x64fe,0xf9be,0x66dc,0xf9bf,0x6a48,0xf9c0,0x71ff,0x7464,0xf9c1 }, { /* ku 69 */ UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON, UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON, UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON, UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON, UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON, UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON, UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON, UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON, UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON, UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,0x7a88,0x7aaf,0x7e47,0x7e5e, 0x8000,0x8170,0xf9c2,0x87ef,0x8981,0x8b20,0x9059,0xf9c3,0x9080,0x9952, 0x617e,0x6b32,0x6d74,0x7e1f,0x8925,0x8fb1,0x4fd1,0x50ad,0x5197,0x52c7, 0x57c7,0x5889,0x5bb9,0x5eb8,0x6142,0x6995,0x6d8c,0x6e67,0x6eb6,0x7194, 0x7462,0x7528,0x752c,0x8073,0x8338,0x84c9,0x8e0a,0x9394,0x93de,0xf9c4, 0x4e8e,0x4f51,0x5076,0x512a,0x53c8,0x53cb,0x53f3,0x5b87,0x5bd3,0x5c24, 0x611a,0x6182,0x65f4,0x725b,0x7397,0x7440,0x76c2,0x7950,0x7991,0x79b9, 0x7d06,0x7fbd,0x828b,0x85d5,0x865e,0x8fc2,0x9047,0x90f5,0x91ea,0x9685, 0x96e8,0x96e9,0x52d6,0x5f67,0x65ed,0x6631,0x682f,0x715c,0x7a36,0x90c1, 0x980a,0x4e91,0xf9c5,0x6a52,0x6b9e,0x6f90,0x7189,0x8018,0x82b8,0x8553 }, { /* ku 6a */ UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON, UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON, UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON, UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON, UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON, UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON, UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON, UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON, UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON, UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,0x904b,0x9695,0x96f2,0x97fb, 0x851a,0x9b31,0x4e90,0x718a,0x96c4,0x5143,0x539f,0x54e1,0x5713,0x5712, 0x57a3,0x5a9b,0x5ac4,0x5bc3,0x6028,0x613f,0x63f4,0x6c85,0x6d39,0x6e72, 0x6e90,0x7230,0x733f,0x7457,0x82d1,0x8881,0x8f45,0x9060,0xf9c6,0x9662, 0x9858,0x9d1b,0x6708,0x8d8a,0x925e,0x4f4d,0x5049,0x50de,0x5371,0x570d, 0x59d4,0x5a01,0x5c09,0x6170,0x6690,0x6e2d,0x7232,0x744b,0x7def,0x80c3, 0x840e,0x8466,0x853f,0x875f,0x885b,0x8918,0x8b02,0x9055,0x97cb,0x9b4f, 0x4e73,0x4f91,0x5112,0x516a,0xf9c7,0x552f,0x55a9,0x5b7a,0x5ba5,0x5e7c, 0x5e7d,0x5ebe,0x60a0,0x60df,0x6108,0x6109,0x63c4,0x6538,0x6709,0xf9c8, 0x67d4,0x67da,0xf9c9,0x6961,0x6962,0x6cb9,0x6d27,0xf9ca,0x6e38,0xf9cb }, { /* ku 6b */ UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON, UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON, UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON, UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON, UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON, UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON, UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON, UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON, UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON, UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,0x6fe1,0x7336,0x7337,0xf9cc, 0x745c,0x7531,0xf9cd,0x7652,0xf9ce,0xf9cf,0x7dad,0x81fe,0x8438,0x88d5, 0x8a98,0x8adb,0x8aed,0x8e30,0x8e42,0x904a,0x903e,0x907a,0x9149,0x91c9, 0x936e,0xf9d0,0xf9d1,0x5809,0xf9d2,0x6bd3,0x8089,0x80b2,0xf9d3,0xf9d4, 0x5141,0x596b,0x5c39,0xf9d5,0xf9d6,0x6f64,0x73a7,0x80e4,0x8d07,0xf9d7, 0x9217,0x958f,0xf9d8,0xf9d9,0xf9da,0xf9db,0x807f,0x620e,0x701c,0x7d68, 0x878d,0xf9dc,0x57a0,0x6069,0x6147,0x6bb7,0x8abe,0x9280,0x96b1,0x4e59, 0x541f,0x6deb,0x852d,0x9670,0x97f3,0x98ee,0x63d6,0x6ce3,0x9091,0x51dd, 0x61c9,0x81ba,0x9df9,0x4f9d,0x501a,0x5100,0x5b9c,0x610f,0x61ff,0x64ec, 0x6905,0x6bc5,0x7591,0x77e3,0x7fa9,0x8264,0x858f,0x87fb,0x8863,0x8abc }, { /* ku 6c */ UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON, UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON, UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON, UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON, UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON, UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON, UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON, UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON, UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON, UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,0x8b70,0x91ab,0x4e8c,0x4ee5, 0x4f0a,0xf9dd,0xf9de,0x5937,0x59e8,0xf9df,0x5df2,0x5f1b,0x5f5b,0x6021, 0xf9e0,0xf9e1,0xf9e2,0xf9e3,0x723e,0x73e5,0xf9e4,0x7570,0x75cd,0xf9e5, 0x79fb,0xf9e6,0x800c,0x8033,0x8084,0x82e1,0x8351,0xf9e7,0xf9e8,0x8cbd, 0x8cb3,0x9087,0xf9e9,0xf9ea,0x98f4,0x990c,0xf9eb,0xf9ec,0x7037,0x76ca, 0x7fca,0x7fcc,0x7ffc,0x8b1a,0x4eba,0x4ec1,0x5203,0x5370,0xf9ed,0x54bd, 0x56e0,0x59fb,0x5bc5,0x5f15,0x5fcd,0x6e6e,0xf9ee,0xf9ef,0x7d6a,0x8335, 0xf9f0,0x8693,0x8a8d,0xf9f1,0x976d,0x9777,0xf9f2,0xf9f3,0x4e00,0x4f5a, 0x4f7e,0x58f9,0x65e5,0x6ea2,0x9038,0x93b0,0x99b9,0x4efb,0x58ec,0x598a, 0x59d9,0x6041,0xf9f4,0xf9f5,0x7a14,0xf9f6,0x834f,0x8cc3,0x5165,0x5344 }, { /* ku 6d */ UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON, UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON, UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON, UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON, UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON, UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON, UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON, UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON, UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON, UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,0xf9f7,0xf9f8,0xf9f9,0x4ecd, 0x5269,0x5b55,0x82bf,0x4ed4,0x523a,0x54a8,0x59c9,0x59ff,0x5b50,0x5b57, 0x5b5c,0x6063,0x6148,0x6ecb,0x7099,0x716e,0x7386,0x74f7,0x75b5,0x78c1, 0x7d2b,0x8005,0x81ea,0x8328,0x8517,0x85c9,0x8aee,0x8cc7,0x96cc,0x4f5c, 0x52fa,0x56bc,0x65ab,0x6628,0x707c,0x70b8,0x7235,0x7dbd,0x828d,0x914c, 0x96c0,0x9d72,0x5b71,0x68e7,0x6b98,0x6f7a,0x76de,0x5c91,0x66ab,0x6f5b, 0x7bb4,0x7c2a,0x8836,0x96dc,0x4e08,0x4ed7,0x5320,0x5834,0x58bb,0x58ef, 0x596c,0x5c07,0x5e33,0x5e84,0x5f35,0x638c,0x66b2,0x6756,0x6a1f,0x6aa3, 0x6b0c,0x6f3f,0x7246,0xf9fa,0x7350,0x748b,0x7ae0,0x7ca7,0x8178,0x81df, 0x81e7,0x838a,0x846c,0x8523,0x8594,0x85cf,0x88dd,0x8d13,0x91ac,0x9577 }, { /* ku 6e */ UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON, UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON, UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON, UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON, UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON, UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON, UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON, UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON, UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON, UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,0x969c,0x518d,0x54c9,0x5728, 0x5bb0,0x624d,0x6750,0x683d,0x6893,0x6e3d,0x6ed3,0x707d,0x7e21,0x88c1, 0x8ca1,0x8f09,0x9f4b,0x9f4e,0x722d,0x7b8f,0x8acd,0x931a,0x4f47,0x4f4e, 0x5132,0x5480,0x59d0,0x5e95,0x62b5,0x6775,0x696e,0x6a17,0x6cae,0x6e1a, 0x72d9,0x732a,0x75bd,0x7bb8,0x7d35,0x82e7,0x83f9,0x8457,0x85f7,0x8a5b, 0x8caf,0x8e87,0x9019,0x90b8,0x96ce,0x9f5f,0x52e3,0x540a,0x5ae1,0x5bc2, 0x6458,0x6575,0x6ef4,0x72c4,0xf9fb,0x7684,0x7a4d,0x7b1b,0x7c4d,0x7e3e, 0x7fdf,0x837b,0x8b2b,0x8cca,0x8d64,0x8de1,0x8e5f,0x8fea,0x8ff9,0x9069, 0x93d1,0x4f43,0x4f7a,0x50b3,0x5168,0x5178,0x524d,0x526a,0x5861,0x587c, 0x5960,0x5c08,0x5c55,0x5edb,0x609b,0x6230,0x6813,0x6bbf,0x6c08,0x6fb1 }, { /* ku 6f */ UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON, UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON, UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON, UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON, UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON, UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON, UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON, UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON, UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON, UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,0x714e,0x7420,0x7530,0x7538, 0x7551,0x7672,0x7b4c,0x7b8b,0x7bad,0x7bc6,0x7e8f,0x8a6e,0x8f3e,0x8f49, 0x923f,0x9293,0x9322,0x942b,0x96fb,0x985a,0x986b,0x991e,0x5207,0x622a, 0x6298,0x6d59,0x7664,0x7aca,0x7bc0,0x7d76,0x5360,0x5cbe,0x5e97,0x6f38, 0x70b9,0x7c98,0x9711,0x9b8e,0x9ede,0x63a5,0x647a,0x8776,0x4e01,0x4e95, 0x4ead,0x505c,0x5075,0x5448,0x59c3,0x5b9a,0x5e40,0x5ead,0x5ef7,0x5f81, 0x60c5,0x633a,0x653f,0x6574,0x65cc,0x6676,0x6678,0x67fe,0x6968,0x6a89, 0x6b63,0x6c40,0x6dc0,0x6de8,0x6e1f,0x6e5e,0x701e,0x70a1,0x738e,0x73fd, 0x753a,0x775b,0x7887,0x798e,0x7a0b,0x7a7d,0x7cbe,0x7d8e,0x8247,0x8a02, 0x8aea,0x8c9e,0x912d,0x914a,0x91d8,0x9266,0x92cc,0x9320,0x9706,0x9756 }, { /* ku 70 */ UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON, UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON, UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON, UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON, UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON, UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON, UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON, UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON, UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON, UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,0x975c,0x9802,0x9f0e,0x5236, 0x5291,0x557c,0x5824,0x5e1d,0x5f1f,0x608c,0x63d0,0x68af,0x6fdf,0x796d, 0x7b2c,0x81cd,0x85ba,0x88fd,0x8af8,0x8e44,0x918d,0x9664,0x969b,0x973d, 0x984c,0x9f4a,0x4fce,0x5146,0x51cb,0x52a9,0x5632,0x5f14,0x5f6b,0x63aa, 0x64cd,0x65e9,0x6641,0x66fa,0x66f9,0x671d,0x689d,0x68d7,0x69fd,0x6f15, 0x6f6e,0x7167,0x71e5,0x722a,0x74aa,0x773a,0x7956,0x795a,0x79df,0x7a20, 0x7a95,0x7c97,0x7cdf,0x7d44,0x7e70,0x8087,0x85fb,0x86a4,0x8a54,0x8abf, 0x8d99,0x8e81,0x9020,0x906d,0x91e3,0x963b,0x96d5,0x9ce5,0x65cf,0x7c07, 0x8db3,0x93c3,0x5b58,0x5c0a,0x5352,0x62d9,0x731d,0x5027,0x5b97,0x5f9e, 0x60b0,0x616b,0x68d5,0x6dd9,0x742e,0x7a2e,0x7d42,0x7d9c,0x7e31,0x816b }, { /* ku 71 */ UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON, UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON, UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON, UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON, UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON, UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON, UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON, UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON, UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON, UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,0x8e2a,0x8e35,0x937e,0x9418, 0x4f50,0x5750,0x5de6,0x5ea7,0x632b,0x7f6a,0x4e3b,0x4f4f,0x4f8f,0x505a, 0x59dd,0x80c4,0x546a,0x5468,0x55fe,0x594f,0x5b99,0x5dde,0x5eda,0x665d, 0x6731,0x67f1,0x682a,0x6ce8,0x6d32,0x6e4a,0x6f8d,0x70b7,0x73e0,0x7587, 0x7c4c,0x7d02,0x7d2c,0x7da2,0x821f,0x86db,0x8a3b,0x8a85,0x8d70,0x8e8a, 0x8f33,0x9031,0x914e,0x9152,0x9444,0x99d0,0x7af9,0x7ca5,0x4fca,0x5101, 0x51c6,0x57c8,0x5bef,0x5cfb,0x6659,0x6a3d,0x6d5a,0x6e96,0x6fec,0x710c, 0x756f,0x7ae3,0x8822,0x9021,0x9075,0x96cb,0x99ff,0x8301,0x4e2d,0x4ef2, 0x8846,0x91cd,0x537d,0x6adb,0x696b,0x6c41,0x847a,0x589e,0x618e,0x66fe, 0x62ef,0x70dd,0x7511,0x75c7,0x7e52,0x84b8,0x8b49,0x8d08,0x4e4b,0x53ea }, { /* ku 72 */ UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON, UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON, UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON, UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON, UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON, UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON, UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON, UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON, UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON, UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,0x54ab,0x5730,0x5740,0x5fd7, 0x6301,0x6307,0x646f,0x652f,0x65e8,0x667a,0x679d,0x67b3,0x6b62,0x6c60, 0x6c9a,0x6f2c,0x77e5,0x7825,0x7949,0x7957,0x7d19,0x80a2,0x8102,0x81f3, 0x829d,0x82b7,0x8718,0x8a8c,0xf9fc,0x8d04,0x8dbe,0x9072,0x76f4,0x7a19, 0x7a37,0x7e54,0x8077,0x5507,0x55d4,0x5875,0x632f,0x6422,0x6649,0x664b, 0x686d,0x699b,0x6b84,0x6d25,0x6eb1,0x73cd,0x7468,0x74a1,0x755b,0x75b9, 0x76e1,0x771e,0x778b,0x79e6,0x7e09,0x7e1d,0x81fb,0x852f,0x8897,0x8a3a, 0x8cd1,0x8eeb,0x8fb0,0x9032,0x93ad,0x9663,0x9673,0x9707,0x4f84,0x53f1, 0x59ea,0x5ac9,0x5e19,0x684e,0x74c6,0x75be,0x79e9,0x7a92,0x81a3,0x86ed, 0x8cea,0x8dcc,0x8fed,0x659f,0x6715,0xf9fd,0x57f7,0x6f57,0x7ddd,0x8f2f }, { /* ku 73 */ UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON, UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON, UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON, UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON, UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON, UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON, UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON, UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON, UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON, UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,0x93f6,0x96c6,0x5fb5,0x61f2, 0x6f84,0x4e14,0x4f98,0x501f,0x53c9,0x55df,0x5d6f,0x5dee,0x6b21,0x6b64, 0x78cb,0x7b9a,0xf9fe,0x8e49,0x8eca,0x906e,0x6349,0x643e,0x7740,0x7a84, 0x932f,0x947f,0x9f6a,0x64b0,0x6faf,0x71e6,0x74a8,0x74da,0x7ac4,0x7c12, 0x7e82,0x7cb2,0x7e98,0x8b9a,0x8d0a,0x947d,0x9910,0x994c,0x5239,0x5bdf, 0x64e6,0x672d,0x7d2e,0x50ed,0x53c3,0x5879,0x6158,0x6159,0x61fa,0x65ac, 0x7ad9,0x8b92,0x8b96,0x5009,0x5021,0x5275,0x5531,0x5a3c,0x5ee0,0x5f70, 0x6134,0x655e,0x660c,0x6636,0x66a2,0x69cd,0x6ec4,0x6f32,0x7316,0x7621, 0x7a93,0x8139,0x8259,0x83d6,0x84bc,0x50b5,0x57f0,0x5bc0,0x5be8,0x5f69, 0x63a1,0x7826,0x7db5,0x83dc,0x8521,0x91c7,0x91f5,0x518a,0x67f5,0x7b56 }, { /* ku 74 */ UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON, UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON, UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON, UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON, UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON, UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON, UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON, UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON, UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON, UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,0x8cac,0x51c4,0x59bb,0x60bd, 0x8655,0x501c,0xf9ff,0x5254,0x5c3a,0x617d,0x621a,0x62d3,0x64f2,0x65a5, 0x6ecc,0x7620,0x810a,0x8e60,0x965f,0x96bb,0x4edf,0x5343,0x5598,0x5929, 0x5ddd,0x64c5,0x6cc9,0x6dfa,0x7394,0x7a7f,0x821b,0x85a6,0x8ce4,0x8e10, 0x9077,0x91e7,0x95e1,0x9621,0x97c6,0x51f8,0x54f2,0x5586,0x5fb9,0x64a4, 0x6f88,0x7db4,0x8f1f,0x8f4d,0x9435,0x50c9,0x5c16,0x6cbe,0x6dfb,0x751b, 0x77bb,0x7c3d,0x7c64,0x8a79,0x8ac2,0x581e,0x59be,0x5e16,0x6377,0x7252, 0x758a,0x776b,0x8adc,0x8cbc,0x8f12,0x5ef3,0x6674,0x6df8,0x807d,0x83c1, 0x8acb,0x9751,0x9bd6,0xfa00,0x5243,0x66ff,0x6d95,0x6eef,0x7de0,0x8ae6, 0x902e,0x905e,0x9ad4,0x521d,0x527f,0x54e8,0x6194,0x6284,0x62db,0x68a2 }, { /* ku 75 */ UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON, UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON, UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON, UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON, UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON, UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON, UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON, UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON, UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON, UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,0x6912,0x695a,0x6a35,0x7092, 0x7126,0x785d,0x7901,0x790e,0x79d2,0x7a0d,0x8096,0x8278,0x82d5,0x8349, 0x8549,0x8c82,0x8d85,0x9162,0x918b,0x91ae,0x4fc3,0x56d1,0x71ed,0x77d7, 0x8700,0x89f8,0x5bf8,0x5fd6,0x6751,0x90a8,0x53e2,0x585a,0x5bf5,0x60a4, 0x6181,0x6460,0x7e3d,0x8070,0x8525,0x9283,0x64ae,0x50ac,0x5d14,0x6700, 0x589c,0x62bd,0x63a8,0x690e,0x6978,0x6a1e,0x6e6b,0x76ba,0x79cb,0x82bb, 0x8429,0x8acf,0x8da8,0x8ffd,0x9112,0x914b,0x919c,0x9310,0x9318,0x939a, 0x96db,0x9a36,0x9c0d,0x4e11,0x755c,0x795d,0x7afa,0x7b51,0x7bc9,0x7e2e, 0x84c4,0x8e59,0x8e74,0x8ef8,0x9010,0x6625,0x693f,0x7443,0x51fa,0x672e, 0x9edc,0x5145,0x5fe0,0x6c96,0x87f2,0x885d,0x8877,0x60b4,0x81b5,0x8403 }, { /* ku 76 */ UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON, UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON, UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON, UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON, UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON, UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON, UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON, UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON, UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON, UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,0x8d05,0x53d6,0x5439,0x5634, 0x5a36,0x5c31,0x708a,0x7fe0,0x805a,0x8106,0x81ed,0x8da3,0x9189,0x9a5f, 0x9df2,0x5074,0x4ec4,0x53a0,0x60fb,0x6e2c,0x5c64,0x4f88,0x5024,0x55e4, 0x5cd9,0x5e5f,0x6065,0x6894,0x6cbb,0x6dc4,0x71be,0x75d4,0x75f4,0x7661, 0x7a1a,0x7a49,0x7dc7,0x7dfb,0x7f6e,0x81f4,0x86a9,0x8f1c,0x96c9,0x99b3, 0x9f52,0x5247,0x52c5,0x98ed,0x89aa,0x4e03,0x67d2,0x6f06,0x4fb5,0x5be2, 0x6795,0x6c88,0x6d78,0x741b,0x7827,0x91dd,0x937c,0x87c4,0x79e4,0x7a31, 0x5feb,0x4ed6,0x54a4,0x553e,0x58ae,0x59a5,0x60f0,0x6253,0x62d6,0x6736, 0x6955,0x8235,0x9640,0x99b1,0x99dd,0x502c,0x5353,0x5544,0x577c,0xfa01, 0x6258,0xfa02,0x64e2,0x666b,0x67dd,0x6fc1,0x6fef,0x7422,0x7438,0x8a17 }, { /* ku 77 */ UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON, UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON, UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON, UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON, UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON, UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON, UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON, UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON, UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON, UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,0x9438,0x5451,0x5606,0x5766, 0x5f48,0x619a,0x6b4e,0x7058,0x70ad,0x7dbb,0x8a95,0x596a,0x812b,0x63a2, 0x7708,0x803d,0x8caa,0x5854,0x642d,0x69bb,0x5b95,0x5e11,0x6e6f,0xfa03, 0x8569,0x514c,0x53f0,0x592a,0x6020,0x614b,0x6b86,0x6c70,0x6cf0,0x7b1e, 0x80ce,0x82d4,0x8dc6,0x90b0,0x98b1,0xfa04,0x64c7,0x6fa4,0x6491,0x6504, 0x514e,0x5410,0x571f,0x8a0e,0x615f,0x6876,0xfa05,0x75db,0x7b52,0x7d71, 0x901a,0x5806,0x69cc,0x817f,0x892a,0x9000,0x9839,0x5078,0x5957,0x59ac, 0x6295,0x900f,0x9b2a,0x615d,0x7279,0x95d6,0x5761,0x5a46,0x5df4,0x628a, 0x64ad,0x64fa,0x6777,0x6ce2,0x6d3e,0x722c,0x7436,0x7834,0x7f77,0x82ad, 0x8ddb,0x9817,0x5224,0x5742,0x677f,0x7248,0x74e3,0x8ca9,0x8fa6,0x9211 }, { /* ku 78 */ UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON, UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON, UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON, UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON, UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON, UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON, UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON, UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON, UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON, UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,0x962a,0x516b,0x53ed,0x634c, 0x4f69,0x5504,0x6096,0x6557,0x6c9b,0x6d7f,0x724c,0x72fd,0x7a17,0x8987, 0x8c9d,0x5f6d,0x6f8e,0x70f9,0x81a8,0x610e,0x4fbf,0x504f,0x6241,0x7247, 0x7bc7,0x7de8,0x7fe9,0x904d,0x97ad,0x9a19,0x8cb6,0x576a,0x5e73,0x67b0, 0x840d,0x8a55,0x5420,0x5b16,0x5e63,0x5ee2,0x5f0a,0x6583,0x80ba,0x853d, 0x9589,0x965b,0x4f48,0x5305,0x530d,0x530f,0x5486,0x54fa,0x5703,0x5e03, 0x6016,0x629b,0x62b1,0x6355,0xfa06,0x6ce1,0x6d66,0x75b1,0x7832,0x80de, 0x812f,0x82de,0x8461,0x84b2,0x888d,0x8912,0x900b,0x92ea,0x98fd,0x9b91, 0x5e45,0x66b4,0x66dd,0x7011,0x7206,0xfa07,0x4ff5,0x527d,0x5f6a,0x6153, 0x6753,0x6a19,0x6f02,0x74e2,0x7968,0x8868,0x8c79,0x98c7,0x98c4,0x9a43 }, { /* ku 79 */ UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON, UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON, UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON, UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON, UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON, UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON, UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON, UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON, UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON, UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,0x54c1,0x7a1f,0x6953,0x8af7, 0x8c4a,0x98a8,0x99ae,0x5f7c,0x62ab,0x75b2,0x76ae,0x88ab,0x907f,0x9642, 0x5339,0x5f3c,0x5fc5,0x6ccc,0x73cc,0x7562,0x758b,0x7b46,0x82fe,0x999d, 0x4e4f,0x903c,0x4e0b,0x4f55,0x53a6,0x590f,0x5ec8,0x6630,0x6cb3,0x7455, 0x8377,0x8766,0x8cc0,0x9050,0x971e,0x9c15,0x58d1,0x5b78,0x8650,0x8b14, 0x9db4,0x5bd2,0x6068,0x608d,0x65f1,0x6c57,0x6f22,0x6fa3,0x701a,0x7f55, 0x7ff0,0x9591,0x9592,0x9650,0x97d3,0x5272,0x8f44,0x51fd,0x542b,0x54b8, 0x5563,0x558a,0x6abb,0x6db5,0x7dd8,0x8266,0x929c,0x9677,0x9e79,0x5408, 0x54c8,0x76d2,0x86e4,0x95a4,0x95d4,0x965c,0x4ea2,0x4f09,0x59ee,0x5ae6, 0x5df7,0x6052,0x6297,0x676d,0x6841,0x6c86,0x6e2f,0x7f38,0x809b,0x822a }, { /* ku 7a */ UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON, UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON, UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON, UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON, UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON, UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON, UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON, UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON, UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON, UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,0xfa08,0xfa09,0x9805,0x4ea5, 0x5055,0x54b3,0x5793,0x595a,0x5b69,0x5bb3,0x61c8,0x6977,0x6d77,0x7023, 0x87f9,0x89e3,0x8a72,0x8ae7,0x9082,0x99ed,0x9ab8,0x52be,0x6838,0x5016, 0x5e78,0x674f,0x8347,0x884c,0x4eab,0x5411,0x56ae,0x73e6,0x9115,0x97ff, 0x9909,0x9957,0x9999,0x5653,0x589f,0x865b,0x8a31,0x61b2,0x6af6,0x737b, 0x8ed2,0x6b47,0x96aa,0x9a57,0x5955,0x7200,0x8d6b,0x9769,0x4fd4,0x5cf4, 0x5f26,0x61f8,0x665b,0x6ceb,0x70ab,0x7384,0x73b9,0x73fe,0x7729,0x774d, 0x7d43,0x7d62,0x7e23,0x8237,0x8852,0xfa0a,0x8ce2,0x9249,0x986f,0x5b51, 0x7a74,0x8840,0x9801,0x5acc,0x4fe0,0x5354,0x593e,0x5cfd,0x633e,0x6d79, 0x72f9,0x8105,0x8107,0x83a2,0x92cf,0x9830,0x4ea8,0x5144,0x5211,0x578b }, { /* ku 7b */ UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON, UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON, UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON, UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON, UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON, UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON, UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON, UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON, UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON, UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,0x5f62,0x6cc2,0x6ece,0x7005, 0x7050,0x70af,0x7192,0x73e9,0x7469,0x834a,0x87a2,0x8861,0x9008,0x90a2, 0x93a3,0x99a8,0x516e,0x5f57,0x60e0,0x6167,0x66b3,0x8559,0x8e4a,0x91af, 0x978b,0x4e4e,0x4e92,0x547c,0x58d5,0x58fa,0x597d,0x5cb5,0x5f27,0x6236, 0x6248,0x660a,0x6667,0x6beb,0x6d69,0x6dcf,0x6e56,0x6ef8,0x6f94,0x6fe0, 0x6fe9,0x705d,0x72d0,0x7425,0x745a,0x74e0,0x7693,0x795c,0x7cca,0x7e1e, 0x80e1,0x82a6,0x846b,0x84bf,0x864e,0x865f,0x8774,0x8b77,0x8c6a,0x93ac, 0x9800,0x9865,0x60d1,0x6216,0x9177,0x5a5a,0x660f,0x6df7,0x6e3e,0x743f, 0x9b42,0x5ffd,0x60da,0x7b0f,0x54c4,0x5f18,0x6c5e,0x6cd3,0x6d2a,0x70d8, 0x7d05,0x8679,0x8a0c,0x9d3b,0x5316,0x548c,0x5b05,0x6a3a,0x706b,0x7575 }, { /* ku 7c */ UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON, UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON, UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON, UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON, UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON, UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON, UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON, UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON, UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON, UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,0x798d,0x79be,0x82b1,0x83ef, 0x8a71,0x8b41,0x8ca8,0x9774,0xfa0b,0x64f4,0x652b,0x78ba,0x78bb,0x7a6b, 0x4e38,0x559a,0x5950,0x5ba6,0x5e7b,0x60a3,0x63db,0x6b61,0x6665,0x6853, 0x6e19,0x7165,0x74b0,0x7d08,0x9084,0x9a69,0x9c25,0x6d3b,0x6ed1,0x733e, 0x8c41,0x95ca,0x51f0,0x5e4c,0x5fa8,0x604d,0x60f6,0x6130,0x614c,0x6643, 0x6644,0x69a5,0x6cc1,0x6e5f,0x6ec9,0x6f62,0x714c,0x749c,0x7687,0x7bc1, 0x7c27,0x8352,0x8757,0x9051,0x968d,0x9ec3,0x532f,0x56de,0x5efb,0x5f8a, 0x6062,0x6094,0x61f7,0x6666,0x6703,0x6a9c,0x6dee,0x6fae,0x7070,0x736a, 0x7e6a,0x81be,0x8334,0x86d4,0x8aa8,0x8cc4,0x5283,0x7372,0x5b96,0x6a6b, 0x9404,0x54ee,0x5686,0x5b5d,0x6548,0x6585,0x66c9,0x689f,0x6d8d,0x6dc6 }, { /* ku 7d */ UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON, UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON, UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON, UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON, UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON, UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON, UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON, UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON, UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON, UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,0x723b,0x80b4,0x9175,0x9a4d, 0x4faf,0x5019,0x539a,0x540e,0x543c,0x5589,0x55c5,0x5e3f,0x5f8c,0x673d, 0x7166,0x73dd,0x9005,0x52db,0x52f3,0x5864,0x58ce,0x7104,0x718f,0x71fb, 0x85b0,0x8a13,0x6688,0x85a8,0x55a7,0x6684,0x714a,0x8431,0x5349,0x5599, 0x6bc1,0x5f59,0x5fbd,0x63ee,0x6689,0x7147,0x8af1,0x8f1d,0x9ebe,0x4f11, 0x643a,0x70cb,0x7566,0x8667,0x6064,0x8b4e,0x9df8,0x5147,0x51f6,0x5308, 0x6d36,0x80f8,0x9ed1,0x6615,0x6b23,0x7098,0x75d5,0x5403,0x5c79,0x7d07, 0x8a16,0x6b20,0x6b3d,0x6b46,0x5438,0x6070,0x6d3d,0x7fd5,0x8208,0x50d6, 0x51de,0x559c,0x566b,0x56cd,0x59ec,0x5b09,0x5e0c,0x6199,0x6198,0x6231, 0x665e,0x66e6,0x7199,0x71b9,0x71ba,0x72a7,0x79a7,0x7a00,0x7fb2,0x8a70 } }; alpine-2.10+dfsg/imap/src/charset/koi8_u.c0000600000175000017500000000342211512502123022044 0ustar paulproteuspaulproteus/* ======================================================================== * Copyright 1988-2006 University of Washington * * Licensed under the Apache License, Version 2.0 (the "License"); * you may not use this file except in compliance with the License. * You may obtain a copy of the License at * * http://www.apache.org/licenses/LICENSE-2.0 * * * ======================================================================== */ /* * Program: KOI8-U conversion table * * Author: Mark Crispin * Networks and Distributed Computing * Computing & Communications * University of Washington * Administration Building, AG-44 * Seattle, WA 98195 * Internet: MRC@CAC.Washington.EDU * * Date: 25 August 1997 * Last Edited: 30 August 2006 */ /* KOI8-U is a de-facto standard of Ukraine */ static const unsigned short koi8utab[128] = { 0x2500,0x2502,0x250c,0x2510,0x2514,0x2518,0x251c,0x2524, 0x252c,0x2534,0x253c,0x2580,0x2584,0x2588,0x258c,0x2590, 0x2591,0x2592,0x2593,0x2320,0x25a0,0x2219,0x221a,0x2248, 0x2264,0x2265,0x00a0,0x2321,0x00b0,0x00b2,0x00b7,0x00f7, 0x2550,0x2551,0x2552,0x0451,0x0454,0x2554,0x0456,0x0457, 0x2557,0x2558,0x2559,0x255a,0x255b,0x0491,0x255d,0x255e, 0x255f,0x2560,0x2561,0x0401,0x0403,0x2563,0x0406,0x0407, 0x2566,0x2567,0x2568,0x2569,0x256a,0x0490,0x256c,0x00a9, 0x044e,0x0430,0x0431,0x0446,0x0434,0x0435,0x0444,0x0433, 0x0445,0x0438,0x0439,0x043a,0x043b,0x043c,0x043d,0x043e, 0x043f,0x044f,0x0440,0x0441,0x0442,0x0443,0x0436,0x0432, 0x044c,0x044b,0x0437,0x0448,0x044d,0x0449,0x0447,0x044a, 0x042e,0x0410,0x0411,0x0426,0x0414,0x0415,0x0424,0x0413, 0x0425,0x0418,0x0419,0x041a,0x041b,0x041c,0x041d,0x041e, 0x041f,0x042f,0x0420,0x0421,0x0422,0x0423,0x0416,0x0412, 0x042c,0x042b,0x0417,0x0428,0x042d,0x0429,0x0427,0x042a }; alpine-2.10+dfsg/imap/src/charset/cns11643.c0000600000175000017500000176236211512502123022050 0ustar paulproteuspaulproteus/* ======================================================================== * Copyright 1988-2006 University of Washington * * Licensed under the Apache License, Version 2.0 (the "License"); * you may not use this file except in compliance with the License. * You may obtain a copy of the License at * * http://www.apache.org/licenses/LICENSE-2.0 * * * ======================================================================== */ /* * Program: CSN 11643 conversion table * * Author: Mark Crispin * Networks and Distributed Computing * Computing & Communications * University of Washington * Administration Building, AG-44 * Seattle, WA 98195 * Internet: MRC@CAC.Washington.EDU * * Date: 3 July 1997 * Last Edited: 30 August 2006 */ /* CNS 11643 is the national standard of the Republic of China (Taiwan). * Thanks to Emily Hsu of the ROC's Institute for Information Industry for * this data. * * Note: It is assumed that CJK Unified Ideographs Extension A are encoded * in the BMP at U+3400 to U+4DB5. */ #define CNS_EXTENDED 1 /* include extended planes 3-15 */ #define CNS_OBSOLETE 0 /* include obsolete plane 14 */ #define CNS_EXTENSION 0 /* include extension plane 15 */ #define BASE_CNS11643_KU 0x21 #define BASE_CNS11643_TEN 0x21 #define MAX_CNS11643_KU_1 93 #define MAX_CNS11643_KU_2 82 #if CNS_EXTENDED #define MAX_CNS11643_KU_3 71 #define MAX_CNS11643_KU_4 78 #define MAX_CNS11643_KU_5 92 #define MAX_CNS11643_KU_6 68 #define MAX_CNS11643_KU_7 69 #if CNS_OBSOLETE #define MAX_CNS11643_KU_14 71 #endif #if CNS_EXTENSION #define MAX_CNS11643_KU_15 77 #endif #endif #define MAX_CNS11643_TEN 94 #define CNS1TOUNICODE(c,c1,ku,ten) \ ((((ku = (c & 0x7f) - BASE_CNS11643_KU) < MAX_CNS11643_KU_1) && \ ((ten = (c1 & 0x7f) - BASE_CNS11643_TEN) < MAX_CNS11643_TEN)) ? \ cns11643_1tab[ku][ten] : UBOGON) #define CNS2TOUNICODE(c,c1,ku,ten) \ ((((ku = (c & 0x7f) - BASE_CNS11643_KU) < MAX_CNS11643_KU_2) && \ ((ten = (c1 & 0x7f) - BASE_CNS11643_TEN) < MAX_CNS11643_TEN)) ? \ cns11643_2tab[ku][ten] : UBOGON) #if CNS_EXTENDED #define CNS3TOUNICODE(c,c1,ku,ten) \ ((((ku = (c & 0x7f) - BASE_CNS11643_KU) < MAX_CNS11643_KU_3) && \ ((ten = (c1 & 0x7f) - BASE_CNS11643_TEN) < MAX_CNS11643_TEN)) ? \ cns11643_3tab[ku][ten] : UBOGON) #define CNS4TOUNICODE(c,c1,ku,ten) \ ((((ku = (c & 0x7f) - BASE_CNS11643_KU) < MAX_CNS11643_KU_4) && \ ((ten = (c1 & 0x7f) - BASE_CNS11643_TEN) < MAX_CNS11643_TEN)) ? \ cns11643_4tab[ku][ten] : UBOGON) #define CNS5TOUNICODE(c,c1,ku,ten) \ ((((ku = (c & 0x7f) - BASE_CNS11643_KU) < MAX_CNS11643_KU_5) && \ ((ten = (c1 & 0x7f) - BASE_CNS11643_TEN) < MAX_CNS11643_TEN)) ? \ cns11643_5tab[ku][ten] : UBOGON) #define CNS6TOUNICODE(c,c1,ku,ten) \ ((((ku = (c & 0x7f) - BASE_CNS11643_KU) < MAX_CNS11643_KU_6) && \ ((ten = (c1 & 0x7f) - BASE_CNS11643_TEN) < MAX_CNS11643_TEN)) ? \ cns11643_6tab[ku][ten] : UBOGON) #define CNS7TOUNICODE(c,c1,ku,ten) \ ((((ku = (c & 0x7f) - BASE_CNS11643_KU) < MAX_CNS11643_KU_7) && \ ((ten = (c1 & 0x7f) - BASE_CNS11643_TEN) < MAX_CNS11643_TEN)) ? \ cns11643_7tab[ku][ten] : UBOGON) #if CNS_OBSOLETE #define CNS14TOUNICODE(c,c1,ku,ten) \ ((((ku = (c & 0x7f) - BASE_CNS11643_KU) < MAX_CNS11643_KU_14) && \ ((ten = (c1 & 0x7f) - BASE_CNS11643_TEN) < MAX_CNS11643_TEN)) ? \ cns11643_14tab[ku][ten] : UBOGON) #endif #if CNS_EXTENSION #define CNS15TOUNICODE(c,c1,ku,ten) \ ((((ku = (c & 0x7f) - BASE_CNS11643_KU) < MAX_CNS11643_KU_15) && \ ((ten = (c1 & 0x7f) - BASE_CNS11643_TEN) < MAX_CNS11643_TEN)) ? \ cns11643_15tab[ku][ten] : UBOGON) #endif #endif /* CNS 11643 plane 1 conversion table */ static const unsigned short cns11643_1tab[MAX_CNS11643_KU_1][MAX_CNS11643_TEN] = { { /* ku 01 */ 0x3000,0xff0c,0x3001,0x3002,0xff0e,0x30fb,0xff1b,0xff1a,0xff1f,0xff01, 0xfe30,0x2026,0x2025,0xfe50,0xfe51,0xfe52,0x00b7,0xfe54,0xfe55,0xfe56, 0xfe57,0xfe31,0x2014,0xfe32,0x2013,UBOGON,UBOGON,UBOGON,UBOGON,0xff08, 0xff09,0xfe35,0xfe36,0xff5b,0xff5d,0xfe37,0xfe38,0x3014,0x3015,0xfe39, 0xfe3a,0x3010,0x3011,0xfe3b,0xfe3c,0x300a,0x300b,0xfe3d,0xfe3e,0x3008, 0x3009,0xfe3f,0xfe40,0x300c,0x300d,0xfe41,0xfe42,0x300e,0x300f,0xfe43, 0xfe44,0xfe59,0xfe5a,0xfe5b,0xfe5c,0xfe5d,0xfe5e,0x2018,0x2019,0x201c, 0x201d,0x301d,0x301e,0x2032,0x2035,0xff03,0xff06,0xff0a,0x203b,0x00a7, 0x3003,0x25cb,0x25cf,0x25b3,0x25b2,0x25ce,0x2606,0x2605,0x25c7,0x25c6, 0x25a1,0x25a0,0x25bd,0x25bc }, { /* ku 02 */ 0x32a3,0x2105,0x203e,UBOGON,0xff3f,UBOGON,0xfe49,0xfe4a,0xfe4d,0xfe4e, 0xfe4b,0xfe4c,0xfe5f,0xfe60,0xfe61,0xff0b,0xff0d,0x00d7,0x00f7,0x00b1, 0x221a,0xff1c,0xff1e,0xff1d,0x2266,0x2267,0x2260,0x221e,0x2252,0x2261, 0xfe62,0xfe63,0xfe64,0xfe66,0xfe65,0x223c,0x2229,0x222a,0x22a5,0x2220, 0x221f,0x22bf,0x33d2,0x33d1,0x222b,0x222e,0x2235,0x2234,0x2640,0x2642, 0x2641,0x2609,0x2191,0x2193,0x2192,0x2190,0x2196,0x2197,0x2199,0x2198, 0x2016,0xff5c,0xff0f,0xff3c,0x2215,0xfe68,0xff04,0xffe5,0x3012,0xffe0, 0xffe1,0xff05,0xff20,0x2103,0x2109,0xfe69,0xfe6a,0xfe6b,0x33d5,0x339c, 0x339d,0x339e,0x33ce,0x33a1,0x338e,0x338f,0x33c4,0x00b0,0x5159,0x515b, 0x515e,0x515d,0x5161,0x5163 }, { /* ku 03 */ 0x55e7,0x74e9,0x7cce,0x2581,0x2582,0x2583,0x2584,0x2585,0x2586,0x2587, 0x2588,0x258f,0x258e,0x258d,0x258c,0x258b,0x258a,0x2589,0x253c,0x2534, 0x252c,0x2524,0x251c,0x2594,0x2500,0x2502,0x2595,0x250c,0x2510,0x2514, 0x2518,0x256d,0x256e,0x2570,0x256f,0x2550,0x255e,0x256a,0x2561,0x25e2, 0x25e3,0x25e5,0x25e4,0x2571,0x2572,0x2573,UBOGON,UBOGON,UBOGON,UBOGON, UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON, UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON, UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON, UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON, UBOGON,UBOGON,UBOGON,UBOGON }, { /* ku 04 */ 0xff10,0xff11,0xff12,0xff13,0xff14,0xff15,0xff16,0xff17,0xff18,0xff19, 0x2160,0x2161,0x2162,0x2163,0x2164,0x2165,0x2166,0x2167,0x2168,0x2169, 0x3021,0x3022,0x3023,0x3024,0x3025,0x3026,0x3027,0x3028,0x3029,UBOGON, 0x5344,UBOGON,0xff21,0xff22,0xff23,0xff24,0xff25,0xff26,0xff27,0xff28, 0xff29,0xff2a,0xff2b,0xff2c,0xff2d,0xff2e,0xff2f,0xff30,0xff31,0xff32, 0xff33,0xff34,0xff35,0xff36,0xff37,0xff38,0xff39,0xff3a,0xff41,0xff42, 0xff43,0xff44,0xff45,0xff46,0xff47,0xff48,0xff49,0xff4a,0xff4b,0xff4c, 0xff4d,0xff4e,0xff4f,0xff50,0xff51,0xff52,0xff53,0xff54,0xff55,0xff56, 0xff57,0xff58,0xff59,0xff5a,0x0391,0x0392,0x0393,0x0394,0x0395,0x0396, 0x0397,0x0398,0x0399,0x039a }, { /* ku 05 */ 0x039b,0x039c,0x039d,0x039e,0x039f,0x03a0,0x03a1,0x03a3,0x03a4,0x03a5, 0x03a6,0x03a7,0x03a8,0x03a9,0x03b1,0x03b2,0x03b3,0x03b4,0x03b5,0x03b6, 0x03b7,0x03b8,0x03b9,0x03ba,0x03bb,0x03bc,0x03bd,0x03be,0x03bf,0x03c0, 0x03c1,0x03c3,0x03c4,0x03c5,0x03c6,0x03c7,0x03c8,0x03c9,0x3105,0x3106, 0x3107,0x3108,0x3109,0x310a,0x310b,0x310c,0x310d,0x310e,0x310f,0x3110, 0x3111,0x3112,0x3113,0x3114,0x3115,0x3116,0x3117,0x3118,0x3119,0x311a, 0x311b,0x311c,0x311d,0x311e,0x311f,0x3120,0x3121,0x3122,0x3123,0x3124, 0x3125,0x3126,0x3127,0x3128,0x3129,0x02d9,0x02c9,0x02ca,0x02c7,0x02cb, UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON, UBOGON,UBOGON,UBOGON,UBOGON }, { /* ku 06 */ 0x2460,0x2461,0x2462,0x2463,0x2464,0x2465,0x2466,0x2467,0x2468,0x2469, 0x2474,0x2475,0x2476,0x2477,0x2478,0x2479,0x247a,0x247b,0x247c,0x247d, 0x2170,0x2171,0x2172,0x2173,0x2174,0x2175,0x2176,0x2177,0x2178,0x2179, UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON, UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON, UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON, UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON, UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON, UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON, UBOGON,UBOGON,UBOGON,UBOGON }, { /* ku 07 */ UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,0x4ea0,UBOGON,UBOGON, UBOGON,UBOGON,UBOGON,UBOGON,0x51ab,UBOGON,UBOGON,UBOGON,UBOGON,0x52f9, UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON, UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON, UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON, UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON, UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON, UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON, UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON, UBOGON,UBOGON,UBOGON,UBOGON }, { /* ku 08 */ UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON, UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON, UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON, UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON, UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON, UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON, UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON, UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON, UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON, UBOGON,UBOGON,UBOGON,UBOGON }, { /* ku 09 */ UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON, UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON, UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON, UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON, UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON, UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON, UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON, UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON, UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON, UBOGON,UBOGON,UBOGON,UBOGON }, { /* ku 0a */ UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON, UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON, UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON, UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON, UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON, UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON, UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON, UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON, UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON, UBOGON,UBOGON,UBOGON,UBOGON }, { /* ku 0b */ UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON, UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON, UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON, UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON, UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON, UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON, UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON, UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON, UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON, UBOGON,UBOGON,UBOGON,UBOGON }, { /* ku 0c */ UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON, UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON, UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON, UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON, UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON, UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON, UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON, UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON, UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON, UBOGON,UBOGON,UBOGON,UBOGON }, { /* ku 0d */ UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON, UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON, UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON, UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON, UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON, UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON, UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON, UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON, UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON, UBOGON,UBOGON,UBOGON,UBOGON }, { /* ku 0e */ UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON, UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON, UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON, UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON, UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON, UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON, UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON, UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON, UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON, UBOGON,UBOGON,UBOGON,UBOGON }, { /* ku 0f */ UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON, UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON, UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON, UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON, UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON, UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON, UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON, UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON, UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON, UBOGON,UBOGON,UBOGON,UBOGON }, { /* ku 10 */ UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON, UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON, UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON, UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON, UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON, UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON, UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON, UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON, UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON, UBOGON,UBOGON,UBOGON,UBOGON }, { /* ku 11 */ UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON, UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON, UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON, UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON, UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON, UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON, UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON, UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON, UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON, UBOGON,UBOGON,UBOGON,UBOGON }, { /* ku 12 */ UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON, UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON, UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON, UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON, UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON, UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON, UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON, UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON, UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON, UBOGON,UBOGON,UBOGON,UBOGON }, { /* ku 13 */ UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON, UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON, UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON, UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON, UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON, UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON, UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON, UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON, UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON, UBOGON,UBOGON,UBOGON,UBOGON }, { /* ku 14 */ UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON, UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON, UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON, UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON, UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON, UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON, UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON, UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON, UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON, UBOGON,UBOGON,UBOGON,UBOGON }, { /* ku 15 */ UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON, UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON, UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON, UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON, UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON, UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON, UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON, UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON, UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON, UBOGON,UBOGON,UBOGON,UBOGON }, { /* ku 16 */ UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON, UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON, UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON, UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON, UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON, UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON, UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON, UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON, UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON, UBOGON,UBOGON,UBOGON,UBOGON }, { /* ku 17 */ UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON, UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON, UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON, UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON, UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON, UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON, UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON, UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON, UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON, UBOGON,UBOGON,UBOGON,UBOGON }, { /* ku 18 */ UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON, UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON, UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON, UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON, UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON, UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON, UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON, UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON, UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON, UBOGON,UBOGON,UBOGON,UBOGON }, { /* ku 19 */ UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON, UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON, UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON, UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON, UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON, UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON, UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON, UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON, UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON, UBOGON,UBOGON,UBOGON,UBOGON }, { /* ku 1a */ UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON, UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON, UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON, UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON, UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON, UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON, UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON, UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON, UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON, UBOGON,UBOGON,UBOGON,UBOGON }, { /* ku 1b */ UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON, UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON, UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON, UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON, UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON, UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON, UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON, UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON, UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON, UBOGON,UBOGON,UBOGON,UBOGON }, { /* ku 1c */ UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON, UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON, UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON, UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON, UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON, UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON, UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON, UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON, UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON, UBOGON,UBOGON,UBOGON,UBOGON }, { /* ku 1d */ UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON, UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON, UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON, UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON, UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON, UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON, UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON, UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON, UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON, UBOGON,UBOGON,UBOGON,UBOGON }, { /* ku 1e */ UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON, UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON, UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON, UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON, UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON, UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON, UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON, UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON, UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON, UBOGON,UBOGON,UBOGON,UBOGON }, { /* ku 1f */ UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON, UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON, UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON, UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON, UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON, UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON, UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON, UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON, UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON, UBOGON,UBOGON,UBOGON,UBOGON }, { /* ku 20 */ UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON, UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON, UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON, UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON, UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON, UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON, UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON, UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON, UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON, UBOGON,UBOGON,UBOGON,UBOGON }, { /* ku 21 */ UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON, UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON, UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON, UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON, UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON, UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON, UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON, UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON, UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON, UBOGON,UBOGON,UBOGON,UBOGON }, { /* ku 22 */ 0x2400,0x2401,0x2402,0x2403,0x2404,0x2405,0x2406,0x2407,0x2408,0x2409, 0x240a,0x240b,0x240c,0x240d,0x240e,0x240f,0x2410,0x2411,0x2412,0x2413, 0x2414,0x2415,0x2416,0x2417,0x2418,0x2419,0x241a,0x241b,0x241c,0x241d, 0x241e,0x241f,0x2421,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON, UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON, UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON, UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON, UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON, UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON, UBOGON,UBOGON,UBOGON,UBOGON }, { /* ku 23 */ UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON, UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON, UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON, UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON, UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON, UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON, UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON, UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON, UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON, UBOGON,UBOGON,UBOGON,UBOGON }, { /* ku 24 */ 0x4e00,0x4e59,0x4e01,0x4e03,0x4e43,0x4e5d,0x4e86,0x4e8c,0x4eba,0x513f, 0x5165,0x516b,0x51e0,0x5200,0x5201,0x529b,0x5315,0x5341,0x535c,0x53c8, 0x4e09,0x4e0b,0x4e08,0x4e0a,0x4e2b,0x4e38,0x51e1,0x4e45,0x4e48,0x4e5f, 0x4e5e,0x4e8e,0x4ea1,0x5140,0x5203,0x52fa,0x5343,0x53c9,0x53e3,0x571f, 0x58eb,0x5915,0x5927,0x5973,0x5b50,0x5b51,0x5b53,0x5bf8,0x5c0f,0x5c22, 0x5c38,0x5c71,0x5ddd,0x5de5,0x5df1,0x5df2,0x5df3,0x5dfe,0x5e72,0x5efe, 0x5f0b,0x5f13,0x624d,0x4e11,0x4e10,0x4e0d,0x4e2d,0x4e30,0x4e39,0x4e4b, 0x5c39,0x4e88,0x4e91,0x4e95,0x4e92,0x4e94,0x4ea2,0x4ec1,0x4ec0,0x4ec3, 0x4ec6,0x4ec7,0x4ecd,0x4eca,0x4ecb,0x4ec4,0x5143,0x5141,0x5167,0x516d, 0x516e,0x516c,0x5197,0x51f6 }, { /* ku 25 */ 0x5206,0x5207,0x5208,0x52fb,0x52fe,0x52ff,0x5316,0x5339,0x5348,0x5347, 0x5345,0x535e,0x5384,0x53cb,0x53ca,0x53cd,0x58ec,0x5929,0x592b,0x592a, 0x592d,0x5b54,0x5c11,0x5c24,0x5c3a,0x5c6f,0x5df4,0x5e7b,0x5eff,0x5f14, 0x5f15,0x5fc3,0x6208,0x6236,0x624b,0x624e,0x652f,0x6587,0x6597,0x65a4, 0x65b9,0x65e5,0x66f0,0x6708,0x6728,0x6b20,0x6b62,0x6b79,0x6bcb,0x6bd4, 0x6bdb,0x6c0f,0x6c34,0x706b,0x722a,0x7236,0x723b,0x7247,0x7259,0x725b, 0x72ac,0x738b,0x4e19,0x4e16,0x4e15,0x4e14,0x4e18,0x4e3b,0x4e4d,0x4e4f, 0x4e4e,0x4ee5,0x4ed8,0x4ed4,0x4ed5,0x4ed6,0x4ed7,0x4ee3,0x4ee4,0x4ed9, 0x4ede,0x5145,0x5144,0x5189,0x518a,0x51ac,0x51f9,0x51fa,0x51f8,0x520a, 0x52a0,0x529f,0x5305,0x5306 }, { /* ku 26 */ 0x5317,0x531d,0x4edf,0x534a,0x5349,0x5361,0x5360,0x536f,0x536e,0x53bb, 0x53ef,0x53e4,0x53f3,0x53ec,0x53ee,0x53e9,0x53e8,0x53fc,0x53f8,0x53f5, 0x53eb,0x53e6,0x53ea,0x53f2,0x53f1,0x53f0,0x53e5,0x53ed,0x53fb,0x56db, 0x56da,0x5916,0x592e,0x5931,0x5974,0x5976,0x5b55,0x5b83,0x5c3c,0x5de8, 0x5de7,0x5de6,0x5e02,0x5e03,0x5e73,0x5e7c,0x5f01,0x5f18,0x5f17,0x5fc5, 0x620a,0x6253,0x6254,0x6252,0x6251,0x65a5,0x65e6,0x672e,0x672c,0x672a, 0x672b,0x672d,0x6b63,0x6bcd,0x6c11,0x6c10,0x6c38,0x6c41,0x6c40,0x6c3e, 0x72af,0x7384,0x7389,0x74dc,0x74e6,0x7518,0x751f,0x7528,0x7529,0x7530, 0x7531,0x7532,0x7533,0x758b,0x767d,0x76ae,0x76bf,0x76ee,0x77db,0x77e2, 0x77f3,0x793a,0x79be,0x7a74 }, { /* ku 27 */ 0x7acb,0x4e1e,0x4e1f,0x4e52,0x4e53,0x4e69,0x4e99,0x4ea4,0x4ea6,0x4ea5, 0x4eff,0x4f09,0x4f19,0x4f0a,0x4f15,0x4f0d,0x4f10,0x4f11,0x4f0f,0x4ef2, 0x4ef6,0x4efb,0x4ef0,0x4ef3,0x4efd,0x4f01,0x4f0b,0x5149,0x5147,0x5146, 0x5148,0x5168,0x5171,0x518d,0x51b0,0x5217,0x5211,0x5212,0x520e,0x5216, 0x52a3,0x5308,0x5321,0x5320,0x5370,0x5371,0x5409,0x540f,0x540c,0x540a, 0x5410,0x5401,0x540b,0x5404,0x5411,0x540d,0x5408,0x5403,0x540e,0x5406, 0x5412,0x56e0,0x56de,0x56dd,0x5733,0x5730,0x5728,0x572d,0x572c,0x572f, 0x5729,0x5919,0x591a,0x5937,0x5938,0x5984,0x5978,0x5983,0x597d,0x5979, 0x5982,0x5981,0x5b57,0x5b58,0x5b87,0x5b88,0x5b85,0x5b89,0x5bfa,0x5c16, 0x5c79,0x5dde,0x5e06,0x5e76 }, { /* ku 28 */ 0x5e74,0x5f0f,0x5f1b,0x5fd9,0x5fd6,0x620e,0x620c,0x620d,0x6210,0x6263, 0x625b,0x6258,0x6536,0x65e9,0x65e8,0x65ec,0x65ed,0x66f2,0x66f3,0x6709, 0x673d,0x6734,0x6731,0x6735,0x6b21,0x6b64,0x6b7b,0x6c16,0x6c5d,0x6c57, 0x6c59,0x6c5f,0x6c60,0x6c50,0x6c55,0x6c61,0x6c5b,0x6c4d,0x6c4e,0x7070, 0x725f,0x725d,0x767e,0x7af9,0x7c73,0x7cf8,0x7f36,0x7f8a,0x7fbd,0x8001, 0x8003,0x800c,0x8012,0x8033,0x807f,0x8089,0x808b,0x808c,0x81e3,0x81ea, 0x81f3,0x81fc,0x820c,0x821b,0x821f,0x826e,0x8272,0x827e,0x866b,0x8840, 0x884c,0x8863,0x897f,0x9621,0x4e32,0x4ea8,0x4f4d,0x4f4f,0x4f47,0x4f57, 0x4f5e,0x4f34,0x4f5b,0x4f55,0x4f30,0x4f50,0x4f51,0x4f3d,0x4f3a,0x4f38, 0x4f43,0x4f54,0x4f3c,0x4f46 }, { /* ku 29 */ 0x4f63,0x4f5c,0x4f60,0x4f2f,0x4f4e,0x4f36,0x4f59,0x4f5d,0x4f48,0x4f5a, 0x514c,0x514b,0x514d,0x5175,0x51b6,0x51b7,0x5225,0x5224,0x5229,0x522a, 0x5228,0x52ab,0x52a9,0x52aa,0x52ac,0x5323,0x5373,0x5375,0x541d,0x542d, 0x541e,0x543e,0x5426,0x544e,0x5427,0x5446,0x5443,0x5433,0x5448,0x5442, 0x541b,0x5429,0x544a,0x5439,0x543b,0x5438,0x542e,0x5435,0x5436,0x5420, 0x543c,0x5440,0x5431,0x542b,0x541f,0x542c,0x56ea,0x56f0,0x56e4,0x56eb, 0x574a,0x5751,0x5740,0x574d,0x5747,0x574e,0x573e,0x5750,0x574f,0x573b, 0x58ef,0x593e,0x599d,0x5992,0x59a8,0x599e,0x59a3,0x5999,0x5996,0x598d, 0x59a4,0x5993,0x598a,0x59a5,0x5b5d,0x5b5c,0x5b5a,0x5b5b,0x5b8c,0x5b8b, 0x5b8f,0x5c2c,0x5c40,0x5c41 }, { /* ku 2a */ 0x5c3f,0x5c3e,0x5c90,0x5c91,0x5c94,0x5c8c,0x5deb,0x5e0c,0x5e8f,0x5e87, 0x5e8a,0x5ef7,0x5f04,0x5f1f,0x5f64,0x5f62,0x5f77,0x5f79,0x5fd8,0x5fcc, 0x5fd7,0x5fcd,0x5ff1,0x5feb,0x5ff8,0x5fea,0x6212,0x6211,0x6284,0x6297, 0x6296,0x6280,0x6276,0x6289,0x626d,0x628a,0x627c,0x627e,0x6279,0x6273, 0x6292,0x626f,0x6298,0x626e,0x6295,0x6293,0x6291,0x6286,0x6539,0x653b, 0x6538,0x65f1,0x66f4,0x675f,0x674e,0x674f,0x6750,0x6751,0x675c,0x6756, 0x675e,0x6749,0x6746,0x6760,0x6753,0x6757,0x6b65,0x6bcf,0x6c42,0x6c5e, 0x6c99,0x6c81,0x6c88,0x6c89,0x6c85,0x6c9b,0x6c6a,0x6c7a,0x6c90,0x6c70, 0x6c8c,0x6c68,0x6c96,0x6c92,0x6c7d,0x6c83,0x6c72,0x6c7e,0x6c74,0x6c86, 0x6c76,0x6c8d,0x6c94,0x6c98 }, { /* ku 2b */ 0x6c82,0x7076,0x707c,0x707d,0x7078,0x7262,0x7261,0x7260,0x72c4,0x72c2, 0x7396,0x752c,0x752b,0x7537,0x7538,0x7682,0x76ef,0x77e3,0x79c1,0x79c0, 0x79bf,0x7a76,0x7cfb,0x7f55,0x8096,0x8093,0x809d,0x8098,0x809b,0x809a, 0x80b2,0x826f,0x8292,0x828b,0x828d,0x898b,0x89d2,0x8a00,0x8c37,0x8c46, 0x8c55,0x8c9d,0x8d64,0x8d70,0x8db3,0x8eab,0x8eca,0x8f9b,0x8fb0,0x8fc2, 0x8fc6,0x8fc5,0x8fc4,0x5de1,0x9091,0x90a2,0x90aa,0x90a6,0x90a3,0x9149, 0x91c6,0x91cc,0x9632,0x962e,0x9631,0x962a,0x962c,0x4e26,0x4e56,0x4e73, 0x4e8b,0x4e9b,0x4e9e,0x4eab,0x4eac,0x4f6f,0x4f9d,0x4f8d,0x4f73,0x4f7f, 0x4f6c,0x4f9b,0x4f8b,0x4f86,0x4f83,0x4f70,0x4f75,0x4f88,0x4f69,0x4f7b, 0x4f96,0x4f7e,0x4f8f,0x4f91 }, { /* ku 2c */ 0x4f7a,0x5154,0x5152,0x5155,0x5169,0x5177,0x5176,0x5178,0x51bd,0x51fd, 0x523b,0x5238,0x5237,0x523a,0x5230,0x522e,0x5236,0x5241,0x52be,0x52bb, 0x5352,0x5354,0x5353,0x5351,0x5366,0x5377,0x5378,0x5379,0x53d6,0x53d4, 0x53d7,0x5473,0x5475,0x5496,0x5478,0x5495,0x5480,0x547b,0x5477,0x5484, 0x5492,0x5486,0x547c,0x5490,0x5471,0x5476,0x548c,0x549a,0x5462,0x5468, 0x548b,0x547d,0x548e,0x56fa,0x5783,0x5777,0x576a,0x5769,0x5761,0x5766, 0x5764,0x577c,0x591c,0x5949,0x5947,0x5948,0x5944,0x5954,0x59be,0x59bb, 0x59d4,0x59b9,0x59ae,0x59d1,0x59c6,0x59d0,0x59cd,0x59cb,0x59d3,0x59ca, 0x59af,0x59b3,0x59d2,0x59c5,0x5b5f,0x5b64,0x5b63,0x5b97,0x5b9a,0x5b98, 0x5b9c,0x5b99,0x5b9b,0x5c1a }, { /* ku 2d */ 0x5c48,0x5c45,0x5c46,0x5cb7,0x5ca1,0x5cb8,0x5ca9,0x5cab,0x5cb1,0x5cb3, 0x5e18,0x5e1a,0x5e16,0x5e15,0x5e1b,0x5e11,0x5e78,0x5e9a,0x5e97,0x5e9c, 0x5e95,0x5e96,0x5ef6,0x5f26,0x5f27,0x5f29,0x5f80,0x5f81,0x5f7f,0x5f7c, 0x5fdd,0x5fe0,0x5ffd,0x5ff5,0x5fff,0x600f,0x6014,0x602f,0x6035,0x6016, 0x602a,0x6015,0x6021,0x6027,0x6029,0x602b,0x601b,0x6216,0x6215,0x623f, 0x623e,0x6240,0x627f,0x62c9,0x62cc,0x62c4,0x62bf,0x62c2,0x62b9,0x62d2, 0x62db,0x62ab,0x62d3,0x62d4,0x62cb,0x62c8,0x62a8,0x62bd,0x62bc,0x62d0, 0x62d9,0x62c7,0x62cd,0x62b5,0x62da,0x62b1,0x62d8,0x62d6,0x62d7,0x62c6, 0x62ac,0x62ce,0x653e,0x65a7,0x65bc,0x65fa,0x6614,0x6613,0x660c,0x6606, 0x6602,0x660e,0x6600,0x660f }, { /* ku 2e */ 0x6615,0x660a,0x6607,0x670d,0x670b,0x676d,0x678b,0x6795,0x6771,0x679c, 0x6773,0x6777,0x6787,0x679d,0x6797,0x676f,0x6770,0x677f,0x6789,0x677e, 0x6790,0x6775,0x679a,0x6793,0x677c,0x676a,0x6772,0x6b23,0x6b66,0x6b67, 0x6b7f,0x6c13,0x6c1b,0x6ce3,0x6ce8,0x6cf3,0x6cb1,0x6ccc,0x6ce5,0x6cb3, 0x6cbd,0x6cbe,0x6cbc,0x6ce2,0x6cab,0x6cd5,0x6cd3,0x6cb8,0x6cc4,0x6cb9, 0x6cc1,0x6cae,0x6cd7,0x6cc5,0x6cf1,0x6cbf,0x6cbb,0x6ce1,0x6cdb,0x6cca, 0x6cac,0x6cef,0x6cdc,0x6cd6,0x6ce0,0x7095,0x708e,0x7092,0x708a,0x7099, 0x722c,0x722d,0x7238,0x7248,0x7267,0x7269,0x72c0,0x72ce,0x72d9,0x72d7, 0x72d0,0x73a9,0x73a8,0x739f,0x73ab,0x73a5,0x753d,0x759d,0x7599,0x759a, 0x7684,0x76c2,0x76f2,0x76f4 }, { /* ku 2f */ 0x77e5,0x77fd,0x793e,0x7940,0x7941,0x79c9,0x79c8,0x7a7a,0x7a79,0x7afa, 0x7cfe,0x7f54,0x7f8c,0x7f8b,0x8005,0x80ba,0x80a5,0x80a2,0x80b1,0x80a1, 0x80ab,0x80a9,0x80b4,0x80aa,0x80af,0x81e5,0x81fe,0x820d,0x82b3,0x829d, 0x8299,0x82ad,0x82bd,0x829f,0x82b9,0x82b1,0x82ac,0x82a5,0x82af,0x82b8, 0x82a3,0x82b0,0x82be,0x82b7,0x864e,0x8671,0x521d,0x8868,0x8ecb,0x8fce, 0x8fd4,0x8fd1,0x90b5,0x90b8,0x90b1,0x90b6,0x91c7,0x91d1,0x9577,0x9580, 0x961c,0x9640,0x963f,0x963b,0x9644,0x9642,0x96b9,0x96e8,0x9752,0x975e, 0x4e9f,0x4ead,0x4eae,0x4fe1,0x4fb5,0x4faf,0x4fbf,0x4fe0,0x4fd1,0x4fcf, 0x4fdd,0x4fc3,0x4fb6,0x4fd8,0x4fdf,0x4fca,0x4fd7,0x4fae,0x4fd0,0x4fc4, 0x4fc2,0x4fda,0x4fce,0x4fde }, { /* ku 30 */ 0x4fb7,0x5157,0x5192,0x5191,0x51a0,0x524e,0x5243,0x524a,0x524d,0x524c, 0x524b,0x5247,0x52c7,0x52c9,0x52c3,0x52c1,0x530d,0x5357,0x537b,0x539a, 0x53db,0x54ac,0x54c0,0x54a8,0x54ce,0x54c9,0x54b8,0x54a6,0x54b3,0x54c7, 0x54c2,0x54bd,0x54aa,0x54c1,0x54c4,0x54c8,0x54af,0x54ab,0x54b1,0x54bb, 0x54a9,0x54a7,0x54bf,0x56ff,0x5782,0x578b,0x57a0,0x57a3,0x57a2,0x57ce, 0x57ae,0x5793,0x5955,0x5951,0x594f,0x594e,0x5950,0x59dc,0x59d8,0x59ff, 0x59e3,0x59e8,0x5a03,0x59e5,0x59ea,0x59da,0x59e6,0x5a01,0x59fb,0x5b69, 0x5ba3,0x5ba6,0x5ba4,0x5ba2,0x5ba5,0x5c01,0x5c4e,0x5c4f,0x5c4d,0x5c4b, 0x5cd9,0x5cd2,0x5df7,0x5e1d,0x5e25,0x5e1f,0x5e7d,0x5ea0,0x5ea6,0x5efa, 0x5f08,0x5f2d,0x5f65,0x5f88 }, { /* ku 31 */ 0x5f85,0x5f8a,0x5f8b,0x5f87,0x5f8c,0x5f89,0x6012,0x601d,0x6020,0x6025, 0x600e,0x6028,0x604d,0x6070,0x6068,0x6062,0x6046,0x6043,0x606c,0x606b, 0x606a,0x6064,0x6241,0x62dc,0x6316,0x6309,0x62fc,0x62ed,0x6301,0x62ee, 0x62fd,0x6307,0x62f1,0x62f7,0x62ef,0x62ec,0x62fe,0x62f4,0x6311,0x6302, 0x653f,0x6545,0x65ab,0x65bd,0x65e2,0x6625,0x662d,0x6620,0x6627,0x662f, 0x661f,0x6628,0x6631,0x6624,0x66f7,0x67ff,0x67d3,0x67f1,0x67d4,0x67d0, 0x67ec,0x67b6,0x67af,0x67f5,0x67e9,0x67ef,0x67c4,0x67d1,0x67b4,0x67da, 0x67e5,0x67b8,0x67cf,0x67de,0x67f3,0x67b0,0x67d9,0x67e2,0x67dd,0x67d2, 0x6b6a,0x6b83,0x6b86,0x6bb5,0x6bd2,0x6bd7,0x6c1f,0x6cc9,0x6d0b,0x6d32, 0x6d2a,0x6d41,0x6d25,0x6d0c }, { /* ku 32 */ 0x6d31,0x6d1e,0x6d17,0x6d3b,0x6d3d,0x6d3e,0x6d36,0x6d1b,0x6cf5,0x6d39, 0x6d27,0x6d38,0x6d29,0x6d2e,0x6d35,0x6d0e,0x6d2b,0x70ab,0x70ba,0x70b3, 0x70ac,0x70af,0x70ad,0x70b8,0x70ae,0x70a4,0x7230,0x7272,0x726f,0x7274, 0x72e9,0x72e0,0x72e1,0x73b7,0x73ca,0x73bb,0x73b2,0x73cd,0x73c0,0x73b3, 0x751a,0x752d,0x754f,0x754c,0x754e,0x754b,0x75ab,0x75a4,0x75a5,0x75a2, 0x75a3,0x7678,0x7686,0x7687,0x7688,0x76c8,0x76c6,0x76c3,0x76c5,0x7701, 0x76f9,0x76f8,0x7709,0x770b,0x76fe,0x76fc,0x7707,0x77dc,0x7802,0x7814, 0x780c,0x780d,0x7946,0x7949,0x7948,0x7947,0x79b9,0x79ba,0x79d1,0x79d2, 0x79cb,0x7a7f,0x7a81,0x7aff,0x7afd,0x7c7d,0x7d02,0x7d05,0x7d00,0x7d09, 0x7d07,0x7d04,0x7d06,0x7f38 }, { /* ku 33 */ 0x7f8e,0x7fbf,0x8010,0x800d,0x8011,0x8036,0x80d6,0x80e5,0x80da,0x80c3, 0x80c4,0x80cc,0x80e1,0x80db,0x80ce,0x80de,0x80e4,0x80dd,0x81f4,0x8222, 0x82e7,0x8303,0x8305,0x82e3,0x82db,0x82e6,0x8304,0x82e5,0x8302,0x8309, 0x82d2,0x82d7,0x82f1,0x8301,0x82dc,0x82d4,0x82d1,0x82de,0x82d3,0x82df, 0x82ef,0x8306,0x8650,0x8679,0x867b,0x867a,0x884d,0x886b,0x8981,0x89d4, 0x8a08,0x8a02,0x8a03,0x8c9e,0x8ca0,0x8d74,0x8d73,0x8db4,0x8ecd,0x8ecc, 0x8ff0,0x8fe6,0x8fe2,0x8fea,0x8fe5,0x8fed,0x8feb,0x8fe4,0x8fe8,0x90ca, 0x90ce,0x90c1,0x90c3,0x914b,0x914a,0x91cd,0x9582,0x9650,0x964b,0x964c, 0x964d,0x9762,0x9769,0x97cb,0x97ed,0x97f3,0x9801,0x98a8,0x98db,0x98df, 0x9996,0x9999,0x4e58,0x4eb3 }, { /* ku 34 */ 0x500c,0x500d,0x5023,0x4fef,0x5026,0x5025,0x4ff8,0x5029,0x5016,0x5006, 0x503c,0x501f,0x501a,0x5012,0x5011,0x4ffa,0x5000,0x5014,0x5028,0x4ff1, 0x5021,0x500b,0x5019,0x5018,0x4ff3,0x4fee,0x502d,0x502a,0x4ffe,0x502b, 0x5009,0x517c,0x51a4,0x51a5,0x51a2,0x51cd,0x51cc,0x51c6,0x51cb,0x5256, 0x525c,0x5254,0x525b,0x525d,0x532a,0x537f,0x539f,0x539d,0x53df,0x54e8, 0x5510,0x5501,0x5537,0x54fc,0x54e5,0x54f2,0x5506,0x54fa,0x5514,0x54e9, 0x54ed,0x54e1,0x5509,0x54ee,0x54ea,0x54e6,0x5527,0x5507,0x54fd,0x550f, 0x5703,0x5704,0x57c2,0x57d4,0x57cb,0x57c3,0x5809,0x590f,0x5957,0x5958, 0x595a,0x5a11,0x5a18,0x5a1c,0x5a1f,0x5a1b,0x5a13,0x59ec,0x5a20,0x5a23, 0x5a29,0x5a25,0x5a0c,0x5a09 }, { /* ku 35 */ 0x5b6b,0x5c58,0x5bb0,0x5bb3,0x5bb6,0x5bb4,0x5bae,0x5bb5,0x5bb9,0x5bb8, 0x5c04,0x5c51,0x5c55,0x5c50,0x5ced,0x5cfd,0x5cfb,0x5cea,0x5ce8,0x5cf0, 0x5cf6,0x5d01,0x5cf4,0x5dee,0x5e2d,0x5e2b,0x5eab,0x5ead,0x5ea7,0x5f31, 0x5f92,0x5f91,0x5f90,0x6059,0x6063,0x6065,0x6050,0x6055,0x606d,0x6069, 0x606f,0x6084,0x609f,0x609a,0x608d,0x6094,0x608c,0x6085,0x6096,0x6247, 0x62f3,0x6308,0x62ff,0x634e,0x633e,0x632f,0x6355,0x6342,0x6346,0x634f, 0x6349,0x633a,0x6350,0x633d,0x632a,0x632b,0x6328,0x634d,0x634c,0x6548, 0x6549,0x6599,0x65c1,0x65c5,0x6642,0x6649,0x664f,0x6643,0x6652,0x664c, 0x6645,0x6641,0x66f8,0x6714,0x6715,0x6717,0x6821,0x6838,0x6848,0x6846, 0x6853,0x6839,0x6842,0x6854 }, { /* ku 36 */ 0x6829,0x68b3,0x6817,0x684c,0x6851,0x683d,0x67f4,0x6850,0x6840,0x683c, 0x6843,0x682a,0x6845,0x6813,0x6818,0x6841,0x6b8a,0x6b89,0x6bb7,0x6c23, 0x6c27,0x6c28,0x6c26,0x6c24,0x6cf0,0x6d6a,0x6d95,0x6d88,0x6d87,0x6d66, 0x6d78,0x6d77,0x6d59,0x6d93,0x6d6c,0x6d89,0x6d6e,0x6d5a,0x6d74,0x6d69, 0x6d8c,0x6d8a,0x6d79,0x6d85,0x6d65,0x6d94,0x70ca,0x70d8,0x70e4,0x70d9, 0x70c8,0x70cf,0x7239,0x7279,0x72fc,0x72f9,0x72fd,0x72f8,0x72f7,0x7386, 0x73ed,0x7409,0x73ee,0x73e0,0x73ea,0x73de,0x7554,0x755d,0x755c,0x755a, 0x7559,0x75be,0x75c5,0x75c7,0x75b2,0x75b3,0x75bd,0x75bc,0x75b9,0x75c2, 0x75b8,0x768b,0x76b0,0x76ca,0x76cd,0x76ce,0x7729,0x771f,0x7720,0x7728, 0x77e9,0x7830,0x7827,0x7838 }, { /* ku 37 */ 0x781d,0x7834,0x7837,0x7825,0x782d,0x7820,0x781f,0x7832,0x7955,0x7950, 0x7960,0x795f,0x7956,0x795e,0x795d,0x7957,0x795a,0x79e4,0x79e3,0x79e7, 0x79df,0x79e6,0x79e9,0x79d8,0x7a84,0x7a88,0x7ad9,0x7b06,0x7b11,0x7c89, 0x7d21,0x7d17,0x7d0b,0x7d0a,0x7d20,0x7d22,0x7d14,0x7d10,0x7d15,0x7d1a, 0x7d1c,0x7d0d,0x7d19,0x7d1b,0x7f3a,0x7f5f,0x7f94,0x7fc5,0x7fc1,0x8006, 0x8004,0x8018,0x8015,0x8019,0x8017,0x803d,0x803f,0x80f1,0x8102,0x80f0, 0x8105,0x80ed,0x80f4,0x8106,0x80f8,0x80f3,0x8108,0x80fd,0x810a,0x80fc, 0x80ef,0x81ed,0x81ec,0x8200,0x8210,0x822a,0x822b,0x8228,0x822c,0x82bb, 0x832b,0x8352,0x8354,0x834a,0x8338,0x8350,0x8349,0x8335,0x8334,0x834f, 0x8332,0x8339,0x8336,0x8317 }, { /* ku 38 */ 0x8340,0x8331,0x8328,0x8343,0x8654,0x868a,0x86aa,0x8693,0x86a4,0x86a9, 0x868c,0x86a3,0x869c,0x8870,0x8877,0x8881,0x8882,0x887d,0x8879,0x8a18, 0x8a10,0x8a0e,0x8a0c,0x8a15,0x8a0a,0x8a17,0x8a13,0x8a16,0x8a0f,0x8a11, 0x8c48,0x8c7a,0x8c79,0x8ca1,0x8ca2,0x8d77,0x8eac,0x8ed2,0x8ed4,0x8ecf, 0x8fb1,0x9001,0x9006,0x8ff7,0x9000,0x8ffa,0x8ff4,0x9003,0x8ffd,0x9005, 0x8ff8,0x9095,0x90e1,0x90dd,0x90e2,0x9152,0x914d,0x914c,0x91d8,0x91dd, 0x91d7,0x91dc,0x91d9,0x9583,0x9662,0x9663,0x9661,0x965b,0x965d,0x9664, 0x9658,0x965e,0x96bb,0x98e2,0x99ac,0x9aa8,0x9ad8,0x9b25,0x9b32,0x9b3c, 0x4e7e,0x507a,0x507d,0x505c,0x5047,0x5043,0x504c,0x505a,0x5049,0x5065, 0x5076,0x504e,0x5055,0x5075 }, { /* ku 39 */ 0x5074,0x5077,0x504f,0x500f,0x506f,0x506d,0x515c,0x5195,0x51f0,0x526a, 0x526f,0x52d2,0x52d9,0x52d8,0x52d5,0x5310,0x530f,0x5319,0x533f,0x5340, 0x533e,0x53c3,0x66fc,0x5546,0x556a,0x5566,0x5544,0x555e,0x5561,0x5543, 0x554a,0x5531,0x5556,0x554f,0x5555,0x552f,0x5564,0x5538,0x552e,0x555c, 0x552c,0x5563,0x5533,0x5541,0x5557,0x5708,0x570b,0x5709,0x57df,0x5805, 0x580a,0x5806,0x57e0,0x57e4,0x57fa,0x5802,0x5835,0x57f7,0x57f9,0x5920, 0x5962,0x5a36,0x5a41,0x5a49,0x5a66,0x5a6a,0x5a40,0x5a3c,0x5a62,0x5a5a, 0x5a46,0x5a4a,0x5b70,0x5bc7,0x5bc5,0x5bc4,0x5bc2,0x5bbf,0x5bc6,0x5c09, 0x5c08,0x5c07,0x5c60,0x5c5c,0x5c5d,0x5d07,0x5d06,0x5d0e,0x5d1b,0x5d16, 0x5d22,0x5d11,0x5d29,0x5d14 }, { /* ku 3a */ 0x5d19,0x5d24,0x5d27,0x5d17,0x5de2,0x5e38,0x5e36,0x5e33,0x5e37,0x5eb7, 0x5eb8,0x5eb6,0x5eb5,0x5ebe,0x5f35,0x5f37,0x5f57,0x5f6c,0x5f69,0x5f6b, 0x5f97,0x5f99,0x5f9e,0x5f98,0x5fa1,0x5fa0,0x5f9c,0x607f,0x60a3,0x6089, 0x60a0,0x60a8,0x60cb,0x60b4,0x60e6,0x60bd,0x60c5,0x60bb,0x60b5,0x60dc, 0x60bc,0x60d8,0x60d5,0x60c6,0x60df,0x60b8,0x60da,0x60c7,0x621a,0x621b, 0x6248,0x63a0,0x63a7,0x6372,0x6396,0x63a2,0x63a5,0x6377,0x6367,0x6398, 0x63aa,0x6371,0x63a9,0x6389,0x6383,0x639b,0x636b,0x63a8,0x6384,0x6388, 0x6399,0x63a1,0x63ac,0x6392,0x638f,0x6380,0x637b,0x6369,0x6368,0x637a, 0x655d,0x6556,0x6551,0x6559,0x6557,0x555f,0x654f,0x6558,0x6555,0x6554, 0x659c,0x659b,0x65ac,0x65cf }, { /* ku 3b */ 0x65cb,0x65cc,0x65ce,0x665d,0x665a,0x6664,0x6668,0x6666,0x665e,0x66f9, 0x52d7,0x671b,0x6881,0x68af,0x68a2,0x6893,0x68b5,0x687f,0x6876,0x68b1, 0x68a7,0x6897,0x68b0,0x6883,0x68c4,0x68ad,0x6886,0x6885,0x6894,0x689d, 0x68a8,0x689f,0x68a1,0x6882,0x6b32,0x6bba,0x6beb,0x6bec,0x6c2b,0x6d8e, 0x6dbc,0x6df3,0x6dd9,0x6db2,0x6de1,0x6dcc,0x6de4,0x6dfb,0x6dfa,0x6e05, 0x6dc7,0x6dcb,0x6daf,0x6dd1,0x6dae,0x6dde,0x6df9,0x6db8,0x6df7,0x6df5, 0x6dc5,0x6dd2,0x6e1a,0x6db5,0x6dda,0x6deb,0x6dd8,0x6dea,0x6df1,0x6dee, 0x6de8,0x6dc6,0x6dc4,0x6daa,0x6dec,0x6dbf,0x6de6,0x70f9,0x7109,0x710a, 0x70fd,0x70ef,0x723d,0x727d,0x7281,0x731c,0x731b,0x7316,0x7313,0x7319, 0x7387,0x7405,0x740a,0x7403 }, { /* ku 3c */ 0x7406,0x73fe,0x740d,0x74e0,0x74f6,0x74f7,0x751c,0x7522,0x7565,0x7566, 0x7562,0x7570,0x758f,0x75d4,0x75d5,0x75b5,0x75ca,0x75cd,0x768e,0x76d4, 0x76d2,0x76db,0x7737,0x773e,0x773c,0x7736,0x7738,0x773a,0x786b,0x7843, 0x784e,0x7965,0x7968,0x796d,0x79fb,0x7a92,0x7a95,0x7b20,0x7b28,0x7b1b, 0x7b2c,0x7b26,0x7b19,0x7b1e,0x7b2e,0x7c92,0x7c97,0x7c95,0x7d46,0x7d43, 0x7d71,0x7d2e,0x7d39,0x7d3c,0x7d40,0x7d30,0x7d33,0x7d44,0x7d2f,0x7d42, 0x7d32,0x7d31,0x7f3d,0x7f9e,0x7f9a,0x7fcc,0x7fce,0x7fd2,0x801c,0x804a, 0x8046,0x812f,0x8116,0x8123,0x812b,0x8129,0x8130,0x8124,0x8202,0x8235, 0x8237,0x8236,0x8239,0x838e,0x839e,0x8398,0x8378,0x83a2,0x8396,0x83bd, 0x83ab,0x8392,0x838a,0x8393 }, { /* ku 3d */ 0x8389,0x83a0,0x8377,0x837b,0x837c,0x8386,0x83a7,0x8655,0x5f6a,0x86c7, 0x86c0,0x86b6,0x86c4,0x86b5,0x86c6,0x86cb,0x86b1,0x86af,0x86c9,0x8853, 0x889e,0x8888,0x88ab,0x8892,0x8896,0x888d,0x888b,0x8993,0x898f,0x8a2a, 0x8a1d,0x8a23,0x8a25,0x8a31,0x8a2d,0x8a1f,0x8a1b,0x8a22,0x8c49,0x8c5a, 0x8ca9,0x8cac,0x8cab,0x8ca8,0x8caa,0x8ca7,0x8d67,0x8d66,0x8dbe,0x8dba, 0x8edb,0x8edf,0x9019,0x900d,0x901a,0x9017,0x9023,0x901f,0x901d,0x9010, 0x9015,0x901e,0x9020,0x900f,0x9022,0x9016,0x901b,0x9014,0x90e8,0x90ed, 0x90fd,0x9157,0x91ce,0x91f5,0x91e6,0x91e3,0x91e7,0x91ed,0x91e9,0x9589, 0x966a,0x9675,0x9673,0x9678,0x9670,0x9674,0x9676,0x9677,0x966c,0x96c0, 0x96ea,0x96e9,0x7ae0,0x7adf }, { /* ku 3e */ 0x9802,0x9803,0x9b5a,0x9ce5,0x9e75,0x9e7f,0x9ea5,0x9ebb,0x50a2,0x508d, 0x5085,0x5099,0x5091,0x5080,0x5096,0x5098,0x509a,0x6700,0x51f1,0x5272, 0x5274,0x5275,0x5269,0x52de,0x52dd,0x52db,0x535a,0x53a5,0x557b,0x5580, 0x55a7,0x557c,0x558a,0x559d,0x5598,0x5582,0x559c,0x55aa,0x5594,0x5587, 0x558b,0x5583,0x55b3,0x55ae,0x559f,0x553e,0x55b2,0x559a,0x55bb,0x55ac, 0x55b1,0x557e,0x5589,0x55ab,0x5599,0x570d,0x582f,0x582a,0x5834,0x5824, 0x5830,0x5831,0x5821,0x581d,0x5820,0x58f9,0x58fa,0x5960,0x5a77,0x5a9a, 0x5a7f,0x5a92,0x5a9b,0x5aa7,0x5b73,0x5b71,0x5bd2,0x5bcc,0x5bd3,0x5bd0, 0x5c0a,0x5c0b,0x5c31,0x5d4c,0x5d50,0x5d34,0x5d47,0x5dfd,0x5e45,0x5e3d, 0x5e40,0x5e43,0x5e7e,0x5eca }, { /* ku 3f */ 0x5ec1,0x5ec2,0x5ec4,0x5f3c,0x5f6d,0x5fa9,0x5faa,0x5fa8,0x60d1,0x60e1, 0x60b2,0x60b6,0x60e0,0x611c,0x6123,0x60fa,0x6115,0x60f0,0x60fb,0x60f4, 0x6168,0x60f1,0x610e,0x60f6,0x6109,0x6100,0x6112,0x621f,0x6249,0x63a3, 0x638c,0x63cf,0x63c0,0x63e9,0x63c9,0x63c6,0x63cd,0x63d2,0x63e3,0x63d0, 0x63e1,0x63d6,0x63ed,0x63ee,0x6376,0x63f4,0x63ea,0x63db,0x6452,0x63da, 0x63f9,0x655e,0x6566,0x6562,0x6563,0x6591,0x6590,0x65af,0x666e,0x6670, 0x6674,0x6676,0x666f,0x6691,0x667a,0x667e,0x6677,0x66fe,0x66ff,0x671f, 0x671d,0x68fa,0x68d5,0x68e0,0x68d8,0x68d7,0x6905,0x68df,0x68f5,0x68ee, 0x68e7,0x68f9,0x68d2,0x68f2,0x68e3,0x68cb,0x68cd,0x690d,0x6912,0x690e, 0x68c9,0x68da,0x696e,0x68fb }, { /* ku 40 */ 0x6b3e,0x6b3a,0x6b3d,0x6b98,0x6b96,0x6bbc,0x6bef,0x6c2e,0x6c2f,0x6c2c, 0x6e2f,0x6e38,0x6e54,0x6e21,0x6e32,0x6e67,0x6e4a,0x6e20,0x6e25,0x6e23, 0x6e1b,0x6e5b,0x6e58,0x6e24,0x6e56,0x6e6e,0x6e2d,0x6e26,0x6e6f,0x6e34, 0x6e4d,0x6e3a,0x6e2c,0x6e43,0x6e1d,0x6e3e,0x6ecb,0x6e89,0x6e19,0x6e4e, 0x6e63,0x6e44,0x6e72,0x6e69,0x6e5f,0x7119,0x711a,0x7126,0x7130,0x7121, 0x7136,0x716e,0x711c,0x724c,0x7284,0x7280,0x7336,0x7325,0x7334,0x7329, 0x743a,0x742a,0x7433,0x7422,0x7425,0x7435,0x7436,0x7434,0x742f,0x741b, 0x7426,0x7428,0x7525,0x7526,0x756b,0x756a,0x75e2,0x75db,0x75e3,0x75d9, 0x75d8,0x75de,0x75e0,0x767b,0x767c,0x7696,0x7693,0x76b4,0x76dc,0x774f, 0x77ed,0x785d,0x786c,0x786f }, { /* ku 41 */ 0x7a0d,0x7a08,0x7a0b,0x7a05,0x7a00,0x7a98,0x7a97,0x7a96,0x7ae5,0x7ae3, 0x7b49,0x7b56,0x7b46,0x7b50,0x7b52,0x7b54,0x7b4d,0x7b4b,0x7b4f,0x7b51, 0x7c9f,0x7ca5,0x7d5e,0x7d50,0x7d68,0x7d55,0x7d2b,0x7d6e,0x7d72,0x7d61, 0x7d66,0x7d62,0x7d70,0x7d73,0x5584,0x7fd4,0x7fd5,0x800b,0x8052,0x8085, 0x8155,0x8154,0x814b,0x8151,0x814e,0x8139,0x8146,0x813e,0x814c,0x8153, 0x8174,0x8212,0x821c,0x83e9,0x8403,0x83f8,0x840d,0x83e0,0x83c5,0x840b, 0x83c1,0x83ef,0x83f1,0x83f4,0x8457,0x840a,0x83f0,0x840c,0x83cc,0x83fd, 0x83f2,0x83ca,0x8438,0x840e,0x8404,0x83dc,0x8407,0x83d4,0x83df,0x865b, 0x86df,0x86d9,0x86ed,0x86d4,0x86db,0x86e4,0x86d0,0x86de,0x8857,0x88c1, 0x88c2,0x88b1,0x8983,0x8996 }, { /* ku 42 */ 0x8a3b,0x8a60,0x8a55,0x8a5e,0x8a3c,0x8a41,0x8a54,0x8a5b,0x8a50,0x8a46, 0x8a34,0x8a3a,0x8a36,0x8a56,0x8c61,0x8c82,0x8caf,0x8cbc,0x8cb3,0x8cbd, 0x8cc1,0x8cbb,0x8cc0,0x8cb4,0x8cb7,0x8cb6,0x8cbf,0x8cb8,0x8d8a,0x8d85, 0x8d81,0x8dce,0x8ddd,0x8dcb,0x8dda,0x8dd1,0x8dcc,0x8ddb,0x8dc6,0x8efb, 0x8ef8,0x8efc,0x8f9c,0x902e,0x9035,0x9031,0x9038,0x9032,0x9036,0x9102, 0x90f5,0x9109,0x90fe,0x9163,0x9165,0x91cf,0x9214,0x9215,0x9223,0x9209, 0x921e,0x920d,0x9210,0x9207,0x9211,0x9594,0x958f,0x958b,0x9591,0x9593, 0x9592,0x958e,0x968a,0x968e,0x968b,0x967d,0x9685,0x9686,0x968d,0x9672, 0x9684,0x96c1,0x96c5,0x96c4,0x96c6,0x96c7,0x96ef,0x96f2,0x97cc,0x9805, 0x9806,0x9808,0x98e7,0x98ea }, { /* ku 43 */ 0x98ef,0x98e9,0x98f2,0x98ed,0x99ae,0x99ad,0x9ec3,0x9ecd,0x9ed1,0x4e82, 0x50ad,0x50b5,0x50b2,0x50b3,0x50c5,0x50be,0x50ac,0x50b7,0x50bb,0x50af, 0x50c7,0x527f,0x5277,0x527d,0x52df,0x52e6,0x52e4,0x52e2,0x52e3,0x532f, 0x55df,0x55e8,0x55d3,0x55e6,0x55ce,0x55dc,0x55c7,0x55d1,0x55e3,0x55e4, 0x55ef,0x55da,0x55e1,0x55c5,0x55c6,0x55e5,0x55c9,0x5712,0x5713,0x585e, 0x5851,0x5858,0x5857,0x585a,0x5854,0x586b,0x584c,0x586d,0x584a,0x5862, 0x5852,0x584b,0x5967,0x5ac1,0x5ac9,0x5acc,0x5abe,0x5abd,0x5abc,0x5ab3, 0x5ac2,0x5ab2,0x5d69,0x5d6f,0x5e4c,0x5e79,0x5ec9,0x5ec8,0x5f12,0x5f59, 0x5fac,0x5fae,0x611a,0x610f,0x6148,0x611f,0x60f3,0x611b,0x60f9,0x6101, 0x6108,0x614e,0x614c,0x6144 }, { /* ku 44 */ 0x614d,0x613e,0x6134,0x6127,0x610d,0x6106,0x6137,0x6221,0x6222,0x6413, 0x643e,0x641e,0x642a,0x642d,0x643d,0x642c,0x640f,0x641c,0x6414,0x640d, 0x6436,0x6416,0x6417,0x6406,0x656c,0x659f,0x65b0,0x6697,0x6689,0x6687, 0x6688,0x6696,0x6684,0x6698,0x668d,0x6703,0x6994,0x696d,0x695a,0x6977, 0x6960,0x6954,0x6975,0x6930,0x6982,0x694a,0x6968,0x696b,0x695e,0x6953, 0x6979,0x6986,0x695d,0x6963,0x695b,0x6b47,0x6b72,0x6bc0,0x6bbf,0x6bd3, 0x6bfd,0x6ea2,0x6eaf,0x6ed3,0x6eb6,0x6ec2,0x6e90,0x6e9d,0x6ec7,0x6ec5, 0x6ea5,0x6e98,0x6ebc,0x6eba,0x6eab,0x6ed1,0x6e96,0x6e9c,0x6ec4,0x6ed4, 0x6eaa,0x6ea7,0x6eb4,0x714e,0x7159,0x7169,0x7164,0x7149,0x7167,0x715c, 0x716c,0x7166,0x714c,0x7165 }, { /* ku 45 */ 0x715e,0x7146,0x7168,0x7156,0x723a,0x7252,0x7337,0x7345,0x733f,0x733e, 0x746f,0x745a,0x7455,0x745f,0x745e,0x7441,0x743f,0x7459,0x745b,0x745c, 0x7576,0x7578,0x7600,0x75f0,0x7601,0x75f2,0x75f1,0x75fa,0x75ff,0x75f4, 0x75f3,0x76de,0x76df,0x775b,0x776b,0x7766,0x775e,0x7763,0x7779,0x776a, 0x776c,0x775c,0x7765,0x7768,0x7762,0x77ee,0x788e,0x78b0,0x7897,0x7898, 0x788c,0x7889,0x787c,0x7891,0x7893,0x787f,0x797a,0x797f,0x7981,0x842c, 0x79bd,0x7a1c,0x7a1a,0x7a20,0x7a14,0x7a1f,0x7a1e,0x7a9f,0x7aa0,0x7b77, 0x7bc0,0x7b60,0x7b6e,0x7b67,0x7cb1,0x7cb3,0x7cb5,0x7d93,0x7d79,0x7d91, 0x7d81,0x7d8f,0x7d5b,0x7f6e,0x7f69,0x7f6a,0x7f72,0x7fa9,0x7fa8,0x7fa4, 0x8056,0x8058,0x8086,0x8084 }, { /* ku 46 */ 0x8171,0x8170,0x8178,0x8165,0x816e,0x8173,0x816b,0x8179,0x817a,0x8166, 0x8205,0x8247,0x8482,0x8477,0x843d,0x8431,0x8475,0x8466,0x846b,0x8449, 0x846c,0x845b,0x843c,0x8435,0x8461,0x8463,0x8469,0x846d,0x8446,0x865e, 0x865c,0x865f,0x86f9,0x8713,0x8708,0x8707,0x8700,0x86fe,0x86fb,0x8702, 0x8703,0x8706,0x870a,0x8859,0x88df,0x88d4,0x88d9,0x88dc,0x88d8,0x88dd, 0x88e1,0x88ca,0x88d5,0x88d2,0x899c,0x89e3,0x8a6b,0x8a72,0x8a73,0x8a66, 0x8a69,0x8a70,0x8a87,0x8a7c,0x8a63,0x8aa0,0x8a71,0x8a85,0x8a6d,0x8a62, 0x8a6e,0x8a6c,0x8a79,0x8a7b,0x8a3e,0x8a68,0x8c62,0x8c8a,0x8c89,0x8cca, 0x8cc7,0x8cc8,0x8cc4,0x8cb2,0x8cc3,0x8cc2,0x8cc5,0x8de1,0x8ddf,0x8de8, 0x8def,0x8df3,0x8dfa,0x8dea }, { /* ku 47 */ 0x8de4,0x8de6,0x8eb2,0x8f03,0x8f09,0x8efe,0x8f0a,0x8f9f,0x8fb2,0x904b, 0x904a,0x9053,0x9042,0x9054,0x903c,0x9055,0x9050,0x9047,0x904f,0x904e, 0x904d,0x9051,0x903e,0x9041,0x9112,0x9117,0x916c,0x916a,0x9169,0x91c9, 0x9237,0x9257,0x9238,0x923d,0x9240,0x923e,0x925b,0x924b,0x9264,0x9251, 0x9234,0x9249,0x924d,0x9245,0x9239,0x923f,0x925a,0x9598,0x9698,0x9694, 0x9695,0x96cd,0x96cb,0x96c9,0x96ca,0x96f7,0x96fb,0x96f9,0x96f6,0x9756, 0x9774,0x9776,0x9810,0x9811,0x9813,0x980a,0x9812,0x980c,0x98fc,0x98f4, 0x98fd,0x98fe,0x99b3,0x99b1,0x99b4,0x9ae1,0x9ce9,0x9e82,0x9f0e,0x9f13, 0x9f20,0x50e7,0x50ee,0x50e5,0x50d6,0x50ed,0x50da,0x50d5,0x50cf,0x50d1, 0x50f1,0x50ce,0x50e9,0x5162 }, { /* ku 48 */ 0x51f3,0x5283,0x5282,0x5331,0x53ad,0x55fe,0x5600,0x561b,0x5617,0x55fd, 0x5614,0x5606,0x5609,0x560d,0x560e,0x55f7,0x5616,0x561f,0x5608,0x5610, 0x55f6,0x5718,0x5716,0x5875,0x587e,0x5883,0x5893,0x588a,0x5879,0x5885, 0x587d,0x58fd,0x5925,0x5922,0x5924,0x596a,0x5969,0x5ae1,0x5ae6,0x5ae9, 0x5ad7,0x5ad6,0x5ad8,0x5ae3,0x5b75,0x5bde,0x5be7,0x5be1,0x5be5,0x5be6, 0x5be8,0x5be2,0x5be4,0x5bdf,0x5c0d,0x5c62,0x5d84,0x5d87,0x5e5b,0x5e63, 0x5e55,0x5e57,0x5e54,0x5ed3,0x5ed6,0x5f0a,0x5f46,0x5f70,0x5fb9,0x6147, 0x613f,0x614b,0x6177,0x6162,0x6163,0x615f,0x615a,0x6158,0x6175,0x622a, 0x6487,0x6458,0x6454,0x64a4,0x6478,0x645f,0x647a,0x6451,0x6467,0x6434, 0x646d,0x647b,0x6572,0x65a1 }, { /* ku 49 */ 0x65d7,0x65d6,0x66a2,0x66a8,0x669d,0x699c,0x69a8,0x6995,0x69c1,0x69ae, 0x69d3,0x69cb,0x699b,0x69b7,0x69bb,0x69ab,0x69b4,0x69d0,0x69cd,0x69ad, 0x69cc,0x69a6,0x69c3,0x69a3,0x6b49,0x6b4c,0x6c33,0x6f33,0x6f14,0x6efe, 0x6f13,0x6ef4,0x6f29,0x6f3e,0x6f20,0x6f2c,0x6f0f,0x6f02,0x6f22,0x6eff, 0x6eef,0x6f06,0x6f31,0x6f38,0x6f32,0x6f23,0x6f15,0x6f2b,0x6f2f,0x6f88, 0x6f2a,0x6eec,0x6f01,0x6ef2,0x6ecc,0x6ef7,0x7194,0x7199,0x717d,0x718a, 0x7184,0x7192,0x723e,0x7292,0x7296,0x7344,0x7350,0x7464,0x7463,0x746a, 0x7470,0x746d,0x7504,0x7591,0x7627,0x760d,0x760b,0x7609,0x7613,0x76e1, 0x76e3,0x7784,0x777d,0x777f,0x7761,0x78c1,0x789f,0x78a7,0x78b3,0x78a9, 0x78a3,0x798e,0x798f,0x798d }, { /* ku 4a */ 0x7a2e,0x7a31,0x7aaa,0x7aa9,0x7aed,0x7aef,0x7ba1,0x7b95,0x7b8b,0x7b75, 0x7b97,0x7b9d,0x7b94,0x7b8f,0x7bb8,0x7b87,0x7b84,0x7cb9,0x7cbd,0x7cbe, 0x7dbb,0x7db0,0x7d9c,0x7dbd,0x7dbe,0x7da0,0x7dca,0x7db4,0x7db2,0x7db1, 0x7dba,0x7da2,0x7dbf,0x7db5,0x7db8,0x7dad,0x7dd2,0x7dc7,0x7dac,0x7f70, 0x7fe0,0x7fe1,0x7fdf,0x805e,0x805a,0x8087,0x8150,0x8180,0x818f,0x8188, 0x818a,0x817f,0x8182,0x81e7,0x81fa,0x8207,0x8214,0x821e,0x824b,0x84c9, 0x84bf,0x84c6,0x84c4,0x8499,0x849e,0x84b2,0x849c,0x84cb,0x84b8,0x84c0, 0x84d3,0x8490,0x84bc,0x84d1,0x84ca,0x873f,0x871c,0x873b,0x8722,0x8725, 0x8734,0x8718,0x8755,0x8737,0x8729,0x88f3,0x8902,0x88f4,0x88f9,0x88f8, 0x88fd,0x88e8,0x891a,0x88ef }, { /* ku 4b */ 0x8aa6,0x8a8c,0x8a9e,0x8aa3,0x8a8d,0x8aa1,0x8a93,0x8aa4,0x8aaa,0x8aa5, 0x8aa8,0x8a98,0x8a91,0x8a9a,0x8aa7,0x8c6a,0x8c8d,0x8c8c,0x8cd3,0x8cd1, 0x8cd2,0x8d6b,0x8d99,0x8d95,0x8dfc,0x8f14,0x8f12,0x8f15,0x8f13,0x8fa3, 0x9060,0x9058,0x905c,0x9063,0x9059,0x905e,0x9062,0x905d,0x905b,0x9119, 0x9118,0x911e,0x9175,0x9178,0x9177,0x9174,0x9278,0x92ac,0x9280,0x9285, 0x9298,0x9296,0x927b,0x9293,0x929c,0x92a8,0x927c,0x9291,0x95a1,0x95a8, 0x95a9,0x95a3,0x95a5,0x95a4,0x9699,0x969c,0x969b,0x96cc,0x96d2,0x9700, 0x977c,0x9785,0x97f6,0x9817,0x9818,0x98af,0x98b1,0x9903,0x9905,0x990c, 0x9909,0x99c1,0x9aaf,0x9ab0,0x9ae6,0x9b41,0x9b42,0x9cf4,0x9cf6,0x9cf3, 0x9ebc,0x9f3b,0x9f4a,0x5104 }, { /* ku 4c */ 0x5100,0x50fb,0x50f5,0x50f9,0x5102,0x5108,0x5109,0x5105,0x51dc,0x5287, 0x5288,0x5289,0x528d,0x528a,0x52f0,0x53b2,0x562e,0x563b,0x5639,0x5632, 0x563f,0x5634,0x5629,0x5653,0x564e,0x5657,0x5674,0x5636,0x562f,0x5630, 0x5880,0x589f,0x589e,0x58b3,0x589c,0x58ae,0x58a9,0x58a6,0x596d,0x5b09, 0x5afb,0x5b0b,0x5af5,0x5b0c,0x5b08,0x5bee,0x5bec,0x5be9,0x5beb,0x5c64, 0x5c65,0x5d9d,0x5d94,0x5e62,0x5e5f,0x5e61,0x5ee2,0x5eda,0x5edf,0x5edd, 0x5ee3,0x5ee0,0x5f48,0x5f71,0x5fb7,0x5fb5,0x6176,0x6167,0x616e,0x615d, 0x6155,0x6182,0x617c,0x6170,0x616b,0x617e,0x61a7,0x6190,0x61ab,0x618e, 0x61ac,0x619a,0x61a4,0x6194,0x61ae,0x622e,0x6469,0x646f,0x6479,0x649e, 0x64b2,0x6488,0x6490,0x64b0 }, { /* ku 4d */ 0x64a5,0x6493,0x6495,0x64a9,0x6492,0x64ae,0x64ad,0x64ab,0x649a,0x64ac, 0x6499,0x64a2,0x64b3,0x6575,0x6577,0x6578,0x66ae,0x66ab,0x66b4,0x66b1, 0x6a23,0x6a1f,0x69e8,0x6a01,0x6a1e,0x6a19,0x69fd,0x6a21,0x6a13,0x6a0a, 0x69f3,0x6a02,0x6a05,0x69ed,0x6a11,0x6b50,0x6b4e,0x6ba4,0x6bc5,0x6bc6, 0x6f3f,0x6f7c,0x6f84,0x6f51,0x6f66,0x6f54,0x6f86,0x6f6d,0x6f5b,0x6f78, 0x6f6e,0x6f8e,0x6f7a,0x6f70,0x6f64,0x6f97,0x6f58,0x6ed5,0x6f6f,0x6f60, 0x6f5f,0x719f,0x71ac,0x71b1,0x71a8,0x7256,0x729b,0x734e,0x7357,0x7469, 0x748b,0x7483,0x747e,0x7480,0x757f,0x7620,0x7629,0x761f,0x7624,0x7626, 0x7621,0x7622,0x769a,0x76ba,0x76e4,0x778e,0x7787,0x778c,0x7791,0x778b, 0x78cb,0x78c5,0x78ba,0x78ca }, { /* ku 4e */ 0x78be,0x78d5,0x78bc,0x78d0,0x7a3f,0x7a3c,0x7a40,0x7a3d,0x7a37,0x7a3b, 0x7aaf,0x7aae,0x7bad,0x7bb1,0x7bc4,0x7bb4,0x7bc6,0x7bc7,0x7bc1,0x7ba0, 0x7bcc,0x7cca,0x7de0,0x7df4,0x7def,0x7dfb,0x7dd8,0x7dec,0x7ddd,0x7de8, 0x7de3,0x7dda,0x7dde,0x7de9,0x7d9e,0x7dd9,0x7df2,0x7df9,0x7f75,0x7f77, 0x7faf,0x7fe9,0x8026,0x819b,0x819c,0x819d,0x81a0,0x819a,0x8198,0x8517, 0x853d,0x851a,0x84ee,0x852c,0x852d,0x8513,0x8511,0x8523,0x8521,0x8514, 0x84ec,0x8525,0x84ff,0x8506,0x8782,0x8774,0x8776,0x8760,0x8766,0x8778, 0x8768,0x8759,0x8757,0x874c,0x8753,0x885b,0x885d,0x8910,0x8907,0x8912, 0x8913,0x8915,0x890a,0x8abc,0x8ad2,0x8ac7,0x8ac4,0x8a95,0x8acb,0x8af8, 0x8ab2,0x8ac9,0x8ac2,0x8abf }, { /* ku 4f */ 0x8ab0,0x8ad6,0x8acd,0x8ab6,0x8ab9,0x8adb,0x8c4c,0x8c4e,0x8c6c,0x8ce0, 0x8cde,0x8ce6,0x8ce4,0x8cec,0x8ced,0x8ce2,0x8ce3,0x8cdc,0x8cea,0x8ce1, 0x8d6d,0x8d9f,0x8da3,0x8e2b,0x8e10,0x8e1d,0x8e22,0x8e0f,0x8e29,0x8e1f, 0x8e21,0x8e1e,0x8eba,0x8f1d,0x8f1b,0x8f1f,0x8f29,0x8f26,0x8f2a,0x8f1c, 0x8f1e,0x8f25,0x9069,0x906e,0x9068,0x906d,0x9077,0x9130,0x912d,0x9127, 0x9131,0x9187,0x9189,0x918b,0x9183,0x92c5,0x92bb,0x92b7,0x92ea,0x92e4, 0x92c1,0x92b3,0x92bc,0x92d2,0x92c7,0x92f0,0x92b2,0x95ad,0x95b1,0x9704, 0x9706,0x9707,0x9709,0x9760,0x978d,0x978b,0x978f,0x9821,0x982b,0x981c, 0x98b3,0x990a,0x9913,0x9912,0x9918,0x99dd,0x99d0,0x99df,0x99db,0x99d1, 0x99d5,0x99d2,0x99d9,0x9ab7 }, { /* ku 50 */ 0x9aee,0x9aef,0x9b27,0x9b45,0x9b44,0x9b77,0x9b6f,0x9d06,0x9d09,0x9d03, 0x9ea9,0x9ebe,0x9ece,0x58a8,0x9f52,0x5112,0x5118,0x5114,0x5110,0x5115, 0x5180,0x51aa,0x51dd,0x5291,0x5293,0x52f3,0x5659,0x566b,0x5679,0x5669, 0x5664,0x5678,0x566a,0x5668,0x5665,0x5671,0x566f,0x566c,0x5662,0x5676, 0x58c1,0x58be,0x58c7,0x58c5,0x596e,0x5b1d,0x5b34,0x5b78,0x5bf0,0x5c0e, 0x5f4a,0x61b2,0x6191,0x61a9,0x618a,0x61cd,0x61b6,0x61be,0x61ca,0x61c8, 0x6230,0x64c5,0x64c1,0x64cb,0x64bb,0x64bc,0x64da,0x64c4,0x64c7,0x64c2, 0x64cd,0x64bf,0x64d2,0x64d4,0x64be,0x6574,0x66c6,0x66c9,0x66b9,0x66c4, 0x66c7,0x66b8,0x6a3d,0x6a38,0x6a3a,0x6a59,0x6a6b,0x6a58,0x6a39,0x6a44, 0x6a62,0x6a61,0x6a4b,0x6a47 }, { /* ku 51 */ 0x6a35,0x6a5f,0x6a48,0x6b59,0x6b77,0x6c05,0x6fc2,0x6fb1,0x6fa1,0x6fc3, 0x6fa4,0x6fc1,0x6fa7,0x6fb3,0x6fc0,0x6fb9,0x6fb6,0x6fa6,0x6fa0,0x6fb4, 0x71be,0x71c9,0x71d0,0x71d2,0x71c8,0x71d5,0x71b9,0x71ce,0x71d9,0x71dc, 0x71c3,0x71c4,0x7368,0x749c,0x74a3,0x7498,0x749f,0x749e,0x74e2,0x750c, 0x750d,0x7634,0x7638,0x763a,0x76e7,0x76e5,0x77a0,0x779e,0x779f,0x77a5, 0x78e8,0x78da,0x78ec,0x78e7,0x79a6,0x7a4d,0x7a4e,0x7a46,0x7a4c,0x7a4b, 0x7aba,0x7bd9,0x7c11,0x7bc9,0x7be4,0x7bdb,0x7be1,0x7be9,0x7be6,0x7cd5, 0x7cd6,0x7e0a,0x7e11,0x7e08,0x7e1b,0x7e23,0x7e1e,0x7e1d,0x7e09,0x7e10, 0x7f79,0x7fb2,0x7ff0,0x7ff1,0x7fee,0x8028,0x81b3,0x81a9,0x81a8,0x81fb, 0x8208,0x8258,0x8259,0x854a }, { /* ku 52 */ 0x8559,0x8548,0x8568,0x8569,0x8543,0x8549,0x856d,0x856a,0x855e,0x8783, 0x879f,0x879e,0x87a2,0x878d,0x8861,0x892a,0x8932,0x8925,0x892b,0x8921, 0x89aa,0x89a6,0x8ae6,0x8afa,0x8aeb,0x8af1,0x8b00,0x8adc,0x8ae7,0x8aee, 0x8afe,0x8b01,0x8b02,0x8af7,0x8aed,0x8af3,0x8af6,0x8afc,0x8c6b,0x8c6d, 0x8c93,0x8cf4,0x8e44,0x8e31,0x8e34,0x8e42,0x8e39,0x8e35,0x8f3b,0x8f2f, 0x8f38,0x8f33,0x8fa8,0x8fa6,0x9075,0x9074,0x9078,0x9072,0x907c,0x907a, 0x9134,0x9192,0x9320,0x9336,0x92f8,0x9333,0x932f,0x9322,0x92fc,0x932b, 0x9304,0x931a,0x9310,0x9326,0x9321,0x9315,0x932e,0x9319,0x95bb,0x96a7, 0x96a8,0x96aa,0x96d5,0x970e,0x9711,0x9716,0x970d,0x9713,0x970f,0x975b, 0x975c,0x9766,0x9798,0x9830 }, { /* ku 53 */ 0x9838,0x983b,0x9837,0x982d,0x9839,0x9824,0x9910,0x9928,0x991e,0x991b, 0x9921,0x991a,0x99ed,0x99e2,0x99f1,0x9ab8,0x9abc,0x9afb,0x9aed,0x9b28, 0x9b91,0x9d15,0x9d23,0x9d26,0x9d28,0x9d12,0x9d1b,0x9ed8,0x9ed4,0x9f8d, 0x9f9c,0x512a,0x511f,0x5121,0x5132,0x52f5,0x568e,0x5680,0x5690,0x5685, 0x5687,0x568f,0x58d5,0x58d3,0x58d1,0x58ce,0x5b30,0x5b2a,0x5b24,0x5b7a, 0x5c37,0x5c68,0x5dbc,0x5dba,0x5dbd,0x5db8,0x5e6b,0x5f4c,0x5fbd,0x61c9, 0x61c2,0x61c7,0x61e6,0x61cb,0x6232,0x6234,0x64ce,0x64ca,0x64d8,0x64e0, 0x64f0,0x64e6,0x64ec,0x64f1,0x64e2,0x64ed,0x6582,0x6583,0x66d9,0x66d6, 0x6a80,0x6a94,0x6a84,0x6aa2,0x6a9c,0x6adb,0x6aa3,0x6a7e,0x6a97,0x6a90, 0x6aa0,0x6b5c,0x6bae,0x6bda }, { /* ku 54 */ 0x6c08,0x6fd8,0x6ff1,0x6fdf,0x6fe0,0x6fdb,0x6fe4,0x6feb,0x6fef,0x6f80, 0x6fec,0x6fe1,0x6fe9,0x6fd5,0x6fee,0x6ff0,0x71e7,0x71df,0x71ee,0x71e6, 0x71e5,0x71ed,0x71ec,0x71f4,0x71e0,0x7235,0x7246,0x7370,0x7372,0x74a9, 0x74b0,0x74a6,0x74a8,0x7646,0x7642,0x764c,0x76ea,0x77b3,0x77aa,0x77b0, 0x77ac,0x77a7,0x77ad,0x77ef,0x78f7,0x78fa,0x78f4,0x78ef,0x7901,0x79a7, 0x79aa,0x7a57,0x7abf,0x7c07,0x7c0d,0x7bfe,0x7bf7,0x7c0c,0x7be0,0x7ce0, 0x7cdc,0x7cde,0x7ce2,0x7cdf,0x7cd9,0x7cdd,0x7e2e,0x7e3e,0x7e46,0x7e37, 0x7e32,0x7e43,0x7e2b,0x7e3d,0x7e31,0x7e45,0x7e41,0x7e34,0x7e39,0x7e48, 0x7e35,0x7e3f,0x7e2f,0x7f44,0x7ff3,0x7ffc,0x8071,0x8072,0x8070,0x806f, 0x8073,0x81c6,0x81c3,0x81ba }, { /* ku 55 */ 0x81c2,0x81c0,0x81bf,0x81bd,0x81c9,0x81be,0x81e8,0x8209,0x8271,0x85aa, 0x8584,0x857e,0x859c,0x8591,0x8594,0x85af,0x859b,0x8587,0x85a8,0x858a, 0x85a6,0x8667,0x87c0,0x87d1,0x87b3,0x87d2,0x87c6,0x87ab,0x87bb,0x87ba, 0x87c8,0x87cb,0x893b,0x8936,0x8944,0x8938,0x893d,0x89ac,0x8b0e,0x8b17, 0x8b19,0x8b1b,0x8b0a,0x8b20,0x8b1d,0x8b04,0x8b10,0x8c41,0x8c3f,0x8c73, 0x8cfa,0x8cfd,0x8cfc,0x8cf8,0x8cfb,0x8da8,0x8e49,0x8e4b,0x8e48,0x8e4a, 0x8f44,0x8f3e,0x8f42,0x8f45,0x8f3f,0x907f,0x907d,0x9084,0x9081,0x9082, 0x9080,0x9139,0x91a3,0x919e,0x919c,0x934d,0x9382,0x9328,0x9375,0x934a, 0x9365,0x934b,0x9318,0x937e,0x936c,0x935b,0x9370,0x935a,0x9354,0x95ca, 0x95cb,0x95cc,0x95c8,0x95c6 }, { /* ku 56 */ 0x96b1,0x96b8,0x96d6,0x971c,0x971e,0x97a0,0x97d3,0x9846,0x98b6,0x9935, 0x9a01,0x99ff,0x9bae,0x9bab,0x9baa,0x9bad,0x9d3b,0x9d3f,0x9e8b,0x9ecf, 0x9ede,0x9edc,0x9edd,0x9edb,0x9f3e,0x9f4b,0x53e2,0x5695,0x56ae,0x58d9, 0x58d8,0x5b38,0x5f5e,0x61e3,0x6233,0x64f4,0x64f2,0x64fe,0x6506,0x64fa, 0x64fb,0x64f7,0x65b7,0x66dc,0x6726,0x6ab3,0x6aac,0x6ac3,0x6abb,0x6ab8, 0x6ac2,0x6aae,0x6aaf,0x6b5f,0x6b78,0x6baf,0x7009,0x700b,0x6ffe,0x7006, 0x6ffa,0x7011,0x700f,0x71fb,0x71fc,0x71fe,0x71f8,0x7377,0x7375,0x74a7, 0x74bf,0x7515,0x7656,0x7658,0x7652,0x77bd,0x77bf,0x77bb,0x77bc,0x790e, 0x79ae,0x7a61,0x7a62,0x7a60,0x7ac4,0x7ac5,0x7c2b,0x7c27,0x7c2a,0x7c1e, 0x7c23,0x7c21,0x7ce7,0x7e54 }, { /* ku 57 */ 0x7e55,0x7e5e,0x7e5a,0x7e61,0x7e52,0x7e59,0x7f48,0x7ff9,0x7ffb,0x8077, 0x8076,0x81cd,0x81cf,0x820a,0x85cf,0x85a9,0x85cd,0x85d0,0x85c9,0x85b0, 0x85ba,0x85b9,0x87ef,0x87ec,0x87f2,0x87e0,0x8986,0x89b2,0x89f4,0x8b28, 0x8b39,0x8b2c,0x8b2b,0x8c50,0x8d05,0x8e59,0x8e63,0x8e66,0x8e64,0x8e5f, 0x8e55,0x8ec0,0x8f49,0x8f4d,0x9087,0x9083,0x9088,0x91ab,0x91ac,0x91d0, 0x9394,0x938a,0x9396,0x93a2,0x93b3,0x93ae,0x93ac,0x93b0,0x9398,0x939a, 0x9397,0x95d4,0x95d6,0x95d0,0x95d5,0x96e2,0x96dc,0x96d9,0x96db,0x96de, 0x9724,0x97a3,0x97a6,0x97ad,0x97f9,0x984d,0x984f,0x984c,0x984e,0x9853, 0x98ba,0x993e,0x993f,0x993d,0x992e,0x99a5,0x9a0e,0x9ac1,0x9b03,0x9b06, 0x9b4f,0x9b4e,0x9b4d,0x9bca }, { /* ku 58 */ 0x9bc9,0x9bfd,0x9bc8,0x9bc0,0x9d51,0x9d5d,0x9d60,0x9ee0,0x9f15,0x9f2c, 0x5133,0x56a5,0x56a8,0x58de,0x58df,0x58e2,0x5bf5,0x9f90,0x5eec,0x61f2, 0x61f7,0x61f6,0x61f5,0x6500,0x650f,0x66e0,0x66dd,0x6ae5,0x6add,0x6ada, 0x6ad3,0x701b,0x701f,0x7028,0x701a,0x701d,0x7015,0x7018,0x7206,0x720d, 0x7258,0x72a2,0x7378,0x737a,0x74bd,0x74ca,0x74e3,0x7587,0x7586,0x765f, 0x7661,0x77c7,0x7919,0x79b1,0x7a6b,0x7a69,0x7c3e,0x7c3f,0x7c38,0x7c3d, 0x7c37,0x7c40,0x7e6b,0x7e6d,0x7e79,0x7e69,0x7e6a,0x7e73,0x7f85,0x7fb6, 0x7fb9,0x7fb8,0x81d8,0x85e9,0x85dd,0x85ea,0x85d5,0x85e4,0x85e5,0x85f7, 0x87fb,0x8805,0x880d,0x87f9,0x87fe,0x8960,0x895f,0x8956,0x895e,0x8b41, 0x8b5c,0x8b58,0x8b49,0x8b5a }, { /* ku 59 */ 0x8b4e,0x8b4f,0x8b46,0x8b59,0x8d08,0x8d0a,0x8e7c,0x8e72,0x8e87,0x8e76, 0x8e6c,0x8e7a,0x8e74,0x8f54,0x8f4e,0x8fad,0x908a,0x908b,0x91b1,0x91ae, 0x93e1,0x93d1,0x93df,0x93c3,0x93c8,0x93dc,0x93dd,0x93d6,0x93e2,0x93cd, 0x93d8,0x93e4,0x93d7,0x93e8,0x95dc,0x96b4,0x96e3,0x972a,0x9727,0x9761, 0x97dc,0x97fb,0x985e,0x9858,0x985b,0x98bc,0x9945,0x9949,0x9a16,0x9a19, 0x9b0d,0x9be8,0x9be7,0x9bd6,0x9bdb,0x9d89,0x9d61,0x9d72,0x9d6a,0x9d6c, 0x9e92,0x9e97,0x9e93,0x9eb4,0x52f8,0x56b7,0x56b6,0x56b4,0x56bc,0x58e4, 0x5b40,0x5b43,0x5b7d,0x5bf6,0x5dc9,0x61f8,0x61fa,0x6518,0x6514,0x6519, 0x66e6,0x6727,0x6aec,0x703e,0x7030,0x7032,0x7210,0x737b,0x74cf,0x7662, 0x7665,0x7926,0x792a,0x792c }, { /* ku 5a */ 0x792b,0x7ac7,0x7af6,0x7c4c,0x7c43,0x7c4d,0x7cef,0x7cf0,0x8fae,0x7e7d, 0x7e7c,0x7e82,0x7f4c,0x8000,0x81da,0x8266,0x85fb,0x85f9,0x8611,0x85fa, 0x8606,0x860b,0x8607,0x860a,0x8814,0x8815,0x8964,0x89ba,0x89f8,0x8b70, 0x8b6c,0x8b66,0x8b6f,0x8b5f,0x8b6b,0x8d0f,0x8d0d,0x8e89,0x8e81,0x8e85, 0x8e82,0x91b4,0x91cb,0x9418,0x9403,0x93fd,0x95e1,0x9730,0x98c4,0x9952, 0x9951,0x99a8,0x9a2b,0x9a30,0x9a37,0x9a35,0x9c13,0x9c0d,0x9e79,0x9eb5, 0x9ee8,0x9f2f,0x9f5f,0x9f63,0x9f61,0x5137,0x5138,0x56c1,0x56c0,0x56c2, 0x5914,0x5c6c,0x5dcd,0x61fc,0x61fe,0x651d,0x651c,0x6595,0x66e9,0x6afb, 0x6b04,0x6afa,0x6bb2,0x704c,0x721b,0x72a7,0x74d6,0x74d4,0x7669,0x77d3, 0x7c50,0x7e8f,0x7e8c,0x7fbc }, { /* ku 5b */ 0x8617,0x862d,0x861a,0x8823,0x8822,0x8821,0x881f,0x896a,0x896c,0x89bd, 0x8b74,0x8b77,0x8b7d,0x8d13,0x8e8a,0x8e8d,0x8e8b,0x8f5f,0x8faf,0x91ba, 0x942e,0x9433,0x9435,0x943a,0x9438,0x9432,0x942b,0x95e2,0x9738,0x9739, 0x9732,0x97ff,0x9867,0x9865,0x9957,0x9a45,0x9a43,0x9a40,0x9a3e,0x9acf, 0x9b54,0x9b51,0x9c2d,0x9c25,0x9daf,0x9db4,0x9dc2,0x9db8,0x9e9d,0x9eef, 0x9f19,0x9f5c,0x9f66,0x9f67,0x513c,0x513b,0x56c8,0x56ca,0x56c9,0x5b7f, 0x5dd4,0x5dd2,0x5f4e,0x61ff,0x6524,0x6b0a,0x6b61,0x7051,0x7058,0x7380, 0x74e4,0x758a,0x766e,0x766c,0x79b3,0x7c60,0x7c5f,0x807e,0x807d,0x81df, 0x8972,0x896f,0x89fc,0x8b80,0x8d16,0x8d17,0x8e91,0x8e93,0x8f61,0x9148, 0x9444,0x9451,0x9452,0x973d }, { /* ku 5c */ 0x973e,0x97c3,0x97c1,0x986b,0x9955,0x9a55,0x9a4d,0x9ad2,0x9b1a,0x9c49, 0x9c31,0x9c3e,0x9c3b,0x9dd3,0x9dd7,0x9f34,0x9f6c,0x9f6a,0x9f94,0x56cc, 0x5dd6,0x6200,0x6523,0x652b,0x652a,0x66ec,0x6b10,0x74da,0x7aca,0x7c64, 0x7c63,0x7c65,0x7e93,0x7e96,0x7e94,0x81e2,0x8638,0x863f,0x8831,0x8b8a, 0x9090,0x908f,0x9463,0x9460,0x9464,0x9768,0x986f,0x995c,0x9a5a,0x9a5b, 0x9a57,0x9ad3,0x9ad4,0x9ad1,0x9c54,0x9c57,0x9c56,0x9de5,0x9e9f,0x9ef4, 0x56d1,0x58e9,0x652c,0x705e,0x7671,0x7672,0x77d7,0x7f50,0x7f88,0x8836, 0x8839,0x8862,0x8b93,0x8b92,0x8b96,0x8277,0x8d1b,0x91c0,0x946a,0x9742, 0x9748,0x9744,0x97c6,0x9870,0x9a5f,0x9b22,0x9b58,0x9c5f,0x9df9,0x9dfa, 0x9e7c,0x9e7d,0x9f07,0x9f77 }, { /* ku 5d */ 0x9f72,0x5ef3,0x6b16,0x7063,0x7c6c,0x7c6e,0x883b,0x89c0,0x8ea1,0x91c1, 0x9472,0x9470,0x9871,0x995e,0x9ad6,0x9b23,0x9ecc,0x7064,0x77da,0x8b9a, 0x9477,0x97c9,0x9a62,0x9a65,0x7e9c,0x8b9c,0x8eaa,0x91c5,0x947d,0x947e, 0x947c,0x9c77,0x9c78,0x9ef7,0x8c54,0x947f,0x9e1a,0x7228,0x9a6a,0x9b31, 0x9e1b,0x9e1e,0x7c72,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON, UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON, UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON, UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON, UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON, UBOGON,UBOGON,UBOGON,UBOGON } }; /* CNS 11643 plane 2 conversion table */ static const unsigned short cns11643_2tab[MAX_CNS11643_KU_2][MAX_CNS11643_TEN] = { { /* ku 01 */ 0x4e42,0x4e5c,0x51f5,0x531a,0x5382,0x4e07,0x4e0c,0x4e47,0x4e8d,0x56d7, 0x5c6e,0x5f73,0x4e0f,0x5187,0x4e0e,0x4e2e,0x4e93,0x4ec2,0x4ec9,0x4ec8, 0x5198,0x52fc,0x536c,0x53b9,0x5720,0x5903,0x592c,0x5c10,0x5dff,0x65e1, 0x6bb3,0x6bcc,0x6c14,0x723f,0x4e31,0x4e3c,0x4ee8,0x4edc,0x4ee9,0x4ee1, 0x4edd,0x4eda,0x520c,0x5209,0x531c,0x534c,0x5722,0x5723,0x5917,0x592f, 0x5b81,0x5b84,0x5c12,0x5c3b,0x5c74,0x5c73,0x5e04,0x5e80,0x5e82,0x5fc9, 0x6209,0x6250,0x6c15,0x6c36,0x6c43,0x6c3f,0x6c3b,0x72ae,0x72b0,0x738a, 0x79b8,0x808a,0x961e,0x4f0e,0x4f18,0x4f2c,0x4ef5,0x4f14,0x4ef1,0x4f00, 0x4ef7,0x4f08,0x4f1d,0x4f02,0x4f05,0x4f22,0x4f13,0x4f04,0x4ef4,0x4f12, 0x51b1,0x5213,0x5210,0x52a6 }, { /* ku 02 */ 0x5322,0x531f,0x534d,0x538a,0x5407,0x56e1,0x56df,0x572e,0x572a,0x5734, 0x593c,0x5980,0x597c,0x5985,0x597b,0x597e,0x5977,0x597f,0x5b56,0x5c15, 0x5c25,0x5c7c,0x5c7a,0x5c7b,0x5c7e,0x5ddf,0x5e75,0x5e84,0x5f02,0x5f1a, 0x5f74,0x5fd5,0x5fd4,0x5fcf,0x625c,0x625e,0x6264,0x6261,0x6266,0x6262, 0x6259,0x6260,0x625a,0x6265,0x6537,0x65ef,0x65ee,0x673e,0x6739,0x6738, 0x673b,0x673a,0x673f,0x673c,0x6733,0x6c18,0x6c46,0x6c52,0x6c5c,0x6c4f, 0x6c4a,0x6c54,0x6c4b,0x6c4c,0x7071,0x725e,0x72b4,0x72b5,0x738e,0x752a, 0x767f,0x7a75,0x7f51,0x8278,0x827c,0x8280,0x827d,0x827f,0x864d,0x897e, 0x9099,0x9097,0x9098,0x909b,0x9094,0x9622,0x9624,0x9620,0x9623,0x4f56, 0x4f3b,0x4f62,0x4f49,0x4f53 }, { /* ku 03 */ 0x4f64,0x4f3e,0x4f67,0x4f52,0x4f5f,0x4f41,0x4f58,0x4f2d,0x4f33,0x4f3f, 0x4f61,0x518f,0x51b9,0x521c,0x521e,0x5221,0x52ad,0x52ae,0x5309,0x5363, 0x5372,0x538e,0x538f,0x5430,0x5437,0x542a,0x5454,0x5445,0x5419,0x541c, 0x5425,0x5418,0x543d,0x544f,0x5441,0x5428,0x5424,0x5447,0x56ee,0x56e7, 0x56e5,0x5741,0x5745,0x574c,0x5749,0x574b,0x5752,0x5906,0x5940,0x59a6, 0x5998,0x59a0,0x5997,0x598e,0x59a2,0x5990,0x598f,0x59a7,0x59a1,0x5b8e, 0x5b92,0x5c28,0x5c2a,0x5c8d,0x5c8f,0x5c88,0x5c8b,0x5c89,0x5c92,0x5c8a, 0x5c86,0x5c93,0x5c95,0x5de0,0x5e0a,0x5e0e,0x5e8b,0x5e89,0x5e8c,0x5e88, 0x5e8d,0x5f05,0x5f1d,0x5f78,0x5f76,0x5fd2,0x5fd1,0x5fd0,0x5fed,0x5fe8, 0x5fee,0x5ff3,0x5fe1,0x5fe4 }, { /* ku 04 */ 0x5fe3,0x5ffa,0x5fef,0x5ff7,0x5ffb,0x6000,0x5ff4,0x623a,0x6283,0x628c, 0x628e,0x628f,0x6294,0x6287,0x6271,0x627b,0x627a,0x6270,0x6281,0x6288, 0x6277,0x627d,0x6272,0x6274,0x65f0,0x65f4,0x65f3,0x65f2,0x65f5,0x6745, 0x6747,0x6759,0x6755,0x674c,0x6748,0x675d,0x674d,0x675a,0x674b,0x6bd0, 0x6c19,0x6c1a,0x6c78,0x6c67,0x6c6b,0x6c84,0x6c8b,0x6c8f,0x6c71,0x6c6f, 0x6c69,0x6c9a,0x6c6d,0x6c87,0x6c95,0x6c9c,0x6c66,0x6c73,0x6c65,0x6c7b, 0x6c8e,0x7074,0x707a,0x7263,0x72bf,0x72bd,0x72c3,0x72c6,0x72c1,0x72ba, 0x72c5,0x7395,0x7397,0x7393,0x7394,0x7392,0x753a,0x7539,0x7594,0x7595, 0x7681,0x793d,0x8034,0x8095,0x8099,0x8090,0x8092,0x809c,0x8290,0x828f, 0x8285,0x828e,0x8291,0x8293 }, { /* ku 05 */ 0x828a,0x8283,0x8284,0x8c78,0x8fc9,0x8fbf,0x909f,0x90a1,0x90a5,0x909e, 0x90a7,0x90a0,0x9630,0x9628,0x962f,0x962d,0x4e33,0x4f98,0x4f7c,0x4f85, 0x4f7d,0x4f80,0x4f87,0x4f76,0x4f74,0x4f89,0x4f84,0x4f77,0x4f4c,0x4f97, 0x4f6a,0x4f9a,0x4f79,0x4f81,0x4f78,0x4f90,0x4f9c,0x4f94,0x4f9e,0x4f92, 0x4f82,0x4f95,0x4f6b,0x4f6e,0x519e,0x51bc,0x51be,0x5235,0x5232,0x5233, 0x5246,0x5231,0x52bc,0x530a,0x530b,0x533c,0x5392,0x5394,0x5487,0x547f, 0x5481,0x5491,0x5482,0x5488,0x546b,0x547a,0x547e,0x5465,0x546c,0x5474, 0x5466,0x548d,0x546f,0x5461,0x5460,0x5498,0x5463,0x5467,0x5464,0x56f7, 0x56f9,0x576f,0x5772,0x576d,0x576b,0x5771,0x5770,0x5776,0x5780,0x5775, 0x577b,0x5773,0x5774,0x5762 }, { /* ku 06 */ 0x5768,0x577d,0x590c,0x5945,0x59b5,0x59ba,0x59cf,0x59ce,0x59b2,0x59cc, 0x59c1,0x59b6,0x59bc,0x59c3,0x59d6,0x59b1,0x59bd,0x59c0,0x59c8,0x59b4, 0x59c7,0x5b62,0x5b65,0x5b93,0x5b95,0x5c44,0x5c47,0x5cae,0x5ca4,0x5ca0, 0x5cb5,0x5caf,0x5ca8,0x5cac,0x5c9f,0x5ca3,0x5cad,0x5ca2,0x5caa,0x5ca7, 0x5c9d,0x5ca5,0x5cb6,0x5cb0,0x5ca6,0x5e17,0x5e14,0x5e19,0x5f28,0x5f22, 0x5f23,0x5f24,0x5f54,0x5f82,0x5f7e,0x5f7d,0x5fde,0x5fe5,0x602d,0x6026, 0x6019,0x6032,0x600b,0x6034,0x600a,0x6017,0x6033,0x601a,0x601e,0x602c, 0x6022,0x600d,0x6010,0x602e,0x6013,0x6011,0x600c,0x6009,0x601c,0x6214, 0x623d,0x62ad,0x62b4,0x62d1,0x62be,0x62aa,0x62b6,0x62ca,0x62ae,0x62b3, 0x62af,0x62bb,0x62a9,0x62b0 }, { /* ku 07 */ 0x62b8,0x653d,0x65a8,0x65bb,0x6609,0x65fc,0x6604,0x6612,0x6608,0x65fb, 0x6603,0x660b,0x660d,0x6605,0x65fd,0x6611,0x6610,0x66f6,0x670a,0x6785, 0x676c,0x678e,0x6792,0x6776,0x677b,0x6798,0x6786,0x6784,0x6774,0x678d, 0x678c,0x677a,0x679f,0x6791,0x6799,0x6783,0x677d,0x6781,0x6778,0x6779, 0x6794,0x6b25,0x6b80,0x6b7e,0x6bde,0x6c1d,0x6c93,0x6cec,0x6ceb,0x6cee, 0x6cd9,0x6cb6,0x6cd4,0x6cad,0x6ce7,0x6cb7,0x6cd0,0x6cc2,0x6cba,0x6cc3, 0x6cc6,0x6ced,0x6cf2,0x6cd2,0x6cdd,0x6cb4,0x6c8a,0x6c9d,0x6c80,0x6cde, 0x6cc0,0x6d30,0x6ccd,0x6cc7,0x6cb0,0x6cf9,0x6ccf,0x6ce9,0x6cd1,0x7094, 0x7098,0x7085,0x7093,0x7086,0x7084,0x7091,0x7096,0x7082,0x709a,0x7083, 0x726a,0x72d6,0x72cb,0x72d8 }, { /* ku 08 */ 0x72c9,0x72dc,0x72d2,0x72d4,0x72da,0x72cc,0x72d1,0x73a4,0x73a1,0x73ad, 0x73a6,0x73a2,0x73a0,0x73ac,0x739d,0x74dd,0x74e8,0x753f,0x7540,0x753e, 0x758c,0x7598,0x76af,0x76f3,0x76f1,0x76f0,0x76f5,0x77f8,0x77fc,0x77f9, 0x77fb,0x77fa,0x77f7,0x7942,0x793f,0x79c5,0x7a78,0x7a7b,0x7afb,0x7c75, 0x7cfd,0x8035,0x808f,0x80ae,0x80a3,0x80b8,0x80b5,0x80ad,0x8220,0x82a0, 0x82c0,0x82ab,0x829a,0x8298,0x829b,0x82b5,0x82a7,0x82ae,0x82bc,0x829e, 0x82ba,0x82b4,0x82a8,0x82a1,0x82a9,0x82c2,0x82a4,0x82c3,0x82b6,0x82a2, 0x8670,0x866f,0x866d,0x866e,0x8c56,0x8fd2,0x8fcb,0x8fd3,0x8fcd,0x8fd6, 0x8fd5,0x8fd7,0x90b2,0x90b4,0x90af,0x90b3,0x90b0,0x9639,0x963d,0x963c, 0x963a,0x9643,0x4fcd,0x4fc5 }, { /* ku 09 */ 0x4fd3,0x4fb2,0x4fc9,0x4fcb,0x4fc1,0x4fd4,0x4fdc,0x4fd9,0x4fbb,0x4fb3, 0x4fdb,0x4fc7,0x4fd6,0x4fba,0x4fc0,0x4fb9,0x4fec,0x5244,0x5249,0x52c0, 0x52c2,0x533d,0x537c,0x5397,0x5396,0x5399,0x5398,0x54ba,0x54a1,0x54ad, 0x54a5,0x54cf,0x54c3,0x830d,0x54b7,0x54ae,0x54d6,0x54b6,0x54c5,0x54c6, 0x54a0,0x5470,0x54bc,0x54a2,0x54be,0x5472,0x54de,0x54b0,0x57b5,0x579e, 0x579f,0x57a4,0x578c,0x5797,0x579d,0x579b,0x5794,0x5798,0x578f,0x5799, 0x57a5,0x579a,0x5795,0x58f4,0x590d,0x5953,0x59e1,0x59de,0x59ee,0x5a00, 0x59f1,0x59dd,0x59fa,0x59fd,0x59fc,0x59f6,0x59e4,0x59f2,0x59f7,0x59db, 0x59e9,0x59f3,0x59f5,0x59e0,0x59fe,0x59f4,0x59ed,0x5ba8,0x5c4c,0x5cd0, 0x5cd8,0x5ccc,0x5cd7,0x5ccb }, { /* ku 0a */ 0x5cdb,0x5cde,0x5cda,0x5cc9,0x5cc7,0x5cca,0x5cd6,0x5cd3,0x5cd4,0x5ccf, 0x5cc8,0x5cc6,0x5cce,0x5cdf,0x5cf8,0x5df9,0x5e21,0x5e22,0x5e23,0x5e20, 0x5e24,0x5eb0,0x5ea4,0x5ea2,0x5e9b,0x5ea3,0x5ea5,0x5f07,0x5f2e,0x5f56, 0x5f86,0x6037,0x6039,0x6054,0x6072,0x605e,0x6045,0x6053,0x6047,0x6049, 0x605b,0x604c,0x6040,0x6042,0x605f,0x6024,0x6044,0x6058,0x6066,0x606e, 0x6242,0x6243,0x62cf,0x630d,0x630b,0x62f5,0x630e,0x6303,0x62eb,0x62f9, 0x630f,0x630c,0x62f8,0x62f6,0x6300,0x6313,0x6314,0x62fa,0x6315,0x62fb, 0x62f0,0x6541,0x6543,0x65aa,0x65bf,0x6636,0x6621,0x6632,0x6635,0x661c, 0x6626,0x6622,0x6633,0x662b,0x663a,0x661d,0x6634,0x6639,0x662e,0x670f, 0x6710,0x67c1,0x67f2,0x67c8 }, { /* ku 0b */ 0x67ba,0x67dc,0x67bb,0x67f8,0x67d8,0x67c0,0x67b7,0x67c5,0x67eb,0x67e4, 0x67df,0x67b5,0x67cd,0x67b3,0x67f7,0x67f6,0x67ee,0x67e3,0x67c2,0x67b9, 0x67ce,0x67e7,0x67f0,0x67b2,0x67fc,0x67c6,0x67ed,0x67cc,0x67ae,0x67e6, 0x67db,0x67fa,0x67c9,0x67ca,0x67c3,0x67ea,0x67cb,0x6b28,0x6b82,0x6b84, 0x6bb6,0x6bd6,0x6bd8,0x6be0,0x6c20,0x6c21,0x6d28,0x6d34,0x6d2d,0x6d1f, 0x6d3c,0x6d3f,0x6d12,0x6d0a,0x6cda,0x6d33,0x6d04,0x6d19,0x6d3a,0x6d1a, 0x6d11,0x6d00,0x6d1d,0x6d42,0x6d01,0x6d18,0x6d37,0x6d03,0x6d0f,0x6d40, 0x6d07,0x6d20,0x6d2c,0x6d08,0x6d22,0x6d09,0x6d10,0x70b7,0x709f,0x70be, 0x70b1,0x70b0,0x70a1,0x70b4,0x70b5,0x70a9,0x7241,0x7249,0x724a,0x726c, 0x7270,0x7273,0x726e,0x72ca }, { /* ku 0c */ 0x72e4,0x72e8,0x72eb,0x72df,0x72ea,0x72e6,0x72e3,0x7385,0x73cc,0x73c2, 0x73c8,0x73c5,0x73b9,0x73b6,0x73b5,0x73b4,0x73eb,0x73bf,0x73c7,0x73be, 0x73c3,0x73c6,0x73b8,0x73cb,0x74ec,0x74ee,0x752e,0x7547,0x7548,0x75a7, 0x75aa,0x7679,0x76c4,0x7708,0x7703,0x7704,0x7705,0x770a,0x76f7,0x76fb, 0x76fa,0x77e7,0x77e8,0x7806,0x7811,0x7812,0x7805,0x7810,0x780f,0x780e, 0x7809,0x7803,0x7813,0x794a,0x794c,0x794b,0x7945,0x7944,0x79d5,0x79cd, 0x79cf,0x79d6,0x79ce,0x7a80,0x7a7e,0x7ad1,0x7b00,0x7b01,0x7c7a,0x7c78, 0x7c79,0x7c7f,0x7c80,0x7c81,0x7d03,0x7d08,0x7d01,0x7f58,0x7f91,0x7f8d, 0x7fbe,0x8007,0x800e,0x800f,0x8014,0x8037,0x80d8,0x80c7,0x80e0,0x80d1, 0x80c8,0x80c2,0x80d0,0x80c5 }, { /* ku 0d */ 0x80e3,0x80d9,0x80dc,0x80ca,0x80d5,0x80c9,0x80cf,0x80d7,0x80e6,0x80cd, 0x81ff,0x8221,0x8294,0x82d9,0x82fe,0x82f9,0x8307,0x82e8,0x8300,0x82d5, 0x833a,0x82eb,0x82d6,0x82f4,0x82ec,0x82e1,0x82f2,0x82f5,0x830c,0x82fb, 0x82f6,0x82f0,0x82ea,0x82e4,0x82e0,0x82fa,0x82f3,0x82ed,0x8677,0x8674, 0x867c,0x8673,0x8841,0x884e,0x8867,0x886a,0x8869,0x89d3,0x8a04,0x8a07, 0x8d72,0x8fe3,0x8fe1,0x8fee,0x8fe0,0x90f1,0x90bd,0x90bf,0x90d5,0x90c5, 0x90be,0x90c7,0x90cb,0x90c8,0x91d4,0x91d3,0x9654,0x964f,0x9651,0x9653, 0x964a,0x964e,0x501e,0x5005,0x5007,0x5013,0x5022,0x5030,0x501b,0x4ff5, 0x4ff4,0x5033,0x5037,0x502c,0x4ff6,0x4ff7,0x5017,0x501c,0x5020,0x5027, 0x5035,0x502f,0x5031,0x500e }, { /* ku 0e */ 0x515a,0x5194,0x5193,0x51ca,0x51c4,0x51c5,0x51c8,0x51ce,0x5261,0x525a, 0x5252,0x525e,0x525f,0x5255,0x5262,0x52cd,0x530e,0x539e,0x5526,0x54e2, 0x5517,0x5512,0x54e7,0x54f3,0x54e4,0x551a,0x54ff,0x5504,0x5508,0x54eb, 0x5511,0x5505,0x54f1,0x550a,0x54fb,0x54f7,0x54f8,0x54e0,0x550e,0x5503, 0x550b,0x5701,0x5702,0x57cc,0x5832,0x57d5,0x57d2,0x57ba,0x57c6,0x57bd, 0x57bc,0x57b8,0x57b6,0x57bf,0x57c7,0x57d0,0x57b9,0x57c1,0x590e,0x594a, 0x5a19,0x5a16,0x5a2d,0x5a2e,0x5a15,0x5a0f,0x5a17,0x5a0a,0x5a1e,0x5a33, 0x5b6c,0x5ba7,0x5bad,0x5bac,0x5c03,0x5c56,0x5c54,0x5cec,0x5cff,0x5cee, 0x5cf1,0x5cf7,0x5d00,0x5cf9,0x5e29,0x5e28,0x5ea8,0x5eae,0x5eaa,0x5eac, 0x5f33,0x5f30,0x5f67,0x605d }, { /* ku 0f */ 0x605a,0x6067,0x6041,0x60a2,0x6088,0x6080,0x6092,0x6081,0x609d,0x6083, 0x6095,0x609b,0x6097,0x6087,0x609c,0x608e,0x6219,0x6246,0x62f2,0x6310, 0x6356,0x632c,0x6344,0x6345,0x6336,0x6343,0x63e4,0x6339,0x634b,0x634a, 0x633c,0x6329,0x6341,0x6334,0x6358,0x6354,0x6359,0x632d,0x6347,0x6333, 0x635a,0x6351,0x6338,0x6357,0x6340,0x6348,0x654a,0x6546,0x65c6,0x65c3, 0x65c4,0x65c2,0x664a,0x665f,0x6647,0x6651,0x6712,0x6713,0x681f,0x681a, 0x6849,0x6832,0x6833,0x683b,0x684b,0x684f,0x6816,0x6831,0x681c,0x6835, 0x682b,0x682d,0x682f,0x684e,0x6844,0x6834,0x681d,0x6812,0x6814,0x6826, 0x6828,0x682e,0x684d,0x683a,0x6825,0x6820,0x6b2c,0x6b2f,0x6b2d,0x6b31, 0x6b34,0x6b6d,0x8082,0x6b88 }, { /* ku 10 */ 0x6be6,0x6be4,0x6be8,0x6be3,0x6be2,0x6be7,0x6c25,0x6d7a,0x6d63,0x6d64, 0x6d76,0x6d0d,0x6d61,0x6d92,0x6d58,0x6d62,0x6d6d,0x6d6f,0x6d91,0x6d8d, 0x6def,0x6d7f,0x6d86,0x6d5e,0x6d67,0x6d60,0x6d97,0x6d70,0x6d7c,0x6d5f, 0x6d82,0x6d98,0x6d2f,0x6d68,0x6d8b,0x6d7e,0x6d80,0x6d84,0x6d16,0x6d83, 0x6d7b,0x6d7d,0x6d75,0x6d90,0x70dc,0x70d3,0x70d1,0x70dd,0x70cb,0x7f39, 0x70e2,0x70d7,0x70d2,0x70de,0x70e0,0x70d4,0x70cd,0x70c5,0x70c6,0x70c7, 0x70da,0x70ce,0x70e1,0x7242,0x7278,0x7277,0x7276,0x7300,0x72fa,0x72f4, 0x72fe,0x72f6,0x72f3,0x72fb,0x7301,0x73d3,0x73d9,0x73e5,0x73d6,0x73bc, 0x73e7,0x73e3,0x73e9,0x73dc,0x73d2,0x73db,0x73d4,0x73dd,0x73da,0x73d7, 0x73d8,0x73e8,0x74de,0x74df }, { /* ku 11 */ 0x74f4,0x74f5,0x7521,0x755b,0x755f,0x75b0,0x75c1,0x75bb,0x75c4,0x75c0, 0x75bf,0x75b6,0x75ba,0x768a,0x76c9,0x771d,0x771b,0x7710,0x7713,0x7712, 0x7723,0x7711,0x7715,0x7719,0x771a,0x7722,0x7727,0x7823,0x782c,0x7822, 0x7835,0x782f,0x7828,0x782e,0x782b,0x7821,0x7829,0x7833,0x782a,0x7831, 0x7954,0x795b,0x794f,0x795c,0x7953,0x7952,0x7951,0x79eb,0x79ec,0x79e0, 0x79ee,0x79ed,0x79ea,0x79dc,0x79de,0x79dd,0x7a86,0x7a89,0x7a85,0x7a8b, 0x7a8c,0x7a8a,0x7a87,0x7ad8,0x7b10,0x7b04,0x7b13,0x7b05,0x7b0f,0x7b08, 0x7b0a,0x7b0e,0x7b09,0x7b12,0x7c84,0x7c91,0x7c8a,0x7c8c,0x7c88,0x7c8d, 0x7c85,0x7d1e,0x7d1d,0x7d11,0x7d0e,0x7d18,0x7d16,0x7d13,0x7d1f,0x7d12, 0x7d0f,0x7d0c,0x7f5c,0x7f61 }, { /* ku 12 */ 0x7f5e,0x7f60,0x7f5d,0x7f5b,0x7f96,0x7f92,0x7fc3,0x7fc2,0x7fc0,0x8016, 0x803e,0x8039,0x80fa,0x80f2,0x80f9,0x80f5,0x8101,0x80fb,0x8100,0x8201, 0x822f,0x8225,0x8333,0x832d,0x8344,0x8319,0x8351,0x8325,0x8356,0x833f, 0x8341,0x8326,0x831c,0x8322,0x8342,0x834e,0x831b,0x832a,0x8308,0x833c, 0x834d,0x8316,0x8324,0x8320,0x8337,0x832f,0x8329,0x8347,0x8345,0x834c, 0x8353,0x831e,0x832c,0x834b,0x8327,0x8348,0x8653,0x8652,0x86a2,0x86a8, 0x8696,0x868d,0x8691,0x869e,0x8687,0x8697,0x8686,0x868b,0x869a,0x8685, 0x86a5,0x8699,0x86a1,0x86a7,0x8695,0x8698,0x868e,0x869d,0x8690,0x8694, 0x8843,0x8844,0x886d,0x8875,0x8876,0x8872,0x8880,0x8871,0x887f,0x886f, 0x8883,0x887e,0x8874,0x887c }, { /* ku 13 */ 0x8a12,0x8c47,0x8c57,0x8c7b,0x8ca4,0x8ca3,0x8d76,0x8d78,0x8db5,0x8db7, 0x8db6,0x8ed1,0x8ed3,0x8ffe,0x8ff5,0x9002,0x8fff,0x8ffb,0x9004,0x8ffc, 0x8ff6,0x90d6,0x90e0,0x90d9,0x90da,0x90e3,0x90df,0x90e5,0x90d8,0x90db, 0x90d7,0x90dc,0x90e4,0x9150,0x914e,0x914f,0x91d5,0x91e2,0x91da,0x965c, 0x965f,0x96bc,0x98e3,0x9adf,0x9b2f,0x4e7f,0x5070,0x506a,0x5061,0x505e, 0x5060,0x5053,0x504b,0x505d,0x5072,0x5048,0x504d,0x5041,0x505b,0x504a, 0x5062,0x5015,0x5045,0x505f,0x5069,0x506b,0x5063,0x5064,0x5046,0x5040, 0x506e,0x5073,0x5057,0x5051,0x51d0,0x526b,0x526d,0x526c,0x526e,0x52d6, 0x52d3,0x532d,0x539c,0x5575,0x5576,0x553c,0x554d,0x5550,0x5534,0x552a, 0x5551,0x5562,0x5536,0x5535 }, { /* ku 14 */ 0x5530,0x5552,0x5545,0x550c,0x5532,0x5565,0x554e,0x5539,0x5548,0x552d, 0x553b,0x5540,0x554b,0x570a,0x5707,0x57fb,0x5814,0x57e2,0x57f6,0x57dc, 0x57f4,0x5800,0x57ed,0x57fd,0x5808,0x57f8,0x580b,0x57f3,0x57cf,0x5807, 0x57ee,0x57e3,0x57f2,0x57e5,0x57ec,0x57e1,0x580e,0x57fc,0x5810,0x57e7, 0x5801,0x580c,0x57f1,0x57e9,0x57f0,0x580d,0x5804,0x595c,0x5a60,0x5a58, 0x5a55,0x5a67,0x5a5e,0x5a38,0x5a35,0x5a6d,0x5a50,0x5a5f,0x5a65,0x5a6c, 0x5a53,0x5a64,0x5a57,0x5a43,0x5a5d,0x5a52,0x5a44,0x5a5b,0x5a48,0x5a8e, 0x5a3e,0x5a4d,0x5a39,0x5a4c,0x5a70,0x5a69,0x5a47,0x5a51,0x5a56,0x5a42, 0x5a5c,0x5b72,0x5b6e,0x5bc1,0x5bc0,0x5c59,0x5d1e,0x5d0b,0x5d1d,0x5d1a, 0x5d20,0x5d0c,0x5d28,0x5d0d }, { /* ku 15 */ 0x5d26,0x5d25,0x5d0f,0x5d30,0x5d12,0x5d23,0x5d1f,0x5d2e,0x5e3e,0x5e34, 0x5eb1,0x5eb4,0x5eb9,0x5eb2,0x5eb3,0x5f36,0x5f38,0x5f9b,0x5f96,0x5f9f, 0x608a,0x6090,0x6086,0x60be,0x60b0,0x60ba,0x60d3,0x60d4,0x60cf,0x60e4, 0x60d9,0x60dd,0x60c8,0x60b1,0x60db,0x60b7,0x60ca,0x60bf,0x60c3,0x60cd, 0x60c0,0x6332,0x6365,0x638a,0x6382,0x637d,0x63bd,0x639e,0x63ad,0x639d, 0x6397,0x63ab,0x638e,0x636f,0x6387,0x6390,0x636e,0x63af,0x6375,0x639c, 0x636d,0x63ae,0x637c,0x63a4,0x633b,0x639f,0x6378,0x6385,0x6381,0x6391, 0x638d,0x6370,0x6553,0x65cd,0x6665,0x6661,0x665b,0x6659,0x665c,0x6662, 0x6718,0x6879,0x6887,0x6890,0x689c,0x686d,0x686e,0x68ae,0x68ab,0x6956, 0x686f,0x68a3,0x68ac,0x68a9 }, { /* ku 16 */ 0x6875,0x6874,0x68b2,0x688f,0x6877,0x6892,0x687c,0x686b,0x6872,0x68aa, 0x6880,0x6871,0x687e,0x689b,0x6896,0x688b,0x68a0,0x6889,0x68a4,0x6878, 0x687b,0x6891,0x688c,0x688a,0x687d,0x6b36,0x6b33,0x6b37,0x6b38,0x6b91, 0x6b8f,0x6b8d,0x6b8e,0x6b8c,0x6c2a,0x6dc0,0x6dab,0x6db4,0x6db3,0x6e74, 0x6dac,0x6de9,0x6de2,0x6db7,0x6df6,0x6dd4,0x6e00,0x6dc8,0x6de0,0x6ddf, 0x6dd6,0x6dbe,0x6de5,0x6ddc,0x6ddd,0x6ddb,0x6df4,0x6dca,0x6dbd,0x6ded, 0x6df0,0x6dba,0x6dd5,0x6dc2,0x6dcf,0x6dc9,0x6dd0,0x6df2,0x6dd3,0x6dfd, 0x6dd7,0x6dcd,0x6de3,0x6dbb,0x70fa,0x710d,0x70f7,0x7117,0x70f4,0x710c, 0x70f0,0x7104,0x70f3,0x7110,0x70fc,0x70ff,0x7106,0x7113,0x7100,0x70f8, 0x70f6,0x710b,0x7102,0x710e }, { /* ku 17 */ 0x727e,0x727b,0x727c,0x727f,0x731d,0x7317,0x7307,0x7311,0x7318,0x730a, 0x7308,0x72ff,0x730f,0x731e,0x7388,0x73f6,0x73f8,0x73f5,0x7404,0x7401, 0x73fd,0x7407,0x7400,0x73fa,0x73fc,0x73ff,0x740c,0x740b,0x73f4,0x7408, 0x7564,0x7563,0x75ce,0x75d2,0x75cf,0x75cb,0x75cc,0x75d1,0x75d0,0x768f, 0x7689,0x76d3,0x7739,0x772f,0x772d,0x7731,0x7732,0x7734,0x7733,0x773d, 0x7725,0x773b,0x7735,0x7848,0x7852,0x7849,0x784d,0x784a,0x784c,0x7826, 0x7845,0x7850,0x7964,0x7967,0x7969,0x796a,0x7963,0x796b,0x7961,0x79bb, 0x79fa,0x79f8,0x79f6,0x79f7,0x7a8f,0x7a94,0x7a90,0x7b35,0x7b3b,0x7b34, 0x7b25,0x7b30,0x7b22,0x7b24,0x7b33,0x7b18,0x7b2a,0x7b1d,0x7b31,0x7b2b, 0x7b2d,0x7b2f,0x7b32,0x7b38 }, { /* ku 18 */ 0x7b1a,0x7b23,0x7c94,0x7c98,0x7c96,0x7ca3,0x7d35,0x7d3d,0x7d38,0x7d36, 0x7d3a,0x7d45,0x7d2c,0x7d29,0x7d41,0x7d47,0x7d3e,0x7d3f,0x7d4a,0x7d3b, 0x7d28,0x7f63,0x7f95,0x7f9c,0x7f9d,0x7f9b,0x7fca,0x7fcb,0x7fcd,0x7fd0, 0x7fd1,0x7fc7,0x7fcf,0x7fc9,0x801f,0x801e,0x801b,0x8047,0x8043,0x8048, 0x8118,0x8125,0x8119,0x811b,0x812d,0x811f,0x812c,0x811e,0x8121,0x8115, 0x8127,0x811d,0x8122,0x8211,0x8238,0x8233,0x823a,0x8234,0x8232,0x8274, 0x8390,0x83a3,0x83a8,0x838d,0x837a,0x8373,0x83a4,0x8374,0x838f,0x8381, 0x8395,0x8399,0x8375,0x8394,0x83a9,0x837d,0x8383,0x838c,0x839d,0x839b, 0x83aa,0x838b,0x837e,0x83a5,0x83af,0x8388,0x8397,0x83b0,0x837f,0x83a6, 0x8387,0x83ae,0x8376,0x8659 }, { /* ku 19 */ 0x8656,0x86bf,0x86b7,0x86c2,0x86c1,0x86c5,0x86ba,0x86b0,0x86c8,0x86b9, 0x86b3,0x86b8,0x86cc,0x86b4,0x86bb,0x86bc,0x86c3,0x86bd,0x86be,0x8852, 0x8889,0x8895,0x88a8,0x88a2,0x88aa,0x889a,0x8891,0x88a1,0x889f,0x8898, 0x88a7,0x8899,0x889b,0x8897,0x88a4,0x88ac,0x888c,0x8893,0x888e,0x8982, 0x89d6,0x89d9,0x89d5,0x8a30,0x8a27,0x8a2c,0x8a1e,0x8c39,0x8c3b,0x8c5c, 0x8c5d,0x8c7d,0x8ca5,0x8d7d,0x8d7b,0x8d79,0x8dbc,0x8dc2,0x8db9,0x8dbf, 0x8dc1,0x8ed8,0x8ede,0x8edd,0x8edc,0x8ed7,0x8ee0,0x8ee1,0x9024,0x900b, 0x9011,0x901c,0x900c,0x9021,0x90ef,0x90ea,0x90f0,0x90f4,0x90f2,0x90f3, 0x90d4,0x90eb,0x90ec,0x90e9,0x9156,0x9158,0x915a,0x9153,0x9155,0x91ec, 0x91f4,0x91f1,0x91f3,0x91f8 }, { /* ku 1a */ 0x91e4,0x91f9,0x91ea,0x91eb,0x91f7,0x91e8,0x91ee,0x957a,0x9586,0x9588, 0x967c,0x966d,0x966b,0x9671,0x966f,0x96bf,0x976a,0x9804,0x98e5,0x9997, 0x509b,0x5095,0x5094,0x509e,0x508b,0x50a3,0x5083,0x508c,0x508e,0x509d, 0x5068,0x509c,0x5092,0x5082,0x5087,0x515f,0x51d4,0x5312,0x5311,0x53a4, 0x53a7,0x5591,0x55a8,0x55a5,0x55ad,0x5577,0x5645,0x55a2,0x5593,0x5588, 0x558f,0x55b5,0x5581,0x55a3,0x5592,0x55a4,0x557d,0x558c,0x55a6,0x557f, 0x5595,0x55a1,0x558e,0x570c,0x5829,0x5837,0x5819,0x581e,0x5827,0x5823, 0x5828,0x57f5,0x5848,0x5825,0x581c,0x581b,0x5833,0x583f,0x5836,0x582e, 0x5839,0x5838,0x582d,0x582c,0x583b,0x5961,0x5aaf,0x5a94,0x5a9f,0x5a7a, 0x5aa2,0x5a9e,0x5a78,0x5aa6 }, { /* ku 1b */ 0x5a7c,0x5aa5,0x5aac,0x5a95,0x5aae,0x5a37,0x5a84,0x5a8a,0x5a97,0x5a83, 0x5a8b,0x5aa9,0x5a7b,0x5a7d,0x5a8c,0x5a9c,0x5a8f,0x5a93,0x5a9d,0x5bea, 0x5bcd,0x5bcb,0x5bd4,0x5bd1,0x5bca,0x5bce,0x5c0c,0x5c30,0x5d37,0x5d43, 0x5d6b,0x5d41,0x5d4b,0x5d3f,0x5d35,0x5d51,0x5d4e,0x5d55,0x5d33,0x5d3a, 0x5d52,0x5d3d,0x5d31,0x5d59,0x5d42,0x5d39,0x5d49,0x5d38,0x5d3c,0x5d32, 0x5d36,0x5d40,0x5d45,0x5e44,0x5e41,0x5f58,0x5fa6,0x5fa5,0x5fab,0x60c9, 0x60b9,0x60cc,0x60e2,0x60ce,0x60c4,0x6114,0x60f2,0x610a,0x6116,0x6105, 0x60f5,0x6113,0x60f8,0x60fc,0x60fe,0x60c1,0x6103,0x6118,0x611d,0x6110, 0x60ff,0x6104,0x610b,0x624a,0x6394,0x63b1,0x63b0,0x63ce,0x63e5,0x63e8, 0x63ef,0x63c3,0x649d,0x63f3 }, { /* ku 1c */ 0x63ca,0x63e0,0x63f6,0x63d5,0x63f2,0x63f5,0x6461,0x63df,0x63be,0x63dd, 0x63dc,0x63c4,0x63d8,0x63d3,0x63c2,0x63c7,0x63cc,0x63cb,0x63c8,0x63f0, 0x63d7,0x63d9,0x6532,0x6567,0x656a,0x6564,0x655c,0x6568,0x6565,0x658c, 0x659d,0x659e,0x65ae,0x65d0,0x65d2,0x667c,0x666c,0x667b,0x6680,0x6671, 0x6679,0x666a,0x6672,0x6701,0x690c,0x68d3,0x6904,0x68dc,0x692a,0x68ec, 0x68ea,0x68f1,0x690f,0x68d6,0x68f7,0x68eb,0x68e4,0x68f6,0x6913,0x6910, 0x68f3,0x68e1,0x6907,0x68cc,0x6908,0x6970,0x68b4,0x6911,0x68ef,0x68c6, 0x6914,0x68f8,0x68d0,0x68fd,0x68fc,0x68e8,0x690b,0x690a,0x6917,0x68ce, 0x68c8,0x68dd,0x68de,0x68e6,0x68f4,0x68d1,0x6906,0x68d4,0x68e9,0x6915, 0x6925,0x68c7,0x6b39,0x6b3b }, { /* ku 1d */ 0x6b3f,0x6b3c,0x6b94,0x6b97,0x6b99,0x6b95,0x6bbd,0x6bf0,0x6bf2,0x6bf3, 0x6c30,0x6dfc,0x6e46,0x6e47,0x6e1f,0x6e49,0x6e88,0x6e3c,0x6e3d,0x6e45, 0x6e62,0x6e2b,0x6e3f,0x6e41,0x6e5d,0x6e73,0x6e1c,0x6e33,0x6e4b,0x6e40, 0x6e51,0x6e3b,0x6e03,0x6e2e,0x6e5e,0x6e68,0x6e5c,0x6e61,0x6e31,0x6e28, 0x6e60,0x6e71,0x6e6b,0x6e39,0x6e22,0x6e30,0x6e53,0x6e65,0x6e27,0x6e78, 0x6e64,0x6e77,0x6e55,0x6e79,0x6e52,0x6e66,0x6e35,0x6e36,0x6e5a,0x7120, 0x711e,0x712f,0x70fb,0x712e,0x7131,0x7123,0x7125,0x7122,0x7132,0x711f, 0x7128,0x713a,0x711b,0x724b,0x725a,0x7288,0x7289,0x7286,0x7285,0x728b, 0x7312,0x730b,0x7330,0x7322,0x7331,0x7333,0x7327,0x7332,0x732d,0x7326, 0x7323,0x7335,0x730c,0x742e }, { /* ku 1e */ 0x742c,0x7430,0x742b,0x7416,0x741a,0x7421,0x742d,0x7431,0x7424,0x7423, 0x741d,0x7429,0x7420,0x7432,0x74fb,0x752f,0x756f,0x756c,0x75e7,0x75da, 0x75e1,0x75e6,0x75dd,0x75df,0x75e4,0x75d7,0x7695,0x7692,0x76da,0x7746, 0x7747,0x7744,0x774d,0x7745,0x774a,0x774e,0x774b,0x774c,0x77de,0x77ec, 0x7860,0x7864,0x7865,0x785c,0x786d,0x7871,0x786a,0x786e,0x7870,0x7869, 0x7868,0x785e,0x7862,0x7974,0x7973,0x7972,0x7970,0x7a02,0x7a0a,0x7a03, 0x7a0c,0x7a04,0x7a99,0x7ae6,0x7ae4,0x7b4a,0x7b47,0x7b44,0x7b48,0x7b4c, 0x7b4e,0x7b40,0x7b58,0x7b45,0x7ca2,0x7c9e,0x7ca8,0x7ca1,0x7d58,0x7d6f, 0x7d63,0x7d53,0x7d56,0x7d67,0x7d6a,0x7d4f,0x7d6d,0x7d5c,0x7d6b,0x7d52, 0x7d54,0x7d69,0x7d51,0x7d5f }, { /* ku 1f */ 0x7d4e,0x7f3e,0x7f3f,0x7f65,0x7f66,0x7fa2,0x7fa0,0x7fa1,0x7fd7,0x8051, 0x804f,0x8050,0x80fe,0x80d4,0x8143,0x814a,0x8152,0x814f,0x8147,0x813d, 0x814d,0x813a,0x81e6,0x81ee,0x81f7,0x81f8,0x81f9,0x8204,0x823c,0x823d, 0x823f,0x8275,0x833b,0x83cf,0x83f9,0x8423,0x83c0,0x83e8,0x8412,0x83e7, 0x83e4,0x83fc,0x83f6,0x8410,0x83c6,0x83c8,0x83eb,0x83e3,0x83bf,0x8401, 0x83dd,0x83e5,0x83d8,0x83ff,0x83e1,0x83cb,0x83ce,0x83d6,0x83f5,0x83c9, 0x8409,0x840f,0x83de,0x8411,0x8406,0x83c2,0x83f3,0x83d5,0x83fa,0x83c7, 0x83d1,0x83ea,0x8413,0x839a,0x83c3,0x83ec,0x83ee,0x83c4,0x83fb,0x83d7, 0x83e2,0x841b,0x83db,0x83fe,0x86d8,0x86e2,0x86e6,0x86d3,0x86e3,0x86da, 0x86ea,0x86dd,0x86eb,0x86dc }, { /* ku 20 */ 0x86ec,0x86e9,0x86d7,0x86e8,0x86d1,0x8848,0x8856,0x8855,0x88ba,0x88d7, 0x88b9,0x88b8,0x88c0,0x88be,0x88b6,0x88bc,0x88b7,0x88bd,0x88b2,0x8901, 0x88c9,0x8995,0x8998,0x8997,0x89dd,0x89da,0x89db,0x8a4e,0x8a4d,0x8a39, 0x8a59,0x8a40,0x8a57,0x8a58,0x8a44,0x8a45,0x8a52,0x8a48,0x8a51,0x8a4a, 0x8a4c,0x8a4f,0x8c5f,0x8c81,0x8c80,0x8cba,0x8cbe,0x8cb0,0x8cb9,0x8cb5, 0x8d84,0x8d80,0x8d89,0x8dd8,0x8dd3,0x8dcd,0x8dc7,0x8dd6,0x8ddc,0x8dcf, 0x8dd5,0x8dd9,0x8dc8,0x8dd7,0x8dc5,0x8eef,0x8ef7,0x8efa,0x8ef9,0x8ee6, 0x8eee,0x8ee5,0x8ef5,0x8ee7,0x8ee8,0x8ef6,0x8eeb,0x8ef1,0x8eec,0x8ef4, 0x8ee9,0x902d,0x9034,0x902f,0x9106,0x912c,0x9104,0x90ff,0x90fc,0x9108, 0x90f9,0x90fb,0x9101,0x9100 }, { /* ku 21 */ 0x9107,0x9105,0x9103,0x9161,0x9164,0x915f,0x9162,0x9160,0x9201,0x920a, 0x9225,0x9203,0x921a,0x9226,0x920f,0x920c,0x9200,0x9212,0x91ff,0x91fd, 0x9206,0x9204,0x9227,0x9202,0x921c,0x9224,0x9219,0x9217,0x9205,0x9216, 0x957b,0x958d,0x958c,0x9590,0x9687,0x967e,0x9688,0x9689,0x9683,0x9680, 0x96c2,0x96c8,0x96c3,0x96f1,0x96f0,0x976c,0x9770,0x976e,0x9807,0x98a9, 0x98eb,0x9ce6,0x9ef9,0x4e83,0x4e84,0x4eb6,0x50bd,0x50bf,0x50c6,0x50ae, 0x50c4,0x50ca,0x50b4,0x50c8,0x50c2,0x50b0,0x50c1,0x50ba,0x50b1,0x50cb, 0x50c9,0x50b6,0x50b8,0x51d7,0x527a,0x5278,0x527b,0x527c,0x55c3,0x55db, 0x55cc,0x55d0,0x55cb,0x55ca,0x55dd,0x55c0,0x55d4,0x55c4,0x55e9,0x55bf, 0x55d2,0x558d,0x55cf,0x55d5 }, { /* ku 22 */ 0x55e2,0x55d6,0x55c8,0x55f2,0x55cd,0x55d9,0x55c2,0x5714,0x5853,0x5868, 0x5864,0x584f,0x584d,0x5849,0x586f,0x5855,0x584e,0x585d,0x5859,0x5865, 0x585b,0x583d,0x5863,0x5871,0x58fc,0x5ac7,0x5ac4,0x5acb,0x5aba,0x5ab8, 0x5ab1,0x5ab5,0x5ab0,0x5abf,0x5ac8,0x5abb,0x5ac6,0x5ab7,0x5ac0,0x5aca, 0x5ab4,0x5ab6,0x5acd,0x5ab9,0x5a90,0x5bd6,0x5bd8,0x5bd9,0x5c1f,0x5c33, 0x5d71,0x5d63,0x5d4a,0x5d65,0x5d72,0x5d6c,0x5d5e,0x5d68,0x5d67,0x5d62, 0x5df0,0x5e4f,0x5e4e,0x5e4a,0x5e4d,0x5e4b,0x5ec5,0x5ecc,0x5ec6,0x5ecb, 0x5ec7,0x5f40,0x5faf,0x5fad,0x60f7,0x6149,0x614a,0x612b,0x6145,0x6136, 0x6132,0x612e,0x6146,0x612f,0x614f,0x6129,0x6140,0x6220,0x9168,0x6223, 0x6225,0x6224,0x63c5,0x63f1 }, { /* ku 23 */ 0x63eb,0x6410,0x6412,0x6409,0x6420,0x6424,0x6433,0x6443,0x641f,0x6415, 0x6418,0x6439,0x6437,0x6422,0x6423,0x640c,0x6426,0x6430,0x6428,0x6441, 0x6435,0x642f,0x640a,0x641a,0x6440,0x6425,0x6427,0x640b,0x63e7,0x641b, 0x642e,0x6421,0x640e,0x656f,0x6592,0x65d3,0x6686,0x668c,0x6695,0x6690, 0x668b,0x668a,0x6699,0x6694,0x6678,0x6720,0x6966,0x695f,0x6938,0x694e, 0x6962,0x6971,0x693f,0x6945,0x696a,0x6939,0x6942,0x6957,0x6959,0x697a, 0x6948,0x6949,0x6935,0x696c,0x6933,0x693d,0x6965,0x68f0,0x6978,0x6934, 0x6969,0x6940,0x696f,0x6944,0x6976,0x6958,0x6941,0x6974,0x694c,0x693b, 0x694b,0x6937,0x695c,0x694f,0x6951,0x6932,0x6952,0x692f,0x697b,0x693c, 0x6b46,0x6b45,0x6b43,0x6b42 }, { /* ku 24 */ 0x6b48,0x6b41,0x6b9b,0x6bfb,0x6bfc,0x6bf9,0x6bf7,0x6bf8,0x6e9b,0x6ed6, 0x6ec8,0x6e8f,0x6ec0,0x6e9f,0x6e93,0x6e94,0x6ea0,0x6eb1,0x6eb9,0x6ec6, 0x6ed2,0x6ebd,0x6ec1,0x6e9e,0x6ec9,0x6eb7,0x6eb0,0x6ecd,0x6ea6,0x6ecf, 0x6eb2,0x6ebe,0x6ec3,0x6edc,0x6ed8,0x6e99,0x6e92,0x6e8e,0x6e8d,0x6ea4, 0x6ea1,0x6ebf,0x6eb3,0x6ed0,0x6eca,0x6e97,0x6eae,0x6ea3,0x7147,0x7154, 0x7152,0x7163,0x7160,0x7141,0x715d,0x7162,0x7172,0x7178,0x716a,0x7161, 0x7142,0x7158,0x7143,0x714b,0x7170,0x715f,0x7150,0x7153,0x7144,0x714d, 0x715a,0x724f,0x728d,0x728c,0x7291,0x7290,0x728e,0x733c,0x7342,0x733b, 0x733a,0x7340,0x734a,0x7349,0x7444,0x744a,0x744b,0x7452,0x7451,0x7457, 0x7440,0x744f,0x7450,0x744e }, { /* ku 25 */ 0x7442,0x7446,0x744d,0x7454,0x74e1,0x74ff,0x74fe,0x74fd,0x751d,0x7579, 0x7577,0x6983,0x75ef,0x760f,0x7603,0x75f7,0x75fe,0x75fc,0x75f9,0x75f8, 0x7610,0x75fb,0x75f6,0x75ed,0x75f5,0x75fd,0x7699,0x76b5,0x76dd,0x7755, 0x775f,0x7760,0x7752,0x7756,0x775a,0x7769,0x7767,0x7754,0x7759,0x776d, 0x77e0,0x7887,0x789a,0x7894,0x788f,0x7884,0x7895,0x7885,0x7886,0x78a1, 0x7883,0x7879,0x7899,0x7880,0x7896,0x787b,0x797c,0x7982,0x797d,0x7979, 0x7a11,0x7a18,0x7a19,0x7a12,0x7a17,0x7a15,0x7a22,0x7a13,0x7a1b,0x7a10, 0x7aa3,0x7aa2,0x7a9e,0x7aeb,0x7b66,0x7b64,0x7b6d,0x7b74,0x7b69,0x7b72, 0x7b65,0x7b73,0x7b71,0x7b70,0x7b61,0x7b78,0x7b76,0x7b63,0x7cb2,0x7cb4, 0x7caf,0x7d88,0x7d86,0x7d80 }, { /* ku 26 */ 0x7d8d,0x7d7f,0x7d85,0x7d7a,0x7d8e,0x7d7b,0x7d83,0x7d7c,0x7d8c,0x7d94, 0x7d84,0x7d7d,0x7d92,0x7f6d,0x7f6b,0x7f67,0x7f68,0x7f6c,0x7fa6,0x7fa5, 0x7fa7,0x7fdb,0x7fdc,0x8021,0x8164,0x8160,0x8177,0x815c,0x8169,0x815b, 0x8162,0x8172,0x6721,0x815e,0x8176,0x8167,0x816f,0x8144,0x8161,0x821d, 0x8249,0x8244,0x8240,0x8242,0x8245,0x84f1,0x843f,0x8456,0x8476,0x8479, 0x848f,0x848d,0x8465,0x8451,0x8440,0x8486,0x8467,0x8430,0x844d,0x847d, 0x845a,0x8459,0x8474,0x8473,0x845d,0x8507,0x845e,0x8437,0x843a,0x8434, 0x847a,0x8443,0x8478,0x8432,0x8445,0x8429,0x83d9,0x844b,0x842f,0x8442, 0x842d,0x845f,0x8470,0x8439,0x844e,0x844c,0x8452,0x846f,0x84c5,0x848e, 0x843b,0x8447,0x8436,0x8433 }, { /* ku 27 */ 0x8468,0x847e,0x8444,0x842b,0x8460,0x8454,0x846e,0x8450,0x870b,0x8704, 0x86f7,0x870c,0x86fa,0x86d6,0x86f5,0x874d,0x86f8,0x870e,0x8709,0x8701, 0x86f6,0x870d,0x8705,0x88d6,0x88cb,0x88cd,0x88ce,0x88de,0x88db,0x88da, 0x88cc,0x88d0,0x8985,0x899b,0x89df,0x89e5,0x89e4,0x89e1,0x89e0,0x89e2, 0x89dc,0x89e6,0x8a76,0x8a86,0x8a7f,0x8a61,0x8a3f,0x8a77,0x8a82,0x8a84, 0x8a75,0x8a83,0x8a81,0x8a74,0x8a7a,0x8c3c,0x8c4b,0x8c4a,0x8c65,0x8c64, 0x8c66,0x8c86,0x8c84,0x8c85,0x8ccc,0x8d68,0x8d69,0x8d91,0x8d8c,0x8d8e, 0x8d8f,0x8d8d,0x8d93,0x8d94,0x8d90,0x8d92,0x8df0,0x8de0,0x8dec,0x8df1, 0x8dee,0x8dd0,0x8de9,0x8de3,0x8de2,0x8de7,0x8df2,0x8deb,0x8df4,0x8f06, 0x8eff,0x8f01,0x8f00,0x8f05 }, { /* ku 28 */ 0x8f07,0x8f08,0x8f02,0x8f0b,0x9052,0x903f,0x9044,0x9049,0x903d,0x9110, 0x910d,0x910f,0x9111,0x9116,0x9114,0x910b,0x910e,0x916e,0x916f,0x9248, 0x9252,0x9230,0x923a,0x9266,0x9233,0x9265,0x925e,0x9283,0x922e,0x924a, 0x9246,0x926d,0x926c,0x924f,0x9260,0x9267,0x926f,0x9236,0x9261,0x9270, 0x9231,0x9254,0x9263,0x9250,0x9272,0x924e,0x9253,0x924c,0x9256,0x9232, 0x959f,0x959c,0x959e,0x959b,0x9692,0x9693,0x9691,0x9697,0x96ce,0x96fa, 0x96fd,0x96f8,0x96f5,0x9773,0x9777,0x9778,0x9772,0x980f,0x980d,0x980e, 0x98ac,0x98f6,0x98f9,0x99af,0x99b2,0x99b0,0x99b5,0x9aad,0x9aab,0x9b5b, 0x9cea,0x9ced,0x9ce7,0x9e80,0x9efd,0x50e6,0x50d4,0x50d7,0x50e8,0x50f3, 0x50db,0x50ea,0x50dd,0x50e4 }, { /* ku 29 */ 0x50d3,0x50ec,0x50f0,0x50ef,0x50e3,0x50e0,0x51d8,0x5280,0x5281,0x52e9, 0x52eb,0x5330,0x53ac,0x5627,0x5615,0x560c,0x5612,0x55fc,0x560f,0x561c, 0x5601,0x5613,0x5602,0x55fa,0x561d,0x5604,0x55ff,0x55f9,0x5889,0x587c, 0x5890,0x5898,0x5886,0x5881,0x587f,0x5874,0x588b,0x587a,0x5887,0x5891, 0x588e,0x5876,0x5882,0x5888,0x587b,0x5894,0x588f,0x58fe,0x596b,0x5adc, 0x5aee,0x5ae5,0x5ad5,0x5aea,0x5ada,0x5aed,0x5aeb,0x5af3,0x5ae2,0x5ae0, 0x5adb,0x5aec,0x5ade,0x5add,0x5ad9,0x5ae8,0x5adf,0x5b77,0x5be0,0x5be3, 0x5c63,0x5d82,0x5d80,0x5d7d,0x5d86,0x5d7a,0x5d81,0x5d77,0x5d8a,0x5d89, 0x5d88,0x5d7e,0x5d7c,0x5d8d,0x5d79,0x5d7f,0x5e58,0x5e59,0x5e53,0x5ed8, 0x5ed1,0x5ed7,0x5ece,0x5edc }, { /* ku 2a */ 0x5ed5,0x5ed9,0x5ed2,0x5ed4,0x5f44,0x5f43,0x5f6f,0x5fb6,0x612c,0x6128, 0x6141,0x615e,0x6171,0x6173,0x6152,0x6153,0x6172,0x616c,0x6180,0x6174, 0x6154,0x617a,0x615b,0x6165,0x613b,0x616a,0x6161,0x6156,0x6229,0x6227, 0x622b,0x642b,0x644d,0x645b,0x645d,0x6474,0x6476,0x6472,0x6473,0x647d, 0x6475,0x6466,0x64a6,0x644e,0x6482,0x645e,0x645c,0x644b,0x6453,0x6460, 0x6450,0x647f,0x643f,0x646c,0x646b,0x6459,0x6465,0x6477,0x6573,0x65a0, 0x66a1,0x66a0,0x669f,0x6705,0x6704,0x6722,0x69b1,0x69b6,0x69c9,0x69a0, 0x69ce,0x6996,0x69b0,0x69ac,0x69bc,0x6991,0x6999,0x698e,0x69a7,0x698d, 0x69a9,0x69be,0x69af,0x69bf,0x69c4,0x69bd,0x69a4,0x69d4,0x69b9,0x69ca, 0x699a,0x69cf,0x69b3,0x6993 }, { /* ku 2b */ 0x69aa,0x69a1,0x699e,0x69d9,0x6997,0x6990,0x69c2,0x69b5,0x69a5,0x69c6, 0x6b4a,0x6b4d,0x6b4b,0x6b9e,0x6b9f,0x6ba0,0x6bc3,0x6bc4,0x6bfe,0x6ece, 0x6ef5,0x6ef1,0x6f03,0x6f25,0x6ef8,0x6f37,0x6efb,0x6f2e,0x6f09,0x6f4e, 0x6f19,0x6f1a,0x6f27,0x6f18,0x6f3b,0x6f12,0x6eed,0x6f0a,0x6f36,0x6f73, 0x6ef9,0x6eee,0x6f2d,0x6f40,0x6f30,0x6f3c,0x6f35,0x6eeb,0x6f07,0x6f0e, 0x6f43,0x6f05,0x6efd,0x6ef6,0x6f39,0x6f1c,0x6efc,0x6f3a,0x6f1f,0x6f0d, 0x6f1e,0x6f08,0x6f21,0x7187,0x7190,0x7189,0x7180,0x7185,0x7182,0x718f, 0x717b,0x7186,0x7181,0x7197,0x7244,0x7253,0x7297,0x7295,0x7293,0x7343, 0x734d,0x7351,0x734c,0x7462,0x7473,0x7471,0x7475,0x7472,0x7467,0x746e, 0x7500,0x7502,0x7503,0x757d }, { /* ku 2c */ 0x7590,0x7616,0x7608,0x760c,0x7615,0x7611,0x760a,0x7614,0x76b8,0x7781, 0x777c,0x7785,0x7782,0x776e,0x7780,0x776f,0x777e,0x7783,0x78b2,0x78aa, 0x78b4,0x78ad,0x78a8,0x787e,0x78ab,0x789e,0x78a5,0x78a0,0x78ac,0x78a2, 0x78a4,0x7998,0x798a,0x798b,0x7996,0x7995,0x7994,0x7993,0x7997,0x7988, 0x7992,0x7990,0x7a2b,0x7a4a,0x7a30,0x7a2f,0x7a28,0x7a26,0x7aa8,0x7aab, 0x7aac,0x7aee,0x7b88,0x7b9c,0x7b8a,0x7b91,0x7b90,0x7b96,0x7b8d,0x7b8c, 0x7b9b,0x7b8e,0x7b85,0x7b98,0x5284,0x7b99,0x7ba4,0x7b82,0x7cbb,0x7cbf, 0x7cbc,0x7cba,0x7da7,0x7db7,0x7dc2,0x7da3,0x7daa,0x7dc1,0x7dc0,0x7dc5, 0x7d9d,0x7dce,0x7dc4,0x7dc6,0x7dcb,0x7dcc,0x7daf,0x7db9,0x7d96,0x7dbc, 0x7d9f,0x7da6,0x7dae,0x7da9 }, { /* ku 2d */ 0x7da1,0x7dc9,0x7f73,0x7fe2,0x7fe3,0x7fe5,0x7fde,0x8024,0x805d,0x805c, 0x8189,0x8186,0x8183,0x8187,0x818d,0x818c,0x818b,0x8215,0x8497,0x84a4, 0x84a1,0x849f,0x84ba,0x84ce,0x84c2,0x84ac,0x84ae,0x84ab,0x84b9,0x84b4, 0x84c1,0x84cd,0x84aa,0x849a,0x84b1,0x84d0,0x849d,0x84a7,0x84bb,0x84a2, 0x8494,0x84c7,0x84cc,0x849b,0x84a9,0x84af,0x84a8,0x84d6,0x8498,0x84b6, 0x84cf,0x84a0,0x84d7,0x84d4,0x84d2,0x84db,0x84b0,0x8491,0x8661,0x8733, 0x8723,0x8728,0x876b,0x8740,0x872e,0x871e,0x8721,0x8719,0x871b,0x8743, 0x872c,0x8741,0x873e,0x8746,0x8720,0x8732,0x872a,0x872d,0x873c,0x8712, 0x873a,0x8731,0x8735,0x8742,0x8726,0x8727,0x8738,0x8724,0x871a,0x8730, 0x8711,0x88f7,0x88e7,0x88f1 }, { /* ku 2e */ 0x88f2,0x88fa,0x88fe,0x88ee,0x88fc,0x88f6,0x88fb,0x88f0,0x88ec,0x88eb, 0x899d,0x89a1,0x899f,0x899e,0x89e9,0x89eb,0x89e8,0x8aab,0x8a99,0x8a8b, 0x8a92,0x8a8f,0x8a96,0x8c3d,0x8c68,0x8c69,0x8cd5,0x8ccf,0x8cd7,0x8d96, 0x8e09,0x8e02,0x8dff,0x8e0d,0x8dfd,0x8e0a,0x8e03,0x8e07,0x8e06,0x8e05, 0x8dfe,0x8e00,0x8e04,0x8f10,0x8f11,0x8f0e,0x8f0d,0x9123,0x911c,0x9120, 0x9122,0x911f,0x911d,0x911a,0x9124,0x9121,0x911b,0x917a,0x9172,0x9179, 0x9173,0x92a5,0x92a4,0x9276,0x929b,0x927a,0x92a0,0x9294,0x92aa,0x928d, 0x92a6,0x929a,0x92ab,0x9279,0x9297,0x927f,0x92a3,0x92ee,0x928e,0x9282, 0x9295,0x92a2,0x927d,0x9288,0x92a1,0x928a,0x9286,0x928c,0x9299,0x92a7, 0x927e,0x9287,0x92a9,0x929d }, { /* ku 2f */ 0x928b,0x922d,0x969e,0x96a1,0x96ff,0x9758,0x977d,0x977a,0x977e,0x9783, 0x9780,0x9782,0x977b,0x9784,0x9781,0x977f,0x97ce,0x97cd,0x9816,0x98ad, 0x98ae,0x9902,0x9900,0x9907,0x999d,0x999c,0x99c3,0x99b9,0x99bb,0x99ba, 0x99c2,0x99bd,0x99c7,0x9ab1,0x9ae3,0x9ae7,0x9b3e,0x9b3f,0x9b60,0x9b61, 0x9b5f,0x9cf1,0x9cf2,0x9cf5,0x9ea7,0x50ff,0x5103,0x5130,0x50f8,0x5106, 0x5107,0x50f6,0x50fe,0x510b,0x510c,0x50fd,0x510a,0x528b,0x528c,0x52f1, 0x52ef,0x5648,0x5642,0x564c,0x5635,0x5641,0x564a,0x5649,0x5646,0x5658, 0x565a,0x5640,0x5633,0x563d,0x562c,0x563e,0x5638,0x562a,0x563a,0x571a, 0x58ab,0x589d,0x58b1,0x58a0,0x58a3,0x58af,0x58ac,0x58a5,0x58a1,0x58ff, 0x5aff,0x5af4,0x5afd,0x5af7 }, { /* ku 30 */ 0x5af6,0x5b03,0x5af8,0x5b02,0x5af9,0x5b01,0x5b07,0x5b05,0x5b0f,0x5c67, 0x5d99,0x5d97,0x5d9f,0x5d92,0x5da2,0x5d93,0x5d95,0x5da0,0x5d9c,0x5da1, 0x5d9a,0x5d9e,0x5e69,0x5e5d,0x5e60,0x5e5c,0x7df3,0x5edb,0x5ede,0x5ee1, 0x5f49,0x5fb2,0x618b,0x6183,0x6179,0x61b1,0x61b0,0x61a2,0x6189,0x619b, 0x6193,0x61af,0x61ad,0x619f,0x6192,0x61aa,0x61a1,0x618d,0x6166,0x61b3, 0x622d,0x646e,0x6470,0x6496,0x64a0,0x6485,0x6497,0x649c,0x648f,0x648b, 0x648a,0x648c,0x64a3,0x649f,0x6468,0x64b1,0x6498,0x6576,0x657a,0x6579, 0x657b,0x65b2,0x65b3,0x66b5,0x66b0,0x66a9,0x66b2,0x66b7,0x66aa,0x66af, 0x6a00,0x6a06,0x6a17,0x69e5,0x69f8,0x6a15,0x69f1,0x69e4,0x6a20,0x69ff, 0x69ec,0x69e2,0x6a1b,0x6a1d }, { /* ku 31 */ 0x69fe,0x6a27,0x69f2,0x69ee,0x6a14,0x69f7,0x69e7,0x6a40,0x6a08,0x69e6, 0x69fb,0x6a0d,0x69fc,0x69eb,0x6a09,0x6a04,0x6a18,0x6a25,0x6a0f,0x69f6, 0x6a26,0x6a07,0x69f4,0x6a16,0x6b51,0x6ba5,0x6ba3,0x6ba2,0x6ba6,0x6c01, 0x6c00,0x6bff,0x6c02,0x6f41,0x6f26,0x6f7e,0x6f87,0x6fc6,0x6f92,0x6f8d, 0x6f89,0x6f8c,0x6f62,0x6f4f,0x6f85,0x6f5a,0x6f96,0x6f76,0x6f6c,0x6f82, 0x6f55,0x6f72,0x6f52,0x6f50,0x6f57,0x6f94,0x6f93,0x6f5d,0x6f00,0x6f61, 0x6f6b,0x6f7d,0x6f67,0x6f90,0x6f53,0x6f8b,0x6f69,0x6f7f,0x6f95,0x6f63, 0x6f77,0x6f6a,0x6f7b,0x71b2,0x71af,0x719b,0x71b0,0x71a0,0x719a,0x71a9, 0x71b5,0x719d,0x71a5,0x719e,0x71a4,0x71a1,0x71aa,0x719c,0x71a7,0x71b3, 0x7298,0x729a,0x7358,0x7352 }, { /* ku 32 */ 0x735e,0x735f,0x7360,0x735d,0x735b,0x7361,0x735a,0x7359,0x7362,0x7487, 0x7489,0x748a,0x7486,0x7481,0x747d,0x7485,0x7488,0x747c,0x7479,0x7508, 0x7507,0x757e,0x7625,0x761e,0x7619,0x761d,0x761c,0x7623,0x761a,0x7628, 0x761b,0x769c,0x769d,0x769e,0x769b,0x778d,0x778f,0x7789,0x7788,0x78cd, 0x78bb,0x78cf,0x78cc,0x78d1,0x78ce,0x78d4,0x78c8,0x78c3,0x78c4,0x78c9, 0x799a,0x79a1,0x79a0,0x799c,0x79a2,0x799b,0x6b76,0x7a39,0x7ab2,0x7ab4, 0x7ab3,0x7bb7,0x7bcb,0x7bbe,0x7bac,0x7bce,0x7baf,0x7bb9,0x7bca,0x7bb5, 0x7cc5,0x7cc8,0x7ccc,0x7ccb,0x7df7,0x7ddb,0x7dea,0x7de7,0x7dd7,0x7de1, 0x7e03,0x7dfa,0x7de6,0x7df6,0x7df1,0x7df0,0x7dee,0x7ddf,0x7f76,0x7fac, 0x7fb0,0x7fad,0x7fed,0x7feb }, { /* ku 33 */ 0x7fea,0x7fec,0x7fe6,0x7fe8,0x8064,0x8067,0x81a3,0x819f,0x819e,0x8195, 0x81a2,0x8199,0x8197,0x8216,0x824f,0x8253,0x8252,0x8250,0x824e,0x8251, 0x8524,0x853b,0x850f,0x8500,0x8529,0x850e,0x8509,0x850d,0x851f,0x850a, 0x8527,0x851c,0x84fb,0x852b,0x84fa,0x8508,0x850c,0x84f4,0x852a,0x84f2, 0x8515,0x84f7,0x84eb,0x84f3,0x84fc,0x8512,0x84ea,0x84e9,0x8516,0x84fe, 0x8528,0x851d,0x852e,0x8502,0x84fd,0x851e,0x84f6,0x8531,0x8526,0x84e7, 0x84e8,0x84f0,0x84ef,0x84f9,0x8518,0x8520,0x8530,0x850b,0x8519,0x852f, 0x8662,0x8756,0x8763,0x8764,0x8777,0x87e1,0x8773,0x8758,0x8754,0x875b, 0x8752,0x8761,0x875a,0x8751,0x875e,0x876d,0x876a,0x8750,0x874e,0x875f, 0x875d,0x876f,0x876c,0x877a }, { /* ku 34 */ 0x876e,0x875c,0x8765,0x874f,0x877b,0x8775,0x8762,0x8767,0x8769,0x885a, 0x8905,0x890c,0x8914,0x890b,0x8917,0x8918,0x8919,0x8906,0x8916,0x8911, 0x890e,0x8909,0x89a2,0x89a4,0x89a3,0x89ed,0x89f0,0x89ec,0x8acf,0x8ac6, 0x8ab8,0x8ad3,0x8ad1,0x8ad4,0x8ad5,0x8abb,0x8ad7,0x8abe,0x8ac0,0x8ac5, 0x8ad8,0x8ac3,0x8aba,0x8abd,0x8ad9,0x8c3e,0x8c4d,0x8c8f,0x8ce5,0x8cdf, 0x8cd9,0x8ce8,0x8cda,0x8cdd,0x8ce7,0x8da0,0x8d9c,0x8da1,0x8d9b,0x8e20, 0x8e23,0x8e25,0x8e24,0x8e2e,0x8e15,0x8e1b,0x8e16,0x8e11,0x8e19,0x8e26, 0x8e27,0x8e14,0x8e12,0x8e18,0x8e13,0x8e1c,0x8e17,0x8e1a,0x8f2c,0x8f24, 0x8f18,0x8f1a,0x8f20,0x8f23,0x8f16,0x8f17,0x9073,0x9070,0x906f,0x9067, 0x906b,0x912f,0x912b,0x9129 }, { /* ku 35 */ 0x912a,0x9132,0x9126,0x912e,0x9185,0x9186,0x918a,0x9181,0x9182,0x9184, 0x9180,0x92d0,0x92c3,0x92c4,0x92c0,0x92d9,0x92b6,0x92cf,0x92f1,0x92df, 0x92d8,0x92e9,0x92d7,0x92dd,0x92cc,0x92ef,0x92c2,0x92e8,0x92ca,0x92c8, 0x92ce,0x92e6,0x92cd,0x92d5,0x92c9,0x92e0,0x92de,0x92e7,0x92d1,0x92d3, 0x92b5,0x92e1,0x9325,0x92c6,0x92b4,0x957c,0x95ac,0x95ab,0x95ae,0x95b0, 0x96a4,0x96a2,0x96d3,0x9705,0x9708,0x9702,0x975a,0x978a,0x978e,0x9788, 0x97d0,0x97cf,0x981e,0x981d,0x9826,0x9829,0x9828,0x9820,0x981b,0x9827, 0x98b2,0x9908,0x98fa,0x9911,0x9914,0x9916,0x9917,0x9915,0x99dc,0x99cd, 0x99cf,0x99d3,0x99d4,0x99ce,0x99c9,0x99d6,0x99d8,0x99cb,0x99d7,0x99cc, 0x9ab3,0x9aec,0x9aeb,0x9af3 }, { /* ku 36 */ 0x9af2,0x9af1,0x9b46,0x9b43,0x9b67,0x9b74,0x9b71,0x9b66,0x9b76,0x9b75, 0x9b70,0x9b68,0x9b64,0x9b6c,0x9cfc,0x9cfa,0x9cfd,0x9cff,0x9cf7,0x9d07, 0x9d00,0x9cf9,0x9cfb,0x9d08,0x9d05,0x9d04,0x9e83,0x9ed3,0x9f0f,0x9f10, 0x511c,0x5113,0x5117,0x511a,0x5111,0x51de,0x5334,0x53e1,0x5670,0x5660, 0x566e,0x5673,0x5666,0x5663,0x566d,0x5672,0x565e,0x5677,0x571c,0x571b, 0x58c8,0x58bd,0x58c9,0x58bf,0x58ba,0x58c2,0x58bc,0x58c6,0x5b17,0x5b19, 0x5b1b,0x5b21,0x5b14,0x5b13,0x5b10,0x5b16,0x5b28,0x5b1a,0x5b20,0x5b1e, 0x5bef,0x5dac,0x5db1,0x5da9,0x5da7,0x5db5,0x5db0,0x5dae,0x5daa,0x5da8, 0x5db2,0x5dad,0x5daf,0x5db4,0x5e67,0x5e68,0x5e66,0x5e6f,0x5ee9,0x5ee7, 0x5ee6,0x5ee8,0x5ee5,0x5f4b }, { /* ku 37 */ 0x5fbc,0x5fbb,0x619d,0x61a8,0x6196,0x61c5,0x61b4,0x61c6,0x61c1,0x61cc, 0x61ba,0x61bf,0x61b8,0x618c,0x64d7,0x64d6,0x64d0,0x64cf,0x64c9,0x64bd, 0x6489,0x64c3,0x64db,0x64f3,0x64d9,0x6533,0x657f,0x657c,0x65a2,0x66c8, 0x66be,0x66c0,0x66ca,0x66cb,0x66cf,0x66bd,0x66bb,0x66ba,0x66cc,0x6723, 0x6a34,0x6a66,0x6a49,0x6a67,0x6a32,0x6a68,0x6a3e,0x6a5d,0x6a6d,0x6a76, 0x6a5b,0x6a51,0x6a28,0x6a5a,0x6a3b,0x6a3f,0x6a41,0x6a6a,0x6a64,0x6a50, 0x6a4f,0x6a54,0x6a6f,0x6a69,0x6a60,0x6a3c,0x6a5e,0x6a56,0x6a55,0x6a4d, 0x6a4e,0x6a46,0x6b55,0x6b54,0x6b56,0x6ba7,0x6baa,0x6bab,0x6bc8,0x6bc7, 0x6c04,0x6c03,0x6c06,0x6fad,0x6fcb,0x6fa3,0x6fc7,0x6fbc,0x6fce,0x6fc8, 0x6f5e,0x6fc4,0x6fbd,0x6f9e }, { /* ku 38 */ 0x6fca,0x6fa8,0x7004,0x6fa5,0x6fae,0x6fba,0x6fac,0x6faa,0x6fcf,0x6fbf, 0x6fb8,0x6fa2,0x6fc9,0x6fab,0x6fcd,0x6faf,0x6fb2,0x6fb0,0x71c5,0x71c2, 0x71bf,0x71b8,0x71d6,0x71c0,0x71c1,0x71cb,0x71d4,0x71ca,0x71c7,0x71cf, 0x71bd,0x71d8,0x71bc,0x71c6,0x71da,0x71db,0x729d,0x729e,0x7369,0x7366, 0x7367,0x736c,0x7365,0x736b,0x736a,0x747f,0x749a,0x74a0,0x7494,0x7492, 0x7495,0x74a1,0x750b,0x7580,0x762f,0x762d,0x7631,0x763d,0x7633,0x763c, 0x7635,0x7632,0x7630,0x76bb,0x76e6,0x779a,0x779d,0x77a1,0x779c,0x779b, 0x77a2,0x77a3,0x7795,0x7799,0x7797,0x78dd,0x78e9,0x78e5,0x78ea,0x78de, 0x78e3,0x78db,0x78e1,0x78e2,0x78ed,0x78df,0x78e0,0x79a4,0x7a44,0x7a48, 0x7a47,0x7ab6,0x7ab8,0x7ab5 }, { /* ku 39 */ 0x7ab1,0x7ab7,0x7bde,0x7be3,0x7be7,0x7bdd,0x7bd5,0x7be5,0x7bda,0x7be8, 0x7bf9,0x7bd4,0x7bea,0x7be2,0x7bdc,0x7beb,0x7bd8,0x7bdf,0x7cd2,0x7cd4, 0x7cd7,0x7cd0,0x7cd1,0x7e12,0x7e21,0x7e17,0x7e0c,0x7e1f,0x7e20,0x7e13, 0x7e0e,0x7e1c,0x7e15,0x7e1a,0x7e22,0x7e0b,0x7e0f,0x7e16,0x7e0d,0x7e14, 0x7e25,0x7e24,0x7f43,0x7f7b,0x7f7c,0x7f7a,0x7fb1,0x7fef,0x802a,0x8029, 0x806c,0x81b1,0x81a6,0x81ae,0x81b9,0x81b5,0x81ab,0x81b0,0x81ac,0x81b4, 0x81b2,0x81b7,0x81a7,0x81f2,0x8255,0x8256,0x8257,0x8556,0x8545,0x856b, 0x854d,0x8553,0x8561,0x8558,0x8540,0x8546,0x8564,0x8541,0x8562,0x8544, 0x8551,0x8547,0x8563,0x853e,0x855b,0x8571,0x854e,0x856e,0x8575,0x8555, 0x8567,0x8560,0x858c,0x8566 }, { /* ku 3a */ 0x855d,0x8554,0x8565,0x856c,0x8663,0x8665,0x8664,0x87a4,0x879b,0x878f, 0x8797,0x8793,0x8792,0x8788,0x8781,0x8796,0x8798,0x8779,0x8787,0x87a3, 0x8785,0x8790,0x8791,0x879d,0x8784,0x8794,0x879c,0x879a,0x8789,0x891e, 0x8926,0x8930,0x892d,0x892e,0x8927,0x8931,0x8922,0x8929,0x8923,0x892f, 0x892c,0x891f,0x89f1,0x8ae0,0x8ae2,0x8af2,0x8af4,0x8af5,0x8add,0x8b14, 0x8ae4,0x8adf,0x8af0,0x8ac8,0x8ade,0x8ae1,0x8ae8,0x8aff,0x8aef,0x8afb, 0x8c91,0x8c92,0x8c90,0x8cf5,0x8cee,0x8cf1,0x8cf0,0x8cf3,0x8d6c,0x8d6e, 0x8da5,0x8da7,0x8e33,0x8e3e,0x8e38,0x8e40,0x8e45,0x8e36,0x8e3c,0x8e3d, 0x8e41,0x8e30,0x8e3f,0x8ebd,0x8f36,0x8f2e,0x8f35,0x8f32,0x8f39,0x8f37, 0x8f34,0x9076,0x9079,0x907b }, { /* ku 3b */ 0x9086,0x90fa,0x9133,0x9135,0x9136,0x9193,0x9190,0x9191,0x918d,0x918f, 0x9327,0x931e,0x9308,0x931f,0x9306,0x930f,0x937a,0x9338,0x933c,0x931b, 0x9323,0x9312,0x9301,0x9346,0x932d,0x930e,0x930d,0x92cb,0x931d,0x92fa, 0x9313,0x92f9,0x92f7,0x9334,0x9302,0x9324,0x92ff,0x9329,0x9339,0x9335, 0x932a,0x9314,0x930c,0x930b,0x92fe,0x9309,0x9300,0x92fb,0x9316,0x95bc, 0x95cd,0x95be,0x95b9,0x95ba,0x95b6,0x95bf,0x95b5,0x95bd,0x96a9,0x96d4, 0x970b,0x9712,0x9710,0x9799,0x9797,0x9794,0x97f0,0x97f8,0x9835,0x982f, 0x9832,0x9924,0x991f,0x9927,0x9929,0x999e,0x99ee,0x99ec,0x99e5,0x99e4, 0x99f0,0x99e3,0x99ea,0x99e9,0x99e7,0x9ab9,0x9abf,0x9ab4,0x9abb,0x9af6, 0x9afa,0x9af9,0x9af7,0x9b33 }, { /* ku 3c */ 0x9b80,0x9b85,0x9b87,0x9b7c,0x9b7e,0x9b7b,0x9b82,0x9b93,0x9b92,0x9b90, 0x9b7a,0x9b95,0x9b7d,0x9b88,0x9d25,0x9d17,0x9d20,0x9d1e,0x9d14,0x9d29, 0x9d1d,0x9d18,0x9d22,0x9d10,0x9d19,0x9d1f,0x9e88,0x9e86,0x9e87,0x9eae, 0x9ead,0x9ed5,0x9ed6,0x9efa,0x9f12,0x9f3d,0x5126,0x5125,0x5122,0x5124, 0x5120,0x5129,0x52f4,0x5693,0x568c,0x568d,0x5686,0x5684,0x5683,0x567e, 0x5682,0x567f,0x5681,0x58d6,0x58d4,0x58cf,0x58d2,0x5b2d,0x5b25,0x5b32, 0x5b23,0x5b2c,0x5b27,0x5b26,0x5b2f,0x5b2e,0x5b7b,0x5bf1,0x5bf2,0x5db7, 0x5e6c,0x5e6a,0x5fbe,0x61c3,0x61b5,0x61bc,0x61e7,0x61e0,0x61e5,0x61e4, 0x61e8,0x61de,0x64ef,0x64e9,0x64e3,0x64eb,0x64e4,0x64e8,0x6581,0x6580, 0x65b6,0x65da,0x66d2,0x6a8d }, { /* ku 3d */ 0x6a96,0x6a81,0x6aa5,0x6a89,0x6a9f,0x6a9b,0x6aa1,0x6a9e,0x6a87,0x6a93, 0x6a8e,0x6a95,0x6a83,0x6aa8,0x6aa4,0x6a91,0x6a7f,0x6aa6,0x6a9a,0x6a85, 0x6a8c,0x6a92,0x6b5b,0x6bad,0x6c09,0x6fcc,0x6fa9,0x6ff4,0x6fd4,0x6fe3, 0x6fdc,0x6fed,0x6fe7,0x6fe6,0x6fde,0x6ff2,0x6fdd,0x6fe2,0x6fe8,0x71e1, 0x71f1,0x71e8,0x71f2,0x71e4,0x71f0,0x71e2,0x7373,0x736e,0x736f,0x7497, 0x74b2,0x74ab,0x7490,0x74aa,0x74ad,0x74b1,0x74a5,0x74af,0x7510,0x7511, 0x7512,0x750f,0x7584,0x7643,0x7648,0x7649,0x7647,0x76a4,0x76e9,0x77b5, 0x77ab,0x77b2,0x77b7,0x77b6,0x77b4,0x77b1,0x77a8,0x77f0,0x78f3,0x78fd, 0x7902,0x78fb,0x78fc,0x78ff,0x78f2,0x7905,0x78f9,0x78fe,0x7904,0x79ab, 0x79a8,0x7a5c,0x7a5b,0x7a56 }, { /* ku 3e */ 0x7a58,0x7a54,0x7a5a,0x7abe,0x7ac0,0x7ac1,0x7c05,0x7c0f,0x7bf2,0x7c00, 0x7bff,0x7bfb,0x7c0e,0x7bf4,0x7c0b,0x7bf3,0x7c02,0x7c09,0x7c03,0x7c01, 0x7bf8,0x7bfd,0x7c06,0x7bf0,0x7bf1,0x7c10,0x7c0a,0x7ce8,0x7e2d,0x7e3c, 0x7e42,0x7e33,0x9848,0x7e38,0x7e2a,0x7e49,0x7e40,0x7e47,0x7e29,0x7e4c, 0x7e30,0x7e3b,0x7e36,0x7e44,0x7e3a,0x7f45,0x7f7f,0x7f7e,0x7f7d,0x7ff4, 0x7ff2,0x802c,0x81bb,0x81c4,0x81cc,0x81ca,0x81c5,0x81c7,0x81bc,0x81e9, 0x825b,0x825a,0x825c,0x8583,0x8580,0x858f,0x85a7,0x8595,0x85a0,0x858b, 0x85a3,0x857b,0x85a4,0x859a,0x859e,0x8577,0x857c,0x8589,0x85a1,0x857a, 0x8578,0x8557,0x858e,0x8596,0x8586,0x858d,0x8599,0x859d,0x8581,0x85a2, 0x8582,0x8588,0x8585,0x8579 }, { /* ku 3f */ 0x8576,0x8598,0x8590,0x859f,0x8668,0x87be,0x87aa,0x87ad,0x87c5,0x87b0, 0x87ac,0x87b9,0x87b5,0x87bc,0x87ae,0x87c9,0x87c3,0x87c2,0x87cc,0x87b7, 0x87af,0x87c4,0x87ca,0x87b4,0x87b6,0x87bf,0x87b8,0x87bd,0x87de,0x87b2, 0x8935,0x8933,0x893c,0x893e,0x8941,0x8952,0x8937,0x8942,0x89ad,0x89af, 0x89ae,0x89f2,0x89f3,0x8b1e,0x8b18,0x8b16,0x8b11,0x8b05,0x8b0b,0x8b22, 0x8b0f,0x8b12,0x8b15,0x8b07,0x8b0d,0x8b08,0x8b06,0x8b1c,0x8b13,0x8b1a, 0x8c4f,0x8c70,0x8c72,0x8c71,0x8c6f,0x8c95,0x8c94,0x8cf9,0x8d6f,0x8e4e, 0x8e4d,0x8e53,0x8e50,0x8e4c,0x8e47,0x8f43,0x8f40,0x9085,0x907e,0x9138, 0x919a,0x91a2,0x919b,0x9199,0x919f,0x91a1,0x919d,0x91a0,0x93a1,0x9383, 0x93af,0x9364,0x9356,0x9347 }, { /* ku 40 */ 0x937c,0x9358,0x935c,0x9376,0x9349,0x9350,0x9351,0x9360,0x936d,0x938f, 0x934c,0x936a,0x9379,0x9357,0x9355,0x9352,0x934f,0x9371,0x9377,0x937b, 0x9361,0x935e,0x9363,0x9367,0x934e,0x9359,0x95c7,0x95c0,0x95c9,0x95c3, 0x95c5,0x95b7,0x96ae,0x96b0,0x96ac,0x9720,0x971f,0x9718,0x971d,0x9719, 0x979a,0x97a1,0x979c,0x979e,0x979d,0x97d5,0x97d4,0x97f1,0x9841,0x9844, 0x984a,0x9849,0x9845,0x9843,0x9925,0x992b,0x992c,0x992a,0x9933,0x9932, 0x992f,0x992d,0x9931,0x9930,0x9998,0x99a3,0x99a1,0x9a02,0x99fa,0x99f4, 0x99f7,0x99f9,0x99f8,0x99f6,0x99fb,0x99fd,0x99fe,0x99fc,0x9a03,0x9abe, 0x9afe,0x9afd,0x9b01,0x9afc,0x9b48,0x9b9a,0x9ba8,0x9b9e,0x9b9b,0x9ba6, 0x9ba1,0x9ba5,0x9ba4,0x9b86 }, { /* ku 41 */ 0x9ba2,0x9ba0,0x9baf,0x9d33,0x9d41,0x9d67,0x9d36,0x9d2e,0x9d2f,0x9d31, 0x9d38,0x9d30,0x9d45,0x9d42,0x9d43,0x9d3e,0x9d37,0x9d40,0x9d3d,0x7ff5, 0x9d2d,0x9e8a,0x9e89,0x9e8d,0x9eb0,0x9ec8,0x9eda,0x9efb,0x9eff,0x9f24, 0x9f23,0x9f22,0x9f54,0x9fa0,0x5131,0x512d,0x512e,0x5698,0x569c,0x5697, 0x569a,0x569d,0x5699,0x5970,0x5b3c,0x5c69,0x5c6a,0x5dc0,0x5e6d,0x5e6e, 0x61d8,0x61df,0x61ed,0x61ee,0x61f1,0x61ea,0x61f0,0x61eb,0x61d6,0x61e9, 0x64ff,0x6504,0x64fd,0x64f8,0x6501,0x6503,0x64fc,0x6594,0x65db,0x66da, 0x66db,0x66d8,0x6ac5,0x6ab9,0x6abd,0x6ae1,0x6ac6,0x6aba,0x6ab6,0x6ab7, 0x6ac7,0x6ab4,0x6aad,0x6b5e,0x6bc9,0x6c0b,0x7007,0x700c,0x700d,0x7001, 0x7005,0x7014,0x700e,0x6fff }, { /* ku 42 */ 0x7000,0x6ffb,0x7026,0x6ffc,0x6ff7,0x700a,0x7201,0x71ff,0x71f9,0x7203, 0x71fd,0x7376,0x74b8,0x74c0,0x74b5,0x74c1,0x74be,0x74b6,0x74bb,0x74c2, 0x7514,0x7513,0x765c,0x7664,0x7659,0x7650,0x7653,0x7657,0x765a,0x76a6, 0x76bd,0x76ec,0x77c2,0x77ba,0x790c,0x7913,0x7914,0x7909,0x7910,0x7912, 0x7911,0x79ad,0x79ac,0x7a5f,0x7c1c,0x7c29,0x7c19,0x7c20,0x7c1f,0x7c2d, 0x7c1d,0x7c26,0x7c28,0x7c22,0x7c25,0x7c30,0x7e5c,0x7e50,0x7e56,0x7e63, 0x7e58,0x7e62,0x7e5f,0x7e51,0x7e60,0x7e57,0x7e53,0x7fb5,0x7fb3,0x7ff7, 0x7ff8,0x8075,0x81d1,0x81d2,0x81d0,0x825f,0x825e,0x85b4,0x85c6,0x85c0, 0x85c3,0x85c2,0x85b3,0x85b5,0x85bd,0x85c7,0x85c4,0x85bf,0x85cb,0x85ce, 0x85c8,0x85c5,0x85b1,0x85b6 }, { /* ku 43 */ 0x85d2,0x8624,0x85b8,0x85b7,0x85be,0x8669,0x87e7,0x87e6,0x87e2,0x87db, 0x87eb,0x87ea,0x87e5,0x87df,0x87f3,0x87e4,0x87d4,0x87dc,0x87d3,0x87ed, 0x87d8,0x87e3,0x87d7,0x87d9,0x8801,0x87f4,0x87e8,0x87dd,0x8953,0x894b, 0x894f,0x894c,0x8946,0x8950,0x8951,0x8949,0x8b2a,0x8b27,0x8b23,0x8b33, 0x8b30,0x8b35,0x8b47,0x8b2f,0x8b3c,0x8b3e,0x8b31,0x8b25,0x8b37,0x8b26, 0x8b36,0x8b2e,0x8b24,0x8b3b,0x8b3d,0x8b3a,0x8c42,0x8c75,0x8c99,0x8c98, 0x8c97,0x8cfe,0x8d04,0x8d02,0x8d00,0x8e5c,0x8e62,0x8e60,0x8e57,0x8e56, 0x8e5e,0x8e65,0x8e67,0x8e5b,0x8e5a,0x8e61,0x8e5d,0x8e69,0x8e54,0x8f46, 0x8f47,0x8f48,0x8f4b,0x9128,0x913a,0x913b,0x913e,0x91a8,0x91a5,0x91a7, 0x91af,0x91aa,0x93b5,0x938c }, { /* ku 44 */ 0x9392,0x93b7,0x939b,0x939d,0x9389,0x93a7,0x938e,0x93aa,0x939e,0x93a6, 0x9395,0x9388,0x9399,0x939f,0x9380,0x938d,0x93b1,0x9391,0x93b2,0x93a4, 0x93a8,0x93b4,0x93a3,0x95d2,0x95d3,0x95d1,0x96b3,0x96d7,0x96da,0x5dc2, 0x96df,0x96d8,0x96dd,0x9723,0x9722,0x9725,0x97ac,0x97ae,0x97a8,0x97ab, 0x97a4,0x97aa,0x97a2,0x97a5,0x97d7,0x97d9,0x97d6,0x97d8,0x97fa,0x9850, 0x9851,0x9852,0x98b8,0x9941,0x993c,0x993a,0x9a0f,0x9a0b,0x9a09,0x9a0d, 0x9a04,0x9a11,0x9a0a,0x9a05,0x9a07,0x9a06,0x9ac0,0x9adc,0x9b08,0x9b04, 0x9b05,0x9b29,0x9b35,0x9b4a,0x9b4c,0x9b4b,0x9bc7,0x9bc6,0x9bc3,0x9bbf, 0x9bc1,0x9bb5,0x9bb8,0x9bd3,0x9bb6,0x9bc4,0x9bb9,0x9bbd,0x9d5c,0x9d53, 0x9d4f,0x9d4a,0x9d5b,0x9d4b }, { /* ku 45 */ 0x9d59,0x9d56,0x9d4c,0x9d57,0x9d52,0x9d54,0x9d5f,0x9d58,0x9d5a,0x9e8e, 0x9e8c,0x9edf,0x9f01,0x9f00,0x9f16,0x9f25,0x9f2b,0x9f2a,0x9f29,0x9f28, 0x9f4c,0x9f55,0x5134,0x5135,0x5296,0x52f7,0x53b4,0x56ab,0x56ad,0x56a6, 0x56a7,0x56aa,0x56ac,0x58da,0x58dd,0x58db,0x5912,0x5b3d,0x5b3e,0x5b3f, 0x5dc3,0x5e70,0x5fbf,0x61fb,0x6507,0x6510,0x650d,0x6509,0x650c,0x650e, 0x6584,0x65de,0x65dd,0x66de,0x6ae7,0x6ae0,0x6acc,0x6ad1,0x6ad9,0x6acb, 0x6adf,0x6adc,0x6ad0,0x6aeb,0x6acf,0x6acd,0x6ade,0x6b60,0x6bb0,0x6c0c, 0x7019,0x7027,0x7020,0x7016,0x702b,0x7021,0x7022,0x7023,0x7029,0x7017, 0x7024,0x701c,0x720c,0x720a,0x7207,0x7202,0x7205,0x72a5,0x72a6,0x72a4, 0x72a3,0x72a1,0x74cb,0x74c5 }, { /* ku 46 */ 0x74b7,0x74c3,0x7516,0x7660,0x77c9,0x77ca,0x77c4,0x77f1,0x791d,0x791b, 0x7921,0x791c,0x7917,0x791e,0x79b0,0x7a67,0x7a68,0x7c33,0x7c3c,0x7c39, 0x7c2c,0x7c3b,0x7cec,0x7cea,0x7e76,0x7e75,0x7e78,0x7e70,0x7e77,0x7e6f, 0x7e7a,0x7e72,0x7e74,0x7e68,0x7f4b,0x7f4a,0x7f83,0x7f86,0x7fb7,0x7ffd, 0x7ffe,0x8078,0x81d7,0x81d5,0x820b,0x8264,0x8261,0x8263,0x85eb,0x85f1, 0x85ed,0x85d9,0x85e1,0x85e8,0x85da,0x85d7,0x85ec,0x85f2,0x85f8,0x85d8, 0x85df,0x85e3,0x85dc,0x85d1,0x85f0,0x85e6,0x85ef,0x85de,0x85e2,0x8800, 0x87fa,0x8803,0x87f6,0x87f7,0x8809,0x880c,0x880b,0x8806,0x87fc,0x8808, 0x87ff,0x880a,0x8802,0x8962,0x895a,0x895b,0x8957,0x8961,0x895c,0x8958, 0x895d,0x8959,0x8988,0x89b7 }, { /* ku 47 */ 0x89b6,0x89f6,0x8b50,0x8b48,0x8b4a,0x8b40,0x8b53,0x8b56,0x8b54,0x8b4b, 0x8b55,0x8b51,0x8b42,0x8b52,0x8b57,0x8c43,0x8c77,0x8c76,0x8c9a,0x8d06, 0x8d07,0x8d09,0x8dac,0x8daa,0x8dad,0x8dab,0x8e6d,0x8e78,0x8e73,0x8e6a, 0x8e6f,0x8e7b,0x8ec2,0x8f52,0x8f51,0x8f4f,0x8f50,0x8f53,0x8fb4,0x9140, 0x913f,0x91b0,0x91ad,0x93de,0x93c7,0x93cf,0x93c2,0x93da,0x93d0,0x93f9, 0x93ec,0x93cc,0x93d9,0x93a9,0x93e6,0x93ca,0x93d4,0x93ee,0x93e3,0x93d5, 0x93c4,0x93ce,0x93c0,0x93d2,0x93a5,0x93e7,0x957d,0x95da,0x95db,0x96e1, 0x9729,0x972b,0x972c,0x9728,0x9726,0x97b3,0x97b7,0x97b6,0x97dd,0x97de, 0x97df,0x985c,0x9859,0x985d,0x9857,0x98bf,0x98bd,0x98bb,0x98be,0x9948, 0x9947,0x9943,0x99a6,0x99a7 }, { /* ku 48 */ 0x9a1a,0x9a15,0x9a25,0x9a1d,0x9a24,0x9a1b,0x9a22,0x9a20,0x9a27,0x9a23, 0x9a1e,0x9a1c,0x9a14,0x9ac2,0x9b0b,0x9b0a,0x9b0e,0x9b0c,0x9b37,0x9bea, 0x9beb,0x9be0,0x9bde,0x9be4,0x9be6,0x9be2,0x9bf0,0x9bd4,0x9bd7,0x9bec, 0x9bdc,0x9bd9,0x9be5,0x9bd5,0x9be1,0x9bda,0x9d77,0x9d81,0x9d8a,0x9d84, 0x9d88,0x9d71,0x9d80,0x9d78,0x9d86,0x9d8b,0x9d8c,0x9d7d,0x9d6b,0x9d74, 0x9d75,0x9d70,0x9d69,0x9d85,0x9d73,0x9d7b,0x9d82,0x9d6f,0x9d79,0x9d7f, 0x9d87,0x9d68,0x9e94,0x9e91,0x9ec0,0x9efc,0x9f2d,0x9f40,0x9f41,0x9f4d, 0x9f56,0x9f57,0x9f58,0x5337,0x56b2,0x56b5,0x56b3,0x58e3,0x5b45,0x5dc6, 0x5dc7,0x5eee,0x5eef,0x5fc0,0x5fc1,0x61f9,0x6517,0x6516,0x6515,0x6513, 0x65df,0x66e8,0x66e3,0x66e4 }, { /* ku 49 */ 0x6af3,0x6af0,0x6aea,0x6ae8,0x6af9,0x6af1,0x6aee,0x6aef,0x703c,0x7035, 0x702f,0x7037,0x7034,0x7031,0x7042,0x7038,0x703f,0x703a,0x7039,0x702a, 0x7040,0x703b,0x7033,0x7041,0x7213,0x7214,0x72a8,0x737d,0x737c,0x74ba, 0x76ab,0x76aa,0x76be,0x76ed,0x77cc,0x77ce,0x77cf,0x77cd,0x77f2,0x7925, 0x7923,0x7927,0x7928,0x7924,0x7929,0x79b2,0x7a6e,0x7a6c,0x7a6d,0x7af7, 0x7c49,0x7c48,0x7c4a,0x7c47,0x7c45,0x7cee,0x7e7b,0x7e7e,0x7e81,0x7e80, 0x7fba,0x7fff,0x8079,0x81db,0x81d9,0x8268,0x8269,0x8622,0x85ff,0x8601, 0x85fe,0x861b,0x8600,0x85f6,0x8604,0x8609,0x8605,0x860c,0x85fd,0x8819, 0x8810,0x8811,0x8817,0x8813,0x8816,0x8963,0x8966,0x89b9,0x89f7,0x8b60, 0x8b6a,0x8b5d,0x8b68,0x8b63 }, { /* ku 4a */ 0x8b65,0x8b67,0x8b6d,0x8dae,0x8e86,0x8e88,0x8e84,0x8f59,0x8f56,0x8f57, 0x8f55,0x8f58,0x8f5a,0x908d,0x9143,0x9141,0x91b7,0x91b5,0x91b2,0x91b3, 0x940b,0x9413,0x93fb,0x9420,0x940f,0x9414,0x93fe,0x9415,0x9410,0x9428, 0x9419,0x940d,0x93f5,0x9400,0x93f7,0x9407,0x940e,0x9416,0x9412,0x93fa, 0x9409,0x93f8,0x943c,0x940a,0x93ff,0x93fc,0x940c,0x93f6,0x9411,0x9406, 0x95de,0x95e0,0x95df,0x972e,0x972f,0x97b9,0x97bb,0x97fd,0x97fe,0x9860, 0x9862,0x9863,0x985f,0x98c1,0x98c2,0x9950,0x994e,0x9959,0x994c,0x994b, 0x9953,0x9a32,0x9a34,0x9a31,0x9a2c,0x9a2a,0x9a36,0x9a29,0x9a2e,0x9a38, 0x9a2d,0x9ac7,0x9aca,0x9ac6,0x9b10,0x9b12,0x9b11,0x9c0b,0x9c08,0x9bf7, 0x9c05,0x9c12,0x9bf8,0x9c40 }, { /* ku 4b */ 0x9c07,0x9c0e,0x9c06,0x9c17,0x9c14,0x9c09,0x9d9f,0x9d99,0x9da4,0x9d9d, 0x9d92,0x9d98,0x9d90,0x9d9b,0x9da0,0x9d94,0x9d9c,0x9daa,0x9d97,0x9da1, 0x9d9a,0x9da2,0x9da8,0x9d9e,0x9da3,0x9dbf,0x9da9,0x9d96,0x9da6,0x9da7, 0x9e99,0x9e9b,0x9e9a,0x9ee5,0x9ee4,0x9ee7,0x9ee6,0x9f30,0x9f2e,0x9f5b, 0x9f60,0x9f5e,0x9f5d,0x9f59,0x9f91,0x513a,0x5139,0x5298,0x5297,0x56c3, 0x56bd,0x56be,0x5b48,0x5b47,0x5dcb,0x5dcf,0x5ef1,0x61fd,0x651b,0x6b02, 0x6afc,0x6b03,0x6af8,0x6b00,0x7043,0x7044,0x704a,0x7048,0x7049,0x7045, 0x7046,0x721d,0x721a,0x7219,0x737e,0x7517,0x766a,0x77d0,0x792d,0x7931, 0x792f,0x7c54,0x7c53,0x7cf2,0x7e8a,0x7e87,0x7e88,0x7e8b,0x7e86,0x7e8d, 0x7f4d,0x7fbb,0x8030,0x81dd }, { /* ku 4c */ 0x8618,0x862a,0x8626,0x861f,0x8623,0x861c,0x8619,0x8627,0x862e,0x8621, 0x8620,0x8629,0x861e,0x8625,0x8829,0x881d,0x881b,0x8820,0x8824,0x881c, 0x882b,0x884a,0x896d,0x8969,0x896e,0x896b,0x89fa,0x8b79,0x8b78,0x8b45, 0x8b7a,0x8b7b,0x8d10,0x8d14,0x8daf,0x8e8e,0x8e8c,0x8f5e,0x8f5b,0x8f5d, 0x9146,0x9144,0x9145,0x91b9,0x943f,0x943b,0x9436,0x9429,0x943d,0x9430, 0x9439,0x942a,0x9437,0x942c,0x9440,0x9431,0x95e5,0x95e4,0x95e3,0x9735, 0x973a,0x97bf,0x97e1,0x9864,0x98c9,0x98c6,0x98c0,0x9958,0x9956,0x9a39, 0x9a3d,0x9a46,0x9a44,0x9a42,0x9a41,0x9a3a,0x9a3f,0x9acd,0x9b15,0x9b17, 0x9b18,0x9b16,0x9b3a,0x9b52,0x9c2b,0x9c1d,0x9c1c,0x9c2c,0x9c23,0x9c28, 0x9c29,0x9c24,0x9c21,0x9db7 }, { /* ku 4d */ 0x9db6,0x9dbc,0x9dc1,0x9dc7,0x9dca,0x9dcf,0x9dbe,0x9dc5,0x9dc3,0x9dbb, 0x9db5,0x9dce,0x9db9,0x9dba,0x9dac,0x9dc8,0x9db1,0x9dad,0x9dcc,0x9db3, 0x9dcd,0x9db2,0x9e7a,0x9e9c,0x9eeb,0x9eee,0x9eed,0x9f1b,0x9f18,0x9f1a, 0x9f31,0x9f4e,0x9f65,0x9f64,0x9f92,0x4eb9,0x56c6,0x56c5,0x56cb,0x5971, 0x5b4b,0x5b4c,0x5dd5,0x5dd1,0x5ef2,0x6521,0x6520,0x6526,0x6522,0x6b0b, 0x6b08,0x6b09,0x6c0d,0x7055,0x7056,0x7057,0x7052,0x721e,0x721f,0x72a9, 0x737f,0x74d8,0x74d5,0x74d9,0x74d7,0x766d,0x76ad,0x7935,0x79b4,0x7a70, 0x7a71,0x7c57,0x7c5c,0x7c59,0x7c5b,0x7c5a,0x7cf4,0x7cf1,0x7e91,0x7f4f, 0x7f87,0x81de,0x826b,0x8634,0x8635,0x8633,0x862c,0x8632,0x8636,0x882c, 0x8828,0x8826,0x882a,0x8825 }, { /* ku 4e */ 0x8971,0x89bf,0x89be,0x89fb,0x8b7e,0x8b84,0x8b82,0x8b86,0x8b85,0x8b7f, 0x8d15,0x8e95,0x8e94,0x8e9a,0x8e92,0x8e90,0x8e96,0x8e97,0x8f60,0x8f62, 0x9147,0x944c,0x9450,0x944a,0x944b,0x944f,0x9447,0x9445,0x9448,0x9449, 0x9446,0x973f,0x97e3,0x986a,0x9869,0x98cb,0x9954,0x995b,0x9a4e,0x9a53, 0x9a54,0x9a4c,0x9a4f,0x9a48,0x9a4a,0x9a49,0x9a52,0x9a50,0x9ad0,0x9b19, 0x9b2b,0x9b3b,0x9b56,0x9b55,0x9c46,0x9c48,0x9c3f,0x9c44,0x9c39,0x9c33, 0x9c41,0x9c3c,0x9c37,0x9c34,0x9c32,0x9c3d,0x9c36,0x9ddb,0x9dd2,0x9dde, 0x9dda,0x9dcb,0x9dd0,0x9ddc,0x9dd1,0x9ddf,0x9de9,0x9dd9,0x9dd8,0x9dd6, 0x9df5,0x9dd5,0x9ddd,0x9eb6,0x9ef0,0x9f35,0x9f33,0x9f32,0x9f42,0x9f6b, 0x9f95,0x9fa2,0x513d,0x5299 }, { /* ku 4f */ 0x58e8,0x58e7,0x5972,0x5b4d,0x5dd8,0x882f,0x5f4f,0x6201,0x6203,0x6204, 0x6529,0x6525,0x6596,0x66eb,0x6b11,0x6b12,0x6b0f,0x6bca,0x705b,0x705a, 0x7222,0x7382,0x7381,0x7383,0x7670,0x77d4,0x7c67,0x7c66,0x7e95,0x826c, 0x863a,0x8640,0x8639,0x863c,0x8631,0x863b,0x863e,0x8830,0x8832,0x882e, 0x8833,0x8976,0x8974,0x8973,0x89fe,0x8b8c,0x8b8e,0x8b8b,0x8b88,0x8c45, 0x8d19,0x8e98,0x8f64,0x8f63,0x91bc,0x9462,0x9455,0x945d,0x9457,0x945e, 0x97c4,0x97c5,0x9800,0x9a56,0x9a59,0x9b1e,0x9b1f,0x9b20,0x9c52,0x9c58, 0x9c50,0x9c4a,0x9c4d,0x9c4b,0x9c55,0x9c59,0x9c4c,0x9c4e,0x9dfb,0x9df7, 0x9def,0x9de3,0x9deb,0x9df8,0x9de4,0x9df6,0x9de1,0x9dee,0x9de6,0x9df2, 0x9df0,0x9de2,0x9dec,0x9df4 }, { /* ku 50 */ 0x9df3,0x9de8,0x9ded,0x9ec2,0x9ed0,0x9ef2,0x9ef3,0x9f06,0x9f1c,0x9f38, 0x9f37,0x9f36,0x9f43,0x9f4f,0x9f71,0x9f70,0x9f6e,0x9f6f,0x56d3,0x56cd, 0x5b4e,0x5c6d,0x652d,0x66ed,0x66ee,0x6b13,0x705f,0x7061,0x705d,0x7060, 0x7223,0x74db,0x74e5,0x77d5,0x7938,0x79b7,0x79b6,0x7c6a,0x7e97,0x7f89, 0x826d,0x8643,0x8838,0x8837,0x8835,0x884b,0x8b94,0x8b95,0x8e9e,0x8e9f, 0x8ea0,0x8e9d,0x91be,0x91bd,0x91c2,0x946b,0x9468,0x9469,0x96e5,0x9746, 0x9743,0x9747,0x97c7,0x97e5,0x9a5e,0x9ad5,0x9b59,0x9c63,0x9c67,0x9c66, 0x9c62,0x9c5e,0x9c60,0x9e02,0x9dfe,0x9e07,0x9e03,0x9e06,0x9e05,0x9e00, 0x9e01,0x9e09,0x9dff,0x9dfd,0x9e04,0x9ea0,0x9f1e,0x9f46,0x9f74,0x9f75, 0x9f76,0x56d4,0x652e,0x65b8 }, { /* ku 51 */ 0x6b18,0x6b19,0x6b17,0x6b1a,0x7062,0x7226,0x72aa,0x77d8,0x77d9,0x7939, 0x7c69,0x7c6b,0x7cf6,0x7e9a,0x7e98,0x7e9b,0x7e99,0x81e0,0x81e1,0x8646, 0x8647,0x8648,0x8979,0x897a,0x897c,0x897b,0x89ff,0x8b98,0x8b99,0x8ea5, 0x8ea4,0x8ea3,0x946e,0x946d,0x946f,0x9471,0x9473,0x9749,0x9872,0x995f, 0x9c68,0x9c6e,0x9c6d,0x9e0b,0x9e0d,0x9e10,0x9e0f,0x9e12,0x9e11,0x9ea1, 0x9ef5,0x9f09,0x9f47,0x9f78,0x9f7b,0x9f7a,0x9f79,0x571e,0x7066,0x7c6f, 0x883c,0x8db2,0x8ea6,0x91c3,0x9474,0x9478,0x9476,0x9475,0x9a60,0x9b2e, 0x9c74,0x9c73,0x9c71,0x9c75,0x9e14,0x9e13,0x9ef6,0x9f0a,0x9fa4,0x7068, 0x7065,0x7cf7,0x866a,0x883e,0x883d,0x883f,0x8b9e,0x8c9c,0x8ea9,0x8ec9, 0x974b,0x9873,0x9874,0x98cc }, { /* ku 52 */ 0x9961,0x99ab,0x9a64,0x9a66,0x9a67,0x9b24,0x9e15,0x9e17,0x9f48,0x6207, 0x6b1e,0x7227,0x864c,0x8ea8,0x9482,0x9480,0x9481,0x9a69,0x9a68,0x9e19, 0x864b,0x8b9f,0x9483,0x9c79,0x9eb7,0x7675,0x9a6b,0x9c7a,0x9e1d,0x7069, 0x706a,0x7229,0x9ea4,0x9f7e,0x9f49,0x9f98,UBOGON,UBOGON,UBOGON,UBOGON, UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON, UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON, UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON, UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON, UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON, UBOGON,UBOGON,UBOGON,UBOGON } }; #if CNS_EXTENDED /* CNS 11643 plane 3 conversion table */ static const unsigned short cns11643_3tab[MAX_CNS11643_KU_3][MAX_CNS11643_TEN] = { { /* ku 01 */ 0x4e28,0x4e36,0x4e3f,0x4e85,0x4e05,0x4e04,0x5182,0x5196,0x5338,0x5369, 0x53b6,0x4e2a,0x4e87,0x4e49,0x51e2,0x4e46,0x4e8f,0x4ebc,0x4ebe,0x5166, 0x51e3,0x5204,0x529c,0x5344,0x5902,0x590a,0x5b80,0x5ddb,0x5e7a,0x5e7f, 0x5ef4,0x5f50,0x5f51,0x5f61,0x961d,UBOGON,0x4e63,0x4e62,0x4ea3,0x5185, 0x4ec5,0x4ecf,0x4ece,0x4ecc,0x5184,0x5186,UBOGON,0x34c5,0x51e4,0x5205, 0x529e,0x529d,0x52fd,0x5300,0x533a,0x3539,0x5346,0x535d,0x5386,0x53b7, 0x3555,0x53cc,0x355b,0x53ce,0x5721,0x37a2,0x5e00,0x5f0c,0x6237,0x6238, 0x6534,0x6535,0x65e0,0x3e26,0x738d,0x4e97,0x4ee0,0x3432,UBOGON,0x4ee7, 0x3433,0x4ee6,0x3434,0x36a2,0x3431,0x34b0,0x56d8,0x518b,0x518c,0x5199, 0x51e5,UBOGON,0x520b,0x34dc }, { /* ku 02 */ 0x361e,0x5304,0x5303,0x5307,UBOGON,0x531e,0x535f,0x536d,0x5389,0x53ba, 0x53d0,0x3565,0x53f6,0x53f7,0x53f9,0x3564,0x53f4,0x361d,0x3626,0x5724, 0x5904,0x5918,0x5932,0x5930,0x5934,0x368e,0x5975,0x374a,0x5b82,0x5bf9, 0x5c14,0x378b,0x37a6,0x37a4,0x37a5,0x37a7,0x382f,0x3832,0x5e81,0x5e83, 0x5f0d,0x5f52,0x38d4,0x5fca,0x5fc7,0x6239,0x39c5,0x624f,0x65e7,0x672f, 0x6b7a,0x6c39,0x3cba,0x3cb9,0x6c37,0x6c44,0x6c45,0x738c,0x7592,0x7676, 0x9093,0x9092,0x48b3,0x49ba,0x4e21,0x4e20,0x4e22,0x4e68,0x4e89,0x4e98, 0x4ef9,0x4eef,0x343b,0x343c,0x4ef8,0x4f06,0x4f03,0x4efc,0x4eee,0x4f16, 0x3439,0x4f28,0x4f1c,0x4f07,0x4f1a,0x4efa,0x4f17,0x514a,0x34b2,0x5172, UBOGON,0x51b4,0x51b3,0x51b2 }, { /* ku 03 */ 0x34c7,0x51e8,0x342b,0x5214,0x520f,0x5215,0x5218,0x52a8,UBOGON,0x534b, 0x534f,0x353b,0x5350,0x3544,0x538b,0x3542,0x53be,0x355c,0x53d2,0x5416, 0x53ff,0x3567,0x5400,0x3566,0x5405,0x5413,0x5415,UBOGON,0x361f,0x56e3, 0x5735,0x5736,0x5731,0x5732,0x58ee,0x5905,0x4e54,0x368f,0x5936,0x3690, 0x36a8,0x36a4,0x597a,0x36a3,0x5986,0x373d,0x374c,0x5b86,0x5f53,0x5c18, 0x378c,0x5c3d,0x5c78,0x37a8,0x37ad,0x37af,UBOGON,0x5c80,0x3829,0x5e08, 0x3836,0x3871,0x3870,0x386f,0x5ef5,0x5f0e,0x38a9,0x38aa,0x38fb,0x5fd3, 0x5fda,0x38fc,0x5fdb,0x39ae,0x620f,0x625d,0x625f,0x6267,0x6257,0x9f50, 0x3ac3,0x65eb,0x65ea,0x3b30,0x6737,0x3b41,0x6732,0x6736,0x6b22,0x6bce, 0x3c8c,0x6c58,0x6c51,0x6c77 }, { /* ku 04 */ 0x6c3c,0x3cbb,0x6c5a,UBOGON,0x6c53,0x706f,0x7072,0x706e,UBOGON,0x3da1, 0x7073,0x72b1,0x72b2,0x3ea8,0x738f,0x3eaa,0x3eab,0x4096,0x793c,0x41c2, 0x808d,0x808e,0x4493,0x827b,0x4494,0x8d71,0x8fb9,0x9096,0x909a,0x49bb, 0x4e24,0x4e71,UBOGON,0x4e9c,0x4f45,0x4f4a,0x4f39,0x4f37,0x3443,0x4f32, 0x4f42,0x3442,0x4f44,0x4f4b,0x3444,0x4f40,0x4f35,0x4f31,0x5151,UBOGON, 0x5150,0x514e,0x34b3,0x34b7,0x519d,0x34c8,0x51b5,0x51b8,0x51ec,0x5223, 0x5227,0x5226,0x521f,0x522b,0x5220,0x52b4,0x52b3,0x3518,0x5325,0x533b, 0x5374,0x3547,0x3546,0x3545,0x356b,0x3569,0x544d,0x3572,0x3571,0x543a, 0x356c,0x356f,0x5444,0x544c,0x5423,0x541a,0x5432,0x544b,0x5421,0x3573, 0x5434,0x5449,0x5450,0x5422 }, { /* ku 05 */ 0x543f,0x5451,0x545a,0x542f,0x3576,0x56e9,0x56f2,0x56f3,0x56ef,0x56ed, 0x56ec,0x56e6,0x5748,0x3627,0x5744,0x573f,0x573c,0x5753,0x5756,0x3630, 0x575f,0x5743,0x5758,0x5757,0x3629,0x362a,0x362f,0x5746,0x362c,0x573d, 0x362d,0x5742,0x5754,0x5755,0x58f1,0x58f2,0x58f0,0x590b,0x9ea6,0x56f1, 0x593d,0x3693,0x5994,0x598c,0x36ad,0x599c,0x36ac,0x36ab,0x599f,0x36a9, 0x599b,0x36ae,0x5989,0x599a,0x36aa,0x6588,0x374e,0x5b8d,0x3750,0x5bfe, 0x5bff,0x5bfd,0x5c2b,0x37b2,0x5c84,0x5c8e,0x5c9c,0x37b5,0x37b6,0x5c85, 0x5df5,0x5e09,0x3839,0x383b,0x5e0b,0x3872,0x5e92,0x5e90,0x5f03,0x38ac, 0x5f1e,0x5f63,0x3908,0x5fe7,0x5ffe,0x5fe6,0x5fdc,0x5fce,0x3903,0x5ffc, 0x5fdf,0x5fec,0x5ff6,UBOGON }, { /* ku 06 */ 0x5ff2,0x5ff0,0x5ff9,0x390b,0x6213,0x39af,UBOGON,0x623b,0x623c,0x6282, 0x39ce,0x39cb,0x39cc,0x6278,0x628b,0x39cd,0x629e,0x62a5,0x629b,0x629c, 0x6299,0x628d,0x6285,0x629d,0x6275,0x3a80,0x3aaf,0x3ad3,0x65f6,0x3ad5, 0x3ad4,0x3ad7,0x66f5,0x675b,0x3b42,0x6754,0x6752,0x3b44,0x6758,0x6744, 0x674a,0x6761,0x3cc6,0x6c7f,0x6c91,0x6c9e,0x3cc0,0x6c6e,0x6c7c,0x6c9f, 0x6c75,0x3cbe,0x6c56,0x6ca2,0x6c79,0x3cca,0x6ca1,0x3cc4,0x6caa,0x6ca0, 0x3cc2,0x7079,0x7077,0x707e,0x3da4,0x7075,0x707b,0x7264,0x3e29,0x72bb, 0x72bc,0x72c7,0x72b9,0x72be,0x72b6,0x3e60,0x3e5e,0x7398,0x3ead,0x3eae, 0x3eac,0x3f57,0x7593,0x7680,0x3fdd,0x7683,0x76c0,0x76c1,0x400e,0x4097, 0x77f4,0x77f5,0x4127,0x7acc }, { /* ku 07 */ 0x7acd,0x7cfa,0x809f,0x8091,0x8097,0x8094,0x4495,0x8286,0x828c,UBOGON, 0x8295,0x4498,0x866c,0x459d,0x8fb5,0x8fbe,0x8fc7,0x488a,0x8fc1,0x90a9, 0x90a4,0x48b5,0x48b6,0x48b7,0x90a8,0x9627,0x9626,0x962b,0x9633,0x9634, 0x9629,0x4e3d,0x3428,0x4e9d,0x4f93,0x4f8a,0x344d,0x3449,0x4f6d,0x4f8e, 0x4fa0,0x4fa2,0x4fa1,0x4f9f,0x4fa3,UBOGON,0x4f72,0x3451,0x4f8c,0x5156, UBOGON,UBOGON,0x5190,0x34cb,0x34ca,0x34cc,0x51ed,0x51fe,0x522f,UBOGON, 0x523c,0x5234,0x5239,0x52b9,0x52b5,0x52bf,0x5355,0x353d,0x5376,0x537a, 0x5393,0x3548,0x53c1,0x53c2,0x53d5,0x5485,0x3578,0x545f,0x5493,0x5489, 0x5479,0x9efe,0x548f,0x5469,0x546d,0x357a,0x5494,0x546a,0x548a,0x3577, 0x56fd,0x56fb,0x56f8,0x3621 }, { /* ku 08 */ 0x56fc,0x56f6,0x5765,0x5781,0x5763,0x5767,0x3631,0x576e,0x5778,0x577f, 0x3633,0x3634,0x58f3,0x594b,0x594c,0x36c1,0x36b0,0x36b4,0x59ad,0x36b8, 0x59c4,0x36bc,0x59c2,0x59b0,0x36bf,0x36b5,0x36b1,0x36bd,0x59bf,0x36bb, 0x59c9,0x59b8,0x59ac,0x36b3,0x36b6,0x36ba,0x59b7,0x59d7,0x36b7,0x5b60, 0x3740,0x5b96,0x5b9e,0x5b94,0x5b9f,0x5b9d,0x3752,0x5c00,0x5c19,0x3790, 0x3791,0x5c49,0x5c4a,0x37be,0x5cbb,0x5cc1,0x37c0,0x37c1,0x37b9,0x5cb9, 0x5c9e,0x5cb4,0x5cba,0x5df6,0x5e13,0x5e12,0x5e77,0x3879,0x5e98,0x387b, 0x5e99,0x5e9d,0x5ef8,0x38a0,0x5ef9,0x3429,0x5f06,0x5f21,0x38ae,0x5f25, 0x5f55,0x38cd,0x38cb,0x38d9,0x5f84,0x5f83,0x6030,0x6007,0x390c,0x6036, 0x3901,0x3905,0x3902,0x5fe9 }, { /* ku 09 */ 0x603d,0x6008,0x3913,0x3911,0x62ba,0x62b2,0x39e4,0x62b7,0x62e4,0x62a7, 0x39da,0x39d5,0x39d3,0x62d5,0x62e1,0x62dd,0x62a6,0x62c1,0x62c5,0x62c0, 0x62df,0x62e0,0x62de,0x39d6,0x6589,0x3ab4,0x65a6,0x65ba,0x3ad9,0x65ff, 0x3ad8,0x6617,0x6618,0x6601,0x65fe,0x3b33,0x670c,0x3b48,0x676b,0x6796, 0x6782,0x678a,0x3b47,0x67a3,0x3b4b,0x67a2,0x678f,0x3b4a,0x67f9,0x6780, 0x6b26,0x6b27,0x6b68,0x6b69,0x3c5a,0x6b81,0x6bb4,0x6bd1,0x3c8e,0x3cb4, 0x6c1c,0x3ccd,0x3ccc,0x3ccf,0x3ccb,0x3cce,0x6c97,0x6c6c,0x6cdf,0x3cd2, 0x6cea,0x3cd1,0x6ce4,0x6cd8,0x6cb2,0x6cce,0x6cc8,0x3da6,0x708b,0x7088, 0x7090,0x708f,0x3daa,0x7087,0x7089,0x708d,0x7081,0x3da8,0x708c,0x3e13, 0x3e1a,0x7240,0x3e1d,0x3e1e }, { /* ku 0a */ 0x7265,0x7266,0x7268,0x3e65,0x3e66,0x72cd,0x72d3,0x72db,0x3e64,0x72cf, 0x73a7,0x73a3,0x739e,0x3eb0,0x73af,0x3eb3,0x3eb5,0x73aa,0x739c,0x3f19, 0x7542,0x7544,0x753b,0x7541,UBOGON,0x759b,0x759e,0x3f75,0x79c4,0x79c3, 0x79c6,0x412b,0x412c,0x79c7,0x412d,0x79ca,UBOGON,0x41c3,0x7acf,0x7c76, 0x7c74,0x7cff,0x7cfc,0x34ba,0x4350,0x7f59,0x80a8,0x43d3,0x43d0,0x80b0, 0x43dc,0x80b3,0x43d2,0x80a4,0x80b6,0x80a7,0x80ac,0x43db,0x80a6,0x5367, 0x820e,0x82c4,0x833e,0x829c,0x44a5,0x449f,0x449a,0x449c,0x44a2,0x82aa, 0x449b,0x82c9,0x44a3,0x449d,0x82a6,0x82b2,0x4588,0x461a,0x488d,0x8fcc, 0x8fd9,0x8fca,0x8fd8,0x8fcf,0x90b7,0x48b8,0x90ad,0x90b9,0x9637,0x49c3, 0x9641,0x963e,0x96b6,0x9751 }, { /* ku 0b */ 0x9763,0x4e57,0x4e79,0x4eb2,0x4eb0,0x4eaf,0x4eb1,0x4fd2,0x4fd5,0x345d, 0x4fbe,0x4fb8,0x4fb0,0x4fb1,0x4fc8,0x345a,0x3457,0x4fc6,0x4fcc,0x4fe5, 0x4fe3,0x4fb4,0x516a,0x34b8,0x519f,0x34c2,0x51c1,0x34cf,0x51c2,0x51c3, 0x5245,0x5248,0x34e7,0x34e9,0x524f,0x4452,0x34e8,0x52c5,0x52ca,0x52c4, 0x5327,0x5358,0x537d,0x354a,0x53dd,0x53dc,0x53da,0x53d9,0x54b9,0x3580, 0x54d0,0x54b4,0x54ca,0x3587,0x54a3,0x54da,0x54a4,0x3584,0x54b2,0x549e, 0x549f,0x54b5,0x3582,0x3581,0x54cd,0x3583,0x54cc,0x3622,0x5700,0x57ac, 0x5791,0x578e,0x578d,0x5792,0x57a1,0x5790,0x57a6,0x57a8,0x363b,0x579c, 0x5796,0x57a7,0x363a,0x3638,0x3639,0x3636,0x58f5,0x3685,0x5909,0x5908, 0x3c54,0x5952,0x369a,0x36c4 }, { /* ku 0c */ 0x59df,0x36c5,0x59eb,0x59ef,0x59f0,0x59d5,0x5a0d,0x5a04,0x59f9,0x5a02, 0x59f8,0x59e2,0x59d9,0x59e7,0x5b6a,0x3754,0x3755,0x5bab,0x3756,0x5c1b, 0x5c2f,0x3796,0x663c,0x3795,0x3794,0x37c4,0x5cd1,0x5cdc,0x5ce6,0x5ce1, 0x5ccd,UBOGON,0x5ce2,0x5cdd,0x5ce5,0x5dfb,0x5dfa,0x5e1e,0x3844,0x5ea1, 0x387d,0x387e,0x5efc,0x5efb,0x5f2f,0x38b2,0x38b6,0x5f66,UBOGON,0x38dc, 0x38df,0x605c,0x3928,0x604e,0x6051,0x3919,0x3910,0x6023,0x6031,0x607c, 0x6052,0x392c,0x6060,0x604a,0x6061,0x391b,0x6218,0x39c2,0x39ef,0x39e3, 0x39e5,0x39ea,0x39e6,0x39ee,0x631f,0x6317,0x62ea,0x6321,0x6304,0x6305, 0x39e8,0x6531,0x6544,0x6540,0x3a85,0x6542,0x65be,0x3ae0,0x6629,0x661b, 0x3add,0x6623,0x662c,0x661a }, { /* ku 0d */ 0x6630,0x663b,0x661e,0x6637,0x6638,0x3ae1,0x670e,0x3b51,0x3b55,0x67e8, 0x67d6,0x3b52,0x67c7,0x67bc,0x6852,0x67bf,0x67d5,0x67fe,0x8363,0x67fb, UBOGON,0x67b1,0x6801,0x6805,0x6800,0x67d7,0x409e,0x6b2a,0x6b6b,0x3c52, 0x3c5e,0x3c60,0x3c5f,0x6be1,0x3c92,0x3cd6,0x6d23,0x6cff,0x6d14,0x6d05, 0x6d13,0x6d06,0x6d21,0x3cde,0x6d15,0x6caf,0x6cf4,0x6d02,0x6d45,UBOGON, 0x6d26,0x3cd9,0x6d44,0x3cdd,0x6d24,0x70a5,0x3dac,0x70a3,0x3db0,0x70a2, 0x70bb,0x70a0,0x70aa,0x3daf,0x3dae,0x70a8,0x70b6,0x70b2,0x70a7,0x3dad, 0x3dab,0x70b9,0x722e,0x3e16,0x723c,0x3e30,0x726d,0x3e33,0x3e31,0x72e7, 0x72ed,0x3e6e,0x72ec,0x72e5,0x72e2,0x3eb1,0x73c4,0x73bd,0x73cf,0x73c9, 0x73c1,0x73d0,0x3eb7,0x73ce }, { /* ku 0e */ 0x74ed,0x74eb,0x3f1a,0x74ef,0x7549,0x7550,0x7546,0x754a,0x3f59,0x754d, 0x75a6,0x3f7a,0x3f78,0x3f7b,0x75a8,0x3fde,0x3fec,0x76c7,0x76ff,0x401e, 0x76fd,0x77e6,0x780a,0x409b,0x7804,0x780b,0x7807,0x409d,0x7815,0x7808, 0x40fd,0x79d3,0x79d4,0x79d0,0x79d7,0x7a7c,0x4194,0x4193,0x7a7d,0x7a83, 0x7a82,0x41c6,0x7ad4,0x7ad5,0x7ad3,0x7ad0,0x7ad2,0x7afe,0x7afc,0x7c77, 0x7c7c,0x7c7b,0x42b8,UBOGON,0x42b7,0x42b9,0x4353,UBOGON,0x4352,0x4351, 0x7f8f,0x80d3,0x43e3,0x80cb,0x80d2,0x43e2,0x8109,0x80e2,0x80df,0x80c6, 0x4463,0x8224,0x82f7,0x82d8,0x82dd,0x44aa,0x44a6,0x82f8,0x82fc,0x44a8, 0x44a9,0x82e9,0x44ab,0x82ee,0x44ac,0x82d0,0x830e,0x82e2,0x830b,0x82fd, 0x5179,0x8676,0x459e,0x8678 }, { /* ku 0f */ 0x459f,0x45a0,0x8675,0x867d,0x460f,0x8842,0x8866,0x461c,0x898c,0x8a05, 0x46ae,0x8a06,0x46b0,0x8c9f,0x47d4,0x8ff1,0x8fe7,0x8fe9,0x8fef,0x90c2, 0x90bc,0x48bb,0x90c6,0x90c0,0x48c1,0x48c2,0x90cd,0x90c9,0x48be,0x90c4, 0x48e5,0x9581,0x49c6,0x9cec,0x5032,0x4ff9,0x501d,0x4fff,0x5004,0x4ff0, 0x5003,0x462e,0x5002,0x4ffc,0x4ff2,0x5024,0x5008,0x5036,0x502e,0x3465, 0x5010,0x5038,0x5039,0x4ffd,0x5056,0x4ffb,0x51a3,0x51a6,0x51a1,0x34d1, 0x34d0,0x51c7,0x51c9,0x5260,0x5264,0x5259,0x5265,0x5267,0x5257,0x5263, 0x34ee,0x5253,0x34ef,0x52cf,0x351e,0x52ce,0x52d0,0x52d1,0x52cc,0x354b, 0x354d,0x3556,0x550d,0x54f4,0x3592,0x5513,0x54ef,0x54f5,0x54f9,0x5502, 0x5500,0x3593,0x3590,0x5518 }, { /* ku 10 */ 0x54f0,0x54f6,UBOGON,0x3597,0x5519,0x3623,0x5705,0x57c9,0x363f,0x57b7, 0x57cd,0x3643,0x3642,0x3644,0x57be,0x57bb,0x3645,0x57db,0x57c8,0x57c4, 0x57c5,0x57d1,0x57ca,0x57c0,0x36d9,0x36de,0x5a21,0x5a2a,0x36cf,0x5a1d, 0x36cd,0x5a0b,0x36dd,0x36ce,0x36d3,0x36d6,0x5a22,0x36dc,0x36d1,0x5a24, 0x36d0,0x5a14,0x5a31,0x36d5,0x5a2f,0x5a1a,0x5a12,0x36d4,0x36db,0x5a26, UBOGON,0x3743,0x5bbc,0x5bbb,0x5bb7,0x5c05,0x5c06,0x5c52,0x5c53,0x37cd, 0x37d1,0x5cfa,0x5ceb,0x37ca,0x5cf3,0x5cf5,0x5ce9,0x5cef,0x37d4,0x5e2a, 0x5e30,0x5e2e,0x5e2c,0x5e2f,0x5eaf,0x5ea9,0x3886,0x5efd,0x5f32,0x5f8e, 0x5f93,0x5f8f,0x604f,0x6099,0x3933,0x607e,0x3937,0x6074,0x604b,0x6073, 0x6075,0x392a,0x391f,0x6056 }, { /* ku 11 */ 0x60a9,0x608b,0x60a6,0x3939,0x6093,0x60ae,0x609e,0x60a7,0x6245,0x39f2, 0x39f8,0x632e,0x39f7,0x6352,0x6330,0x635b,0x39f4,0x6319,0x631b,0x39f1, 0x6331,0x635d,0x6337,0x6335,0x6353,0x39f5,0x635c,0x633f,0x654b,0x3a87, 0x4369,0x658b,0x3ab6,0x659a,0x6650,0x6646,0x664e,0x6640,0x3ae9,0x664b, 0x6648,0x3aeb,0x6660,0x6644,0x664d,0x3b34,0x6837,0x6824,0x3b62,0x3b5c, 0x681b,0x6836,0x3b60,0x682c,0x6819,0x6856,0x6847,0x683e,0x681e,UBOGON, 0x6815,0x6822,0x6827,0x6859,0x6858,0x6855,0x6830,0x6823,0x6b2e,0x6b2b, 0x6b30,0x6b6c,0x3c61,0x6b8b,0x3c7f,0x6be9,0x6bea,0x6be5,0x6d6b,0x3ce5, 0x3ce6,0x6d73,0x6d57,0x3ce9,0x3cf3,0x6d5d,0x6d56,0x6d8f,0x6d5b,0x6d1c, 0x6d9a,0x6d9b,0x6d99,0x3cee }, { /* ku 12 */ 0x6d81,0x6d71,0x3ced,0x3cec,0x6d72,0x6d5c,0x6d96,0x70c4,0x70db,0x70cc, 0x70d0,0x70e3,0x70df,0x3db3,0x70d6,0x70ee,0x70d5,0x3db5,0x3e27,0x3e35, 0x3e36,0x727a,0x3e71,0x72f5,0x7302,0x3eb8,0x3ec2,0x73e2,0x73ec,0x73d5, 0x73f9,0x73df,0x73e6,0x3ec8,0x3ec0,0x3ec1,0x3ec4,0x73e4,0x73e1,0x74f3, 0x3f1f,0x3f1c,0x3f1d,0x3f4d,0x7556,0x7555,0x7558,0x7557,0x755e,0x75c3, 0x3f87,0x3f82,0x75b4,0x3f7d,0x75b1,0x3fdf,0x4000,0x76cb,0x76cc,0x772a, 0x4020,0x7716,0x770f,0x4022,0x4024,0x773f,0x772b,0x770e,0x7724,0x4021, 0x7721,0x7718,0x77dd,0x40a4,0x40a5,0x7824,0x7836,0x4101,0x7958,0x7959, 0x4103,0x7962,0x79da,0x79d9,0x4137,0x79e1,0x79e5,0x79e8,0x79db,0x4138, 0x79e2,0x79f0,0x4199,0x4198 }, { /* ku 13 */ 0x4197,0x41c9,0x7ada,0x7add,0x41c7,0x7adb,0x7adc,0x41d9,0x41db,0x7b0d, 0x7b0b,0x7b14,0x7c8e,0x7c86,0x427b,0x7c87,0x7c83,0x7c8b,0x427c,0x42bd, 0x42bc,0x42c3,0x7d24,0x42c1,0x42bf,0x42c4,0x7d25,0x7f62,0x7f93,0x7f99, 0x7f97,0x437e,0x437f,0x7fc4,0x7fc6,0x800a,0x43b4,0x43b3,0x8040,0x803c, 0x803b,0x80f6,0x80ff,0x80ee,0x8104,0x8103,0x8107,UBOGON,0x43e6,0x80f7, 0x4459,0x445a,0x822d,0x4464,0x8227,0x8229,0x831f,0x8357,0x44b4,0x44b9, 0x44b7,0x44b5,0x8321,0x44c1,0x44b1,0x8318,0x8358,0x44b3,0x44ba,0x458c, 0x458b,0x458d,0x8684,0x869f,0x869b,0x8689,0x86a6,0x8692,0x868f,0x86a0, 0x884f,0x8878,0x887a,0x886e,0x887b,0x8884,0x8873,0x4678,0x4677,0x8a0d, 0x8a0b,0x8a19,0x46b2,0x47d6 }, { /* ku 14 */ 0x8ed0,0x4845,0x4892,0x4895,0x8ff9,0x9009,0x9008,0x48c6,0x90de,0x9151, 0x48e7,0x48e8,0x91db,0x91df,0x91de,0x91d6,0x91e0,0x9585,0x9660,0x9659, 0x49cb,0x9656,0x49cd,0x49f1,0x96bd,0x4b22,0x3421,0x5042,0x5059,0x346f, 0x5044,0x5066,0x5052,0x5054,0x5071,0x5050,0x507b,0x507c,0x5058,0x3470, 0x3464,0x5079,0x506c,0x5078,0x51a8,0x51d1,0x51cf,0x5268,0x5276,0x52d4, 0x352d,0x53a0,0x53c4,0x3558,0x5558,0x554c,0x5568,0x35a6,0x5549,0x35a4, 0x359f,0x555d,0x5529,UBOGON,0x5554,0x5553,0x35a3,0x555a,0x35a0,0x553a, 0x553f,0x552b,0x57ea,0x364a,0x57ef,0x3647,0x3648,0x57dd,0x57fe,UBOGON, 0x57de,0x57e6,0x3649,0x57e8,0x57ff,0x5803,0x58f7,0x68a6,0x591f,0x369e, 0x595b,0x595d,0x595e,UBOGON }, { /* ku 15 */ 0x36e8,0x5a2b,0x36ec,0x5a3b,0x36ed,0x36e6,0x5a61,0x5a3a,0x5a6e,0x5a4b, 0x5a6b,0x36eb,0x36e7,0x5a45,0x5a4e,0x5a68,0x5a3d,0x5a71,0x5a3f,0x5a6f, 0x5a75,0x36e9,0x5a73,0x5a2c,0x5a59,0x5a54,0x5a4f,0x5a63,0x375c,0x375d, 0x5bc8,0x3760,0x5bc3,0x375b,0x5c5b,0x5c61,0x3799,0x5d21,0x5d0a,0x5d09, 0x37d8,0x5d2c,0x5d08,0x37da,0x37dd,0x5d2a,0x5d15,0x37e0,0x5d10,0x5d13, 0x37e5,0x5d2f,0x5d18,0x37d7,0x5de3,0x5e39,0x5e35,0x5e3a,0x5e32,0x384e, 0x388c,0x3888,UBOGON,0x5ebb,0x5eba,0x5f34,0x5f39,0x38ce,UBOGON,0x38e5, 0x38e6,0x6098,0x3932,0x60d0,0x3940,0x3947,0x394c,0x60d7,0x60aa,0x3935, 0x60a1,0x60a4,0x3930,0x60ee,0x3943,0x60e7,0x394d,0x60e8,0x60de,0x39b7, 0x39f3,0x637e,0x638b,0x3a02 }, { /* ku 16 */ 0x3a0b,0x6379,0x6386,0x6393,0x3a04,0x6373,0x636a,UBOGON,0x636c,0x3a08, 0x637f,0x39fc,0x63b2,0x63ba,0x39ff,0x3a00,0x6366,0x6374,0x3a8b,0x655a, 0x3a8d,0x654e,0x654d,0x658d,0x658e,0x65ad,0x3aca,0x65c7,0x65ca,0x3acb, 0x65c9,UBOGON,0x65e3,0x6657,0x3af3,0x6663,0x6667,0x671a,0x6719,0x6716, 0x3b36,0x3b6a,0x689e,0x68b6,0x6898,0x6873,0x3b6b,0x689a,0x688e,0x68b7, 0x68db,0x68a5,0x686c,0x68c1,0x6884,0x3b71,0x3b68,0x6895,0x687a,0x6899, 0x3b72,0x68b8,0x68b9,0x6870,0x3c2e,0x6b35,0x3c62,0x6b90,0x6bbb,0x6bed, 0x3c98,0x3cb5,0x3ceb,0x6dc1,0x6dc3,0x6dce,0x3cfb,0x3cf8,0x6dad,0x6e04, 0x3cf5,0x6db9,0x3d08,0x6de7,UBOGON,0x6e08,0x6e06,0x3d0a,0x6e0a,0x6db0, 0x3d06,0x6df8,0x6e0c,0x3cfd }, { /* ku 17 */ 0x6db1,0x3cfa,0x6e02,0x6e07,0x6e09,0x6e01,0x6e17,0x6dff,0x6e12,0x3dba, 0x3db9,0x7103,0x7107,0x7101,0x70f5,0x70f1,0x7108,0x70f2,0x710f,0x3dbb, 0x70fe,0x3e18,0x3e40,0x3e3d,0x731a,0x7310,0x730e,0x7402,0x73f3,0x3ecd, 0x3ec9,0x73fb,0x3ecb,0x3eca,0x3ece,0x751b,0x7523,0x7561,0x7568,0x3f5e, 0x7567,0x75d3,0x3f91,0x3f8c,0x7690,0x3fe1,0x4002,0x76d5,0x76d7,0x76d6, 0x7730,0x402b,0x7726,0x402a,0x7740,0x3e14,0x771e,0x40ad,0x40a3,0x40ab, 0x7847,0x40af,0x784b,0x7851,0x784f,0x7842,0x7846,0x4104,0x796e,0x796c, 0x79f2,0x4144,0x79f1,0x79f5,0x79f3,0x79f9,0x413d,0x4147,0x419c,0x7a9a, 0x7a93,0x7a91,0x7ae1,0x41e0,0x41e4,0x7b21,0x7b1c,0x7b16,0x7b17,0x7b36, 0x7b1f,0x4280,0x7c93,0x7c99 }, { /* ku 18 */ 0x7c9a,0x7c9c,0x42ca,0x7d49,0x42d4,0x7d34,0x7d37,0x42d2,0x7d2d,0x42cb, 0x7d4c,0x42ce,0x42d3,0x7d48,0x4344,0x4348,0x7f3b,0x4345,0x4381,0x4386, 0x4385,0x8008,0x801a,0x43a3,0x801d,0x43b5,0x8049,0x8045,0x8044,0x7c9b, 0x43fa,0x43f9,0x812a,0x812e,0x43fb,0x43f2,0x8131,0x43ef,0x811a,0x8134, 0x8117,0x445b,0x4466,0x44ce,0x831d,0x8371,0x8384,0x8380,0x8372,0x83a1, 0x35b4,0x8379,0x8391,0x44c8,0x839f,0x83ad,0x44d1,0x44c5,0x8323,0x44d2, 0x8385,0x839c,0x83b7,0x8658,0x865a,0x458f,0x8657,0x86b2,0x45a7,0x86ae, 0x45a5,0x45a4,0x4611,0x8845,0x889c,0x8894,0x88a3,0x888f,0x88a5,0x88a9, 0x88a6,0x888a,0x88a0,0x8890,0x8992,0x8991,0x8994,0x46b5,0x8a26,0x8a32, 0x8a28,0x46b4,0x46bd,0x8a1c }, { /* ku 19 */ 0x46bb,0x8a2b,0x8a20,0x46b9,0x8a29,0x46c2,0x46be,0x46ba,0x8a21,0x8c3a, 0x3ab7,0x8c5b,0x8c58,0x8c7c,0x4758,0x8ca6,0x8cae,0x8cad,0x8d65,0x479b, 0x8d7e,0x479c,0x8d7c,0x8d7f,0x8d7a,0x8dbd,0x47da,0x47de,0x8dc0,0x8dbb, 0x8ead,0x8eaf,0x8ed6,0x484d,0x4846,0x4847,0x484b,0x484c,0x8ed9,0x4848, 0x4899,0x9012,0x900e,0x9025,0x489b,0x9013,0x90ee,0x48ce,0x90ab,0x90f7, 0x48eb,0x9159,0x9154,0x91f2,0x91f0,0x91e5,0x91f6,0x491c,0x498c,0x9587, 0x49d1,0x965a,0x49d6,0x49d3,0x966e,0x49d4,0x49d0,0x49d5,0x9679,0x4a0b, 0x98e1,0x98e6,0x4bc6,0x9ec4,0x9ed2,0x4e80,0x3424,0x4e81,0x508f,0x5097, 0x5088,0x5089,0x3474,0x347a,0x5081,0x5160,UBOGON,0x34c3,0x5e42,0x51d3, 0x34d4,0x34d5,0x51d2,0x51d6 }, { /* ku 1a */ 0x5273,0x34fb,0x5270,0x34f7,0x3532,UBOGON,0x53a8,0x53a6,0x53c5,0x5597, 0x55de,0x35ba,0x35bf,0x5596,0x55b4,0x35c7,0x5585,0x35b7,0x559b,0x55a0, 0x35b9,0x5559,0x35c3,0x5586,0x35bd,0x35d0,0x55af,0x557a,0x35c1,0x35be, 0x35cd,0x559e,0x35cb,0x55a9,0x570f,0x570e,0x581a,0x364f,0x581f,0x3653, 0x583c,0x5818,0x583e,0x5826,0x3655,0x583a,UBOGON,0x5822,0x3651,0x58fb, 0x5963,0x5964,0x369f,0x5aa8,0x5aa3,0x5a82,0x5a88,0x5aa1,0x5a85,0x5a98, 0x36fe,0x5a99,0x36fb,0x5a89,0x5a81,0x5a96,0x5a80,0x36f1,0x36f5,0x5a91, 0x36ef,0x3704,0x3703,0x36f4,0x5acf,0x36f3,0x3702,0x36f7,0x36fa,0x36fd, 0x36ee,0x5a87,0x5aa0,0x36f0,0x5a79,0x36f2,0x5a86,0x5aab,0x5aaa,0x5aa4, 0x5a8d,0x5a7e,0x3744,0x5bd5 }, { /* ku 1b */ 0x3762,0x3777,0x3dc9,0x5c1e,0x5c5f,0x5c5e,0x5d44,0x5d3e,0x37e8,0x5d48, 0x5d1c,0x37ef,0x5d5b,0x5d4d,0x37e6,0x37ed,0x5d57,0x37e7,0x5d53,0x5d4f, 0x37eb,0x5d3b,0x5d46,0x382d,0x3855,0x5e46,0x5e47,0x3853,0x5e48,0x5ec0, 0x5ebd,0x5ebf,0x3890,0x5f11,0x38be,0x5f3e,0x5f3b,0x38bd,0x5f3a,0x38cf, 0x38d0,0x38ec,0x5fa7,0x394b,0x60ea,0x3948,0x6107,0x6122,0x610c,0x3955, 0x3951,0x60b3,0x60d6,0x60d2,0x394e,0x60e3,0x60e5,0x60e9,0x396b,0x395e, 0x6111,0x60fd,0x3960,0x3967,0x611e,0x6120,0x6121,0x621e,0x39b8,0x63e2, 0x63de,0x63e6,0x3a14,0x3a0f,0x3a07,0x3a13,0x63f8,0x3a17,0x63fe,0x63c1, 0x63bf,0x63f7,0x63d1,0x655f,0x6560,0x6561,0x3a9a,0x3ab8,0x65d1,0x3af7, 0x3af8,0x667d,0x666b,0x667f }, { /* ku 1c */ 0x3afd,0x3af5,0x6673,0x6681,0x666d,0x6669,0x3afa,0x3b38,0x671e,0x68ed, 0x3b87,0x3b80,0x3b88,0x3b79,0x6903,0x3b7c,0x68fe,0x68e5,0x691e,0x6902, 0x3b83,0x3b85,0x6909,0x68ca,0x6900,UBOGON,0x6901,0x6918,0x68e2,0x68cf, 0x3b7b,0x692e,0x68c5,0x68ff,0x3b86,0x691c,0x68c3,0x3c34,0x6b6f,0x3c55, 0x6b6e,0x3c68,0x6bbe,0x3c9c,0x6bf4,0x6c2d,0x3cfc,0x6db6,0x6e75,0x6e1e, 0x3d1a,0x6e18,0x3d17,0x6e48,0x3d1b,0x6e4f,0x3d13,0x6e42,0x6e6a,0x6e70, 0x6dfe,0x3d05,0x3d07,0x6e6d,0x3d1c,0x6e7b,0x6e7e,0x6e59,0x3d11,0x6e57, 0x3d16,0x6e80,0x6e50,0x3d15,0x6e29,0x6e76,0x6e2a,0x6e4c,0x712a,0x3dcb, 0x7135,0x712c,0x7137,0x711d,0x3dc5,0x3dc2,0x7138,0x3dcd,0x7134,0x712b, 0x7133,0x7127,0x7124,0x3dca }, { /* ku 1d */ 0x712d,0x7232,0x7283,0x7282,0x7287,0x7306,0x7324,0x7338,0x732a,0x732c, 0x732b,0x3e83,0x732f,0x7328,0x7417,0x3ed6,0x3ed5,0x7419,0x7438,0x3ed1, 0x741f,0x7414,0x743c,0x73f7,0x741c,0x7415,0x7418,0x7439,0x74f9,0x7524, UBOGON,0x3f52,0x3f5f,0x756e,0x756d,0x7571,0x758e,0x3f95,0x75e5,0x3f9d, 0x3f98,0x3f9e,0x3f96,0x7694,0x76b3,0x4003,0x76d9,0x402f,0x7748,0x7749, 0x7743,0x4031,0x4033,0x7742,0x77df,0x40b4,0x7863,0x7876,0x40b0,0x785f, 0x7866,0x7966,0x7971,0x4108,0x4107,0x7976,0x7984,0x7975,0x79ff,0x7a07, 0x414e,0x7a0e,0x7a09,0x4150,0x4152,0x41a1,0x41a3,0x41a5,0x41cc,0x7ae7, 0x7ae2,0x7b55,0x41ef,0x41ea,0x7b43,0x7b57,0x7b6c,0x7b42,0x7b53,0x41ed, 0x7b41,0x4285,0x4284,0x7ca7 }, { /* ku 1e */ 0x7ca0,0x7ca6,0x7ca4,0x7d74,0x42db,0x7d59,0x42d9,0x7d60,0x7d57,0x7d6c, 0x7d7e,0x7d64,0x42d7,0x7d5a,0x7d5d,0x42da,0x42de,0x42d8,0x7d76,0x7d4d, 0x7d75,0x42d5,0x7fd3,0x7fd6,0x439c,0x439d,0x8060,0x804e,0x8145,0x813b, 0x43fe,0x8148,0x8142,0x8149,0x8140,0x8114,0x8141,0x4407,0x81ef,0x81f6, 0x8203,0x446a,0x83ed,0x44e7,0x83da,0x8418,0x83d2,0x8408,0x44e2,0x8400, 0x44df,0x44e1,0x44e5,0x8417,0x8346,0x8414,0x83d3,0x8405,0x841f,0x8402, 0x8416,0x83cd,0x83e6,0x4591,0x865d,0x86d5,0x86e1,0x45b4,0x45b0,0x45b5, 0x45ae,0x86ee,0x8847,0x8846,0x462d,0x462c,0x88bb,0x462b,0x88bf,0x88b4, 0x4629,0x88b5,0x467f,0x899a,0x8a43,0x46c9,0x46cb,0x8a5a,0x46c5,0x46c6, 0x46ca,0x8a35,0x8a38,0x8a42 }, { /* ku 1f */ 0x8a49,0x8a5d,0x8a4b,0x8a3d,0x46d2,0x46d0,0x472d,0x4735,0x8c60,0x8c5e, 0x8c7f,0x8c7e,0x8c83,0x476c,0x8cb1,0x8d87,0x479d,0x47a0,0x8d88,0x8d83, 0x47a2,0x479f,0x8d86,0x8d8b,0x8d82,0x8dca,0x8dd2,0x47eb,0x47e2,0x8dd4, 0x8dc9,0x8eb0,0x4836,0x4832,0x4850,0x8ef2,0x8ee4,0x8ef3,0x8eea,0x484f, 0x8efd,0x4852,0x8f9d,0x902b,0x902a,0x489e,0x9028,0x9029,0x902c,0x48a0, 0x489c,0x903a,0x9030,0x9037,0x903b,0x48d1,0x910a,0x48ef,0x48f0,0x48f1, 0x91fe,0x9220,0x491d,0x920b,0x491f,0x9218,0x9222,0x491e,0x921b,0x9208, 0x4920,0x920e,0x9213,0x498e,0x4991,0x9595,UBOGON,0x4990,0x49d7,0x968c, 0x967b,0x967f,0x9681,0x49d9,0x9682,0x49f4,0x49f6,0x3560,0x49f5,0x49f3, 0x96ee,0x96ed,0x4a0c,0x96ec }, { /* ku 20 */ 0x975f,0x976f,0x4a51,0x976d,0x4aa6,0x4aa7,0x4aa8,0x4b27,0x4b24,0x4b25, 0x98f0,0x4b2a,0x4b74,0x4bc7,0x9aa9,0x4be7,0x4bed,0x9ae0,0x4eb7,0x342e, 0x347b,0x50cc,0x50bc,0x347c,0x50aa,0x50b9,0x347d,0x50ab,0x50c3,0x50cd, 0x517e,0x527e,0x5279,0x34fd,UBOGON,0x52e1,0x52e0,0x52e7,0x5380,0x53ab, 0x53aa,0x53a9,0x53e0,0x55ea,0x35da,0x55d7,0x35d6,0x35db,0x55c1,0x5715, 0x365b,0x586c,0x365c,0x585c,0x5850,0x5861,0x586a,0x5869,0x5856,0x5860, 0x5866,0x585f,0x5923,0x5966,0x5968,0x3706,0x370b,0x5ace,0x370d,0x5ac5, 0x5ac3,0x370a,0x3713,0x5ad0,0x3710,0x3712,0x3709,0x3708,0x3711,0x370f, 0x5b74,0x5b76,0x5bdc,0x5bd7,0x5bda,0x5bdb,0x3767,0x5c20,0x5d6d,0x5d66, 0x37f6,0x5d64,0x5d6e,UBOGON }, { /* ku 21 */ 0x5d60,0x5f42,0x5f5a,0x5f6e,0x3964,0x396c,0x6130,0x613a,0x612a,0x6143, 0x6119,0x6131,0x396d,0x613d,0x397a,0x3975,0x3a0d,0x6408,0x6432,0x6438, 0x3a1e,0x6431,0x3a1b,0x6419,0x3a2a,0x6411,0x3a1f,0x3a22,0x6429,0x641d, 0x3a25,0x3a27,0x3a29,0x643c,0x3a24,0x6446,0x6447,0x3a28,0x3a26,0x643a, 0x6407,0x3a23,0x656b,0x3a9f,0x6570,0x656d,0x3ab1,0x65e4,0x6693,0x3b03, 0x3b07,0x3b0c,0x3b06,0x668f,0x3b04,0x3b09,0x6692,0x3b05,0x668e,0x3b08, 0x6946,0x3b96,0x3b9c,0x3b9f,0x3b9b,0x3b98,0x3b99,0x3b94,0x6931,0x3b8d, 0x3ba3,0x693e,0x3b93,0x697c,0x6943,0x3b92,0x6973,UBOGON,0x6955,0x3b8e, 0x3b8c,0x6985,0x694d,0x6950,0x6947,0x6967,0x6936,0x6964,0x6961,0x3b9a, 0x697d,0x6b44,0x6b40,0x6b71 }, { /* ku 22 */ 0x6b73,0x6b9c,0x3c6a,0x3c6d,0x3c84,0x6bc1,0x3ca0,0x6bfa,0x6c31,0x6c32, 0x3d1d,0x3d26,0x6eb8,0x6ea8,0x3d33,0x6e91,0x6ebb,0x3d38,0x6e9a,0x3d30, 0x3d28,0x6ea9,0x3d27,0x3d2a,0x6eb5,0x6e6c,0x6ee8,0x3d31,0x6edd,0x6eda, 0x6ee6,0x6eac,0x3d34,0x3d2e,0x3d3b,0x6ed9,0x6ee3,0x6ee9,0x6edb,0x3d29, 0x716f,0x3dd2,0x3dd8,0x7148,0x3dcf,0x714a,0x716b,0x3dd9,0x714f,0x7157, 0x7174,0x3dce,0x3dd3,0x3dd0,0x7145,0x7151,0x716d,0x3ba1,0x7251,0x7250, 0x724e,0x3e47,0x7341,0x3e8b,0x732e,0x7346,0x3ed4,0x7427,0x3ede,0x7448, 0x7453,0x743d,0x3edf,0x745d,0x7456,0x3ed7,0x741e,0x7447,0x7443,0x7458, 0x7449,0x3ee1,0x744c,0x7445,0x743e,0x3f2f,0x7501,0x751e,0x3f62,0x3f63, 0x757a,0x75ee,0x7602,0x7697 }, { /* ku 23 */ 0x7698,0x3fe2,0x4004,0x4043,0x775d,0x7764,0x7753,0x7758,0x7882,0x7890, 0x788a,0x40be,0x787a,0x787d,0x40ba,0x788b,0x7878,0x40bc,UBOGON,0x788d, 0x7888,0x7892,0x7881,0x797e,0x7983,0x410d,0x410e,0x4111,0x7980,0x410f, 0x4112,0x4155,0x7a0f,0x4159,0x415b,0x7a1d,0x4157,0x7aa1,0x7aa4,0x41ce, 0x7ae9,0x7aea,0x41fe,0x7b62,0x7b6b,0x41fc,0x7b5e,0x41f5,0x7b79,0x41f9, 0x41fa,0x7b6f,0x7b68,0x4288,0x4289,0x7cae,0x428a,0x4287,0x428b,0x7cb0, 0x42e6,0x7d90,0x42ed,0x7d8a,0x42e5,0x7d8b,0x7d99,0x7d95,0x42e0,0x7d87, 0x7d78,0x7d97,0x7d89,0x7d98,0x42e1,0x435b,0x435c,0x7fa3,0x438f,0x438b, 0x438d,0x7fdd,0x8057,0x43b9,0x8163,0x816a,0x816c,0x440f,0x4419,0x4413, 0x815d,0x8175,0x4418,0x815f }, { /* ku 24 */ 0x4416,0x817d,0x816d,0x4453,UBOGON,0x8241,0x844f,0x8484,0x44f6,0x847f, 0x44f5,0x8448,0x842a,0x847b,0x8472,0x8464,0x842e,0x845c,0x8453,0x44f7, 0x8441,0x84c8,0x44f0,0x8462,0x8480,0x843e,0x8483,0x8471,0x44f9,0x844a, 0x8455,0x8458,0x4592,0x4595,0x4596,0x86fc,0x86fd,0x8715,0x45b9,0x8716, 0x86ff,0x45bd,0x45b8,0x4612,0x8858,0x88cf,0x88e0,0x4680,0x4681,0x469a, 0x4698,0x89e7,0x8a6a,0x8a80,0x46d4,0x8a6f,0x8a65,0x46da,0x8a78,0x8a7d, 0x8a88,0x46d6,0x46db,0x8a64,0x8a7e,0x46dc,0x8a67,0x8c63,0x8c88,0x4771, 0x8ccd,0x4772,0x8cc9,0x47a8,0x8ded,0x47f0,UBOGON,0x47f1,0x47fd,0x4838, 0x4837,0x4839,0x8eb1,0x4855,0x4853,0x8f04,0x8f9e,0x8fa0,0x9043,0x9046, 0x9048,0x9045,0x9040,0x904c }, { /* ku 25 */ 0x48d5,0x48bd,0x910c,0x9113,0x9115,0x48f5,0x916b,0x9167,0x925d,0x9255, 0x9235,0x4921,0x9259,0x922f,0x923c,0x928f,0x925c,0x926a,0x9262,0x925f, 0x926b,0x926e,0x923b,0x9244,0x9241,0x959a,0x4992,0x9599,0x49de,0x49db, 0x49da,0x968f,0x49df,0x9696,0x49f9,0x49f8,0x49fa,0x96f4,0x96fc,0x4a0e, 0x9755,0x4a43,0x9779,0x4a56,0x4a53,0x4a9e,0x97ee,0x97f5,0x4aa9,0x980b, 0x4afa,0x98f3,0x4b31,0x4b30,0x98f7,0x98ff,0x98f5,0x4b32,0x98ec,0x98f1, 0x4b29,0x4b2e,0x999a,0x4b76,0x9ae2,0x9b3d,0x9b5d,0x9ce8,0x4ca5,0x9ceb, 0x9cef,0x9cee,0x9e81,0x9f14,0x50d0,0x50d9,0x50dc,0x50d8,0x348c,0x50e1, 0x50eb,0x348b,0x3489,0x50f4,0x50e2,0x50de,0x348d,0x3486,0x34d7,0x51f4, 0x3504,0x3507,0x3503,0x52ed }, { /* ku 26 */ 0x52ea,0x3522,0x5332,0x3551,0x53ae,0x53b0,0x3561,0x55fb,0x5603,0x560b, 0x35e9,0x5607,0x35e5,0x55f8,0x35e4,0x5628,0x561e,0x35e3,0x5618,0x5611, 0x5651,0x5605,0x5717,0x5892,0x3665,0x588c,0x3663,0x5878,0x5884,0x5873, 0x58ad,0x5897,0x5895,0x5877,0x5872,0x5896,0x588d,0x5910,0x368c,0x596c, 0x371a,0x5ae7,0x3715,0x5ae4,0x3720,0x3721,0x5aef,0x5626,0x371c,0x371b, 0x5af0,0x5d7b,0x37fe,0x5d83,0x3804,0x3801,0x5d8b,0x5d8c,0x3800,0x5d78, 0x5e52,0x386d,0x3893,0x5ed0,0x5ecf,0x38a1,0x5fb3,0x5fb4,0x3976,0x3979, 0x3972,0x617b,0x3983,0x616f,0x6181,0x613c,0x6142,0x6138,0x6133,UBOGON, 0x6160,0x6169,0x617d,0x6186,0x622c,0x6228,0x3a38,0x644c,0x3a30,0x6457, 0x647c,0x3a34,0x3a3a,0x6455 }, { /* ku 27 */ 0x6462,0x6471,0x646a,0x6456,0x643b,0x6481,0x3a35,0x644f,0x647e,0x6464, 0x3a3f,0x3a40,0x3a32,0x3a31,0x3a36,0x6571,UBOGON,0x3b0f,0x66a5,0x669a, 0x669c,0x3b10,0x66a6,0x3b0d,0x66a4,0x698f,0x69c5,0x69c8,0x6992,0x69b2, 0x3ba9,0x3bb4,0x3bac,0x69e3,0x69c0,0x69d6,0x69d1,0x699f,0x69a2,0x69d2, 0x3bb8,0x3bae,UBOGON,0x69e1,0x69d5,0x699d,0x3bb3,0x3bba,0x6998,0x3c3f, 0x6b74,0x6ba1,0x3d3c,0x6ef0,0x6ef3,0x3d42,0x3d40,0x6f1b,0x6f0c,0x6f1d, 0x6f34,0x6f28,0x6f17,0x3d3e,0x6f44,0x6f42,0x6f04,0x6f11,0x6efa,0x6f4a, 0x7191,0x718e,0x3de1,0x718b,0x718d,0x717f,0x718c,0x717e,0x717c,0x7183, 0x3de6,0x7188,0x3de0,0x3e15,0x7294,0x3e93,0x7355,0x7353,0x734f,0x7354, 0x746c,0x7465,0x7466,0x7461 }, { /* ku 28 */ 0x746b,0x7468,0x7476,0x3ee7,0x7460,UBOGON,0x7474,0x7506,0x760e,0x3fad, 0x7607,0x3fae,0x3fe3,0x76b9,0x3ff5,0x76b7,0x76e2,0x4006,0x7774,0x7777, 0x7776,0x7775,0x404f,0x7778,0x7771,0x4054,0x777a,0x715b,0x777b,0x78a6, 0x78ae,0x78b8,0x40cb,0x40e3,0x40c9,0x78b1,0x78af,0x4113,0x7989,0x7987, 0x4115,0x4161,0x7a29,0x4166,0x7a2a,0x4164,0x7a2d,0x7a2c,0x4160,0x7a32, 0x4163,0x7aec,0x7af0,0x7b81,0x7b9e,0x7b83,0x420a,0x7b92,0x4204,0x7ba3, 0x7b9f,0x7b93,0x4207,0x7b86,0x7cb8,0x7cb7,0x428d,0x428f,0x4290,0x4292, 0x42ec,0x7dc8,0x7db6,UBOGON,0x7dd1,0x42e7,0x7da8,0x7dab,0x42f2,0x7db3, 0x7dcd,0x42ee,0x7dcf,0x7da4,0x42ef,0x434c,0x7f41,0x7f6f,0x7f71,0x435e, 0x435f,0x4376,0x4374,0x4372 }, { /* ku 29 */ 0x4390,0x8023,0x805b,0x43be,0x8061,0x805f,0x8181,0x4426,0x4425,0x8184, 0x8213,0x4474,0x824a,0x824c,0x44fd,0x4505,0x4501,0x84bd,0x8495,0x4509, 0x8492,0x84c3,0x450c,0x8496,0x84a5,0x84b5,0x84b3,0x84a3,0x84e4,0x84d8, 0x84d5,0x450d,0x84b7,0x84ad,0x84da,0x8493,0x8736,0x45c0,0x45c5,0x45c9, 0x873d,0x872b,0x8747,0x8739,0x45d5,0x8745,0x871d,0x4641,0x88ff,0x88ea, 0x4633,0x88f5,0x463a,0x8900,0x88ed,0x8903,0x88e9,0x4640,0x4642,0x89ea, 0x46e8,0x8a9b,0x8a8e,0x8aa2,0x46e4,0x8a9c,0x8a94,0x8a90,0x8aa9,0x8aac, 0x46e7,0x8a9f,0x46e6,0x46e1,0x8a9d,0x4739,0x8c67,0x475c,0x4775,0x8cd0, 0x8cd6,0x8cd4,0x8d98,0x8d9a,0x8d97,0x47ae,0x47b0,0x47fa,0x8e0b,0x8e08, 0x8e01,0x8eb4,0x8eb3,0x485b }, { /* ku 2a */ 0x8fa1,0x8fa2,0x48a5,0x905a,0x48a2,0x9061,0x905f,0x48db,0x48da,0x9125, 0x917b,0x9176,0x917c,0x4924,0x9289,0x92f6,0x92b1,0x92ad,0x9292,0x9281, 0x9284,0x4926,0x92ae,0x9290,0x929e,0x4998,0x4996,0x499a,0x95a2,0x95a7, 0x4997,0x49e1,0x49e0,0x49e3,0x49e2,0x96a0,0x969d,0x969f,0x96d0,0x49fb, 0x96d1,0x4a12,0x4a14,0x9759,0x4a45,0x9764,0x4a5c,0x4a5d,0x4ab8,0x9819, 0x4aba,0x9814,0x9815,0x981a,0x4b03,0x4b35,0x4b36,0x4b39,0x9906,0x4b2d, 0x98f8,0x9901,0x4b7a,0x99be,0x99bc,0x99b7,0x99b6,0x99c0,0x4b78,0x99b8, 0x4b7b,0x4b7c,0x4b7e,0x99c4,0x4b7d,0x99bf,0x4bc9,0x9ada,0x9ae4,0x9ae9, 0x9ae8,0x9aea,0x9ae5,0x4bf3,0x9b26,0x4c1a,0x4c19,0x9b40,0x4c1f,0x4ca6, 0x4ca7,0x4ca8,0x4cab,0x4ca9 }, { /* ku 2b */ 0x4d2e,0x9ebd,0x4d5e,0x3495,0x3493,0x3492,0x510e,0x3496,0x50f7,0x3497, 0x50fc,0x510d,0x5101,0x51da,0x51d9,0x51db,0x5286,0x528e,0x52ee,0x5333, 0x53b1,0x35f5,0x5647,0x562d,0x5654,0x35ea,0x564b,0x5652,0x5631,0x5644, 0x5656,0x5650,0x562b,0x35f3,0x564d,0x5637,0x564f,0x58a2,0x58b7,0x3669, 0x58b2,0x366b,0x58aa,0x58b5,0x58b0,0x366c,0x58b4,0x58a4,0x58a7,0x3668, 0x5926,0x5afe,0x3728,0x5b04,0x3726,0x5afc,0x3725,0x5b06,0x5b0a,0x5afa, 0x5b0d,0x5b00,0x5b0e,0x376b,0x380f,0x3808,0x5d91,0x380c,0x5d8f,0x5d90, 0x5d98,0x5da4,0x5d9b,0x5da3,0x5d96,0x5de4,0x5e5a,0x3860,0x3862,0x5e5e, 0x3898,0x5fb8,0x6157,0x615c,0x61a6,0x6195,0x6188,0x398a,0x61a3,0x618f, 0x3984,0x6164,0x397f,0x6159 }, { /* ku 2c */ 0x6178,0x3982,0x6185,0x6187,0x619e,0x3996,0x3989,0x6198,0x619c,0x398d, 0x39bc,0x622f,0x6480,0x649b,0x648e,0x648d,0x6494,0x64c6,0x3a44,0x64a8, 0x6483,0x3a3c,0x64b9,0x6486,0x64b4,0x64af,0x6491,0x3a4e,0x64aa,0x64a1, 0x64a7,0x66b6,0x66b3,0x3b14,0x66bc,0x66ac,0x3b15,0x66ad,0x6a0e,0x3bce, 0x6a1c,0x6a1a,0x3be0,0x3bc2,0x6a0b,0x3bbf,0x69ef,0x6a0c,0x69f0,0x6a22, 0x3bc4,0x69d8,0x3bcf,0x6a12,0x69fa,0x3bc8,0x6a2a,0x3bcc,0x6a10,0x3bcd, 0x3bc7,0x6a29,0x69f9,0x69ea,0x6a2c,0x6a24,0x4cb7,0x69e9,0x6b52,0x6b4f, 0x6b53,0x3c43,0x3cb6,0x6f10,0x6f65,0x6f75,0x3d51,0x3d4a,0x3d4d,0x3d56, 0x6fd0,0x3d53,0x6f5c,0x6f3d,0x6f71,0x3d59,0x6f91,0x6f0b,0x6f79,0x6f81, 0x6f8f,0x3d4e,0x6f59,0x6f74 }, { /* ku 2d */ 0x3dee,0x71ae,0x3dec,0x71a3,0x71ad,0x3deb,0x3def,0x71ab,0x71a6,0x71a2, 0x3ded,0x52f2,0x7257,0x7255,0x7299,0x734b,0x747a,0x3ef2,0x3eef,0x3ef1, 0x748c,0x7484,0x3eed,0x3ef0,0x7482,0x7493,0x747b,0x3eee,0x7509,0x4c1b, 0x3f50,0x3f66,0x3684,0x3fb8,0x3ff6,0x778a,0x4057,0x7790,0x405e,0x78c6, 0x78d3,0x78c0,0x78d2,0x78c7,0x78c2,0x4119,0x799f,0x799d,0x799e,0x4170, 0x7a41,0x416e,0x7a38,0x7a3a,0x7a42,0x4172,0x4176,0x7a3e,0x7ab0,0x7bae, 0x7bb3,0x4212,0x421f,0x7bbf,0x4211,0x4216,0x7bcd,0x4219,0x7bb2,0x4224, 0x4214,0x4225,0x4295,0x4296,0x4293,0x4294,0x7cc4,0x7ccd,0x7cc2,0x7cc6, 0x7cc3,0x7cc9,0x7cc7,0x42a0,0x7df8,0x42fb,0x7ded,0x7de2,0x42fc,0x4300, 0x42f8,0x7ddc,0x7e02,0x7e01 }, { /* ku 2e */ 0x42f9,0x7dd6,0x4304,0x7de4,0x7dfe,0x4303,0x7e00,0x7dfc,0x7dfd,0x42f3, 0x7df5,0x7dff,0x42fa,0x7deb,0x7de5,0x7f78,0x7fae,0x7fe7,0x43bf,0x8065, 0x806a,0x8066,0x8068,0x806b,0x8194,0x81a1,0x8192,0x8196,0x8193,0x4479, 0x4510,0x8501,0x4514,0x84f8,0x450e,0x84f5,0x451a,0x8504,0x4519,0x4521, 0x4523,0x451f,0x851b,0x8503,0x8533,0x8534,0x84ed,0x4525,0x452b,0x8535, 0x4516,0x8505,0x4522,0x451b,0x45ce,0x45cf,0x877d,0x45cb,0x45d1,0x45cc, 0x8771,0x4617,0x885c,0x88e6,0x890f,0x891b,0x4651,0x89a9,0x89a5,0x89ee, 0x8ab1,0x46ed,0x8acc,0x8ace,0x46f4,0x8ab7,0x46f1,0x8ab5,0x8ae9,0x8ab4, 0x46f8,0x8ab3,0x8ac1,0x8aaf,0x8aca,0x8ad0,0x472f,0x475e,0x475d,0x8c8e, 0x4776,0x4777,0x8ce9,0x8cdb }, { /* ku 2f */ 0x477e,0x8ceb,0x8da4,0x47b6,0x8da2,0x8d9d,0x47b3,0x47fc,0x4803,0x4800, 0x8e2a,0x8e28,0x480a,0x4802,0x8eb8,0x8eb6,0x8eb9,0x8eb7,0x8f22,0x8f2b, 0x8f27,0x8f19,0x8fa4,0x4887,0x8fb3,0x48a6,0x9071,0x906a,0x48a9,0x48de, 0x9188,0x918c,0x92bf,0x92b8,0x92be,0x92dc,0x92e5,0x492e,0x492d,0x92d4, 0x92d6,0x4930,0x92da,0x92ed,0x92f3,0x92db,0x492b,0x92b9,0x92e2,0x92eb, 0x95af,0x499e,0x95b2,0x95b3,0x499f,0x49e5,0x49e4,0x96a3,0x96a5,0x49fd, 0x49fc,0x4a17,0x4a19,0x970a,0x4a18,0x9787,0x9789,0x978c,0x97ef,0x982a, 0x9822,0x4abf,0x981f,0x4b3c,0x9919,0x4b6b,0x99ca,0x99da,0x4b83,0x4b81, 0x4b80,0x99de,0x99c8,0x99e0,0x4bca,0x9ab6,0x9ab5,0x4bce,0x9af4,0x4bf6, 0x9b6b,0x9b69,0x9b72,0x9b63 }, { /* ku 30 */ 0x4c39,0x9d0d,0x4cae,0x9d01,0x9d0c,0x4cb5,0x9cf8,0x4cb3,0x4cb4,0x9cfe, 0x9d02,0x9e84,0x4d22,0x9eab,0x9eaa,0x511d,0x5116,0x3499,0x512b,0x511e, 0x511b,0x5290,0x5294,0x5314,UBOGON,0x3602,0x5667,0x3601,0x567b,0x36a1, 0x565f,0x5661,0x35fd,0x3673,0x3674,0x3670,0x3676,0x3675,0x3672,0x58c3, 0x58ca,0x58bb,0x58c0,0x58c4,0x5901,0x5b1f,0x5b18,0x5b11,0x5b15,0x3729, 0x5b12,0x5b1c,0x372a,0x5b22,0x5b79,0x5da6,0x3816,0x5db3,0x5dab,0x5eea, 0x3899,0x5f5b,0x38d3,0x38f5,0x61b7,0x61ce,0x61b9,0x61bd,0x61cf,0x61c0, 0x6199,0x6197,0x3994,0x61bb,0x61d0,0x61c4,0x6231,0x3a56,0x64d3,0x64c0, 0x3a59,0x3a58,0x3a55,0x3a52,0x64dc,0x64d1,0x64c8,0x3a57,0x64d5,0x66c3, 0x3b1b,0x3b1c,0x66bf,0x66c5 }, { /* ku 31 */ 0x3b19,0x66cd,0x66c1,0x6706,0x3b3f,0x6724,0x6a63,0x6a42,0x6a52,0x3bdb, 0x6a43,0x6a33,0x3be2,0x6a6c,0x6a57,0x3bd7,0x6a4c,0x6a6e,0x3bde,0x3be5, 0x3be4,0x3be6,0x3bd6,0x6a37,0x3bdf,0x6a71,0x6a4a,0x6a36,0x3bdc,0x6a53, 0x3bda,0x6a45,0x6a70,0x3bd3,0x3bd0,0x6a5c,0x6b58,0x6b57,0x3c86,0x3c87, 0x3cad,0x3cb7,0x3d58,0x3d6a,0x6fbb,0x3d62,0x3d61,0x6fbe,0x3d69,0x3d6c, 0x3d65,0x6fb5,0x6fd3,0x6f9f,0x3d66,0x6fb7,0x6ff5,0x71b7,0x3df5,0x71bb, 0x3df4,0x71d1,0x3df7,0x71ba,0x3df8,0x71b6,0x71cc,0x3dfb,0x3dfc,0x71d3, 0x749b,0x3ef5,0x3ef8,0x7496,0x74a2,0x749d,0x750a,0x750e,0x3f3c,0x7581, 0x762c,0x7637,0x7636,0x763b,0x3fc5,0x76a1,0x4062,0x4063,0x7798,0x4067, 0x7796,0x4066,0x40d9,0x40db }, { /* ku 32 */ 0x78d6,0x78eb,0x40d8,0x78dc,0x411b,0x79a5,0x79a9,0x9834,0x7a53,0x7a45, 0x4179,0x7a4f,0x417d,0x7abd,0x7abb,0x7af1,0x422c,0x4237,0x7bec,0x7bed, 0x4230,0x429a,0x7cd3,0x4a00,0x7ce1,0x4305,0x7e19,0x4307,0x4309,0x430a, 0x7e27,0x7e26,0x4379,0x43c2,0x806e,0x81af,0x4438,0x4437,0x81ad,0x4421, 0x81aa,0x8218,0x445e,0x453d,0x4537,0x4540,0x856f,0x854c,0x451d,0x8542, 0x4533,0x855c,0x8570,0x855f,0x4535,0x855a,0x854b,0x853f,0x878a,0x45d8, 0x878b,0x87a1,0x878e,0x45dc,0x45de,0x8799,0x885e,0x885f,0x8924,0x89a7, 0x8aea,0x8afd,0x8af9,0x8ae3,0x8ae5,0x46fa,0x46fb,0x8aec,0x473d,0x473b, 0x473f,0x475f,0x8cf2,0x477f,0x8cef,0x4784,0x8da6,0x47bc,0x4814,0x480f, 0x8e3b,0x8e43,0x480e,0x8e32 }, { /* ku 33 */ 0x8f31,0x8f30,0x4860,0x8f2d,0x8f3c,0x8fa7,0x8fa5,0x48ab,0x48ac,0x48aa, 0x9137,0x9195,0x918e,0x4904,0x9196,0x4908,0x9345,0x930a,0x4933,0x4934, 0x92fd,0x9317,0x931c,0x9307,0x9331,0x9332,0x932c,0x9330,0x9303,0x9305, 0x49a2,0x95c2,0x49a4,0x95b8,0x49a5,0x95c1,0x49a7,0x49a6,0x49e7,0x96ab, 0x96b7,0x49ff,0x49fe,0x9715,0x9714,0x4a1d,0x4a1c,0x970c,0x9717,0x4a67, 0x9793,0x4a94,0x97d2,0x4ac5,0x4ac8,0x9836,0x9831,0x9833,0x983c,0x982e, 0x983a,0x4ac9,0x983d,0x4ac7,0x98b5,0x9922,0x9923,0x9920,0x991c,0x991d, 0x4b6c,0x99a0,0x4b8a,0x99ef,0x99e8,0x99eb,0x4b88,0x4b87,0x4b86,0x99e1, 0x99e6,0x4bcf,0x4bd0,0x9af8,0x9af5,0x4c1c,0x4c23,0x9b83,0x9b94,0x9b84, 0x4c49,0x9b8b,0x9b8f,0x4c43 }, { /* ku 34 */ 0x9b8c,0x4c48,0x9b89,0x4c47,0x9b8e,0x4c46,0x4c3f,0x4c44,0x9d24,0x9d0f, 0x4cbe,0x9d13,0x9d0a,0x4cc2,0x4cba,0x4cbc,0x4cc6,0x9d2a,0x9d1a,0x4cc8, 0x9d27,0x9d16,0x9d21,0x4d23,0x9e85,0x9eac,0x9ec6,0x9ec5,0x9ed7,0x9f53, 0x349d,0x5128,0x5127,0x51df,0x3524,0x5335,0x53b3,0x3607,0x568a,0x567d, 0x5689,0x3679,0x58cd,0x58d0,0x3678,0x5b2b,0x5b33,0x5b29,0x5b35,0x5b31, 0x5b37,0x5c36,0x5dbe,0x3819,0x5db9,0x381c,0x5dbb,0x3818,0x61e2,0x61db, 0x61dd,0x61dc,0x61da,UBOGON,0x61d9,0x39bd,0x3a5d,0x64df,0x3a5a,0x3a5e, 0x64e1,0x3a5c,0x64ee,0x3a5b,0x65b5,0x66d4,0x66d5,0x3b21,0x66d0,0x66d1, 0x66ce,0x66d7,0x3b20,0x3b32,0x6a7d,0x6a8a,0x3bf2,0x6aa7,0x3bf5,0x6a99, 0x6a82,0x6a88,0x3bee,0x3bec }, { /* ku 35 */ 0x6a86,0x3bea,0x6a98,0x6a9d,0x3bed,0x3bf3,0x6a8f,0x3bf6,0x6aaa,0x3c48, 0x6b5d,0x3c49,0x6c0a,0x3d75,0x6fd7,0x6fd6,0x6fe5,0x3d6f,0x3d7b,0x3d73, 0x6fd9,0x6fda,0x6fea,0x3d70,0x6ff6,UBOGON,0x3d78,0x71e3,0x3dfe,0x71e9, 0x3e00,0x71eb,0x71ef,0x71f3,0x71ea,0x3e01,UBOGON,0x3e55,0x3e56,0x3e9d, 0x7371,0x3ef9,0x74ae,0x3eff,0x74b3,0x3efd,0x74ac,0x3f43,0x3f41,0x7583, 0x7645,0x764e,0x7644,0x76a3,0x76a5,0x77a6,0x77a4,0x406f,0x77a9,0x77af, 0x408a,0x40e5,0x40e6,0x78f0,0x78f8,0x78f1,0x417f,0x7a49,0x41b5,0x41b6, 0x41bb,0x7ac2,0x7af2,0x7af3,0x7bfa,0x4240,0x7bf6,0x7bfc,0x7c18,0x7c08, 0x7c12,0x429d,0x429c,0x7cdb,0x7cda,0x430f,0x4311,0x430d,0x7e2c,0x7e4d, 0x4314,0x4313,0x7f46,0x7ff6 }, { /* ku 36 */ 0x802b,0x8074,0x81b8,0x81c8,0x4482,0x4483,0x454d,0x8592,0x8593,0x454f, 0x857f,0x85ab,0x8597,0x454c,0x4551,0x85ac,0x45ee,0x45e8,0x4ccb,0x87ce, 0x45eb,0x87cd,0x45e2,0x45e6,0x87c1,0x87b1,0x87c7,0x45ec,0x8940,0x4659, 0x893f,0x8939,0x465d,0x8943,0x4657,0x465b,0x4656,0x89ab,0x46fe,0x8b1f, 0x8b09,0x8b0c,0x4700,0x4701,0x8c40,0x4742,0x8c96,0x4760,0x8cf6,0x8cf7, 0x481d,0x8e46,0x8e4f,0x483e,0x4869,0x4865,0x8f3d,0x8f41,0x9366,0x9378, 0x935d,0x9369,0x9374,0x937d,0x936e,0x9372,0x9373,0x9362,0x9348,0x9353, 0x935f,0x9368,0x4938,0x937f,0x936b,0x49ae,0x95c4,0x49ad,0x96af,0x96ad, 0x96b2,0x4a02,0x4a1f,0x971a,0x971b,0x4a22,0x4a20,UBOGON,0x4a6c,0x979b, 0x979f,0x4a68,0x4a6d,0x4a6e }, { /* ku 37 */ 0x4aa0,0x4ace,0x4ad0,0x4ad1,0x4acb,0x9840,0x4ad2,0x9847,0x4ad3,0x98b7, 0x4b20,0x4b4e,0x4b4b,0x4b72,0x4b70,0x99a2,0x4b92,0x4b8f,0x9a00,0x99f3, 0x4b90,UBOGON,0x99f5,0x4bd9,0x4bd5,0x9abd,0x9b00,0x9b02,0x4bfa,0x9b34, 0x9b49,0x9b9f,0x4c4b,0x9ba3,0x9bcd,0x9b99,0x9b9d,0x4cd0,0x4cce,0x9d39, 0x4ccf,0x9d44,0x4cc4,0x4ccc,0x9d35,0x4cd2,0x4d35,0x9eaf,0x3e03,0x512f, 0x349e,0x34af,0x9f8e,0x360c,0x569f,0x569b,0x569e,0x5696,0x5694,0x56a0, 0x367c,0x5b3b,0x3730,0x3731,0x5b3a,0x5dc1,0x5f4d,0x5f5d,0x61f3,0x39a1, 0x399e,0x3a68,0x3a61,0x64f6,0x64e5,0x64ea,0x64e7,0x6505,0x3a65,0x64f9, 0x3a66,0x3a6a,0x3aab,0x6aab,0x6aed,0x6ab2,0x6ab0,0x6ab5,0x6abe,0x6ac1, 0x6ac8,0x3bf9,0x6ac0,0x6abc }, { /* ku 38 */ 0x6ab1,0x6ac4,0x6abf,0x3c58,0x3c8a,0x7008,0x7003,0x6ffd,0x7010,0x7002, 0x7013,0x3e04,0x71fa,0x7200,0x74b9,0x74bc,0x3f02,0x765b,0x7651,0x764f, 0x76eb,0x77b8,0x4079,0x77b9,0x77c1,0x77c0,0x77be,0x790b,0x40eb,0x7907, 0x790a,0x7908,0x40e9,0x790d,0x7906,0x7915,0x79af,0x4120,0x4121,0x4181, 0x7af5,0x424d,0x4259,0x7c2e,0x4258,0x7c1b,UBOGON,0x7c1a,0x7c24,0x42a5, 0x42a9,0x7ce6,0x7ce3,0x431a,0x4319,0x7e5d,0x7e4f,0x7e66,0x7e5b,0x7f47, 0x7fb4,0x4396,0x4398,0x4397,0x7ffa,0x802e,UBOGON,0x43c8,0x81ce,0x4443, 0x4445,0x8219,0x4552,0x4557,0x85cc,0x85b2,0x4555,0x85bb,0x85c1,0x4556, 0x4558,0x45f2,0x87e9,0x87ee,0x87f0,0x87d6,0x880e,0x87da,0x8948,0x894a, 0x894e,0x894d,0x89b1,0x89b0 }, { /* ku 39 */ 0x89b3,0x4707,0x8b38,0x8b32,0x4708,0x8b2d,0x470a,0x8b34,0x431b,0x8b29, 0x8c74,0x4761,0x4762,0x8d03,0x47c2,0x47c6,0x8da9,0x8e58,0x481e,0x4825, 0x8ebf,0x8ec1,0x8f4a,0x8fac,0x48b0,0x9089,0x913d,0x913c,0x91a9,0x93a0, 0x493d,0x9390,0x493e,0x9393,0x938b,0x93ad,0x93bb,0x93b8,0x4946,0x4945, 0x939c,0x95d8,0x95d7,0x4a03,0x4a26,0x4a27,0x975d,0x97a9,0x97da,0x4a98, 0x4aad,0x4ad5,0x4ada,0x9854,0x4ad9,0x9855,0x984b,0x4add,0x983f,0x98b9, 0x4b15,0x4b16,0x4b17,0x4b21,0x9938,0x9936,0x9940,0x4b4c,0x993b,0x9939, 0x99a4,0x4b96,0x4b98,0x9a08,0x9a0c,0x4b9b,0x9a10,0x4bff,0x9b07,0x4c25, 0x9bd2,0x4c4f,0x9bc2,0x9bbb,0x9bcc,0x9bcb,0x4c56,0x4c54,0x9d4d,0x9d63, 0x9d4e,0x4cd8,0x9d50,0x9d55 }, { /* ku 3a */ 0x4cd7,0x9d5e,0x4d26,0x9e90,0x9eb2,0x9eb1,0x4d38,0x9eca,0x9f02,0x9f27, 0x9f26,0x4d8a,0x56af,0x58e0,0x58dc,0x3734,0x5b39,0x3735,UBOGON,0x5b7c, 0x5bf3,UBOGON,0x37a1,0x5c6b,0x5dc4,0x650b,0x6508,0x650a,0x3a6c,0x3a6d, 0x65dc,0x3b29,0x3b2a,0x66e1,0x66df,0x6ace,0x6ad4,0x6ae3,0x6ad7,0x6ae2, 0x3c00,0x3c08,0x3c06,0x3c05,0x6ad8,0x6ad5,0x6ad2,0x3cb1,0x3d88,0x701e, 0x702c,0x7025,0x6ff3,0x7204,0x7208,0x7215,0x3e09,0x74c4,0x74c9,0x74c7, 0x74c8,0x76a9,0x77c6,0x77c5,0x7918,0x791a,0x7920,0x4122,0x7a66,0x7a64, 0x7a6a,0x41d5,0x4261,0x425d,0x4262,0x424f,0x4260,0x7c35,0x7c34,0x42aa, 0x4322,0x7e6c,0x4321,0x7e6e,0x7e71,0x4446,0x81d4,0x81d6,0x821a,0x8262, 0x8265,0x8276,0x85db,0x85d6 }, { /* ku 3b */ 0x4562,0x85e7,0x4560,0x4564,0x85f4,UBOGON,0x87fd,0x87d5,0x8807,0x45f6, 0x880f,0x87f8,UBOGON,0x4619,0x8987,0x4691,0x89b5,0x89f5,0x470d,0x8b3f, 0x8b43,0x8b4c,0x4765,0x8d0b,0x8e6b,0x8e68,0x8e70,0x8e75,0x8e77,0x483f, 0x8ec3,0x494b,0x93e9,0x93ea,0x93cb,0x93c5,0x93c6,0x4948,0x93ed,0x93d3, 0x4952,0x93e5,0x494a,0x4951,0x93db,0x93eb,0x93e0,0x93c1,0x4950,0x494c, 0x95dd,0x49ee,0x4a04,0x4a06,0x4a2d,0x4a2e,0x4a2f,0x4a7b,0x4a78,0x4a77, 0x97b2,0x97b4,0x97b1,0x97b5,0x97f2,0x4aa2,0x4aa1,0x4ae3,0x9856,0x4b1a, 0x4b19,0x4b57,0x9944,0x4b9e,0x9a26,0x9a1f,0x9a18,0x9a21,0x9a17,0x4bdd, 0x9b09,0x4c05,0x4c28,0x9bc5,0x9bdf,0x4c60,0x9be3,0x4c66,0x9be9,0x9bee, 0x4c67,0x4c68,0x9d66,0x9d7a }, { /* ku 3c */ 0x4cde,0x9d6e,0x9d91,0x9d83,0x9d76,0x9d7e,0x9d6d,0x4ce1,0x9e95,0x9ee3, 0x4d69,0x4d77,0x9f03,0x9f04,UBOGON,0x9f17,0x34a6,0x5136,0x34a5,0x5336, 0x3614,0x5b42,0x3736,0x3738,0x5b44,0x5b46,0x5b7e,0x5dca,0x5dc8,0x5dcc, 0x5ef0,0x3a70,0x6585,0x66e5,0x66e7,0x3b2b,0x3c11,0x3c0a,0x6af4,0x3c0d, 0x6ae9,0x3c16,0x3c10,0x3c09,0x3c0e,0x3c7a,0x703d,0x3d8c,0x7036,0x3d91, 0x7216,0x3e0a,0x7212,0x720f,0x7217,0x7211,0x720b,0x3e08,0x3e0b,0x74cd, 0x74d0,0x74cc,0x74ce,0x74d1,0x3f07,0x7589,0x40f2,0x7a6f,0x7c4b,0x7c44, 0x7c55,0x42ae,0x4324,0x4326,0x4327,0x7e7f,0x8b71,0x4399,0x802f,0x807a, 0x807b,0x807c,0x455f,0x456a,0x4571,0x85fc,0x8610,0x8602,0x456c,0x456f, 0x85ee,0x8603,0x4568,0x860d }, { /* ku 3d */ 0x8613,0x8608,0x860f,0x8818,0x8812,0x4601,0x4668,0x8967,0x8965,0x89bb, 0x8b69,0x8b62,0x4713,0x8b6e,0x4716,0x8b61,0x4718,0x8b64,0x8b4d,0x8c51, 0x4789,0x47c8,0x8e83,0x8ec6,0x4884,0x941f,0x4954,0x9404,0x9417,0x9408, 0x9405,0x4956,0x93f3,0x941e,0x9402,0x941a,0x941b,0x9427,0x941c,0x495a, 0x96b5,0x4a05,0x4a07,0x9733,0x4a31,0x9734,0x9731,0x97b8,0x97ba,0x4aa3, 0x97fc,0x4aeb,0x4b1c,0x98c3,0x4b5a,0x994d,0x4b5b,0x9a2f,0x4ba6,0x4baa, 0x4ba5,0x9ac9,0x4be1,0x9ac8,0x9ac4,0x9b2a,0x9b38,0x9b50,0x4c2a,0x9c0a, 0x9bfb,0x9c04,0x9bfc,0x9bfe,0x4c72,0x4c6f,0x4c73,0x9c02,0x9bf6,0x9c1b, 0x9bf9,0x9c15,0x9c10,0x9bff,0x9c00,0x9c0c,0x4c6b,0x4ce6,0x9d95,0x9da5, 0x4ce9,0x4cec,0x4ce8,0x4cf0 }, { /* ku 3e */ 0x9e98,0x9ec1,0x4d8c,0x9f5a,0x5164,0x56bb,0x3615,0x58e6,0x5b49,0x5bf7, 0x3771,0x3826,0x5dd0,0x38c6,0x5fc2,0x39a8,0x6511,0x3a73,0x6aff,0x6afe, 0x6afd,0x3c15,0x6b01,0x3d98,0x3d97,0x704b,0x704d,0x7047,0x74d3,0x7668, 0x7667,0x3fd7,0x4080,0x77d1,0x7930,0x7932,0x792e,0x4188,0x9f9d,0x7ac9, 0x7ac8,0x4269,0x7c56,0x7c51,0x426b,0x4329,0x4328,0x7e85,0x7e89,0x7e8e, 0x7e84,0x445f,0x826a,0x862b,0x862f,0x8628,0x4574,0x8616,0x8615,0x861d, 0x881a,0x4602,0x466a,0x4694,0x89bc,0x8b75,0x8b7c,0x478a,0x8d11,0x8d12, 0x8f5c,0x91bb,0x4964,0x93f4,0x495e,0x4961,0x942d,0x4965,0x4966,0x96e4, 0x9737,0x9736,0x9767,0x97be,0x97bd,0x97e2,0x9868,0x9866,0x98c8,0x98ca, 0x98c7,0x98dc,0x4b5f,0x994f }, { /* ku 3f */ 0x99a9,0x9a3c,0x4baf,0x9a3b,0x9ace,0x4c0d,0x9b14,0x9b53,0x4c7c,0x9c2e, 0x4c7a,0x9c1f,0x4c76,0x4c79,0x4c7d,0x4c77,0x9db0,0x9dbd,0x4cf6,0x4cf1, 0x9dae,0x9dc4,0x9e7b,0x400b,0x4d29,0x9e9e,0x4d6f,0x9f05,0x4d9a,0x9f69, 0x9fa1,0x56c7,0x571d,0x5b4a,0x5dd3,0x3869,0x5f72,0x6202,0x39ab,0x6235, 0x6527,0x651e,0x651f,0x3b2c,0x3b2d,0x6b07,0x6b06,0x3c17,0x3d9a,0x7054, 0x721c,0x7220,0x7af8,0x426e,0x7c5d,0x7c58,0x432c,0x7e92,0x7f4e,0x43ca, 0x4578,0x4606,0x8827,0x4607,0x8b81,0x8b83,0x4720,0x8c44,0x4753,0x47ce, 0x487a,0x4879,0x9442,0x944d,0x9454,0x944e,0x496b,0x9443,0x4967,0x496d, 0x973c,0x9740,0x97c0,0x4a85,0x4ab0,0x4af3,0x4b63,0x995a,0x9a51,0x4bb6, 0x9add,0x4c82,0x4c7f,0x9c38 }, { /* ku 40 */ 0x4c86,0x9c45,0x9c3a,0x4c84,0x9c35,0x4cfc,0x4cfd,0x4cfa,0x9ef1,0x4d87, 0x9f93,0x529a,0x361a,0x3619,0x8641,0x5dd7,0x3a75,0x6528,0x3c1a,0x3c1b, 0x3c19,0x7053,0x7059,0x3d9c,0x7221,0x3e10,0x766f,0x7937,0x79b5,0x7c62, 0x7c5e,0x7cf5,0x457b,0x457c,0x863d,0x4608,0x882d,0x8989,0x8b8d,0x8b87, 0x8b90,0x8d1a,0x8e99,0x4841,0x48e3,0x4972,0x945f,0x4973,0x4968,0x9456, 0x9461,0x945b,0x945a,0x945c,0x9465,0x4a35,0x9741,0x4a88,0x4a9d,0x986e, 0x986c,0x986d,0x4275,0x99aa,0x9a5c,0x9a58,0x9ade,0x4c8f,0x9c4f,0x9c51, 0x4c8e,0x9c53,0x4d05,0x4d04,0x4cff,0x9dfc,0x9f39,0x4d9e,0x513e,0x3554, 0x56d2,0x3681,0x5b4f,0x6b14,0x40fa,0x7a72,0x7a73,0x4332,0x4670,0x466e, 0x8b91,UBOGON,0x487c,0x91bf }, { /* ku 41 */ 0x4975,0x946c,0x4974,0x4977,0x96e6,0x9745,0x4a37,0x97c8,0x97e4,0x995d, 0x4bba,0x9b21,0x4c11,0x9b2c,0x9b57,0x4c92,0x4c99,0x9c5d,0x9c61,0x9c65, 0x9e08,0x4d0a,0x4d2a,0x4d2b,0x4d44,0x4d79,0x9f45,0x34aa,0x3748,0x6205, 0x66ef,0x6b1b,0x6b1d,0x7225,0x7224,0x7c6d,0x42b4,0x8642,0x8649,0x460d, 0x8978,0x898a,0x8b97,0x4754,0x8c9b,0x8d1c,0x4830,0x8ea2,0x4a09,0x4a38, 0x4a36,0x4a8b,0x4af7,0x4b66,0x4bbd,0x4c1e,0x9c6c,0x4c96,0x9c6f,0x4d0d, 0x9e0e,0x4d73,0x9f08,0x9f1d,0x9fa3,0x373b,0x373c,0x5f60,0x6b1c,0x3da0, 0x40fb,UBOGON,0x7cf3,0x4581,0x8b9b,0x8ea7,0x91c4,0x4978,0x947a,0x4a8d, 0x4b73,0x9a61,0x9a63,0x9ad7,0x9c76,0x4da6,0x9fa5,0x39ad,0x7067,0x3e11, 0x72ab,0x864a,0x897d,0x8b9d }, { /* ku 42 */ 0x8c53,0x8f65,0x947b,0x4a39,0x98cd,0x98dd,0x4bbf,0x9b30,0x9e16,0x4d0f, 0x4da7,0x4db5,0x3fdc,0x4831,0x96e7,0x9e18,0x9ea2,0x4da8,0x9f7c,0x4125, 0x7e9e,0x9484,0x4bc1,0x9e1c,0x4190,0x7c71,0x97ca,0x4696,0x487f,0x4d10, 0x9ea3,0x4a0a,0x9c7b,0x9f97,0x4d12,0x4a3a,0x9750,0x4a3b,UBOGON,UBOGON, UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON, UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON, UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON, UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON, UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON, UBOGON,UBOGON,UBOGON,UBOGON }, { /* ku 43 */ UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON, UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON, UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON, UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON, UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON, UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON, UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON, UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON, UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON, UBOGON,UBOGON,UBOGON,UBOGON }, { /* ku 44 */ UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON, UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON, UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON, UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,0x4f66, 0x4f68,0x4fe7,0x503f,UBOGON,0x50a6,0x510f,0x523e,0x5324,0x5365,0x539b, 0x517f,0x54cb,0x5573,0x5571,0x556b,0x55f4,0x5622,0x5620,0x5692,0x56ba, 0x5691,0x56b0,0x5759,0x578a,0x580f,0x5812,0x5813,0x5847,0x589b,0x5900, 0x594d,0x5ad1,0x5ad3,0x5b67,0x5c57,0x5c77,0x5cd5,0x5d75,0x5d8e,0x5da5, 0x5db6,0x5dbf,0x5e65,0x5ecd,0x5eed,0x5f94,0x5f9a,0x5fba,0x6125,0x6150, 0x62a3,0x6360,0x6364,0x63b6 }, { /* ku 45 */ 0x6403,0x64b6,0x651a,0x7a25,0x5c21,0x66e2,0x6702,0x67a4,0x67ac,0x6810, 0x6806,0x685e,0x685a,0x692c,0x6929,0x6a2d,0x6a77,0x6a7a,0x6aca,0x6ae6, 0x6af5,0x6b0d,0x6b0e,0x6bdc,0x6bdd,0x6bf6,0x6c1e,0x6c63,0x6da5,0x6e0f, 0x6e8a,0x6e84,0x6e8b,0x6e7c,0x6f4c,0x6f48,0x6f49,0x6f9d,0x6f99,0x6ff8, 0x702e,0x702d,0x705c,0x79cc,0x70bf,0x70ea,0x70e5,0x7111,0x7112,0x713f, 0x7139,0x713b,0x713d,0x7177,0x7175,0x7176,0x7171,0x7196,0x7193,0x71b4, 0x71dd,0x71de,0x720e,0x5911,0x7218,0x7347,0x7348,0x73ef,0x7412,0x743b, 0x74a4,0x748d,0x74b4,0x7673,0x7677,0x76bc,0x7819,0x781b,0x783d,0x7853, 0x7854,0x7858,0x78b7,0x78d8,0x78ee,0x7922,0x794d,0x7986,0x7999,0x79a3, 0x79bc,0x7aa7,0x7b37,0x7b59 }, { /* ku 46 */ 0x7bd0,0x7c2f,0x7c32,0x7c42,0x7c4e,0x7c68,0x7ca9,0x7ced,0x7dd0,0x7e07, 0x7dd3,0x7e64,0x7f40,UBOGON,0x8041,0x8063,0x80bb,0x6711,0x6725,0x8248, 0x8310,0x8362,0x8312,0x8421,0x841e,0x84e2,0x84de,0x84e1,0x8573,0x85d4, 0x85f5,0x8637,0x8645,0x8672,0x874a,0x87a9,0x87a5,0x87f5,0x8834,0x8850, 0x8887,0x8954,0x8984,0x8b03,0x8c52,0x8cd8,0x8d0c,0x8d18,0x8db0,0x8ebc, 0x8ed5,0x8faa,0x909c,UBOGON,0x915c,0x922b,0x9221,0x9273,0x92f4,0x92f5, 0x933f,0x9342,0x9386,0x93be,0x93bc,0x93bd,0x93f1,0x93f2,0x93ef,0x9422, 0x9423,0x9424,0x9467,0x9466,0x9597,0x95ce,0x95e7,0x973b,0x974d,0x98e4, 0x9942,0x9b1d,0x9b98,UBOGON,0x9d49,0x6449,0x5e71,0x5e85,0x61d3,0x990e, 0x8002,0x781e,UBOGON,UBOGON }, { /* ku 47 */ 0x5528,0x5572,0x55ba,0x55f0,0x55ee,0x56b8,0x56b9,0x56c4,0x8053,0x92b0, UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON, UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON, UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON, UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON, UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON, UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON, UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON, UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON, UBOGON,UBOGON,UBOGON,UBOGON } }; /* CNS 11643 plane 4 conversion table */ static const unsigned short cns11643_4tab[MAX_CNS11643_KU_4][MAX_CNS11643_TEN] = { { /* ku 01 */ UBOGON,0x4e40,0x4e41,0x4e5a,UBOGON,0x4e02,0x4e29,UBOGON,UBOGON,0x5202, 0x353e,0x5ddc,UBOGON,UBOGON,UBOGON,0x5342,0x536a,0x5b52,UBOGON,UBOGON, UBOGON,0x5fc4,0x624c,0x72ad,0x4e12,0x4e2f,0x4e96,0x4ed0,0x5142,0x5183, UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,0x5383,0x53b8,UBOGON,UBOGON,UBOGON, 0x5928,UBOGON,0x5c23,0x5e01,0x5f00,UBOGON,0x3cb8,0x706c,0x722b,0x5188, 0x8279,0x8fb6,0x4e17,UBOGON,0x340c,UBOGON,0x3430,0x4ee2,0x4edb,UBOGON, UBOGON,0x51ad,UBOGON,0x51f7,0x34da,UBOGON,UBOGON,0x3513,0x531b,0x5388, 0x5387,UBOGON,0x53cf,0x53fd,0x3563,0x53e7,0x56dc,UBOGON,0x56d9,0x5725, 0x5727,0x5933,0x5c13,UBOGON,UBOGON,0x5c75,UBOGON,UBOGON,UBOGON,0x39c4, 0x39c3,0x66f1,UBOGON,UBOGON }, { /* ku 02 */ 0x7f52,UBOGON,UBOGON,0x3401,UBOGON,UBOGON,0x4e51,0x4e6a,UBOGON,0x4f0c, UBOGON,UBOGON,0x4efe,0x4f1b,UBOGON,UBOGON,0x343a,UBOGON,0x34ab,0x5173, UBOGON,0x518e,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,0x34dd,UBOGON,UBOGON, 0x52a5,0x3515,0x52a7,0x52a4,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,0x53bd, UBOGON,UBOGON,UBOGON,0x5402,UBOGON,UBOGON,UBOGON,UBOGON,0x572b,0x591b, 0x5935,UBOGON,0x36a7,0x36a5,UBOGON,UBOGON,0x36a6,UBOGON,UBOGON,0x5c17, 0x377c,UBOGON,0x5c70,0x5c7d,0x37a9,UBOGON,0x5de9,UBOGON,0x3834,0x3835, UBOGON,UBOGON,UBOGON,0x38a8,0x5f19,0x5f1c,0x5f75,UBOGON,UBOGON,0x38ff, 0x5fc8,UBOGON,0x39c7,0x39c6,0x39c8,UBOGON,UBOGON,0x3ad0,0x3ad1,UBOGON, UBOGON,0x3c59,UBOGON,UBOGON }, { /* ku 03 */ 0x6c12,0x3cbd,UBOGON,UBOGON,UBOGON,0x3e28,0x72b3,UBOGON,0x3ea9,0x7390, 0x7536,UBOGON,0x43cc,UBOGON,0x8281,0x8fb8,UBOGON,0x48b4,UBOGON,UBOGON, 0x4e23,0x3416,0x342c,UBOGON,0x4f2e,UBOGON,0x514f,UBOGON,0x51ba,0x34df, 0x34e0,0x5222,UBOGON,UBOGON,UBOGON,0x3517,UBOGON,0x52af,0x52b0,0x52b1, UBOGON,UBOGON,0x352f,UBOGON,0x5364,UBOGON,0x53d3,UBOGON,0x3574,UBOGON, 0x3570,0x356d,UBOGON,UBOGON,UBOGON,UBOGON,0x356e,UBOGON,UBOGON,UBOGON, UBOGON,0x362b,0x3628,UBOGON,UBOGON,0x593f,UBOGON,UBOGON,0x3692,UBOGON, 0x598b,UBOGON,0x5991,0x5995,UBOGON,UBOGON,0x373f,UBOGON,0x5b8a,0x374f, 0x3774,UBOGON,UBOGON,0x377d,UBOGON,0x37b7,0x37a3,0x37b0,0x37b1,0x5c87, 0x37ab,UBOGON,UBOGON,UBOGON }, { /* ku 04 */ 0x383a,0x3837,0x5e0d,0x3838,0x3840,UBOGON,UBOGON,0x5e8e,0x389f,UBOGON, UBOGON,0x5f7a,UBOGON,0x3904,0x3909,0x3906,0x38fd,0x390a,0x3907,UBOGON, UBOGON,0x39ca,UBOGON,UBOGON,0x6290,0x39c9,UBOGON,0x629a,UBOGON,0x653c, 0x653a,0x3a7f,0x6598,UBOGON,0x3ad2,UBOGON,UBOGON,0x6765,UBOGON,0x3b43, UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,0x3cc1,UBOGON,0x3cc5,0x3da3, UBOGON,UBOGON,0x3e2a,0x3e5f,UBOGON,UBOGON,0x3e5d,UBOGON,UBOGON,UBOGON, UBOGON,0x3f17,UBOGON,UBOGON,0x3f71,0x3f72,UBOGON,UBOGON,0x400f,UBOGON, UBOGON,0x79c2,0x4191,UBOGON,UBOGON,UBOGON,0x43b2,0x43cf,0x43ce,0x809e, UBOGON,UBOGON,0x81eb,UBOGON,0x8289,0x4496,UBOGON,UBOGON,0x8296,UBOGON, 0x8287,UBOGON,0x4497,UBOGON }, { /* ku 05 */ 0x8fc0,0x488b,0x8fc3,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON, 0x9578,UBOGON,UBOGON,0x9625,UBOGON,0x4e75,0x4e74,UBOGON,UBOGON,0x342d, UBOGON,0x4f99,UBOGON,0x3450,0x344b,UBOGON,0x344f,0x344c,UBOGON,0x4f71, 0x5153,0x51bf,UBOGON,UBOGON,0x51c0,UBOGON,0x51ee,UBOGON,0x34e4,0x34e3, UBOGON,0x34e1,UBOGON,0x34e2,UBOGON,0x523d,0x3519,0x52bd,0x530c,UBOGON, UBOGON,UBOGON,UBOGON,0x3541,0x7f37,UBOGON,0x53c0,0x355e,UBOGON,UBOGON, 0x3579,UBOGON,0x546e,0x5483,UBOGON,UBOGON,0x545e,0x545d,0x577e,0x5779, UBOGON,0x577a,0x576c,UBOGON,UBOGON,UBOGON,0x3632,0x5787,UBOGON,0x591d, 0x3694,0x5946,0x3697,UBOGON,0x5943,UBOGON,0x3696,0x3698,UBOGON,UBOGON, 0x36b2,UBOGON,UBOGON,UBOGON }, { /* ku 06 */ 0x36b9,0x5b61,0x5b66,UBOGON,0x5b90,0x3775,0x377f,0x377e,0x5c29,0x378f, UBOGON,UBOGON,UBOGON,0x37bd,0x5cb2,UBOGON,0x37bb,0x37bc,UBOGON,0x5cc0, UBOGON,0x383d,0x383e,0x3874,UBOGON,0x387a,0x3876,0x3878,0x3875,UBOGON, UBOGON,0x38af,0x38b0,0x38c7,0x38cc,UBOGON,UBOGON,0x3916,UBOGON,0x3912, 0x391d,UBOGON,UBOGON,0x3915,0x390f,0x3914,0x601f,0x5fe2,UBOGON,UBOGON, UBOGON,0x39b0,0x39bf,0x39c0,UBOGON,0x39d2,0x39d9,UBOGON,0x3a7a,UBOGON, UBOGON,UBOGON,UBOGON,UBOGON,0x6616,0x65f9,0x3ada,UBOGON,0x6788,UBOGON, 0x679b,UBOGON,0x676e,0x679e,UBOGON,0x3c22,0x3c1f,UBOGON,UBOGON,0x3c21, 0x6b24,UBOGON,UBOGON,UBOGON,0x3c5c,0x6b7d,UBOGON,0x3c7d,0x3c8d,0x3c8f, 0x6ce6,UBOGON,0x6ccb,0x3cd0 }, { /* ku 07 */ UBOGON,0x3cd8,UBOGON,UBOGON,UBOGON,0x6cb5,0x3da7,UBOGON,0x7097,UBOGON, 0x709b,0x3e12,UBOGON,UBOGON,0x3e2f,UBOGON,0x726b,0x3e2e,0x3e2c,0x3e5c, UBOGON,0x72d5,UBOGON,UBOGON,0x3e62,0x3e67,0x3eb4,UBOGON,UBOGON,UBOGON, UBOGON,0x7543,UBOGON,UBOGON,0x759c,UBOGON,UBOGON,0x3fea,UBOGON,0x3ffb, UBOGON,0x4014,UBOGON,0x4013,0x4012,0x4010,0x4011,UBOGON,0x4086,0x77e4, 0x4098,UBOGON,UBOGON,0x412a,UBOGON,UBOGON,UBOGON,UBOGON,0x7ace,0x42b5, UBOGON,UBOGON,UBOGON,UBOGON,0x8013,0x43d6,0x43d8,0x80b7,0x43d9,0x43d4, 0x43d7,UBOGON,0x80b9,UBOGON,UBOGON,0x81e4,0x81fd,0x820f,0x4460,UBOGON, UBOGON,0x449e,0x44a1,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,0x82bf, 0x82ca,UBOGON,UBOGON,0x82c1 }, { /* ku 08 */ 0x44a0,UBOGON,UBOGON,UBOGON,UBOGON,0x8fd0,UBOGON,UBOGON,0x48b9,UBOGON, 0x90ae,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,0x49c1,0x49c2,0x9638,UBOGON, 0x341c,UBOGON,0x345e,0x4fbc,0x3459,0x345c,UBOGON,0x345f,0x4fe9,0x4fbd, 0x4fe2,0x5158,UBOGON,UBOGON,0x34ce,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON, 0x52c6,UBOGON,0x52c8,UBOGON,UBOGON,0x5328,UBOGON,0x5329,UBOGON,UBOGON, UBOGON,UBOGON,UBOGON,UBOGON,0x355f,UBOGON,0x3585,UBOGON,UBOGON,0x3586, UBOGON,0x57b4,UBOGON,0x57a9,0x3687,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON, 0x36ca,UBOGON,0x36c3,UBOGON,UBOGON,UBOGON,0x36c2,0x5b68,UBOGON,0x3741, UBOGON,UBOGON,UBOGON,0x3780,0x3781,UBOGON,UBOGON,0x3793,0x3792,UBOGON, 0x37c5,UBOGON,UBOGON,UBOGON }, { /* ku 09 */ 0x3846,0x3841,0x3845,0x3842,0x383f,UBOGON,UBOGON,0x3882,0x3881,0x387f, 0x38a5,0x5f2b,0x38b3,0x38b5,UBOGON,UBOGON,0x5f8d,0x38da,UBOGON,0x38db, 0x390d,0x6018,0x390e,UBOGON,0x391e,0x3925,0x3926,0x391c,0x3921,0x6057, 0x6048,0x3927,0x391a,UBOGON,UBOGON,UBOGON,0x6038,UBOGON,UBOGON,0x3924, UBOGON,UBOGON,0x6071,UBOGON,0x39c1,0x39e1,UBOGON,UBOGON,0x6312,0x39eb, UBOGON,0x39e2,0x39d7,0x39e9,UBOGON,UBOGON,0x630a,UBOGON,0x6323,UBOGON, 0x3a84,UBOGON,UBOGON,UBOGON,0x3ab5,0x3abc,0x3adc,0x3ade,0x3adf,UBOGON, 0x662a,UBOGON,UBOGON,UBOGON,UBOGON,0x3b54,0x67e0,0x67be,0x3b53,0x3c24, 0x3c25,0x6b29,0x3c28,0x3c27,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON, 0x3c8b,UBOGON,UBOGON,0x3cdc }, { /* ku 0a */ 0x6d43,UBOGON,UBOGON,UBOGON,UBOGON,0x70a6,0x3db2,0x70c0,UBOGON,0x722f, UBOGON,0x3e1b,UBOGON,0x3e32,0x7271,UBOGON,UBOGON,0x3e6b,UBOGON,0x3e6c, 0x3e6d,UBOGON,0x3eb9,0x3eba,0x3f09,0x3f0a,UBOGON,0x74ea,0x3f1b,UBOGON, UBOGON,0x7520,0x3f58,UBOGON,0x3f5a,UBOGON,UBOGON,0x3f77,UBOGON,UBOGON, 0x3f79,0x75a9,UBOGON,0x7685,UBOGON,0x3feb,UBOGON,0x3ffd,0x3ffc,0x7706, 0x4015,0x4018,0x76f6,0x4016,0x4017,0x4019,0x7700,0x401b,UBOGON,UBOGON, 0x7702,UBOGON,0x4087,UBOGON,UBOGON,0x409c,UBOGON,0x409a,UBOGON,0x40ff, 0x40fe,UBOGON,0x4131,0x412e,0x4130,0x4132,UBOGON,UBOGON,0x412f,UBOGON, 0x4195,0x4196,UBOGON,UBOGON,UBOGON,0x41c5,0x427a,UBOGON,0x4342,UBOGON, 0x4354,UBOGON,UBOGON,UBOGON }, { /* ku 0b */ UBOGON,UBOGON,UBOGON,UBOGON,0x8009,UBOGON,0x439f,0x43a0,0x43a2,0x43e0, UBOGON,0x43e1,UBOGON,UBOGON,0x43df,UBOGON,UBOGON,0x4462,0x4461,UBOGON, UBOGON,0x44a7,UBOGON,UBOGON,UBOGON,0x82da,UBOGON,UBOGON,0x830a,0x4589, UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,0x461d,UBOGON,UBOGON, 0x472a,UBOGON,UBOGON,0x47d3,0x4842,0x4843,UBOGON,0x4891,UBOGON,UBOGON, 0x4890,0x48bf,UBOGON,0x48bc,UBOGON,0x48c0,0x49c7,0x49c5,0x9655,UBOGON, 0x9652,0x4e35,UBOGON,UBOGON,0x5034,0x5001,UBOGON,0x500a,0x3466,UBOGON, UBOGON,UBOGON,0x34ad,UBOGON,UBOGON,UBOGON,UBOGON,0x5258,UBOGON,UBOGON, UBOGON,UBOGON,UBOGON,UBOGON,0x351d,UBOGON,0x3531,0x532b,UBOGON,0x354c, UBOGON,UBOGON,0x3595,0x3591 }, { /* ku 0c */ 0x3594,UBOGON,UBOGON,UBOGON,0x358f,0x54ec,UBOGON,0x5515,0x54fe,UBOGON, UBOGON,UBOGON,0x54e3,0x5516,0x3640,UBOGON,0x3641,UBOGON,0x57d3,UBOGON, UBOGON,UBOGON,UBOGON,0x5959,0x5a27,0x36d8,0x36d2,0x36da,0x5a28,0x5a10, 0x36d7,0x5a0e,0x3742,0x3757,UBOGON,UBOGON,UBOGON,0x5baf,UBOGON,0x5bba, 0x5bb1,UBOGON,UBOGON,0x3778,0x3782,0x3797,UBOGON,UBOGON,0x37c9,UBOGON, 0x37c8,0x37d6,0x37cc,UBOGON,0x37d0,UBOGON,UBOGON,0x37ce,0x37c7,0x5cfc, UBOGON,0x37cf,0x37cb,0x5cf2,0x5cfe,UBOGON,UBOGON,0x5df8,UBOGON,0x3847, UBOGON,0x3848,UBOGON,UBOGON,0x3883,0x3885,0x3884,UBOGON,UBOGON,0x5f2c, 0x38b8,0x38bc,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON, UBOGON,UBOGON,UBOGON,UBOGON }, { /* ku 0d */ UBOGON,0x3931,0x3934,0x3936,0x6082,UBOGON,UBOGON,0x3923,UBOGON,UBOGON, 0x393a,0x6091,0x608f,UBOGON,0x39b4,0x39b5,0x39ed,0x39ec,0x39d8,UBOGON, UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,0x39f6,0x39e7,UBOGON,UBOGON, 0x3a7c,0x3a7b,UBOGON,UBOGON,0x6547,0x654c,UBOGON,UBOGON,0x658a,UBOGON, 0x3abe,UBOGON,0x3ae7,0x3ae5,0x3aee,0x67e1,0x684a,UBOGON,0x3b59,0x3b5e, UBOGON,0x3b5a,0x683f,0x3b61,0x3b58,0x3b5b,0x67bd,UBOGON,0x3b5f,UBOGON, 0x3c2a,0x3c2d,UBOGON,0x3c23,0x3c2b,0x3c2c,UBOGON,0x3c7e,UBOGON,0x3c93, 0x3c99,UBOGON,UBOGON,0x3cb3,0x3ce7,0x3cea,UBOGON,UBOGON,UBOGON,UBOGON, UBOGON,UBOGON,0x3db4,UBOGON,0x70c9,0x3e17,UBOGON,UBOGON,UBOGON,0x3e21, UBOGON,0x3e38,0x3e37,0x3e74 }, { /* ku 0e */ 0x3e73,0x3e75,UBOGON,UBOGON,UBOGON,0x3e76,0x3e78,UBOGON,UBOGON,0x73ba, 0x3f0c,0x3f20,0x3f1e,UBOGON,0x3f5b,UBOGON,0x3f5c,UBOGON,0x3f83,0x75c6, 0x3f80,0x3f81,0x3f7e,0x3f88,0x3f85,0x3f89,0x3f7f,0x3f8e,UBOGON,UBOGON, 0x3f84,0x75b7,0x768c,UBOGON,0x768d,UBOGON,0x3fee,0x3fed,0x3ffe,UBOGON, 0x3fff,UBOGON,UBOGON,UBOGON,0x4023,UBOGON,0x7717,UBOGON,0x771c,0x401f, UBOGON,UBOGON,0x7714,UBOGON,0x408f,0x4090,UBOGON,UBOGON,UBOGON,0x40a0, UBOGON,0x40a6,0x409f,UBOGON,0x40a7,0x40a1,UBOGON,0x4102,0x4136,UBOGON, UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,0x41c8,UBOGON,UBOGON,0x41d8, 0x7b0c,0x41dd,0x41dc,UBOGON,0x41d7,UBOGON,0x41da,0x42ba,UBOGON,UBOGON, UBOGON,0x42be,0x42c2,0x42bb }, { /* ku 0f */ 0x42c0,UBOGON,UBOGON,UBOGON,0x7d23,UBOGON,UBOGON,UBOGON,0x4343,0x4355, UBOGON,UBOGON,0x4357,0x4368,0x7f98,0x7f90,UBOGON,UBOGON,UBOGON,UBOGON, UBOGON,UBOGON,UBOGON,0x43a1,UBOGON,0x803a,UBOGON,UBOGON,UBOGON,UBOGON, 0x43ea,UBOGON,0x43e7,UBOGON,UBOGON,UBOGON,UBOGON,0x43e8,0x43e9,UBOGON, UBOGON,0x4454,UBOGON,UBOGON,UBOGON,UBOGON,0x8226,0x4465,UBOGON,UBOGON, 0x448a,UBOGON,0x44b0,UBOGON,UBOGON,UBOGON,0x44bc,0x832e,UBOGON,0x8355, 0x831a,0x44b8,0x833d,UBOGON,0x44b2,UBOGON,0x8330,0x44bd,UBOGON,UBOGON, 0x458a,0x8651,0x45a1,UBOGON,0x45a2,UBOGON,0x8688,UBOGON,0x4615,UBOGON, UBOGON,0x4620,0x4673,UBOGON,0x898e,0x898d,UBOGON,UBOGON,UBOGON,UBOGON, UBOGON,0x8a09,0x8a14,0x46b1 }, { /* ku 10 */ UBOGON,UBOGON,0x472b,UBOGON,0x4745,UBOGON,0x4797,0x4798,UBOGON,0x47d5, UBOGON,UBOGON,0x4893,0x4896,0x9007,0x4894,UBOGON,UBOGON,0x48c7,0x48c5, UBOGON,UBOGON,UBOGON,0x48c4,UBOGON,0x9579,0x9584,0x49ce,0x49ca,0x49cc, 0x9657,0x49c9,0x96ba,UBOGON,UBOGON,UBOGON,0x346e,UBOGON,0x5067,UBOGON, UBOGON,0x3471,UBOGON,0x34bb,0x34d3,UBOGON,UBOGON,UBOGON,UBOGON,0x34f3, 0x34ed,0x34f5,UBOGON,UBOGON,0x34f1,0x34f2,0x34f6,0x3520,UBOGON,0x3528, UBOGON,0x5318,0x532c,0x5359,UBOGON,UBOGON,UBOGON,0x5368,0x537e,UBOGON, UBOGON,0x53a1,UBOGON,0x35a1,0x555b,0x35aa,0x35a9,UBOGON,0x35b5,0x35a5, 0x35a8,0x5542,0x35a7,0x5547,UBOGON,UBOGON,0x553d,UBOGON,UBOGON,0x5560, 0x57eb,UBOGON,UBOGON,UBOGON }, { /* ku 11 */ 0x364d,UBOGON,UBOGON,UBOGON,0x369c,0x595f,UBOGON,0x36ea,0x36e5,UBOGON, UBOGON,0x5b6f,UBOGON,0x375e,UBOGON,UBOGON,UBOGON,0x3786,0x3784,UBOGON, 0x5c5a,UBOGON,0x37d9,UBOGON,0x37de,UBOGON,UBOGON,UBOGON,0x37db,UBOGON, UBOGON,UBOGON,UBOGON,0x3831,UBOGON,UBOGON,0x384b,UBOGON,0x3849,0x384a, 0x384c,UBOGON,UBOGON,0x388a,UBOGON,0x3889,0x388b,UBOGON,0x38bb,0x5fa2, 0x5f9d,0x38e4,UBOGON,UBOGON,0x5fa3,UBOGON,UBOGON,0x393b,0x392e,0x393e, 0x3946,0x3953,UBOGON,0x3944,UBOGON,0x393f,0x3942,0x394f,UBOGON,0x3952, 0x394a,0x60c2,UBOGON,0x395a,0x60a5,0x3949,UBOGON,0x621c,UBOGON,0x621d, 0x3a03,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,0x6395,0x639a,0x3a01,0x3a06, 0x39fb,0x39f9,UBOGON,0x3a05 }, { /* ku 12 */ 0x39fa,UBOGON,0x63a6,UBOGON,0x39fe,UBOGON,0x3a7d,UBOGON,UBOGON,UBOGON, 0x6550,UBOGON,UBOGON,UBOGON,0x6552,UBOGON,UBOGON,UBOGON,UBOGON,0x65c8, UBOGON,0x3af0,0x3af2,UBOGON,0x6658,0x3af1,0x3ae6,UBOGON,UBOGON,UBOGON, 0x6888,UBOGON,0x3b6f,0x3b6d,0x3b69,UBOGON,UBOGON,0x3b6e,UBOGON,0x3c2f, 0x3c30,0x3c63,UBOGON,UBOGON,UBOGON,0x6bb8,0x3c80,0x6bb9,0x3c9a,0x3c94, 0x3c96,0x3c95,0x3c97,UBOGON,0x3cf4,0x3cfe,UBOGON,0x3d01,UBOGON,0x3d02, UBOGON,0x3cf9,UBOGON,UBOGON,UBOGON,UBOGON,0x3cf6,0x3cf7,UBOGON,UBOGON, UBOGON,0x3cff,UBOGON,UBOGON,UBOGON,UBOGON,0x6e0b,UBOGON,UBOGON,0x3dbf, 0x3dbc,0x7105,UBOGON,UBOGON,UBOGON,0x3dbe,0x3dc0,UBOGON,0x3e3b,0x3e39, UBOGON,UBOGON,UBOGON,0x3e3c }, { /* ku 13 */ UBOGON,0x7314,0x7304,UBOGON,0x3e7d,UBOGON,0x3e7f,0x3e7a,0x3e7c,0x7305, 0x3e7e,0x7315,0x730d,0x3e80,0x3ebf,0x3ec3,UBOGON,UBOGON,0x3ecc,0x3f0e, 0x3f0d,UBOGON,0x3f26,0x3f24,0x3f25,0x3f23,0x3f21,0x3f29,UBOGON,UBOGON, 0x3f8f,0x3f8d,UBOGON,0x3f8b,0x3f92,UBOGON,0x3f90,UBOGON,0x3fef,0x3ff0, UBOGON,UBOGON,0x4001,UBOGON,0x402e,0x402d,0x772e,0x4028,0x4029,0x402c, UBOGON,UBOGON,UBOGON,0x7741,0x4088,UBOGON,0x4092,0x4091,0x77ea,UBOGON, 0x7844,0x40a9,0x40ac,0x40ae,0x40aa,0x4106,0x4105,0x414a,0x413e,0x413c, 0x413b,UBOGON,0x4142,0x4141,0x4143,UBOGON,0x4145,UBOGON,0x419a,0x419b, 0x419f,0x419e,UBOGON,UBOGON,UBOGON,0x41de,0x41e2,0x41e6,UBOGON,0x7b29, 0x41e3,0x7b27,0x41df,UBOGON }, { /* ku 14 */ UBOGON,0x7c9d,UBOGON,UBOGON,0x427e,0x42c9,0x42cc,UBOGON,0x42d1,UBOGON, 0x42d0,UBOGON,0x42cf,0x42c8,UBOGON,0x42cd,UBOGON,UBOGON,0x4349,0x4347, 0x4358,0x436b,0x436c,0x436a,UBOGON,0x4380,0x4382,0x4384,0x7fc8,0x4383, UBOGON,UBOGON,0x43b6,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,0x8126,0x43f1, UBOGON,0x43f6,0x43f3,0x43f0,0x811c,UBOGON,UBOGON,0x8128,0x43f5,0x43f4, 0x43f7,UBOGON,UBOGON,UBOGON,UBOGON,0x4455,UBOGON,UBOGON,UBOGON,0x448b, 0x44cb,0x44c2,UBOGON,UBOGON,UBOGON,0x44ca,0x44cc,UBOGON,0x44c7,0x44c9, 0x8370,UBOGON,0x44c6,UBOGON,UBOGON,0x44c3,0x8382,UBOGON,0x83ac,UBOGON, 0x44c4,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,0x45a9,0x86ad, 0x45a8,0x45a6,UBOGON,UBOGON }, { /* ku 15 */ UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,0x86ca,0x8851,UBOGON,UBOGON,0x4622, UBOGON,0x4626,0x4624,0x4625,0x889d,0x462a,0x4674,UBOGON,0x4679,0x8990, 0x467a,UBOGON,UBOGON,0x89d8,0x89d7,0x4697,UBOGON,UBOGON,0x8a2e,UBOGON, 0x46bc,UBOGON,0x46b3,UBOGON,0x46bf,0x46b7,UBOGON,UBOGON,UBOGON,UBOGON, UBOGON,0x4734,0x4746,0x4748,0x8c59,UBOGON,UBOGON,0x4756,0x4767,UBOGON, UBOGON,0x4768,0x4799,0x479a,UBOGON,UBOGON,0x47d8,UBOGON,0x47db,0x47dc, 0x47dd,0x47d7,UBOGON,UBOGON,0x4849,0x484a,0x8eda,UBOGON,UBOGON,0x9033, UBOGON,0x9018,0x489a,UBOGON,0x48cd,0x48ca,UBOGON,0x48cb,UBOGON,0x48cf, UBOGON,UBOGON,0x48cc,0x48ea,0x48ed,UBOGON,UBOGON,0x48e9,UBOGON,0x491a, 0x91ef,0x498d,0x49d2,UBOGON }, { /* ku 16 */ UBOGON,UBOGON,UBOGON,0x49f2,UBOGON,UBOGON,UBOGON,0x4a3d,UBOGON,0x4a3e, 0x4af8,0x4b23,0x9ad9,0x4eb4,UBOGON,0x50a0,0x5090,0x3475,0x5086,0x5084, UBOGON,0x508a,0x3476,0x3473,0x509f,0x50a1,UBOGON,0x5093,0x34bd,UBOGON, 0x51d5,UBOGON,UBOGON,0x34f9,UBOGON,UBOGON,0x34fa,UBOGON,UBOGON,UBOGON, UBOGON,UBOGON,0x3521,UBOGON,0x3529,UBOGON,UBOGON,0x3538,0x354e,UBOGON, UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,0x35c8,0x35bc,UBOGON,UBOGON,0x5590, UBOGON,0x35bb,0x35c2,0x35c0,UBOGON,UBOGON,0x35ca,UBOGON,0x35c9,UBOGON, 0x35b8,0x5710,0x5817,UBOGON,0x364e,UBOGON,0x5844,0x3650,0x582b,UBOGON, 0x5845,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,0x368a,UBOGON,0x5965,UBOGON, UBOGON,UBOGON,0x36fc,0x36f9 }, { /* ku 17 */ UBOGON,0x3763,UBOGON,0x5bcf,UBOGON,UBOGON,UBOGON,0x3787,0x3788,UBOGON, 0x379a,UBOGON,UBOGON,UBOGON,0x5d56,UBOGON,UBOGON,0x37e9,UBOGON,0x37ea, 0x5d54,0x3850,UBOGON,UBOGON,0x3856,0x3852,0x384f,0x3854,0x3851,UBOGON, UBOGON,0x388e,0x388f,UBOGON,UBOGON,UBOGON,0x5f3d,UBOGON,UBOGON,0x38ed, 0x38eb,0x5fa4,UBOGON,UBOGON,UBOGON,0x3962,UBOGON,0x395d,UBOGON,UBOGON, UBOGON,0x3961,0x3965,0x395c,UBOGON,UBOGON,0x395f,UBOGON,UBOGON,UBOGON, UBOGON,UBOGON,UBOGON,0x63ec,0x3a16,0x3a0a,UBOGON,0x3a0e,0x3a12,UBOGON, UBOGON,0x3a11,UBOGON,UBOGON,0x3a10,UBOGON,UBOGON,0x3a09,0x63fa,0x3a15, 0x63d4,UBOGON,UBOGON,UBOGON,0x3a91,0x3a95,0x3a93,0x3a92,0x3a8f,UBOGON, UBOGON,UBOGON,UBOGON,0x3af6 }, { /* ku 18 */ UBOGON,0x3afb,UBOGON,0x6675,0x3af9,UBOGON,UBOGON,UBOGON,0x671c,0x3b7d, UBOGON,0x3b7a,0x3b7f,UBOGON,0x3b78,UBOGON,UBOGON,0x68d9,UBOGON,0x3b70, 0x3b82,UBOGON,0x3b84,UBOGON,0x3c33,UBOGON,0x3c32,0x3c36,UBOGON,UBOGON, 0x3c56,UBOGON,UBOGON,0x3c67,UBOGON,0x3c65,0x3c64,0x3c66,UBOGON,UBOGON, 0x3c81,0x3c82,0x3c83,0x3c9e,UBOGON,0x6bf1,0x3c9d,UBOGON,0x3d0f,0x3d12, UBOGON,UBOGON,UBOGON,0x3d10,0x3d18,UBOGON,0x3d14,0x3d19,0x6e37,UBOGON, UBOGON,0x6e7d,0x6e86,0x3dc8,0x3dc4,0x3dc6,UBOGON,0x3dc7,0x3dc3,UBOGON, UBOGON,UBOGON,UBOGON,UBOGON,0x3e19,0x3e1c,UBOGON,UBOGON,UBOGON,0x3e41, UBOGON,0x3e42,0x3e43,UBOGON,UBOGON,UBOGON,0x3e82,UBOGON,0x3e81,0x3e94, 0x3e84,UBOGON,0x3ed2,0x3f0f }, { /* ku 19 */ 0x3f22,UBOGON,0x3f27,0x3f2a,0x74fa,0x3f28,UBOGON,0x3f60,UBOGON,UBOGON, UBOGON,0x7572,UBOGON,UBOGON,0x3f9b,0x3f9c,UBOGON,0x3f93,0x3f94,0x75dc, 0x3fa0,0x3f99,UBOGON,0x3fa1,UBOGON,0x3ff1,UBOGON,UBOGON,UBOGON,UBOGON, 0x4036,UBOGON,0x4037,0x403f,0x403c,UBOGON,0x4034,0x4039,0x403b,0x4035, 0x4030,0x4032,0x4038,0x403e,0x403a,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON, 0x40b6,0x7867,UBOGON,UBOGON,UBOGON,0x40b3,0x4109,0x7977,UBOGON,UBOGON, UBOGON,0x414c,UBOGON,UBOGON,0x4153,0x414d,0x4151,0x414f,0x7a9b,UBOGON, 0x41a2,UBOGON,UBOGON,0x41cd,UBOGON,UBOGON,0x41e7,UBOGON,0x41f0,UBOGON, 0x41e9,0x41ec,UBOGON,0x41e8,0x41ee,0x4202,UBOGON,UBOGON,UBOGON,UBOGON, 0x4282,0x4283,0x4286,UBOGON }, { /* ku 1a */ UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,0x7d2a,0x7d65,0x434a,UBOGON,0x435a, 0x7f64,UBOGON,0x436e,UBOGON,UBOGON,0x4370,0x436f,UBOGON,0x438a,0x4387, 0x4388,UBOGON,UBOGON,0x8020,0x43b7,0x43fd,0x8120,UBOGON,0x4405,0x813c, 0x4408,0x4403,0x4402,0x4404,0x3b39,0x4409,0x43ff,UBOGON,0x813f,UBOGON, 0x43fc,0x4401,0x440a,0x81f0,0x81f5,0x446b,0x446c,UBOGON,UBOGON,UBOGON, UBOGON,UBOGON,UBOGON,0x44de,UBOGON,UBOGON,0x44db,UBOGON,0x44dd,0x44e3, UBOGON,0x44e0,0x44d9,0x44d8,0x44e4,UBOGON,UBOGON,0x44da,0x44ef,UBOGON, 0x8415,0x83be,UBOGON,UBOGON,UBOGON,0x44d7,0x45b3,0x45bb,0x86e5,0x45b2, 0x86d2,0x45ad,UBOGON,0x45af,UBOGON,0x86e0,UBOGON,0x4616,0x4628,0x4623, 0x88b3,UBOGON,UBOGON,UBOGON }, { /* ku 1b */ 0x4675,0x467e,0x467c,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,0x46ce,0x46cd, 0x46cf,0x8a53,UBOGON,UBOGON,0x8a37,0x8a47,0x8a5c,UBOGON,0x46c4,0x46cc, 0x46c8,0x46c7,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,0x475a, 0x476a,UBOGON,0x476b,0x476d,0x476f,UBOGON,0x479e,UBOGON,0x47a4,0x47a3, 0x47e4,0x47e8,0x47e9,0x47e0,0x47e3,UBOGON,0x47ea,0x47e1,0x47ed,0x4834, 0x4835,0x4851,0x8ef0,UBOGON,0x489d,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON, UBOGON,0x48d0,UBOGON,0x48ee,UBOGON,UBOGON,UBOGON,0x48f2,UBOGON,0x921d, 0x4988,UBOGON,UBOGON,UBOGON,0x498f,UBOGON,0x49d8,UBOGON,UBOGON,UBOGON, UBOGON,UBOGON,UBOGON,0x4a3f,UBOGON,0x4a52,0x976b,UBOGON,0x4a50,UBOGON, 0x4ab1,UBOGON,UBOGON,0x4af9 }, { /* ku 1c */ UBOGON,UBOGON,UBOGON,0x4b26,0x4b28,UBOGON,UBOGON,0x3480,0x50c0,0x3481, UBOGON,0x347e,0x347f,UBOGON,UBOGON,UBOGON,UBOGON,0x34be,UBOGON,0x34d6, UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,0x52e5,UBOGON,0x3534, UBOGON,0x53af,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,0x35d5,0x35d8,UBOGON, UBOGON,0x35d4,0x55d8,0x35d9,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,0x5711, 0x5867,UBOGON,UBOGON,0x365d,0x5843,0x365e,0x3659,UBOGON,0x365a,0x36a0, UBOGON,UBOGON,0x3705,UBOGON,0x3707,UBOGON,0x370e,0x370c,UBOGON,UBOGON, 0x3745,UBOGON,UBOGON,0x3764,UBOGON,0x3765,UBOGON,0x5bdd,0x3766,UBOGON, 0x3789,0x37ec,0x37f1,0x5d70,0x5d6a,0x37f0,0x37f8,0x5d74,0x5d5f,UBOGON, 0x5d61,0x5d73,UBOGON,0x37f2 }, { /* ku 1d */ 0x37f4,UBOGON,0x3858,UBOGON,UBOGON,0x385a,0x3859,0x3857,0x385b,0x5e50, UBOGON,UBOGON,0x38a6,0x38c2,0x38c1,0x5f3f,UBOGON,UBOGON,0x38ef,0x5fb0, UBOGON,UBOGON,0x3968,0x6135,0x612d,0x3973,0x396e,0x3974,0x6102,0x3966, UBOGON,UBOGON,UBOGON,0x39b9,0x6226,UBOGON,0x3a0c,UBOGON,UBOGON,0x3a20, UBOGON,0x3a1d,UBOGON,0x3a1c,UBOGON,0x3a21,0x3a1a,0x3a19,UBOGON,UBOGON, UBOGON,0x3a7e,UBOGON,UBOGON,UBOGON,UBOGON,0x3a9d,UBOGON,0x3a9e,UBOGON, 0x656e,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,0x65b1,0x65d4,0x3acd,UBOGON, 0x3b0b,0x3b0a,0x6685,UBOGON,0x3b8f,0x6972,0x3b95,0x3b90,0x3b91,UBOGON, 0x693a,0x3bb9,UBOGON,UBOGON,0x3b97,0x3b9e,UBOGON,0x3b8b,UBOGON,UBOGON, 0x3c3b,0x3c3a,0x3c3c,0x3c3d }, { /* ku 1e */ 0x3c39,0x3c3e,0x3c6b,0x3c6c,UBOGON,UBOGON,0x3ca2,0x3ca1,0x3c9f,UBOGON, UBOGON,UBOGON,0x3d2d,UBOGON,0x3d36,0x3d2b,UBOGON,0x3d37,UBOGON,UBOGON, UBOGON,0x6ead,0x3d25,0x3d2f,0x3d2c,UBOGON,UBOGON,0x3d32,UBOGON,UBOGON, 0x6e95,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,0x3dd5,UBOGON,0x3dd4, 0x3dd6,UBOGON,0x3dd1,0x7243,UBOGON,0x3e46,0x728f,UBOGON,UBOGON,0x3e8c, 0x3e8a,0x3e88,UBOGON,UBOGON,UBOGON,UBOGON,0x3edd,UBOGON,UBOGON,UBOGON, 0x3f2d,UBOGON,UBOGON,0x3f2e,0x3f2c,0x3f2b,0x3f30,UBOGON,0x3f4e,UBOGON, UBOGON,0x3f64,0x3f61,UBOGON,0x7575,UBOGON,0x3f70,0x3fa6,0x3fa4,UBOGON, UBOGON,UBOGON,0x3fa8,0x3fa2,UBOGON,0x3fa7,0x75ec,0x3fa5,UBOGON,0x3fa9, UBOGON,UBOGON,UBOGON,UBOGON }, { /* ku 1f */ UBOGON,0x403d,UBOGON,UBOGON,0x4044,0x4045,0x4046,UBOGON,0x7757,UBOGON, 0x4047,0x4048,0x4042,UBOGON,UBOGON,0x4041,UBOGON,UBOGON,0x4094,UBOGON, UBOGON,UBOGON,UBOGON,0x40c0,0x40b8,0x40c1,0x40c2,0x40bb,0x40bd,0x40bf, 0x40b9,0x40b7,UBOGON,0x40c7,UBOGON,0x410c,0x410b,0x797b,0x4110,UBOGON, 0x415d,0x7a21,0x415a,0x4158,0x4156,UBOGON,0x4154,0x7a16,UBOGON,0x41a8, 0x41a7,0x41cf,0x41d0,UBOGON,0x7ae8,UBOGON,UBOGON,0x41d1,0x41eb,UBOGON, 0x41fb,0x7b6a,UBOGON,0x41fd,0x41f8,0x41f7,0x4200,UBOGON,UBOGON,0x41f6, 0x7b5f,UBOGON,UBOGON,0x42df,UBOGON,UBOGON,UBOGON,0x42e2,0x42e4,UBOGON, 0x7d82,UBOGON,0x42e3,UBOGON,0x4359,0x4371,0x438e,0x438c,UBOGON,0x43a4, UBOGON,0x8055,0x4414,UBOGON }, { /* ku 20 */ UBOGON,UBOGON,0x4411,UBOGON,0x441b,0x4412,0x440e,0x4415,0x8168,0x4410, UBOGON,0x4417,0x8246,0x8243,0x4470,0x44ed,UBOGON,0x44ee,UBOGON,UBOGON, UBOGON,0x8481,UBOGON,UBOGON,UBOGON,0x44f4,UBOGON,UBOGON,UBOGON,UBOGON, UBOGON,UBOGON,0x847c,UBOGON,UBOGON,0x846a,UBOGON,0x8488,0x44f2,0x44f8, 0x44f3,UBOGON,UBOGON,0x44fa,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,0x8710, UBOGON,UBOGON,0x871f,0x45b6,0x45b7,UBOGON,0x870f,UBOGON,0x45ba,UBOGON, 0x45bc,UBOGON,UBOGON,0x463b,0x88d3,0x462f,UBOGON,UBOGON,UBOGON,0x4637, 0x4699,UBOGON,UBOGON,UBOGON,UBOGON,0x46d9,0x46d8,0x46d7,UBOGON,UBOGON, UBOGON,UBOGON,UBOGON,0x4736,UBOGON,UBOGON,UBOGON,0x8c87,UBOGON,UBOGON, UBOGON,UBOGON,UBOGON,0x8cc6 }, { /* ku 21 */ 0x4770,UBOGON,UBOGON,UBOGON,UBOGON,0x47a5,0x47a6,0x47a9,0x47ee,0x4854, UBOGON,0x4857,UBOGON,UBOGON,0x48a1,UBOGON,UBOGON,UBOGON,UBOGON,0x48d3, UBOGON,0x48d4,UBOGON,0x48d7,0x90cc,0x916d,0x9170,0x48f7,0x48f6,0x48f9, 0x48f8,0x9258,0x9242,0x9268,0x9269,UBOGON,UBOGON,0x9243,UBOGON,0x9247, 0x498a,UBOGON,UBOGON,UBOGON,UBOGON,0x4994,UBOGON,0x4993,UBOGON,UBOGON, 0x959d,0x49dd,0x49dc,0x49f7,0x96cf,UBOGON,UBOGON,0x4a42,UBOGON,UBOGON, 0x4a54,UBOGON,0x4a55,UBOGON,0x4a8f,UBOGON,0x97f4,0x4ab4,0x4ab3,UBOGON, UBOGON,0x9809,UBOGON,UBOGON,UBOGON,UBOGON,0x4afb,0x4afd,UBOGON,UBOGON, 0x98ab,0x4afc,UBOGON,0x4b2c,0x4b2f,UBOGON,0x4b2b,UBOGON,0x4b33,0x4b34, 0x98fb,UBOGON,0x9aac,0x9aae }, { /* ku 22 */ 0x9aaa,0x4be8,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,0x9b5c,UBOGON, UBOGON,0x4d5d,0x50d2,0x3485,0x3488,UBOGON,UBOGON,0x348e,0x3484,UBOGON, 0x50df,UBOGON,0x3483,UBOGON,UBOGON,UBOGON,UBOGON,0x3502,UBOGON,0x3506, 0x3505,UBOGON,0x34fe,0x3501,0x3500,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON, UBOGON,0x35e7,0x5619,UBOGON,UBOGON,UBOGON,0x35e6,UBOGON,0x35ed,0x35e2, 0x35eb,UBOGON,0x35e8,0x35ec,0x560a,0x3624,0x589a,UBOGON,0x3662,UBOGON, 0x3661,0x3660,0x3664,0x368b,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,0x3719, 0x3716,0x3718,0x3722,UBOGON,0x371d,0x3717,0x371e,UBOGON,UBOGON,UBOGON, UBOGON,UBOGON,UBOGON,0x3769,0x376a,UBOGON,0x376c,0x377a,0x378a,UBOGON, UBOGON,UBOGON,0x379c,UBOGON }, { /* ku 23 */ 0x37fd,0x37f9,UBOGON,0x37ff,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,0x37fc, UBOGON,0x5d85,0x37fb,0x3802,0x385f,0x5e56,0x385e,0x385d,0x385c,UBOGON, 0x5e51,0x3892,UBOGON,UBOGON,0x3894,0x3895,0x38d1,UBOGON,0x38f1,UBOGON, 0x5fb1,UBOGON,UBOGON,0x3977,0x396f,UBOGON,UBOGON,0x3987,0x397d,0x397c, 0x397e,0x3985,0x398b,0x3986,0x3980,UBOGON,UBOGON,0x3978,UBOGON,UBOGON, UBOGON,0x39ba,UBOGON,0x3a33,UBOGON,0x3a2d,UBOGON,UBOGON,UBOGON,0x3a37, 0x645a,0x6463,UBOGON,UBOGON,0x3a2e,UBOGON,UBOGON,0x3a3d,UBOGON,0x3aa0, UBOGON,UBOGON,0x3aa3,UBOGON,0x669b,UBOGON,0x66a3,0x3b0e,0x669e,UBOGON, 0x3bb6,UBOGON,0x3bab,0x3bad,0x3ba6,UBOGON,0x69b8,0x3baa,0x69ba,0x3bb1, UBOGON,0x3ba8,0x3baf,0x3bb0 }, { /* ku 24 */ 0x3ba7,0x3bb2,0x3b9d,0x3ba5,0x3bb5,UBOGON,0x69c7,0x69d7,UBOGON,0x3c41, UBOGON,UBOGON,0x6b70,UBOGON,UBOGON,0x3c72,0x6b9d,0x3c6f,0x3c71,UBOGON, 0x3c85,UBOGON,UBOGON,0x3ca4,0x3ca5,0x3ca6,UBOGON,0x3ca8,UBOGON,UBOGON, 0x3ca3,UBOGON,UBOGON,UBOGON,0x6f16,0x6f24,UBOGON,0x3d43,UBOGON,UBOGON, 0x3d3d,0x3d45,UBOGON,UBOGON,0x3d44,UBOGON,UBOGON,UBOGON,UBOGON,0x6f45, UBOGON,UBOGON,UBOGON,0x3de3,0x7179,UBOGON,0x3ddf,0x3de4,0x717a,0x3de5, UBOGON,0x7254,0x3e22,0x3e4a,UBOGON,0x3e49,0x3e44,0x3e4b,0x3e87,0x3e89, 0x3e92,0x3e91,0x3e90,0x3e8e,UBOGON,UBOGON,UBOGON,UBOGON,0x3f12,0x3f10, 0x3f11,UBOGON,0x3f32,0x3f34,0x3f37,0x3f33,0x3f36,0x3f35,0x3f65,UBOGON, 0x757c,0x757b,UBOGON,0x7612 }, { /* ku 25 */ 0x3fb0,UBOGON,0x3faf,0x3faa,UBOGON,UBOGON,UBOGON,0x3fab,UBOGON,UBOGON, UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,0x3ff3,UBOGON,0x3ff4,UBOGON,0x76b6, 0x76e0,0x4008,0x404e,0x4055,0x404b,UBOGON,UBOGON,0x404d,0x7773,UBOGON, 0x4052,0x7772,0x404c,0x7770,0x4050,0x4053,UBOGON,0x4051,UBOGON,UBOGON, UBOGON,0x4089,UBOGON,0x4095,0x40cc,0x40c8,0x40ce,UBOGON,0x40ca,UBOGON, 0x789d,UBOGON,0x40cd,UBOGON,0x415c,0x4167,0x4169,0x4165,0x4162,UBOGON, 0x7a27,0x7a35,UBOGON,0x41aa,UBOGON,UBOGON,0x41d2,0x7ba2,0x4203,0x420c, UBOGON,0x4209,0x4206,0x4205,0x7b89,UBOGON,0x420b,0x4208,UBOGON,0x7ba5, UBOGON,0x428e,UBOGON,0x7cb6,0x42e8,UBOGON,UBOGON,UBOGON,0x42ea,UBOGON, 0x7da5,0x7dc3,UBOGON,0x42e9 }, { /* ku 26 */ 0x42eb,UBOGON,0x42f0,UBOGON,0x434b,0x7fab,0x4373,0x4375,0x4392,0x4391, 0x4393,0x8025,0x43a7,0x43a6,0x43a8,0x43aa,UBOGON,0x43a9,0x8059,0x43bb, 0x43bc,0x43ba,0x43bd,0x4427,0x8185,UBOGON,0x4424,0x441e,0x441f,0x441d, 0x4420,0x4423,0x4429,0x4422,UBOGON,UBOGON,0x441c,0x818e,0x4428,UBOGON, UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,0x4471,0x4473,0x4472,UBOGON, 0x4502,UBOGON,UBOGON,UBOGON,0x44fe,0x84be,UBOGON,UBOGON,UBOGON,0x4508, UBOGON,UBOGON,UBOGON,0x4507,0x4504,UBOGON,UBOGON,0x4500,0x44fc,UBOGON, 0x4544,UBOGON,0x44f1,UBOGON,UBOGON,0x84a6,0x4506,UBOGON,UBOGON,0x45c6, 0x45c3,0x45c1,0x45c2,UBOGON,0x45c4,0x45c7,UBOGON,0x45bf,0x45d2,UBOGON, 0x45ca,UBOGON,UBOGON,0x872f }, { /* ku 27 */ UBOGON,UBOGON,0x4613,UBOGON,0x4630,0x463e,0x4639,UBOGON,UBOGON,0x463c, 0x463f,UBOGON,0x4634,0x463d,UBOGON,UBOGON,0x4638,UBOGON,UBOGON,UBOGON, 0x89a0,0x4682,UBOGON,0x4683,UBOGON,0x469b,UBOGON,0x46e0,0x46dd,UBOGON, UBOGON,0x46de,UBOGON,0x46e3,0x46e5,UBOGON,0x8a97,0x46e2,UBOGON,UBOGON, UBOGON,0x46df,UBOGON,0x472e,UBOGON,0x4737,0x4738,UBOGON,UBOGON,UBOGON, UBOGON,0x8c8b,UBOGON,0x3562,UBOGON,0x4794,0x4793,0x47ab,0x47ad,UBOGON, UBOGON,0x47f5,0x47f7,UBOGON,0x47f6,0x47f8,UBOGON,0x47fb,0x47f9,0x4858, 0x485a,UBOGON,0x4859,0x8f0f,0x4885,0x48a4,0x48d8,0x48d9,UBOGON,0x48dd, 0x48c8,UBOGON,0x48fa,0x48fb,0x9275,0x4927,0x929f,0x492a,0x4925,UBOGON, 0x4928,UBOGON,UBOGON,UBOGON }, { /* ku 28 */ UBOGON,0x95a6,0x4995,0x969a,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON, UBOGON,UBOGON,0x4a0f,0x4a11,UBOGON,UBOGON,0x4a10,UBOGON,0x4a15,0x4a13, 0x9757,UBOGON,0x4a47,0x4a46,UBOGON,0x4a59,0x4a5b,UBOGON,0x4a5e,UBOGON, UBOGON,0x4a5a,0x4a91,0x4a92,0x4a90,0x4a93,UBOGON,0x97f7,0x4abe,UBOGON, UBOGON,UBOGON,0x4abc,0x4abb,0x4ab7,0x4ab9,UBOGON,0x4b01,0x4afe,UBOGON, UBOGON,0x4b02,UBOGON,0x4aff,0x98b0,UBOGON,0x4b00,UBOGON,0x4b37,0x4b3a, 0x4b6f,0x4b77,0x4b79,0x99c6,UBOGON,0x4bc8,UBOGON,UBOGON,UBOGON,UBOGON, 0x4bf2,UBOGON,0x4bf1,0x4bf0,0x9b62,UBOGON,0x4c34,UBOGON,UBOGON,UBOGON, UBOGON,UBOGON,0x4d2c,0x4d2d,UBOGON,UBOGON,UBOGON,UBOGON,0x50fa,UBOGON, 0x3491,UBOGON,0x3494,UBOGON }, { /* ku 29 */ UBOGON,0x34c4,0x350a,UBOGON,0x5285,UBOGON,0x3552,UBOGON,0x3559,0x366f, UBOGON,0x35f2,0x35f4,0x5643,UBOGON,0x35f1,0x563c,UBOGON,0x366a,UBOGON, UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,0x3724,UBOGON,0x3723,UBOGON,UBOGON, UBOGON,0x3727,UBOGON,UBOGON,0x376d,0x5bed,0x376e,0x376f,UBOGON,UBOGON, 0x5c35,0x379f,0x380a,0x3806,0x380e,UBOGON,0x380d,0x3805,UBOGON,UBOGON, 0x380b,0x3810,0x382e,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,0x3896,0x3897, 0x38c4,0x5f47,0x38c5,UBOGON,0x38d2,UBOGON,UBOGON,UBOGON,0x3981,UBOGON, 0x398e,0x3990,0x398f,UBOGON,0x3991,0x3995,0x3993,UBOGON,0x616d,UBOGON, UBOGON,UBOGON,UBOGON,UBOGON,0x3a3b,0x3a48,UBOGON,UBOGON,0x3a46,0x3a47, UBOGON,UBOGON,UBOGON,0x3a4c }, { /* ku 2a */ UBOGON,0x3a4a,0x3a50,0x3a43,UBOGON,UBOGON,UBOGON,0x3a49,0x3aa6,0x3aa5, 0x3aa4,UBOGON,UBOGON,0x3ab9,UBOGON,0x3ace,0x3acf,0x3b13,UBOGON,UBOGON, UBOGON,0x3bc6,0x3bc5,0x3bca,0x3bd9,0x3bc1,UBOGON,UBOGON,0x69f5,UBOGON, UBOGON,UBOGON,UBOGON,0x3bcb,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,0x6a03, UBOGON,UBOGON,0x6a65,0x3c42,UBOGON,0x6b75,0x3c74,0x3c73,UBOGON,UBOGON, UBOGON,UBOGON,UBOGON,UBOGON,0x6f8a,0x6f56,0x3d52,UBOGON,UBOGON,UBOGON, 0x3d50,UBOGON,0x3d4b,UBOGON,0x3d4c,0x3d6d,UBOGON,0x6f98,UBOGON,UBOGON, UBOGON,0x3d4f,0x6f68,0x3df0,UBOGON,0x7234,0x7245,0x3e4d,0x3e4c,UBOGON, 0x3e4f,0x3e4e,0x3e50,UBOGON,0x735c,0x3e96,0x7356,UBOGON,UBOGON,0x3e97, 0x3e95,0x3e98,UBOGON,UBOGON }, { /* ku 2b */ 0x3eec,0x3eeb,0x3f13,0x3f14,0x3f38,0x3f3a,0x3f39,UBOGON,0x3f68,0x3f67, UBOGON,UBOGON,UBOGON,0x3fbe,0x3fbc,UBOGON,UBOGON,UBOGON,0x3fbb,UBOGON, 0x3fba,UBOGON,0x3fb9,0x3fb7,UBOGON,UBOGON,0x3fc1,UBOGON,0x3ff7,UBOGON, 0x4060,UBOGON,UBOGON,0x4059,0x405c,0x405a,0x4058,UBOGON,0x405b,UBOGON, UBOGON,UBOGON,UBOGON,UBOGON,0x405d,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON, UBOGON,UBOGON,0x40d4,0x40d3,0x78bf,0x40d2,0x78bd,UBOGON,0x40d7,0x40d1, 0x78e4,0x40d5,UBOGON,UBOGON,0x416d,0x416f,0x7a34,0x4175,0x416c,0x4174, UBOGON,0x4173,UBOGON,UBOGON,0x7a36,0x41ac,UBOGON,UBOGON,UBOGON,0x4210, UBOGON,UBOGON,0x7bba,0x7bbc,0x420f,0x7bc8,0x4223,0x7bc3,0x421d,0x7bb6, 0x420e,UBOGON,UBOGON,0x4215 }, { /* ku 2c */ 0x7bc2,0x4213,UBOGON,UBOGON,0x421b,0x7bc5,0x4222,0x4226,UBOGON,0x7bbd, 0x7bb0,0x4221,0x421c,0x4217,UBOGON,0x421a,0x7bbb,UBOGON,UBOGON,UBOGON, 0x4299,UBOGON,0x4297,UBOGON,UBOGON,0x42fd,UBOGON,0x42f6,0x42fe,0x42f5, 0x42ff,0x42f7,UBOGON,UBOGON,UBOGON,0x4301,0x7e04,UBOGON,UBOGON,UBOGON, 0x4377,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,0x43ab,UBOGON,UBOGON,0x43c0, UBOGON,0x4431,0x442e,UBOGON,UBOGON,0x442c,UBOGON,UBOGON,0x4432,0x442f, 0x442b,0x442d,0x4433,UBOGON,UBOGON,0x81f1,0x4457,0x445c,0x447b,UBOGON, UBOGON,0x447a,UBOGON,0x8522,0x4513,0x451e,0x4517,0x4520,0x452a,0x4511, 0x4515,0x450f,0x4518,0x8538,UBOGON,UBOGON,0x452c,0x8532,UBOGON,0x8510, UBOGON,UBOGON,0x451c,UBOGON }, { /* ku 2d */ 0x4529,UBOGON,UBOGON,0x4512,0x854f,0x4597,UBOGON,0x8772,UBOGON,UBOGON, UBOGON,UBOGON,UBOGON,UBOGON,0x45d4,0x45d0,0x877c,UBOGON,UBOGON,UBOGON, UBOGON,0x45d3,0x4614,UBOGON,0x4646,0x4645,UBOGON,0x4643,UBOGON,0x890d, 0x4644,0x4648,UBOGON,0x4647,UBOGON,UBOGON,UBOGON,0x8908,0x4649,0x4685, UBOGON,0x4684,UBOGON,0x469d,UBOGON,0x469e,0x46a0,UBOGON,0x469c,UBOGON, 0x469f,UBOGON,0x46f7,0x46ea,UBOGON,0x46ef,0x46e9,0x46f3,0x46f0,0x46eb, UBOGON,0x46ec,0x46f2,0x46f5,0x46ee,UBOGON,UBOGON,0x473a,0x474b,UBOGON, 0x474a,0x474c,UBOGON,UBOGON,UBOGON,0x4779,0x477b,0x4778,UBOGON,UBOGON, 0x47b5,UBOGON,0x47b4,0x47b7,0x8d9e,0x4809,0x47fe,0x4808,0x4807,UBOGON, UBOGON,UBOGON,0x4806,0x4804 }, { /* ku 2e */ 0x4805,0x47ff,0x480b,UBOGON,UBOGON,0x483b,0x485d,0x485c,0x485f,0x485e, 0x8f28,UBOGON,0x8f21,0x4883,UBOGON,UBOGON,0x48a7,0x9066,0x906c,UBOGON, 0x48a8,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,0x90f6,0x48e0,0x48df,0x48fe, 0x48fc,0x48ff,0x48fd,UBOGON,0x492c,0x92ec,0x92ba,0x92e3,0x92bd,0x499d, UBOGON,0x95b4,UBOGON,0x4a40,UBOGON,UBOGON,0x4a5f,UBOGON,UBOGON,UBOGON, UBOGON,UBOGON,UBOGON,UBOGON,0x97d1,UBOGON,0x4ac0,0x9823,UBOGON,0x4ac1, 0x4ac6,UBOGON,UBOGON,0x4b04,0x4b05,UBOGON,0x990b,0x4b3e,0x4b3d,0x4b40, 0x4b3f,UBOGON,0x4b42,UBOGON,UBOGON,UBOGON,0x4b84,0x4b82,0x4b7f,0x4b85, UBOGON,UBOGON,0x4bcc,0x9ab2,0x4bcb,0x4bcd,UBOGON,UBOGON,0x9adb,UBOGON, 0x4bf5,UBOGON,UBOGON,UBOGON }, { /* ku 2f */ 0x9af0,UBOGON,UBOGON,0x4c20,0x4c21,UBOGON,UBOGON,0x4c37,0x4c3e,0x9b73, 0x4c3d,0x9b6e,UBOGON,UBOGON,UBOGON,0x9b65,UBOGON,0x4c3c,UBOGON,0x4c38, 0x9b6a,UBOGON,0x9b6d,UBOGON,0x4c3b,UBOGON,0x4cb0,UBOGON,UBOGON,UBOGON, 0x4cad,0x4cb2,0x4cb8,0x9d0b,UBOGON,0x4caf,UBOGON,UBOGON,0x4d1a,0x9e76, 0x4d20,0x4d21,0x4d30,0x9ea8,0x4d2f,UBOGON,UBOGON,UBOGON,UBOGON,0x4d5f, 0x4d60,UBOGON,UBOGON,0x9f11,UBOGON,UBOGON,0x348a,0x5119,0x349c,UBOGON, 0x349a,UBOGON,UBOGON,UBOGON,0x350c,0x350b,0x350d,0x5292,UBOGON,UBOGON, 0x35fe,UBOGON,UBOGON,0x35ff,0x35fb,0x35fc,0x3609,UBOGON,0x3600,UBOGON, 0x5675,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,0x3671,UBOGON,UBOGON, 0x596f,UBOGON,UBOGON,UBOGON }, { /* ku 30 */ 0x372b,UBOGON,UBOGON,UBOGON,0x3814,0x3811,0x3812,UBOGON,0x3863,UBOGON, 0x386e,0x389a,UBOGON,0x389b,UBOGON,UBOGON,0x38c8,UBOGON,UBOGON,0x38f6, UBOGON,UBOGON,0x61a5,0x398c,0x3997,0x39a2,0x61a0,UBOGON,UBOGON,UBOGON, UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,0x3a54,UBOGON,UBOGON,UBOGON, 0x3aa8,UBOGON,UBOGON,0x3aa9,UBOGON,0x65b4,0x65d8,0x66c2,0x3b18,0x3b17, 0x3b1d,UBOGON,UBOGON,0x3b31,UBOGON,UBOGON,0x3bd8,0x3bd5,UBOGON,UBOGON, UBOGON,0x3be1,UBOGON,0x3bd4,UBOGON,UBOGON,UBOGON,0x3be3,UBOGON,0x3c44, 0x3c45,UBOGON,UBOGON,0x3c76,0x3c75,UBOGON,0x6ba8,0x3c88,0x3caa,UBOGON, 0x3cab,0x3cac,UBOGON,0x3d57,0x6f83,0x3d60,0x3d5d,0x3d6b,UBOGON,0x3d63, 0x3d67,UBOGON,0x3d5e,UBOGON }, { /* ku 31 */ UBOGON,0x6fc5,0x71cd,0x3df9,0x3df3,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON, 0x3df6,UBOGON,0x729c,0x3e51,0x3e53,0x3e52,UBOGON,0x3e9b,UBOGON,0x3e9c, UBOGON,UBOGON,0x3ef7,0x7499,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON, 0x3f3b,UBOGON,0x3f3e,0x3f3d,UBOGON,0x3f69,UBOGON,UBOGON,UBOGON,0x3fc3, 0x3fc4,0x3fc7,UBOGON,UBOGON,0x7639,0x3fc6,0x762e,0x3fc8,UBOGON,UBOGON, UBOGON,0x769f,0x76a0,0x3fe6,0x3ff8,UBOGON,UBOGON,0x4007,UBOGON,0x4064, 0x4068,UBOGON,0x7794,0x4065,0x77ae,UBOGON,UBOGON,0x4069,UBOGON,UBOGON, UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,0x40da,0x40e0,0x78e6,UBOGON,0x40de, UBOGON,UBOGON,UBOGON,0x411c,0x411d,0x411a,UBOGON,0x417b,0x417a,0x417c, UBOGON,0x4178,0x4177,UBOGON }, { /* ku 32 */ UBOGON,0x41b1,UBOGON,0x41b2,0x41b0,UBOGON,0x7abc,UBOGON,0x4236,UBOGON, 0x422e,UBOGON,0x7bd6,UBOGON,0x4234,UBOGON,UBOGON,UBOGON,UBOGON,0x422a, UBOGON,0x4233,0x422d,0x422f,0x4231,0x422b,0x4232,UBOGON,0x4235,UBOGON, UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,0x7ccf,UBOGON,UBOGON,0x4308,UBOGON, 0x4306,UBOGON,UBOGON,0x7e18,UBOGON,0x434d,0x4361,UBOGON,UBOGON,UBOGON, 0x4378,UBOGON,0x4394,0x4395,UBOGON,UBOGON,UBOGON,0x43c1,0x43c3,0x806d, UBOGON,0x4439,UBOGON,UBOGON,0x443a,0x443b,0x4435,0x4436,UBOGON,0x443c, 0x8190,UBOGON,UBOGON,UBOGON,0x4458,0x447c,0x447d,0x448d,0x448c,UBOGON, UBOGON,0x453b,0x453f,UBOGON,UBOGON,0x4532,0x452d,UBOGON,0x452f,0x4539, 0x452e,0x453a,UBOGON,0x4536 }, { /* ku 33 */ 0x4531,0x453e,0x4538,0x8552,0x4534,UBOGON,0x4541,UBOGON,UBOGON,UBOGON, UBOGON,0x4530,UBOGON,UBOGON,UBOGON,UBOGON,0x4543,UBOGON,0x8550,UBOGON, UBOGON,0x4598,UBOGON,UBOGON,0x87a0,UBOGON,UBOGON,0x8786,0x45da,0x45d7, UBOGON,UBOGON,0x8795,UBOGON,UBOGON,0x878c,UBOGON,UBOGON,UBOGON,UBOGON, UBOGON,0x4618,0x8860,UBOGON,UBOGON,UBOGON,0x4652,0x8928,UBOGON,0x464e, 0x8920,UBOGON,0x464f,0x4650,UBOGON,UBOGON,0x89a8,0x4686,0x4687,0x4689, UBOGON,UBOGON,UBOGON,UBOGON,0x46a2,0x46a3,UBOGON,0x46a1,UBOGON,UBOGON, UBOGON,UBOGON,UBOGON,0x46f9,0x46fd,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON, UBOGON,0x473e,0x473c,UBOGON,0x474d,UBOGON,0x474e,UBOGON,0x4781,0x4783, 0x4782,UBOGON,0x4780,0x4788 }, { /* ku 34 */ UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,0x47b9,UBOGON,UBOGON,0x8e3a,UBOGON, UBOGON,UBOGON,0x4811,0x480d,0x4810,0x4813,UBOGON,0x483c,0x4862,0x4863, UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,0x4903,0x4906,0x4902,0x4901,UBOGON, UBOGON,0x4905,UBOGON,0x9194,0x9311,UBOGON,0x9337,0x4936,UBOGON,0x4935, 0x9343,UBOGON,0x49a1,0x49a3,UBOGON,UBOGON,0x49a0,UBOGON,0x49ea,0x96a6, 0x49e8,UBOGON,UBOGON,UBOGON,UBOGON,0x4a21,0x4a1b,UBOGON,UBOGON,0x4a49, 0x4a48,UBOGON,0x9795,0x4a62,0x4a61,0x4a64,0x4a60,0x4a63,UBOGON,UBOGON, 0x9796,0x4a66,0x4aac,0x4aab,UBOGON,UBOGON,0x4ac3,UBOGON,0x4ac4,0x9825, UBOGON,UBOGON,0x4b08,0x4b09,0x4b0a,0x4b06,0x4b07,0x4b41,UBOGON,0x4b45, UBOGON,0x4b43,0x4b44,0x9926 }, { /* ku 35 */ 0x9934,0x4b47,UBOGON,UBOGON,UBOGON,0x4b71,UBOGON,UBOGON,UBOGON,UBOGON, UBOGON,UBOGON,0x4b8b,0x4bd4,0x4bd3,0x4bd1,0x9aba,0x4bd2,UBOGON,UBOGON, 0x4bf7,0x4bf8,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON, 0x4c22,UBOGON,0x4c45,0x4c41,0x9b81,0x4c40,0x9b8a,UBOGON,0x9b7f,0x4c42, UBOGON,0x4cc1,0x4cc5,UBOGON,0x4cbb,0x4cb9,0x4cbd,0x4cc9,UBOGON,0x9d11, UBOGON,0x4cbf,0x4cc7,UBOGON,0x4cc3,0x4d24,0x4d31,0x4d33,UBOGON,0x4d32, 0x4d34,0x4d52,0x4d61,0x9ed9,0x4d7a,0x4d82,0x9f3c,UBOGON,0x5123,UBOGON, UBOGON,UBOGON,0x512c,UBOGON,UBOGON,0x350f,0x5295,UBOGON,0x3523,0x3525, UBOGON,0x3606,0x3608,0x5688,UBOGON,UBOGON,UBOGON,0x568b,UBOGON,UBOGON, 0x367a,0x3677,UBOGON,UBOGON }, { /* ku 36 */ UBOGON,0x372e,UBOGON,0x372f,UBOGON,UBOGON,0x381b,0x3813,UBOGON,UBOGON, 0x3866,UBOGON,0x3865,UBOGON,0x38f7,UBOGON,UBOGON,0x61e1,0x61d7,UBOGON, UBOGON,0x399c,UBOGON,UBOGON,0x3a53,UBOGON,UBOGON,UBOGON,UBOGON,0x3aba, 0x65a3,0x3b22,0x66d3,UBOGON,UBOGON,UBOGON,0x6a8b,UBOGON,UBOGON,0x3beb, 0x3bdd,UBOGON,0x3bef,UBOGON,UBOGON,0x3c47,0x3c46,UBOGON,0x3c78,0x6bac, 0x3c89,UBOGON,UBOGON,0x3d68,0x3d76,0x3d74,0x3d79,UBOGON,0x3d7a,0x3d77, UBOGON,0x3d71,UBOGON,0x3d72,UBOGON,0x3dff,UBOGON,0x3e05,UBOGON,UBOGON, 0x3e54,UBOGON,UBOGON,0x3e9e,0x3e9f,0x7374,UBOGON,UBOGON,0x3efa,UBOGON, 0x3f44,0x3f3f,0x3f40,UBOGON,0x3f42,UBOGON,UBOGON,0x3f51,UBOGON,UBOGON, UBOGON,UBOGON,UBOGON,UBOGON }, { /* ku 37 */ 0x7640,0x3fca,UBOGON,0x7641,0x3fce,0x3fc9,UBOGON,UBOGON,UBOGON,UBOGON, UBOGON,0x4009,0x76e8,0x406c,0x406e,0x4070,0x406d,0x406b,0x4071,0x4072, UBOGON,UBOGON,UBOGON,0x408c,0x40e4,UBOGON,0x40e1,UBOGON,UBOGON,0x78f6, 0x40e7,0x7900,0x40e2,0x411f,UBOGON,UBOGON,0x417e,UBOGON,0x4180,0x7a59, 0x7a55,UBOGON,0x41b9,0x41b7,0x41b8,UBOGON,0x41ba,0x7af4,UBOGON,0x41d3, 0x423f,0x7c04,0x4245,0x4241,0x7c15,0x4242,0x4243,0x423b,0x4238,UBOGON, UBOGON,0x423a,0x7bf5,UBOGON,UBOGON,0x423c,UBOGON,UBOGON,0x423e,UBOGON, UBOGON,UBOGON,0x429e,0x429f,0x42a1,UBOGON,0x429b,0x4312,UBOGON,UBOGON, UBOGON,0x4318,0x430c,UBOGON,0x4362,UBOGON,0x437a,UBOGON,UBOGON,0x43ae, 0x43af,UBOGON,0x43ad,UBOGON }, { /* ku 38 */ 0x43c4,0x43c7,0x43c6,0x43c5,UBOGON,UBOGON,0x81c1,0x4440,UBOGON,UBOGON, 0x443f,0x4441,UBOGON,UBOGON,UBOGON,0x447f,UBOGON,0x4486,0x4481,0x4480, 0x448e,0x454a,UBOGON,0x4547,UBOGON,UBOGON,0x454b,0x4546,0x454e,0x857d, UBOGON,0x85a5,UBOGON,0x4548,UBOGON,0x4545,UBOGON,UBOGON,UBOGON,UBOGON, UBOGON,UBOGON,UBOGON,UBOGON,0x45db,0x45e7,0x45e4,UBOGON,UBOGON,0x45e1, UBOGON,0x45e9,UBOGON,0x45e5,0x45e0,0x45e3,UBOGON,UBOGON,UBOGON,UBOGON, UBOGON,UBOGON,0x45ea,UBOGON,UBOGON,0x893a,0x4654,0x4658,0x465c,UBOGON, 0x4655,0x468b,0x468c,0x46a6,0x46a5,UBOGON,UBOGON,UBOGON,UBOGON,0x46ff, UBOGON,UBOGON,UBOGON,UBOGON,0x4730,0x4740,0x4741,UBOGON,UBOGON,0x4786, UBOGON,0x47bf,0x47bd,UBOGON }, { /* ku 39 */ UBOGON,UBOGON,UBOGON,UBOGON,0x47be,0x4819,UBOGON,0x481c,UBOGON,0x481b, 0x4817,0x4818,0x8e51,UBOGON,UBOGON,0x483d,0x486a,0x4866,UBOGON,UBOGON, 0x4867,UBOGON,0x4868,0x48ad,0x48ae,UBOGON,UBOGON,0x48d6,0x4909,UBOGON, 0x9198,UBOGON,0x490c,0x490a,UBOGON,0x493b,0x493a,0x9384,0x9381,UBOGON, 0x936f,UBOGON,UBOGON,UBOGON,0x49af,0x49aa,0x49ab,UBOGON,UBOGON,0x49b1, UBOGON,0x49ac,0x49ec,UBOGON,UBOGON,0x4a01,UBOGON,UBOGON,UBOGON,UBOGON, 0x4a23,UBOGON,0x4a24,0x4a1e,UBOGON,0x4a4a,0x4a65,0x4a6a,UBOGON,UBOGON, UBOGON,0x4a69,UBOGON,UBOGON,0x4a95,UBOGON,UBOGON,UBOGON,UBOGON,0x9842, UBOGON,UBOGON,0x4acc,UBOGON,UBOGON,UBOGON,0x4acf,UBOGON,UBOGON,0x4b0f, UBOGON,0x4b0e,0x4b0b,0x4b10 }, { /* ku 3a */ 0x4b0d,0x4b0c,UBOGON,UBOGON,UBOGON,UBOGON,0x4b46,0x4b48,0x9937,0x4b49, UBOGON,UBOGON,0x4b91,0x4b8e,UBOGON,0x4bd8,0x4bd6,UBOGON,0x4bda,UBOGON, 0x4bd7,UBOGON,0x9aff,0x4bf9,UBOGON,UBOGON,0x4bfc,UBOGON,UBOGON,UBOGON, 0x9ba9,0x4c4a,0x9ba7,0x4c4e,0x9bb3,0x9bac,0x9bb0,UBOGON,UBOGON,UBOGON, 0x9b9c,UBOGON,UBOGON,UBOGON,0x9d3c,0x9d1c,0x9d3a,0x4cd3,0x4ccd,0x4cd1, UBOGON,UBOGON,0x9d32,0x9d34,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON, 0x9ec7,UBOGON,0x4d62,UBOGON,UBOGON,UBOGON,0x4d83,0x9f3f,UBOGON,0x4d92, 0x349f,0x34a0,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,0x3527,UBOGON,0x360b, UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,0x368d, UBOGON,UBOGON,0x3770,UBOGON }, { /* ku 3b */ 0x5eeb,UBOGON,0x399a,0x399f,0x399d,UBOGON,UBOGON,UBOGON,0x399b,UBOGON, 0x61d5,UBOGON,0x3a60,0x3a64,0x3a69,0x3a63,0x3a67,0x3a62,UBOGON,UBOGON, UBOGON,0x6502,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON, 0x3b26,0x3b23,0x3b25,UBOGON,UBOGON,0x3bf8,UBOGON,UBOGON,UBOGON,0x3bf7, 0x3bfb,0x3bfa,UBOGON,UBOGON,UBOGON,UBOGON,0x3cb0,0x3caf,UBOGON,UBOGON, UBOGON,0x3d7e,UBOGON,0x3d7d,0x3d80,UBOGON,UBOGON,0x3d7f,0x3d86,UBOGON, UBOGON,0x7012,UBOGON,0x3d81,UBOGON,UBOGON,UBOGON,0x3e24,0x3e58,0x3e57, 0x3ea0,UBOGON,0x3efe,UBOGON,UBOGON,0x3f15,UBOGON,0x3f47,0x3f46,UBOGON, UBOGON,0x3f6b,0x3f6c,0x7585,0x7654,UBOGON,0x3fcc,UBOGON,0x7655,UBOGON, 0x3fcb,0x76a7,0x76a8,0x3ff9 }, { /* ku 3c */ UBOGON,UBOGON,UBOGON,UBOGON,0x4078,0x407a,0x4075,UBOGON,0x4076,0x4077, UBOGON,UBOGON,0x40ea,0x40ee,0x40ed,UBOGON,0x40ec,0x790f,UBOGON,UBOGON, 0x4184,0x4185,0x4183,UBOGON,0x41bc,0x41bd,0x41d4,UBOGON,UBOGON,UBOGON, UBOGON,0x4255,UBOGON,0x4250,0x424c,0x4248,UBOGON,0x4253,UBOGON,0x4257, 0x4254,0x424e,0x424a,0x4251,UBOGON,UBOGON,0x4249,0x424b,0x4263,UBOGON, UBOGON,0x42a7,0x42a6,0x42a4,UBOGON,UBOGON,UBOGON,0x7ce4,0x7ce5,UBOGON, UBOGON,0x7e65,0x7e4e,0x4317,UBOGON,0x4316,UBOGON,UBOGON,0x4363,UBOGON, UBOGON,0x7f82,UBOGON,0x437b,0x437c,UBOGON,UBOGON,UBOGON,UBOGON,0x43b0, 0x802d,UBOGON,UBOGON,0x4442,UBOGON,0x4444,UBOGON,UBOGON,UBOGON,UBOGON, UBOGON,0x4488,0x448f,0x4553 }, { /* ku 3d */ 0x455b,UBOGON,0x4559,UBOGON,UBOGON,UBOGON,UBOGON,0x85ca,UBOGON,UBOGON, 0x4554,0x85bc,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,0x4599,UBOGON,UBOGON, UBOGON,UBOGON,UBOGON,UBOGON,0x45f1,UBOGON,0x45ef,UBOGON,UBOGON,UBOGON, UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,0x4662,UBOGON,0x4663,UBOGON,0x4660, 0x4661,0x465f,UBOGON,UBOGON,UBOGON,0x468d,UBOGON,0x468e,UBOGON,UBOGON, UBOGON,0x4709,UBOGON,UBOGON,0x4705,UBOGON,UBOGON,0x4703,0x4706,UBOGON, UBOGON,UBOGON,UBOGON,UBOGON,0x4731,UBOGON,UBOGON,0x474f,UBOGON,UBOGON, UBOGON,0x4766,0x8cff,0x47c4,UBOGON,0x47c3,0x47c1,0x47c5,UBOGON,UBOGON, UBOGON,0x4821,UBOGON,0x481f,0x4822,UBOGON,0x4827,0x4820,UBOGON,0x486d, 0x486c,0x486b,0x486f,0x4870 }, { /* ku 3e */ UBOGON,UBOGON,UBOGON,0x91a6,UBOGON,UBOGON,0x4942,UBOGON,0x93b6,UBOGON, 0x4944,0x4940,UBOGON,UBOGON,0x493f,UBOGON,0x93ab,0x498b,UBOGON,UBOGON, 0x4a25,0x4a28,UBOGON,0x9721,UBOGON,UBOGON,0x4a75,0x4a72,UBOGON,0x4a6f, UBOGON,UBOGON,0x4a76,0x4a71,0x97a7,UBOGON,0x4a97,UBOGON,0x4ad7,UBOGON, 0x4ad6,UBOGON,0x4ad8,0x4adc,0x4adb,0x4ad4,0x983e,0x4b13,0x4b11,0x4b14, UBOGON,UBOGON,UBOGON,UBOGON,0x4b51,0x4b50,0x4b53,0x4b54,0x4b52,UBOGON, UBOGON,UBOGON,0x4b6d,UBOGON,UBOGON,0x4b95,0x4b99,UBOGON,0x4b9a,UBOGON, 0x4b93,0x4b97,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,0x4bdc,UBOGON,0x4bfd, UBOGON,UBOGON,0x4bfe,0x4c00,0x4c02,0x4c01,0x4c03,UBOGON,UBOGON,UBOGON, UBOGON,0x4c27,0x4c26,0x4c24 }, { /* ku 3f */ 0x4c4c,0x9bbc,0x4c50,0x4c55,0x4c53,0x9bb7,0x4c52,UBOGON,0x4c57,0x9bbe, 0x4c58,0x4cd6,UBOGON,UBOGON,0x4cd4,UBOGON,0x4cda,0x4cd9,UBOGON,0x9d62, 0x4cd5,0x4ce4,UBOGON,0x4cdc,0x4d1b,0x9e8f,0x4d37,0x4d36,0x4d4b,0x9ecb, 0x4d66,0x4d76,UBOGON,0x4d7e,0x4d7d,0x4d7f,0x4d84,0x4d8b,UBOGON,0x4d94, 0x34a1,0x3511,UBOGON,0x3610,0x56a9,UBOGON,UBOGON,UBOGON,UBOGON,0x5913, UBOGON,0x3732,0x5bf4,UBOGON,UBOGON,UBOGON,UBOGON,0x3820,UBOGON,UBOGON, UBOGON,0x389d,UBOGON,0x61ec,0x61ef,UBOGON,UBOGON,0x39a5,UBOGON,UBOGON, UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,0x3c02,0x3bfe,0x3c01, 0x6ad6,0x3c03,0x3bff,UBOGON,0x3c04,UBOGON,0x3c4a,UBOGON,0x3d87,UBOGON, 0x3d84,UBOGON,0x3d85,0x7209 }, { /* ku 40 */ UBOGON,UBOGON,UBOGON,0x3e59,0x7379,UBOGON,0x74c6,UBOGON,UBOGON,0x3f04, 0x3f49,0x3f48,UBOGON,0x3f6d,0x3fd2,0x3fd3,UBOGON,0x3fd1,UBOGON,UBOGON, UBOGON,UBOGON,0x3fe7,0x400a,0x77c3,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON, 0x40f0,UBOGON,UBOGON,0x791f,UBOGON,UBOGON,0x7a65,UBOGON,UBOGON,0x41be, 0x41bf,UBOGON,0x7ac6,0x7c3a,UBOGON,0x7c36,UBOGON,UBOGON,UBOGON,UBOGON, 0x425e,UBOGON,UBOGON,0x425b,UBOGON,UBOGON,UBOGON,0x7ceb,0x42ab,UBOGON, 0x42ac,UBOGON,UBOGON,UBOGON,UBOGON,0x431f,0x431d,UBOGON,UBOGON,0x431c, UBOGON,0x431e,UBOGON,UBOGON,UBOGON,UBOGON,0x4364,UBOGON,0x7f84,UBOGON, UBOGON,UBOGON,0x4448,0x4447,UBOGON,UBOGON,0x455e,0x4561,UBOGON,0x85e0, 0x85f3,UBOGON,UBOGON,UBOGON }, { /* ku 41 */ 0x45f7,UBOGON,UBOGON,0x45f4,0x45f8,0x881e,UBOGON,UBOGON,UBOGON,0x4664, UBOGON,0x4692,0x468f,0x4690,0x89b4,0x4693,0x46a8,UBOGON,UBOGON,0x46a9, UBOGON,UBOGON,0x89f9,UBOGON,UBOGON,0x8b44,0x470e,UBOGON,0x470f,UBOGON, UBOGON,0x470b,UBOGON,UBOGON,UBOGON,UBOGON,0x4710,0x4751,UBOGON,0x4750, UBOGON,0x4763,UBOGON,UBOGON,0x47c7,UBOGON,0x8e71,0x4824,0x4826,0x8e6e, UBOGON,0x8e79,UBOGON,0x8ec4,0x4874,0x4873,0x4872,UBOGON,UBOGON,UBOGON, UBOGON,0x48b1,0x908c,UBOGON,0x490e,0x4911,0x4910,0x490f,0x4912,0x4949, 0x93c9,0x494f,0x494d,UBOGON,UBOGON,0x4955,UBOGON,UBOGON,UBOGON,UBOGON, UBOGON,UBOGON,0x4a2c,0x4a2b,UBOGON,UBOGON,0x4a79,UBOGON,UBOGON,UBOGON, 0x4a7a,0x97b0,0x4a99,0x4a9a }, { /* ku 42 */ UBOGON,0x4aae,0x4aaf,UBOGON,0x4ae4,0x4ae1,0x4ade,0x4ae6,0x4adf,UBOGON, 0x4ae7,0x4ae2,0x4ae0,UBOGON,0x4ae5,0x985a,UBOGON,0x4b18,UBOGON,UBOGON, UBOGON,0x4b56,UBOGON,0x9946,UBOGON,UBOGON,UBOGON,0x4b6e,UBOGON,UBOGON, 0x4b9d,0x4ba0,0x4b9c,UBOGON,UBOGON,0x4ba1,0x4ba2,0x4b9f,0x4bdf,0x4bde, 0x9ac3,0x4bea,UBOGON,0x4c06,UBOGON,0x4c04,0x9b0f,UBOGON,UBOGON,UBOGON, UBOGON,0x4c5f,0x9bf4,0x9bfa,0x4c5c,UBOGON,0x4c5e,UBOGON,UBOGON,0x9bdd, 0x4c59,UBOGON,UBOGON,0x4c64,0x4c5d,0x4c62,UBOGON,0x4c65,UBOGON,0x9bed, 0x4c5b,0x9bef,UBOGON,0x4cdd,UBOGON,0x4cdf,UBOGON,UBOGON,0x4ce2,UBOGON, UBOGON,0x4d27,UBOGON,UBOGON,0x9e96,0x4d3a,0x4d3c,UBOGON,0x4d39,UBOGON, UBOGON,0x4d3d,0x4d3b,0x9eb3 }, { /* ku 43 */ 0x4d4c,UBOGON,0x4d68,0x9ee2,UBOGON,0x4d80,0x4d85,UBOGON,0x4d95,UBOGON, 0x4d96,UBOGON,0x9f8f,UBOGON,0x34a4,0x3512,0x56b1,0x3625,UBOGON,0x5b41, 0x3737,UBOGON,UBOGON,UBOGON,UBOGON,0x3868,0x3867,0x389e,UBOGON,UBOGON, UBOGON,0x39aa,UBOGON,0x39a9,0x39a4,UBOGON,UBOGON,0x3a71,0x3a6f,UBOGON, UBOGON,UBOGON,UBOGON,0x3aad,UBOGON,0x6af6,0x3c0c,0x6af2,0x3c0b,UBOGON, UBOGON,0x3c0f,0x3c79,UBOGON,UBOGON,UBOGON,UBOGON,0x3d8d,0x3d8f,UBOGON, UBOGON,0x3d8e,0x3e0c,UBOGON,UBOGON,UBOGON,0x3ea6,UBOGON,0x3ea3,0x3ea4, 0x3ea5,0x7588,0x3f6e,UBOGON,UBOGON,0x3ffa,UBOGON,0x407c,0x407e,0x407b, 0x407d,UBOGON,UBOGON,0x408d,0x40f4,0x40f3,UBOGON,UBOGON,0x4189,UBOGON, UBOGON,0x41c0,UBOGON,0x4265 }, { /* ku 44 */ UBOGON,UBOGON,0x42ad,0x4325,UBOGON,UBOGON,UBOGON,0x43c9,UBOGON,0x444a, UBOGON,0x8267,0x4489,UBOGON,0x4566,0x4570,UBOGON,0x456d,0x4569,0x4567, UBOGON,0x4572,0x860e,0x456e,UBOGON,0x459c,0x45fc,0x45fd,0x4604,0x45ff, UBOGON,0x45fe,0x4600,UBOGON,0x4666,0x4669,UBOGON,0x46aa,0x46ab,0x4717, UBOGON,UBOGON,UBOGON,0x4715,0x8b5e,0x4712,0x8d0e,UBOGON,UBOGON,UBOGON, 0x47ca,UBOGON,0x47c9,0x47cb,UBOGON,UBOGON,UBOGON,0x4829,0x4828,UBOGON, UBOGON,UBOGON,0x4840,0x4875,0x4876,UBOGON,0x4888,UBOGON,0x91b6,0x4957, 0x9401,UBOGON,0x495f,UBOGON,0x941d,0x4958,0x495b,UBOGON,0x942f,UBOGON, 0x49b3,UBOGON,0x49ef,UBOGON,0x4a30,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON, 0x4a41,0x4a4b,UBOGON,0x4a7d }, { /* ku 45 */ UBOGON,UBOGON,0x4a7c,UBOGON,UBOGON,UBOGON,0x97e0,UBOGON,0x97db,UBOGON, UBOGON,0x9861,UBOGON,UBOGON,0x4ae8,0x4aea,0x4ae9,UBOGON,UBOGON,UBOGON, UBOGON,0x4b1b,UBOGON,UBOGON,0x4b55,0x994a,0x4b59,0x4b58,UBOGON,UBOGON, UBOGON,0x4ba4,0x4ba3,UBOGON,UBOGON,UBOGON,UBOGON,0x9a33,0x4ba7,UBOGON, 0x4be0,UBOGON,UBOGON,UBOGON,0x4c08,0x4c0a,0x4c09,UBOGON,UBOGON,UBOGON, 0x4c71,0x9c0f,0x4c6c,UBOGON,0x9c11,UBOGON,0x9c03,0x9c01,0x4c6e,UBOGON, 0x9c16,UBOGON,UBOGON,UBOGON,0x4ce0,0x4cee,UBOGON,0x4ceb,UBOGON,UBOGON, UBOGON,UBOGON,0x9d93,0x4cea,0x4cef,0x4ce7,UBOGON,UBOGON,UBOGON,UBOGON, 0x4d48,0x4d49,UBOGON,UBOGON,UBOGON,0x4d4d,UBOGON,UBOGON,0x4d55,UBOGON, UBOGON,0x4d6a,0x4d6c,UBOGON }, { /* ku 46 */ 0x4d6b,UBOGON,UBOGON,UBOGON,0x4d98,0x4d99,0x4d97,UBOGON,UBOGON,UBOGON, UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,0x535b,UBOGON,0x3616,UBOGON,0x56bf, UBOGON,UBOGON,0x3739,UBOGON,UBOGON,0x3825,0x5dce,UBOGON,UBOGON,UBOGON, UBOGON,0x3a74,UBOGON,UBOGON,0x3aae,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON, 0x3d92,0x3d94,UBOGON,0x3d95,UBOGON,0x3e0d,UBOGON,0x3e25,UBOGON,UBOGON, UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,0x3fd5,0x3fd6,0x76ac,0x3fe8,UBOGON, 0x407f,0x77d2,0x40f5,0x40f6,0x40f7,UBOGON,0x4124,0x418d,0x418a,UBOGON, UBOGON,0x426c,0x4266,0x426a,UBOGON,0x4267,0x426d,0x4268,0x7c52,UBOGON, UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON, 0x4365,UBOGON,0x439a,UBOGON }, { /* ku 47 */ 0x43b1,0x444b,0x444d,0x444c,0x444e,UBOGON,0x4573,0x4575,UBOGON,UBOGON, UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,0x4603,UBOGON,UBOGON,UBOGON,UBOGON, UBOGON,UBOGON,UBOGON,UBOGON,0x471e,UBOGON,0x8b73,UBOGON,0x4719,0x471c, 0x471a,0x471d,0x8b76,UBOGON,UBOGON,0x4743,0x4752,UBOGON,UBOGON,0x4795, UBOGON,0x47cc,UBOGON,0x482b,UBOGON,UBOGON,UBOGON,0x482a,0x8ec7,0x4877, UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,0x4913,0x4914,0x9434, UBOGON,UBOGON,0x495d,UBOGON,0x4960,0x943e,0x4962,UBOGON,UBOGON,0x49b2, 0x49f0,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,0x4a4c,UBOGON,0x4a82, 0x97bc,0x4a81,0x4a9b,UBOGON,0x4aa4,0x4aee,0x4aec,UBOGON,0x4aed,UBOGON, 0x4af0,0x4aef,UBOGON,0x4b1d }, { /* ku 48 */ UBOGON,0x4b60,0x4b5e,0x4b5d,UBOGON,UBOGON,UBOGON,0x4bb1,0x4bab,0x4bac, 0x4bad,UBOGON,0x4bae,UBOGON,UBOGON,0x4be2,UBOGON,UBOGON,UBOGON,UBOGON, UBOGON,0x9b39,UBOGON,UBOGON,0x9c2a,0x4c7b,0x9c26,0x4c78,0x4c75,0x9c27, UBOGON,0x4cf2,0x4cf4,0x4cf3,0x9dc0,0x9dc9,UBOGON,UBOGON,UBOGON,0x4d3f, 0x4d3e,0x4d40,0x4d4e,0x4d57,0x4d59,0x4d58,0x4d56,UBOGON,UBOGON,0x4d6e, UBOGON,UBOGON,UBOGON,0x9eec,UBOGON,UBOGON,0x4d81,0x4d86,UBOGON,0x4d8f, UBOGON,UBOGON,UBOGON,0x9f68,0x4d9b,0x4db1,0x4db3,UBOGON,0x373a,UBOGON, UBOGON,0x3827,UBOGON,UBOGON,0x386a,0x39ac,UBOGON,0x3c18,UBOGON,UBOGON, 0x3c4c,UBOGON,0x3d96,UBOGON,0x3f4a,UBOGON,UBOGON,0x4081,UBOGON,0x4083, 0x40f9,0x40f8,UBOGON,0x418e }, { /* ku 49 */ 0x418f,0x41c1,UBOGON,UBOGON,UBOGON,0x4270,UBOGON,0x4271,UBOGON,0x432a, 0x432d,0x437d,0x8032,0x8031,UBOGON,0x444f,UBOGON,UBOGON,0x4490,UBOGON, UBOGON,UBOGON,0x4579,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,0x4605, UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,0x89fd,UBOGON,UBOGON,0x4721, UBOGON,UBOGON,UBOGON,0x4732,UBOGON,UBOGON,0x47cf,UBOGON,UBOGON,0x908e, 0x4916,0x4915,0x49b5,0x4a08,UBOGON,0x4a32,UBOGON,0x4a33,0x4a34,0x4a3c, UBOGON,0x97c2,UBOGON,0x4a9c,UBOGON,0x4af4,0x4af2,UBOGON,0x4b62,UBOGON, 0x4b61,0x4b64,0x4bb5,0x9a4b,0x4bb4,UBOGON,UBOGON,0x4be3,UBOGON,UBOGON, 0x9b1c,0x4c0e,UBOGON,0x9b1b,UBOGON,0x4c2c,0x4c2b,UBOGON,UBOGON,UBOGON, 0x4c85,0x4c81,0x4c7e,0x4c83 }, { /* ku 4a */ 0x4c80,UBOGON,0x9c42,UBOGON,0x9dd4,0x4cfb,0x4cf7,UBOGON,UBOGON,UBOGON, UBOGON,0x4cf8,UBOGON,UBOGON,UBOGON,UBOGON,0x4d5a,UBOGON,UBOGON,UBOGON, UBOGON,UBOGON,0x4d78,UBOGON,UBOGON,UBOGON,UBOGON,0x4d9d,0x4d9c,UBOGON, UBOGON,UBOGON,0x34a9,0x34bf,0x56d0,0x56cf,UBOGON,0x5dda,UBOGON,0x3a77, 0x3a76,UBOGON,0x3abb,0x66ea,UBOGON,0x3d9b,UBOGON,0x3e0f,0x3e5b,UBOGON, 0x3f4c,0x3f6f,0x3fd9,UBOGON,0x4082,UBOGON,UBOGON,UBOGON,UBOGON,0x4274, 0x4272,UBOGON,UBOGON,UBOGON,0x4273,UBOGON,UBOGON,UBOGON,0x42b1,0x432e, UBOGON,UBOGON,UBOGON,UBOGON,0x434e,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON, UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,0x460b,UBOGON,UBOGON, 0x466c,0x8b89,UBOGON,UBOGON }, { /* ku 4b */ 0x478b,UBOGON,0x47d0,0x482d,UBOGON,0x48e4,0x4971,UBOGON,0x9458,0x496f, UBOGON,0x4a87,0x4aa5,UBOGON,UBOGON,0x4b1e,0x4b65,0x4bb9,0x4bb7,0x4bb8, 0x4be4,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,0x4c8c,0x4c89,0x4c8a,UBOGON, UBOGON,0x4c8b,UBOGON,UBOGON,UBOGON,0x4d01,0x4cfe,0x9de7,0x4d03,0x4d06, UBOGON,0x9dea,0x9df1,UBOGON,0x4d1d,0x4d43,UBOGON,UBOGON,UBOGON,0x4d4f, UBOGON,UBOGON,0x4d5b,0x4d70,UBOGON,0x4d88,UBOGON,UBOGON,0x4d89,0x9f44, UBOGON,UBOGON,UBOGON,UBOGON,0x9f6d,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON, UBOGON,0x5dd9,UBOGON,UBOGON,UBOGON,UBOGON,0x3d9e,0x3d9f,0x3ea7,0x3f4b, 0x3fdb,0x3fda,UBOGON,0x77d6,0x408e,0x4276,UBOGON,0x4330,0x432f,UBOGON, 0x4366,UBOGON,0x457e,UBOGON }, { /* ku 4c */ UBOGON,UBOGON,0x883a,UBOGON,0x8975,0x466f,UBOGON,0x47d1,0x482f,UBOGON, UBOGON,0x48b2,0x4918,0x4917,UBOGON,0x4976,UBOGON,UBOGON,0x4a4f,0x4a89, UBOGON,UBOGON,UBOGON,UBOGON,0x4af5,0x4b1f,UBOGON,UBOGON,0x9a5d,0x4be5, UBOGON,UBOGON,0x4c10,UBOGON,0x4c0f,UBOGON,UBOGON,UBOGON,UBOGON,0x4c2f, 0x4c30,0x9c64,UBOGON,UBOGON,0x4c93,0x4c94,UBOGON,0x4d07,0x4d09,0x4d08, UBOGON,0x4d0b,UBOGON,0x9e0a,UBOGON,UBOGON,UBOGON,0x4d50,0x4d71,UBOGON, UBOGON,UBOGON,UBOGON,UBOGON,0x4d7b,0x4d7c,UBOGON,0x9f73,UBOGON,0x4da1, UBOGON,UBOGON,0x4da0,0x4da2,UBOGON,0x361b,UBOGON,0x3682,UBOGON,UBOGON, UBOGON,UBOGON,0x3fe9,UBOGON,0x4084,0x77e1,UBOGON,UBOGON,UBOGON,0x42b3, 0x4334,0x4333,0x4580,UBOGON }, { /* ku 4d */ UBOGON,0x46ad,UBOGON,0x4744,0x4755,UBOGON,0x47d2,UBOGON,UBOGON,UBOGON, UBOGON,UBOGON,0x4a8a,UBOGON,UBOGON,0x4b67,UBOGON,UBOGON,0x4be6,UBOGON, 0x4c13,UBOGON,0x9b2d,UBOGON,0x4c97,0x9e0c,UBOGON,UBOGON,0x4d0c,UBOGON, UBOGON,UBOGON,0x4d46,0x4d5c,0x4d74,0x4d72,UBOGON,UBOGON,UBOGON,0x9f1f, UBOGON,UBOGON,0x4da4,0x4da3,UBOGON,UBOGON,UBOGON,UBOGON,0x4db4,UBOGON, 0x3536,UBOGON,UBOGON,UBOGON,0x3cb2,UBOGON,UBOGON,0x3f16,0x7c70,0x4277, UBOGON,0x457f,UBOGON,UBOGON,0x487d,0x9479,UBOGON,0x974a,0x4a8c,UBOGON, 0x4b68,0x4bbe,0x4c15,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,0x4d75,0x4da5, UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,0x4278,0x4335,0x7e9d,0x4582,UBOGON, 0x4583,UBOGON,0x4671,UBOGON }, { /* ku 4e */ 0x487e,0x4a8e,UBOGON,0x9960,0x4b69,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON, UBOGON,0x4c9a,0x4c9b,UBOGON,UBOGON,UBOGON,0x4d90,UBOGON,0x9f9e,UBOGON, UBOGON,0x4586,0x4585,UBOGON,0x460e,UBOGON,0x4695,UBOGON,0x4919,UBOGON, 0x4bc0,UBOGON,UBOGON,UBOGON,0x9ef8,0x9f3a,0x9f7d,UBOGON,UBOGON,0x400d, 0x4c16,UBOGON,0x4da9,0x4daa,0x4085,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON, UBOGON,UBOGON,0x9f96,UBOGON,0x4bc2,0x4c31,0x4d11,0x4dab,0x4c9c,UBOGON, UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON, UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON, UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON, UBOGON,UBOGON,UBOGON,UBOGON } }; /* CNS 11643 plane 5 conversion table */ static const unsigned short cns11643_5tab[MAX_CNS11643_KU_5][MAX_CNS11643_TEN] = { { /* ku 01 */ UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON, UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON, UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON, UBOGON,UBOGON,0x355a,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,0x6729, UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON, UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON, UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON, UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON, UBOGON,UBOGON,UBOGON,0x3cbc,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON, UBOGON,UBOGON,0x49b9,UBOGON }, { /* ku 02 */ UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON, UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,0x34de,UBOGON,UBOGON,UBOGON,UBOGON, UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,0x3543,UBOGON,UBOGON, UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON, UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,0x37ac,0x37aa,UBOGON, UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,0x5e07, UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,0x5fcb, 0x38fe,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON, UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON, UBOGON,UBOGON,UBOGON,UBOGON }, { /* ku 03 */ UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON, UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,0x3441, UBOGON,UBOGON,0x34b4,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON, UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON, UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON, UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON, UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON, UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,0x37b3, UBOGON,UBOGON,UBOGON,0x37b4,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON, UBOGON,UBOGON,UBOGON,UBOGON }, { /* ku 04 */ UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON, UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON, UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON, UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,0x3c1d, UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,0x3c7c,UBOGON,UBOGON,UBOGON,UBOGON, UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON, UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,0x3f55,UBOGON,UBOGON,UBOGON, UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,0x4126,UBOGON,UBOGON, UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON, 0x49bc,UBOGON,UBOGON,UBOGON }, { /* ku 05 */ UBOGON,UBOGON,UBOGON,UBOGON,0x344a,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON, 0x344e,UBOGON,UBOGON,0x34c9,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON, UBOGON,UBOGON,0x52b7,0x52b8,UBOGON,0x52b6,0x52ba,UBOGON,UBOGON,UBOGON, UBOGON,UBOGON,UBOGON,0x357b,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON, UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON, 0x3620,UBOGON,UBOGON,UBOGON,UBOGON,0x3689,0x3695,UBOGON,UBOGON,UBOGON, 0x36be,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON, UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,0x37c3,UBOGON,UBOGON, UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON, UBOGON,UBOGON,UBOGON,UBOGON }, { /* ku 06 */ UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,0x3877,UBOGON,UBOGON,UBOGON,UBOGON, UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON, UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,0x39d4,UBOGON,UBOGON,UBOGON,UBOGON, UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON, UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,0x3b4c,UBOGON, UBOGON,UBOGON,UBOGON,0x3c20,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON, UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,0x3c5b,UBOGON,UBOGON,UBOGON,UBOGON, UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON, UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,0x3e2d,UBOGON,UBOGON,UBOGON, UBOGON,UBOGON,UBOGON,UBOGON }, { /* ku 07 */ UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON, UBOGON,UBOGON,UBOGON,0x3e63,UBOGON,UBOGON,UBOGON,0x3f18,UBOGON,UBOGON, UBOGON,UBOGON,0x3f74,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON, UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,0x4128,UBOGON,UBOGON, UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON, UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,0x43da,UBOGON,UBOGON,UBOGON,UBOGON, UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,0x44a4,UBOGON,UBOGON,UBOGON, UBOGON,UBOGON,0x488e,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON, UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON, UBOGON,UBOGON,UBOGON,UBOGON }, { /* ku 08 */ 0x345b,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON, UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON, UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON, UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON, UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON, UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON, UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON, UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,0x3753,UBOGON,UBOGON, UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON, UBOGON,UBOGON,UBOGON,UBOGON }, { /* ku 09 */ UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,0x3880,UBOGON,UBOGON,UBOGON,UBOGON, UBOGON,UBOGON,UBOGON,UBOGON,0x38dd,UBOGON,UBOGON,UBOGON,0x38de,UBOGON, 0x3922,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON, UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,0x6306,UBOGON,UBOGON,UBOGON, UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,0x3adb,UBOGON,UBOGON,UBOGON, UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON, UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON, UBOGON,UBOGON,0x6b85,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON, UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON, 0x3cda,0x3cdb,UBOGON,UBOGON }, { /* ku 0a */ UBOGON,UBOGON,UBOGON,0x3cd7,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON, UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON, UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON, UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON, UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON, UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON, UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON, UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,0x401a,UBOGON,UBOGON,UBOGON, UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON, UBOGON,UBOGON,UBOGON,UBOGON }, { /* ku 0b */ 0x41d6,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON, UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,0x43de,UBOGON, UBOGON,UBOGON,UBOGON,UBOGON,0x43e5,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON, UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,0x4672,UBOGON, 0x46af,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON, UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON, UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,0x49c4,UBOGON,UBOGON, UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,0x3463,UBOGON,UBOGON,UBOGON,UBOGON, UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON, UBOGON,0x34ec,UBOGON,UBOGON }, { /* ku 0c */ UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON, UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON, UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON, UBOGON,UBOGON,UBOGON,UBOGON,0x3598,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON, UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON, UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON, UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON, UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON, UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON, UBOGON,0x3758,UBOGON,UBOGON }, { /* ku 0d */ UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON, UBOGON,UBOGON,UBOGON,0x37d3,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON, UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON, UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,0x38e2,UBOGON, UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON, UBOGON,UBOGON,UBOGON,UBOGON,0x3954,UBOGON,UBOGON,0x392f,UBOGON,UBOGON, 0x39b6,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON, UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON, UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON, UBOGON,UBOGON,UBOGON,UBOGON }, { /* ku 0e */ UBOGON,UBOGON,UBOGON,UBOGON,0x3b35,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON, 0x3b5d,UBOGON,UBOGON,0x3c29,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON, UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON, UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON, UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON, 0x3e1f,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,0x3e72, UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,0x3f0b,UBOGON,UBOGON,UBOGON,UBOGON, UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON, UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON, UBOGON,UBOGON,UBOGON,UBOGON }, { /* ku 0f */ UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON, UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,0x40a2, UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON, UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON, UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON, UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON, UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON, UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,0x43ec,UBOGON,UBOGON,UBOGON, UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON, UBOGON,UBOGON,UBOGON,UBOGON }, { /* ku 10 */ 0x44bb,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON, UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON, UBOGON,UBOGON,UBOGON,UBOGON,0x4621,UBOGON,UBOGON,UBOGON,0x461f,UBOGON, UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,0x8c38,UBOGON,UBOGON, UBOGON,UBOGON,0x4791,0x4796,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON, UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON, UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON, UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON, UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON, UBOGON,UBOGON,UBOGON,UBOGON }, { /* ku 11 */ UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,0x34bc,UBOGON,UBOGON,0x34d8,UBOGON, UBOGON,0x34f4,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON, UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON, UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON, UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON, UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON, UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON, UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON, UBOGON,UBOGON,0x3785,UBOGON,0x3783,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON, UBOGON,UBOGON,UBOGON,UBOGON }, { /* ku 12 */ UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON, UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON, UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON, UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,0x38ba,UBOGON,UBOGON, UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON, UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,0x3969,UBOGON,UBOGON,0x3945,UBOGON, UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON, UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON, UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,0x3b6c,UBOGON, UBOGON,UBOGON,UBOGON,UBOGON }, { /* ku 13 */ UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON, UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON, UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,0x3d04,UBOGON, UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON, UBOGON,UBOGON,UBOGON,UBOGON,0x3e3a,UBOGON,UBOGON,UBOGON,0x3e79,UBOGON, UBOGON,0x7309,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON, UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,0x3f5d,UBOGON,UBOGON, UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,0x3f8a,UBOGON,UBOGON,UBOGON, UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,0x4027,UBOGON,UBOGON,UBOGON,UBOGON, UBOGON,UBOGON,UBOGON,UBOGON }, { /* ku 14 */ UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON, UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON, UBOGON,UBOGON,UBOGON,0x4146,0x4140,UBOGON,0x413f,UBOGON,UBOGON,UBOGON, UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,0x419d,0x41cb,UBOGON,0x41e1, UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON, UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,0x427f,UBOGON,UBOGON,UBOGON, UBOGON,UBOGON,UBOGON,0x4346,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON, UBOGON,UBOGON,UBOGON,0x441a,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON, UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON, UBOGON,UBOGON,UBOGON,UBOGON }, { /* ku 15 */ UBOGON,UBOGON,UBOGON,0x44d3,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,0x44d0, UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON, 0x458e,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON, UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON, UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON, UBOGON,UBOGON,UBOGON,0x46c3,0x46b6,UBOGON,UBOGON,UBOGON,0x8a2f,UBOGON, 0x46c0,0x46b8,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON, UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON, UBOGON,0x47d9,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON, UBOGON,UBOGON,UBOGON,UBOGON }, { /* ku 16 */ UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON, UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON, UBOGON,0x48ec,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON, UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON, UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON, UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON, UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON, UBOGON,UBOGON,UBOGON,0x52dc,UBOGON,UBOGON,UBOGON,0x35cc,UBOGON,0x35a2, UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,0x35b6,UBOGON,UBOGON,0x35c5,0x35c6, UBOGON,UBOGON,UBOGON,UBOGON }, { /* ku 17 */ UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON, UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON, UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,0x3683,0x5921,UBOGON, UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,0x36f8,UBOGON,UBOGON, UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,0x36f6,UBOGON,UBOGON,UBOGON,UBOGON, UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON, UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,0x379b, UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON, UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON, UBOGON,0x5e3f,UBOGON,UBOGON }, { /* ku 18 */ UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,0x388d,UBOGON, UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON, UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON, UBOGON,UBOGON,UBOGON,0x3956,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,0x395b, UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON, UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON, UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON, UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON, UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON, UBOGON,0x3a96,UBOGON,UBOGON }, { /* ku 19 */ UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON, UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,0x3b7e,UBOGON, UBOGON,UBOGON,UBOGON,UBOGON,0x3b81,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON, UBOGON,UBOGON,UBOGON,UBOGON,0x3c35,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON, UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON, UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,0x3c9b,UBOGON, UBOGON,0x3d00,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON, UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON, UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON, UBOGON,UBOGON,UBOGON,UBOGON }, { /* ku 1a */ UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON, UBOGON,UBOGON,0x3ed3,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON, UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,0x3f9f,UBOGON,UBOGON,UBOGON, UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON, UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON, UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,0x40b1,UBOGON,UBOGON,UBOGON, UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,0x414b,UBOGON, UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON, UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON, UBOGON,UBOGON,UBOGON,UBOGON }, { /* ku 1b */ UBOGON,UBOGON,UBOGON,0x7b3f,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON, UBOGON,0x42d6,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON, UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,0x4389,UBOGON,UBOGON,UBOGON,UBOGON, UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON, UBOGON,UBOGON,UBOGON,UBOGON,0x4400,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON, UBOGON,UBOGON,UBOGON,0x44dc,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON, UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON, UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,0x83d0,0x4590, UBOGON,UBOGON,UBOGON,0x45b1,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON, 0x86e7,UBOGON,UBOGON,UBOGON }, { /* ku 1c */ UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,0x45aa,UBOGON,UBOGON,UBOGON,UBOGON, UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON, 0x467d,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON, UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON, UBOGON,UBOGON,UBOGON,0x4769,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,0x47a1, UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,0x47e7, UBOGON,UBOGON,0x47ec,UBOGON,UBOGON,UBOGON,0x47df,UBOGON,UBOGON,UBOGON, 0x4833,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON, UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON, UBOGON,UBOGON,UBOGON,UBOGON }, { /* ku 1d */ UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON, UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON, UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON, UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON, UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,0x4bee, UBOGON,0x4c32,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON, UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON, UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,0x34fc, UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,0x352a,UBOGON,UBOGON, UBOGON,UBOGON,UBOGON,UBOGON }, { /* ku 1e */ UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON, UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON, UBOGON,UBOGON,UBOGON,UBOGON,0x35d3,UBOGON,UBOGON,UBOGON,0x35d7,UBOGON, UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON, UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON, UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON, UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON, UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,0x37f3,UBOGON,UBOGON,UBOGON, UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON, UBOGON,UBOGON,UBOGON,UBOGON }, { /* ku 1f */ 0x3891,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,0x38c0,UBOGON, UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,0x6117,UBOGON,0x3963,UBOGON,UBOGON, UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON, UBOGON,UBOGON,UBOGON,0x3970,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON, UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON, UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON, UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,0x3b02,UBOGON,UBOGON,UBOGON,UBOGON, UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON, UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON, UBOGON,UBOGON,UBOGON,UBOGON }, { /* ku 20 */ UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,0x3d35,UBOGON,UBOGON,UBOGON, UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON, UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON, UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON, UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,0x3ee0,UBOGON,UBOGON,UBOGON,UBOGON, UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON, UBOGON,UBOGON,UBOGON,0x3f9a,UBOGON,UBOGON,UBOGON,0x3fa3,UBOGON,UBOGON, UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,0x4005,UBOGON, UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON, UBOGON,UBOGON,UBOGON,UBOGON }, { /* ku 21 */ UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON, UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,0x415e,UBOGON,UBOGON,UBOGON, UBOGON,UBOGON,UBOGON,UBOGON,0x41a6,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON, UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON, UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON, UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON, UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,0x435d,UBOGON, UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,0x43b8, UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON, UBOGON,UBOGON,UBOGON,UBOGON }, { /* ku 22 */ UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,0x4434,UBOGON,UBOGON, UBOGON,UBOGON,0x446f,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON, UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON, UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON, UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON, 0x4594,0x4593,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON, 0x8714,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON, UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,0x88d1,UBOGON,UBOGON,UBOGON,UBOGON, UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON, UBOGON,UBOGON,UBOGON,UBOGON }, { /* ku 23 */ UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON, UBOGON,UBOGON,0x8ccb,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,0x4792, UBOGON,UBOGON,UBOGON,0x47aa,UBOGON,UBOGON,UBOGON,0x47a7,UBOGON,UBOGON, UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON, UBOGON,UBOGON,0x47ef,UBOGON,UBOGON,UBOGON,UBOGON,0x8eed,UBOGON,UBOGON, UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON, UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON, UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,0x4922,UBOGON,UBOGON,UBOGON, UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON, UBOGON,UBOGON,UBOGON,UBOGON }, { /* ku 24 */ UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON, UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,0x4ab5, UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON, UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON, UBOGON,0x4b75,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON, UBOGON,UBOGON,UBOGON,UBOGON,0x3482,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON, UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,0x52ec,UBOGON,UBOGON,UBOGON, 0x52e8,UBOGON,UBOGON,UBOGON,UBOGON,0x3535,UBOGON,UBOGON,UBOGON,UBOGON, UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON, UBOGON,UBOGON,UBOGON,UBOGON }, { /* ku 25 */ UBOGON,0x35f0,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON, UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON, UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON, UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON, UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON, UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON, UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON, UBOGON,UBOGON,0x38f0,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON, UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON, UBOGON,UBOGON,UBOGON,UBOGON }, { /* ku 26 */ UBOGON,UBOGON,0x3a3e,UBOGON,0x3a39,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON, UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,0x3aa1,UBOGON,UBOGON,UBOGON,UBOGON, UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON, UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,0x3b3b,UBOGON,UBOGON,UBOGON, UBOGON,UBOGON,0x3bb7,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON, UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON, UBOGON,UBOGON,0x3c57,0x3c70,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON, UBOGON,0x3ca7,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON, UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,0x3d54,UBOGON,UBOGON, UBOGON,UBOGON,UBOGON,UBOGON }, { /* ku 27 */ UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON, UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON, UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON, UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,0x3f31, 0x7527,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON, UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,0x3fbf,UBOGON,0x3fe4,UBOGON, UBOGON,UBOGON,UBOGON,UBOGON,0x404a,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON, UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON, UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,0x40cf,UBOGON,UBOGON,UBOGON,UBOGON, UBOGON,UBOGON,UBOGON,0x798c }, { /* ku 28 */ UBOGON,0x7991,UBOGON,0x4114,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON, UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON, UBOGON,0x420d,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON, UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,0x4201,UBOGON,UBOGON, UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON, UBOGON,0x42f1,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON, UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON, UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON, UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON, UBOGON,UBOGON,UBOGON,UBOGON }, { /* ku 29 */ UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON, UBOGON,0x4476,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON, UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,0x450a,0x4503,UBOGON,UBOGON, UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON, UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,0x8660,UBOGON,UBOGON,UBOGON,UBOGON, UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON, UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON, UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,0x4635,0x4636,UBOGON,UBOGON,UBOGON, UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON, UBOGON,UBOGON,UBOGON,UBOGON }, { /* ku 2a */ UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,0x4773,UBOGON, UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,0x47b1,UBOGON,0x47af, UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,0x47f4, UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON, UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON, UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON, UBOGON,UBOGON,UBOGON,0x48dc,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON, UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,0x4999,UBOGON,UBOGON, UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON, UBOGON,UBOGON,UBOGON,UBOGON }, { /* ku 2b */ UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON, UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON, UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,0x4ab6, 0x4abd,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON, UBOGON,UBOGON,UBOGON,0x9904,UBOGON,0x999b,UBOGON,UBOGON,UBOGON,UBOGON, UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,0x4bf4,UBOGON,UBOGON,UBOGON, UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,0x4c35,UBOGON,UBOGON, UBOGON,UBOGON,UBOGON,UBOGON,0x4caa,UBOGON,0x4d1f,UBOGON,UBOGON,UBOGON, UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON, UBOGON,UBOGON,UBOGON,UBOGON }, { /* ku 2c */ UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON, UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,0x3550,UBOGON,UBOGON,UBOGON, UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON, UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON, UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON, UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON, UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,0x377b,UBOGON,UBOGON,UBOGON, UBOGON,0x3809,UBOGON,UBOGON,UBOGON,0x3807,UBOGON,UBOGON,UBOGON,UBOGON, UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON, UBOGON,UBOGON,UBOGON,UBOGON }, { /* ku 2d */ UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON, UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON, UBOGON,UBOGON,0x39bb,UBOGON,UBOGON,0x3a4b,UBOGON,UBOGON,UBOGON,0x3a4d, UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON, UBOGON,UBOGON,0x3ac2,UBOGON,UBOGON,UBOGON,UBOGON,0x3b1a,UBOGON,UBOGON, 0x3b12,UBOGON,UBOGON,UBOGON,UBOGON,0x3b3c,UBOGON,UBOGON,UBOGON,UBOGON, UBOGON,UBOGON,UBOGON,UBOGON,0x3bc3,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON, UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,0x3bc0,UBOGON,UBOGON,UBOGON, UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON, UBOGON,UBOGON,UBOGON,UBOGON }, { /* ku 2e */ UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON, UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON, UBOGON,UBOGON,0x729f,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON, UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON, UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON, UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,0x3fe5,UBOGON,UBOGON,UBOGON, UBOGON,UBOGON,UBOGON,0x405f,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON, UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON, UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,0x4118,UBOGON,UBOGON,UBOGON,UBOGON, UBOGON,UBOGON,UBOGON,UBOGON }, { /* ku 2f */ UBOGON,UBOGON,0x41ad,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON, UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,0x421e,UBOGON,UBOGON, UBOGON,0x4227,UBOGON,UBOGON,UBOGON,UBOGON,0x4218,UBOGON,UBOGON,UBOGON, UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,0x4220,UBOGON,UBOGON,UBOGON, UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON, 0x42f4,0x4302,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON, UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON, UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON, UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON, UBOGON,UBOGON,UBOGON,UBOGON }, { /* ku 30 */ UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON, UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON, UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON, UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,0x4524,UBOGON,UBOGON, UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON, UBOGON,UBOGON,0x8770,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON, UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON, UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON, UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON, UBOGON,UBOGON,UBOGON,UBOGON }, { /* ku 31 */ UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON, UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON, UBOGON,UBOGON,UBOGON,UBOGON,0x477d,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON, UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,0x8e37, UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON, UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON, UBOGON,UBOGON,UBOGON,UBOGON,0x4864,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON, UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON, UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON, UBOGON,UBOGON,UBOGON,UBOGON }, { /* ku 32 */ UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON, UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON, UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,0x9703,UBOGON,UBOGON,UBOGON, UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON, UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON, UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON, UBOGON,UBOGON,UBOGON,0x4ac2,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON, UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON, UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON, UBOGON,UBOGON,UBOGON,UBOGON }, { /* ku 33 */ UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON, UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON, UBOGON,UBOGON,UBOGON,0x4cac,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON, UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON, UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON, UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,0x349b,UBOGON,UBOGON,UBOGON, UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,0x52f6,0x3526,UBOGON,UBOGON,UBOGON, UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON, UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON, UBOGON,UBOGON,UBOGON,UBOGON }, { /* ku 34 */ UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON, UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON, UBOGON,0x3815,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON, UBOGON,UBOGON,UBOGON,0x389c,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON, UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON, UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON, UBOGON,0x64cc,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON, UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON, UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON, UBOGON,UBOGON,UBOGON,UBOGON }, { /* ku 35 */ UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON, UBOGON,UBOGON,0x3d64,0x3d6e,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON, UBOGON,0x3d5f,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON, UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON, UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON, UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON, 0x3ef6,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON, UBOGON,UBOGON,0x764a,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON, UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON, UBOGON,UBOGON,UBOGON,UBOGON }, { /* ku 36 */ UBOGON,0x4073,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON, UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,0x40dd,UBOGON, UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON, UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON, UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,0x7ab9, UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON, UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON, UBOGON,UBOGON,0x7bd7,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON, UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON, UBOGON,UBOGON,UBOGON,UBOGON }, { /* ku 37 */ UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON, UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON, UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON, UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON, UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON, UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON, UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON, UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON, UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON, UBOGON,UBOGON,UBOGON,UBOGON }, { /* ku 38 */ UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON, UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,0x4688,UBOGON,UBOGON, UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON, UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON, UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON, UBOGON,UBOGON,0x47bb,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,0x47ba, UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,0x4812,UBOGON,UBOGON,UBOGON,UBOGON, UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON, UBOGON,0x4861,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON, UBOGON,UBOGON,UBOGON,0x48e1 }, { /* ku 39 */ UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON, UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON, UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON, UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON, UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON, UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON, UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON, UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON, UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON, UBOGON,UBOGON,UBOGON,UBOGON }, { /* ku 3a */ UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,0x999f,UBOGON,UBOGON,UBOGON,UBOGON, UBOGON,0x4b89,UBOGON,0x4b8c,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON, UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON, UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON, UBOGON,0x9b8d,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON, UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,0x9e77,UBOGON, UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON, UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON, UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON, UBOGON,UBOGON,UBOGON,UBOGON }, { /* ku 3b */ UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON, UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON, UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,0x381a,UBOGON,UBOGON, UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON, UBOGON,UBOGON,UBOGON,0x3998,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON, UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON, UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON, UBOGON,0x3bf1,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON, UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON, UBOGON,UBOGON,UBOGON,UBOGON }, { /* ku 3c */ UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON, UBOGON,UBOGON,UBOGON,UBOGON,0x3f6a,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON, UBOGON,0x764b,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON, UBOGON,UBOGON,UBOGON,UBOGON,0x76a2,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON, UBOGON,UBOGON,UBOGON,UBOGON,0x4485,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON, UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON, UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON, UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,0x4239,UBOGON,UBOGON,UBOGON, UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON, UBOGON,UBOGON,0x423d,0x4244 }, { /* ku 3d */ UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON, UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,0x4246,UBOGON,UBOGON,UBOGON,UBOGON, UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON, 0x430e,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,0x4310,UBOGON,UBOGON, UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON, UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,0x443e,UBOGON, UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON, 0x4484,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON, UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,0x4549,UBOGON, UBOGON,UBOGON,UBOGON,UBOGON }, { /* ku 3e */ UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON, UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,0x45df,UBOGON,UBOGON, 0x45f0,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON, UBOGON,UBOGON,UBOGON,UBOGON,0x468a,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON, UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON, UBOGON,UBOGON,0x4702,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON, UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON, UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,0x47c0,UBOGON,UBOGON,UBOGON, UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON, 0x4815,UBOGON,UBOGON,UBOGON }, { /* ku 3f */ UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON, UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON, UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,0x48e2,UBOGON,UBOGON, UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON, UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON, UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON, UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON, UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON, UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON, UBOGON,UBOGON,UBOGON,UBOGON }, { /* ku 40 */ UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON, UBOGON,0x4b4d,UBOGON,UBOGON,UBOGON,UBOGON,0x4b4a,UBOGON,UBOGON,UBOGON, UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON, UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON, UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON, UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON, UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON, UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON, UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON, UBOGON,UBOGON,UBOGON,UBOGON }, { /* ku 41 */ UBOGON,UBOGON,0x4d63,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON, UBOGON,UBOGON,0x4d93,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON, UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,0x350e,UBOGON,UBOGON,UBOGON, UBOGON,0x360a,UBOGON,UBOGON,UBOGON,UBOGON,0x360d,UBOGON,UBOGON,UBOGON, UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON, UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON, UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON, UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON, UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON, UBOGON,UBOGON,UBOGON,UBOGON }, { /* ku 42 */ UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON, UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON, UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON, UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON, UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON, UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON, UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON, UBOGON,UBOGON,0x4074,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON, UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON, UBOGON,UBOGON,UBOGON,UBOGON }, { /* ku 43 */ UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON, UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,0x4256, UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON, UBOGON,UBOGON,0x425a,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON, UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,0x42a3,UBOGON,UBOGON,UBOGON,UBOGON, UBOGON,0x42a8,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON, UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON, UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON, UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON, UBOGON,UBOGON,UBOGON,UBOGON }, { /* ku 44 */ UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON, UBOGON,UBOGON,0x453c,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON, UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,0x459b,0x459a,UBOGON,UBOGON,UBOGON, UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,0x87f1, UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON, UBOGON,UBOGON,UBOGON,0x465e,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON, UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,0x46a7,UBOGON,UBOGON,UBOGON, UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON, UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON, UBOGON,UBOGON,UBOGON,UBOGON }, { /* ku 45 */ UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON, UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON, 0x486e,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON, UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,0x490d,UBOGON,UBOGON,UBOGON, UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,0x4943,UBOGON,UBOGON,UBOGON, UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON, UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON, UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON, UBOGON,UBOGON,0x4a73,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON, 0x4a74,UBOGON,UBOGON,0x4a70 }, { /* ku 46 */ UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON, UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON, UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON, UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON, UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,0x4bdb,UBOGON, UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON, UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON, UBOGON,0x4c29,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,0x4c51,UBOGON,UBOGON, UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,0x9bba,UBOGON, UBOGON,UBOGON,UBOGON,UBOGON }, { /* ku 47 */ UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,0x4cdb,UBOGON,UBOGON,UBOGON,UBOGON, UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON, UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,0x4d65,UBOGON, UBOGON,0x4d64,0x4d67,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON, UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON, UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,0x3611,UBOGON,UBOGON,UBOGON, UBOGON,0x3733,UBOGON,UBOGON,UBOGON,UBOGON,0x3821,0x3822,UBOGON,UBOGON, UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON, UBOGON,UBOGON,0x39a6,UBOGON,UBOGON,UBOGON,UBOGON,0x39a3,UBOGON,UBOGON, UBOGON,UBOGON,UBOGON,UBOGON }, { /* ku 48 */ UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON, UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON, UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,0x3ea1,UBOGON,UBOGON,UBOGON, UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON, UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON, UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON, UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,0x425f, UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,0x425c,UBOGON,UBOGON, UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON, UBOGON,UBOGON,UBOGON,UBOGON }, { /* ku 49 */ UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON, UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON, UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON, UBOGON,UBOGON,0x45f5,UBOGON,0x8804,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON, UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,0x4711,0x470c, UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON, UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON, UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON, UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON, UBOGON,UBOGON,UBOGON,UBOGON }, { /* ku 4a */ UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON, UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,0x494e,UBOGON, UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON, UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON, UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON, UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON, UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON, UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,0x4b94,UBOGON,UBOGON, UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON, UBOGON,UBOGON,UBOGON,UBOGON }, { /* ku 4b */ UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON, 0x4c63,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,0x4c61,UBOGON,0x9bd8,UBOGON, 0x4c5a,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,0x4ce3,UBOGON,UBOGON, 0x9d7c,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON, UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON, UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON, UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON, UBOGON,UBOGON,0x4daf,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON, UBOGON,UBOGON,0x3613,UBOGON,UBOGON,0x3680,UBOGON,UBOGON,UBOGON,UBOGON, UBOGON,UBOGON,UBOGON,UBOGON }, { /* ku 4c */ UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON, UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON, UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON, UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,0x4db0,UBOGON,UBOGON,UBOGON,UBOGON, UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON, UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON, UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON, UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON, UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,0x7c46,UBOGON, UBOGON,UBOGON,UBOGON,UBOGON }, { /* ku 4d */ UBOGON,0x4323,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON, UBOGON,0x4449,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON, UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON, UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON, UBOGON,UBOGON,0x45fa,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON, UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON, UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON, UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON, UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON, UBOGON,UBOGON,UBOGON,UBOGON }, { /* ku 4e */ UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON, UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON, 0x4959,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON, UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON, 0x4a7e,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON, UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON, UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,0x4ba8, UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,0x4ba9,UBOGON,UBOGON,UBOGON, UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON, UBOGON,UBOGON,UBOGON,UBOGON }, { /* ku 4f */ UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON, UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON, UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,0x9d8d,UBOGON,UBOGON,UBOGON,UBOGON, UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON, UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,0x4d54, UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,0x4d6d,UBOGON,UBOGON,UBOGON,UBOGON, UBOGON,UBOGON,UBOGON,UBOGON,0x4d8e,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON, UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON, UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON, UBOGON,UBOGON,UBOGON,UBOGON }, { /* ku 50 */ UBOGON,UBOGON,UBOGON,0x3a72,UBOGON,UBOGON,0x3c14,UBOGON,UBOGON,UBOGON, UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON, UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,0x3d93, UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON, UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON, UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON, UBOGON,UBOGON,UBOGON,UBOGON,0x426f,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON, UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,0x42b0, UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,0x352e,UBOGON,UBOGON, UBOGON,UBOGON,UBOGON,UBOGON }, { /* ku 51 */ UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON, UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON, UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON, UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON, UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON, UBOGON,UBOGON,0x4969,0x957e,UBOGON,UBOGON,UBOGON,UBOGON,0x49b4,UBOGON, UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,0x4a4d,UBOGON,UBOGON,UBOGON, UBOGON,UBOGON,0x4a83,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON, UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON, UBOGON,UBOGON,UBOGON,UBOGON }, { /* ku 52 */ UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON, UBOGON,UBOGON,0x4bb0,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON, UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON, 0x4c0c,UBOGON,0x4c18,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON, UBOGON,UBOGON,0x9c20,UBOGON,UBOGON,0x9c22,UBOGON,UBOGON,0x9c1e,UBOGON, UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON, UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,0x4cf5,UBOGON,UBOGON,UBOGON, UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON, UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON, UBOGON,UBOGON,UBOGON,UBOGON }, { /* ku 53 */ UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON, UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON, UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON, UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON, UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON, UBOGON,UBOGON,UBOGON,UBOGON,0x3e0e,UBOGON,UBOGON,UBOGON,UBOGON,0x3fd8, UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON, UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON, UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON, UBOGON,UBOGON,UBOGON,UBOGON }, { /* ku 54 */ UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON, UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON, UBOGON,UBOGON,UBOGON,0x8970,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON, UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON, UBOGON,UBOGON,0x482c,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON, UBOGON,UBOGON,0x496e,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON, UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,0x4a86,UBOGON,UBOGON,UBOGON,UBOGON, UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON, UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,0x4bb3,UBOGON,UBOGON,UBOGON,0x4beb, UBOGON,UBOGON,UBOGON,UBOGON }, { /* ku 55 */ UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON, UBOGON,UBOGON,0x9c43,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON, UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON, UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,0x9de0,UBOGON,UBOGON,0x4d42, UBOGON,UBOGON,UBOGON,UBOGON,0x4d41,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON, UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON, UBOGON,UBOGON,UBOGON,UBOGON,0x4dac,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON, UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,0x3b2f,0x3b2e,UBOGON,UBOGON, UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,0x3c4d,0x3c7b,UBOGON,UBOGON, UBOGON,UBOGON,UBOGON,UBOGON }, { /* ku 56 */ UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON, UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON, UBOGON,UBOGON,UBOGON,UBOGON,0x42b2,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON, UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON, UBOGON,UBOGON,UBOGON,0x4722,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON, UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON, 0x9459,UBOGON,0x4970,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON, UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON, UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON, UBOGON,UBOGON,UBOGON,UBOGON }, { /* ku 57 */ UBOGON,UBOGON,UBOGON,0x4c95,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON, UBOGON,0x4d00,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,0x4d02, UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON, UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON, UBOGON,UBOGON,UBOGON,UBOGON,0x4d9f,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON, UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON, UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON, UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON, UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON, UBOGON,UBOGON,UBOGON,UBOGON }, { /* ku 58 */ UBOGON,UBOGON,UBOGON,UBOGON,0x457d,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON, UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON, UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON, UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,0x4af6, UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,0x4c12, UBOGON,UBOGON,UBOGON,0x4c91,UBOGON,UBOGON,UBOGON,UBOGON,0x4c90,UBOGON, UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON, UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON, UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON, UBOGON,UBOGON,UBOGON,UBOGON }, { /* ku 59 */ UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,0x3a79, UBOGON,UBOGON,UBOGON,UBOGON,0x3c4e,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON, UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON, UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON, UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON, UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON, UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON, UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON, UBOGON,UBOGON,0x4d1e,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON, UBOGON,UBOGON,UBOGON,UBOGON }, { /* ku 5a */ UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON, UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON, UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON, UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON, UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON, 0x9c72,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON, UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON, UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON, UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON, UBOGON,UBOGON,UBOGON,UBOGON }, { /* ku 5b */ UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON, UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON, UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,0x3828,UBOGON, UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON, UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON, UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON, UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON, UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON, UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,0x4d91, UBOGON,UBOGON,UBOGON,UBOGON }, { /* ku 5c */ UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON, UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON, UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,0x4587, UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON, UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON, UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON, UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON, UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON, UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON, UBOGON,UBOGON,UBOGON,UBOGON } }; /* CNS 11643 plane 6 conversion table */ static const unsigned short cns11643_6tab[MAX_CNS11643_KU_6][MAX_CNS11643_TEN] = { { /* ku 01 */ UBOGON,UBOGON,0x3405,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON, UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON, UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,0x353f,UBOGON,UBOGON,UBOGON, UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON, UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON, UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON, UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON, UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,0x382a,UBOGON,UBOGON, UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,0x38a7,UBOGON, UBOGON,UBOGON,UBOGON,0x38fa }, { /* ku 02 */ UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON, UBOGON,0x3400,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON, UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON, UBOGON,UBOGON,0x34db,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON, UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON, UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON, UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON, UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON, UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON, UBOGON,UBOGON,UBOGON,UBOGON }, { /* ku 03 */ UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON, UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON, UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON, UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON, UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,0x3438,UBOGON,UBOGON,UBOGON,UBOGON, UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON, UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON, UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,0x6530,UBOGON,UBOGON,UBOGON,UBOGON, 0x353a,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON, UBOGON,UBOGON,UBOGON,UBOGON }, { /* ku 04 */ UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON, UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON, UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON, UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON, UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON, UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON, UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON, UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,0x38c9, UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON, UBOGON,UBOGON,UBOGON,UBOGON }, { /* ku 05 */ UBOGON,UBOGON,UBOGON,UBOGON,0x3c4f,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON, UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON, UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON, UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON, 0x43cd,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,0x4492,UBOGON,UBOGON,UBOGON, UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON, UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON, UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON, 0x3445,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON, 0x34b5,UBOGON,0x34b6,UBOGON }, { /* ku 06 */ UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON, UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON, UBOGON,0x3537,UBOGON,0x3530,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON, UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON, UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON, UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON, UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON, UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON, UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,0x373e,0x374d,0x3751, UBOGON,UBOGON,UBOGON,UBOGON }, { /* ku 07 */ UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON, UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON, UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON, UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,0x3873,UBOGON, UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON, UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON, UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON, UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,0x39be,UBOGON,UBOGON, UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON, UBOGON,UBOGON,UBOGON,UBOGON }, { /* ku 08 */ UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON, UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,0x3c1e,UBOGON,UBOGON,UBOGON,UBOGON, UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON, UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,0x3cc8,UBOGON,UBOGON,UBOGON,UBOGON, 0x3cc3,0x3cc7,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON, UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON, UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,0x3f56,UBOGON,0x3540,UBOGON,UBOGON, UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON, UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON, UBOGON,UBOGON,UBOGON,UBOGON }, { /* ku 09 */ UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON, UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON, 0x49bd,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON, UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON, UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON, UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON, UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON, UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,0x351a,UBOGON, UBOGON,0x352c,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON, UBOGON,UBOGON,UBOGON,UBOGON }, { /* ku 0a */ UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,0x3549, UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON, UBOGON,UBOGON,UBOGON,UBOGON,0x357c,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON, UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON, UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON, UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON, UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON, UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON, UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,0x37bf,UBOGON,UBOGON,UBOGON,UBOGON, 0x37ba,UBOGON,UBOGON,UBOGON }, { /* ku 0b */ UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON, UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON, UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,0x38d8, UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON, UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,0x39b2, UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON, UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON, UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,0x3ac4, UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON, UBOGON,UBOGON,UBOGON,UBOGON }, { /* ku 0c */ UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON, UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON, UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON, UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON, UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON, UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON, UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON, UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON, 0x3e2b,UBOGON,UBOGON,UBOGON,0x3e61,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON, UBOGON,UBOGON,UBOGON,0x72dd }, { /* ku 0d */ 0x3eb2,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON, UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON, UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON, UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON, 0x4129,UBOGON,UBOGON,UBOGON,UBOGON,0x4192,UBOGON,UBOGON,UBOGON,UBOGON, UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON, UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON, UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON, UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON, UBOGON,UBOGON,UBOGON,UBOGON }, { /* ku 0e */ UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON, UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON, UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON, UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON, UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON, UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,0x3458,UBOGON,UBOGON, UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON, UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON, UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON, UBOGON,UBOGON,UBOGON,UBOGON }, { /* ku 0f */ UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,0x351c,UBOGON,UBOGON,UBOGON, UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON, UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON, UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON, UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON, UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON, UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,0x3637,UBOGON, UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON, UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON, UBOGON,UBOGON,UBOGON,UBOGON }, { /* ku 10 */ UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON, UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON, UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON, UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON, UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON, UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON, UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,0x3843,UBOGON,UBOGON,UBOGON, UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON, UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,0x38b4, UBOGON,UBOGON,UBOGON,UBOGON }, { /* ku 11 */ UBOGON,UBOGON,UBOGON,UBOGON,0x38e0,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON, UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON, UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON, UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON, UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON, UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON, UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON, 0x3ae4,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON, UBOGON,0x6804,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,0x3c26,UBOGON,UBOGON, UBOGON,UBOGON,UBOGON,UBOGON }, { /* ku 12 */ UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON, UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON, UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON, UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON, UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON, UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON, UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON, 0x3e6f,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON, UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON, UBOGON,UBOGON,UBOGON,UBOGON }, { /* ku 13 */ UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON, UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON, UBOGON,UBOGON,UBOGON,0x401c,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON, UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,0x4100, UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON, UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON, UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,0x42b6,UBOGON,UBOGON, UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON, UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON, UBOGON,UBOGON,0x43e4,UBOGON }, { /* ku 14 */ UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON, UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON, UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,0x44ad,UBOGON,0x82ff,UBOGON,UBOGON, UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON, UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON, UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON, UBOGON,UBOGON,UBOGON,0x8fec,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON, UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,0x48c3,UBOGON,UBOGON,UBOGON, UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON, UBOGON,UBOGON,UBOGON,UBOGON }, { /* ku 15 */ UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON, UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON, UBOGON,UBOGON,UBOGON,0x3467,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON, UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON, UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON, UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON, UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON, UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON, UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,0x53de,UBOGON,UBOGON, UBOGON,UBOGON,0x3596,UBOGON }, { /* ku 16 */ UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON, UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON, UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON, UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON, UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON, UBOGON,UBOGON,UBOGON,UBOGON,0x5a30,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON, 0x3759,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,0x5bb2, UBOGON,0x3776,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON, UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON, UBOGON,0x37d2,UBOGON,UBOGON }, { /* ku 17 */ UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON, UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON, UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON, UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON, UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON, UBOGON,0x3920,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,0x3929,UBOGON,UBOGON, UBOGON,0x3938,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON, UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON, UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON, UBOGON,UBOGON,UBOGON,UBOGON }, { /* ku 18 */ UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON, 0x3a89,0x3ab0,UBOGON,UBOGON,UBOGON,0x3abf,UBOGON,UBOGON,UBOGON,0x3ac5, UBOGON,UBOGON,0x3aea,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON, UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON, UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON, UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON, UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,0x3c37,UBOGON,UBOGON, UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON, UBOGON,0x3ce4,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON, UBOGON,UBOGON,UBOGON,UBOGON }, { /* ku 19 */ UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON, UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,0x3ce8,UBOGON, UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON, UBOGON,0x3e20,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON, UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON, UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON, UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON, UBOGON,UBOGON,UBOGON,UBOGON,0x3f86,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON, UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON, UBOGON,UBOGON,UBOGON,UBOGON }, { /* ku 1a */ UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON, UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON, UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON, UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON, UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON, UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON, UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON, UBOGON,UBOGON,UBOGON,UBOGON,0x4356,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON, UBOGON,UBOGON,UBOGON,0x4367,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON, UBOGON,UBOGON,UBOGON,UBOGON }, { /* ku 1b */ 0x8038,UBOGON,UBOGON,0x8081,UBOGON,UBOGON,UBOGON,0x43d1,UBOGON,UBOGON, UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,0x43eb,UBOGON,UBOGON,UBOGON, UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON, UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON, UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON, UBOGON,UBOGON,UBOGON,0x44b6,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON, UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON, UBOGON,UBOGON,0x45a3,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON, UBOGON,UBOGON,0x4610,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON, UBOGON,UBOGON,UBOGON,UBOGON }, { /* ku 1c */ UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON, UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON, UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON, UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON, UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON, UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON, UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,0x491b,UBOGON,0x4987,UBOGON, UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON, UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON, UBOGON,UBOGON,UBOGON,UBOGON }, { /* ku 1d */ UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON, UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON, UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON, UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON, UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON, UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON, UBOGON,UBOGON,UBOGON,UBOGON,0x3557,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON, UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON, UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON, UBOGON,UBOGON,UBOGON,UBOGON }, { /* ku 1e */ UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON, UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON, UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON, UBOGON,UBOGON,UBOGON,0x369d,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON, UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON, UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,0x375f,UBOGON,UBOGON, UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,0x3779,UBOGON,UBOGON, UBOGON,UBOGON,UBOGON,UBOGON,0x3798,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON, UBOGON,UBOGON,UBOGON,UBOGON,0x37dc,UBOGON,UBOGON,0x37df,UBOGON,UBOGON, UBOGON,UBOGON,UBOGON,UBOGON }, { /* ku 1f */ UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON, UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON, UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON, UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON, UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON, UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON, UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON, UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON, UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON, UBOGON,UBOGON,UBOGON,UBOGON }, { /* ku 20 */ UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON, UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,0x39fd,UBOGON,UBOGON, UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON, UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON, UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,0x3af4,UBOGON,0x3aef,UBOGON, UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON, UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON, UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,0x3c31,UBOGON,UBOGON, UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON, UBOGON,UBOGON,UBOGON,UBOGON }, { /* ku 21 */ UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON, 0x3d03,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON, UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON, UBOGON,UBOGON,0x3d09,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON, UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON, UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON, UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,0x3e3e, UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,0x3e77,UBOGON,UBOGON,UBOGON, UBOGON,UBOGON,UBOGON,UBOGON,0x3e7b,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON, UBOGON,UBOGON,UBOGON,UBOGON }, { /* ku 22 */ UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON, UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON, UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON, UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON, UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON, UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON, UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,0x413a, UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,0x41a0,UBOGON, UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,0x41e5,UBOGON,UBOGON,UBOGON,UBOGON, UBOGON,UBOGON,UBOGON,UBOGON }, { /* ku 23 */ UBOGON,0x427d,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON, UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON, UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,0x436d,UBOGON,UBOGON, UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON, UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON, UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,0x43f8,UBOGON,0x8158,UBOGON,UBOGON, UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,0x4450,UBOGON,UBOGON, UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,0x4468, 0x4467,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON, UBOGON,UBOGON,UBOGON,UBOGON }, { /* ku 24 */ UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,0x44cf,UBOGON,UBOGON, UBOGON,0x44cd,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON, UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON, UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,0x45ab, UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON, UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON, UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON, UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,0x46c1,UBOGON,UBOGON,0x8a24, UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON, UBOGON,UBOGON,UBOGON,UBOGON }, { /* ku 25 */ UBOGON,0x4747,UBOGON,0x4757,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON, UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON, UBOGON,UBOGON,UBOGON,0x8dc3,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON, UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,0x484e,UBOGON,UBOGON,UBOGON, UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON, UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON, UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON, UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON, UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON, UBOGON,UBOGON,UBOGON,UBOGON }, { /* ku 26 */ UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON, UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON, UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON, UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON, UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON, UBOGON,UBOGON,0x3477,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON, UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,0x51f2,UBOGON, UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON, UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON, UBOGON,UBOGON,UBOGON,UBOGON }, { /* ku 27 */ UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,0x55b6,UBOGON, UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON, UBOGON,UBOGON,UBOGON,UBOGON,0x35c4,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON, UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON, UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,0x3652,UBOGON,UBOGON,UBOGON,UBOGON, UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON, UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON, UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON, UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON, UBOGON,UBOGON,UBOGON,UBOGON }, { /* ku 28 */ UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON, UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON, UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON, UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,0x386b,0x5ec3,UBOGON,UBOGON,UBOGON, UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON, UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON, UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON, UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,0x3941,UBOGON, UBOGON,UBOGON,UBOGON,UBOGON,0x3950,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON, UBOGON,UBOGON,UBOGON,UBOGON }, { /* ku 29 */ UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON, UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON, UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON, UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON, UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON, UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON, UBOGON,UBOGON,UBOGON,UBOGON,0x3ac0,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON, UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON, UBOGON,UBOGON,0x3afc,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON, 0x3479,UBOGON,UBOGON,0x440b }, { /* ku 2a */ UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON, UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON, UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON, UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON, UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON, UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON, UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON, UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,0x3d1e,UBOGON,UBOGON,UBOGON, UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON, UBOGON,UBOGON,UBOGON,UBOGON }, { /* ku 2b */ UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON, UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON, UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON, UBOGON,UBOGON,UBOGON,UBOGON,0x3e85,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON, UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON, UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,0x3f97,UBOGON,UBOGON, UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON, UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON, UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON, UBOGON,UBOGON,UBOGON,UBOGON }, { /* ku 2c */ UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON, 0x4093,UBOGON,UBOGON,UBOGON,0x7861,UBOGON,UBOGON,UBOGON,0x40b2,UBOGON, UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON, UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,0x7a01, UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON, 0x41a4,UBOGON,UBOGON,0x41f2,UBOGON,UBOGON,UBOGON,UBOGON,0x41f1,UBOGON, UBOGON,UBOGON,UBOGON,0x4281,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON, UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON, 0x42dc,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON, UBOGON,UBOGON,UBOGON,UBOGON }, { /* ku 2d */ UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON, UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON, UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON, UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON, UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON, UBOGON,0x440c,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON, UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,0x446d,UBOGON,UBOGON,UBOGON, UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON, UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON, UBOGON,UBOGON,UBOGON,UBOGON }, { /* ku 2e */ UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,0x44e6,UBOGON,UBOGON,UBOGON, UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON, UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON, UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON, UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,0x8849,UBOGON,UBOGON,UBOGON, UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON, UBOGON,UBOGON,UBOGON,0x8999,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON, UBOGON,UBOGON,UBOGON,UBOGON,0x46d1,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON, UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,0x472c, UBOGON,UBOGON,UBOGON,UBOGON }, { /* ku 2f */ UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,0x476e,UBOGON, UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON, UBOGON,0x47e5,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,0x47e6,UBOGON,UBOGON, UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,0x489f, UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON, UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON, UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON, UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,0x921f,UBOGON, UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON, UBOGON,UBOGON,UBOGON,UBOGON }, { /* ku 30 */ UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON, UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,0x4a0d,UBOGON,UBOGON,UBOGON, UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON, UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON, UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON, UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON, UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON, UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,0x34f8,UBOGON,UBOGON,UBOGON,UBOGON, UBOGON,UBOGON,UBOGON,0x5313,UBOGON,0x3533,UBOGON,UBOGON,UBOGON,0x353c, UBOGON,UBOGON,UBOGON,UBOGON }, { /* ku 31 */ UBOGON,0x354f,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON, UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,0x35dc,UBOGON,UBOGON, UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON, UBOGON,UBOGON,UBOGON,UBOGON,0x55e0,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON, UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON, UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON, UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON, UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON, UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON, UBOGON,UBOGON,UBOGON,UBOGON }, { /* ku 32 */ UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON, UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,0x37f5, UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON, UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON, UBOGON,UBOGON,UBOGON,UBOGON,0x38c3,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON, UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON, UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,0x6139,UBOGON,UBOGON, UBOGON,UBOGON,0x3971,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON, UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON, UBOGON,UBOGON,UBOGON,UBOGON }, { /* ku 33 */ UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON, UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON, UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,0x3b01,UBOGON, UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON, UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON, UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON, UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON, UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON, UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON, UBOGON,UBOGON,UBOGON,UBOGON }, { /* ku 34 */ UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON, UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON, UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON, UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON, UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,0x6ed7,UBOGON,0x3d41,UBOGON,UBOGON, UBOGON,0x3dd7,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON, UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON, UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON, UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,0x3e45,UBOGON,UBOGON, UBOGON,0x733d,UBOGON,UBOGON }, { /* ku 35 */ UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON, UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON, UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON, UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON, UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,0x3ff2, UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON, UBOGON,UBOGON,UBOGON,UBOGON,0x4049,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON, UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON, UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON, UBOGON,UBOGON,UBOGON,UBOGON }, { /* ku 36 */ UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,0x41a9,UBOGON,UBOGON,UBOGON, UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON, UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON, UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON, UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON, UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON, UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON, UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,0x43cb,UBOGON,UBOGON,UBOGON, UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,0x440d,UBOGON,UBOGON,UBOGON,UBOGON, UBOGON,UBOGON,UBOGON,UBOGON }, { /* ku 37 */ UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON, UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON, UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON, UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON, UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON, UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON, UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON, UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON, UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON, UBOGON,UBOGON,UBOGON,UBOGON }, { /* ku 38 */ UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON, 0x4631,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON, UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON, UBOGON,UBOGON,0x46d5,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON, UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON, UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON, UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON, UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON, UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON, UBOGON,UBOGON,UBOGON,UBOGON }, { /* ku 39 */ UBOGON,UBOGON,UBOGON,0x4856,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON, UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON, UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON, UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON, UBOGON,UBOGON,UBOGON,0x48f4,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON, UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON, UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON, UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON, UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON, UBOGON,UBOGON,UBOGON,UBOGON }, { /* ku 3a */ UBOGON,UBOGON,UBOGON,0x9775,UBOGON,UBOGON,UBOGON,0x4a58,UBOGON,UBOGON, UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON, UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON, UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON, UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON, UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON, UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON, UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON, UBOGON,UBOGON,0x3487,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON, UBOGON,UBOGON,UBOGON,UBOGON }, { /* ku 3b */ UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON, UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON, UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON, UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON, UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON, UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON, UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON, UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON, UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON, UBOGON,UBOGON,UBOGON,UBOGON }, { /* ku 3c */ UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON, UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON, UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON, UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,0x37fa,UBOGON,UBOGON,UBOGON,UBOGON, UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON, UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON, UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON, 0x38f2,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON, UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON, UBOGON,UBOGON,UBOGON,UBOGON }, { /* ku 3d */ UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON, UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,0x3a2f,UBOGON,UBOGON, UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON, UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON, UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,0x3ac1,UBOGON, UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON, UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON, UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON, UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,0x3c40,UBOGON,UBOGON,UBOGON, UBOGON,UBOGON,UBOGON,UBOGON }, { /* ku 3e */ UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON, UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON, UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,0x3d3f,UBOGON,UBOGON,UBOGON, UBOGON,0x3d46,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON, UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON, UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON, UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON, UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,0x3e8f,UBOGON,UBOGON, UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON, UBOGON,UBOGON,UBOGON,UBOGON }, { /* ku 3f */ UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON, UBOGON,UBOGON,0x3fac,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON, UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON, UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON, UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON, UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON, UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON, UBOGON,UBOGON,UBOGON,UBOGON,0x4168,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON, UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,0x41ab,UBOGON,UBOGON, UBOGON,UBOGON,UBOGON,UBOGON }, { /* ku 40 */ UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON, UBOGON,0x4291,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON, UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON, UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON, UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON, UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,0x7fe4,UBOGON,UBOGON,UBOGON,UBOGON, UBOGON,UBOGON,UBOGON,0x8088,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON, UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,0x4430,UBOGON, UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON, UBOGON,UBOGON,UBOGON,UBOGON }, { /* ku 41 */ 0x445d,UBOGON,UBOGON,0x4475,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON, UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON, UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON, UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,0x44ff,UBOGON,UBOGON,UBOGON,UBOGON, UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON, UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,0x450b,UBOGON,UBOGON,UBOGON,UBOGON, UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON, UBOGON,UBOGON,0x45c8,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON, UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON, UBOGON,UBOGON,UBOGON,UBOGON }, { /* ku 42 */ UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON, UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON, UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON, UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON, UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON, UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON, UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON, UBOGON,UBOGON,UBOGON,0x4774,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON, UBOGON,UBOGON,UBOGON,UBOGON,0x47ac,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON, UBOGON,UBOGON,UBOGON,UBOGON }, { /* ku 43 */ UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON, UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON, UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON, UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON, UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON, UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON, UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON, UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON, UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON, 0x4a16,UBOGON,UBOGON,UBOGON }, { /* ku 44 */ UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON, UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON, UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON, UBOGON,0x4b3b,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON, UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON, UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON, UBOGON,0x4bef,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON, UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON, UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON, UBOGON,UBOGON,UBOGON,UBOGON } }; /* CNS 11643 plane 7 conversion table */ static const unsigned short cns11643_7tab[MAX_CNS11643_KU_7][MAX_CNS11643_TEN] = { { /* ku 01 */ UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON, UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON, UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON, UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON, UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,0x35f6,UBOGON,UBOGON,UBOGON,UBOGON, UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON, UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,0x5655,UBOGON,UBOGON,UBOGON, UBOGON,UBOGON,UBOGON,0x3667,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON, UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON, UBOGON,UBOGON,UBOGON,UBOGON }, { /* ku 02 */ UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON, UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON, UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON, UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON, UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON, UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON, UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON, UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON, 0x617f,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON, UBOGON,0x3992,UBOGON,UBOGON }, { /* ku 03 */ UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON, UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON, UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,0x3a45,UBOGON,UBOGON,UBOGON,UBOGON, UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON, UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON, UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON, UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON, UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,0x3bc9,UBOGON, UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON, UBOGON,UBOGON,UBOGON,UBOGON }, { /* ku 04 */ UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON, UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON, UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON, UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON, UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON, UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON, UBOGON,UBOGON,UBOGON,UBOGON,0x3d55,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON, UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON, UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON, UBOGON,UBOGON,UBOGON,UBOGON }, { /* ku 05 */ UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON, UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON, UBOGON,UBOGON,0x3ee8,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON, UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON, UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON, UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,0x3fb6,UBOGON,UBOGON,UBOGON,0x3fbd, UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON, UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON, UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON, UBOGON,UBOGON,UBOGON,UBOGON }, { /* ku 06 */ UBOGON,UBOGON,UBOGON,0x40d6,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON, UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,0x4171,UBOGON,UBOGON, UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON, UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON, UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON, UBOGON,UBOGON,UBOGON,UBOGON,0x4298,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON, UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON, UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON, UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON, UBOGON,UBOGON,UBOGON,UBOGON }, { /* ku 07 */ UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON, UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON, UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON, UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON, UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON, UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON, UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON, UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON, UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON, UBOGON,UBOGON,UBOGON,UBOGON }, { /* ku 08 */ UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON, UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON, UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON, UBOGON,UBOGON,UBOGON,0x45cd,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON, UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON, UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON, UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON, UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON, UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,0x46f6,UBOGON, UBOGON,UBOGON,UBOGON,UBOGON }, { /* ku 09 */ UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON, UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON, UBOGON,0x477a,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,0x47b8,UBOGON, UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON, UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,0x4801,UBOGON,UBOGON,UBOGON,UBOGON, UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON, UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON, UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON, UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON, UBOGON,UBOGON,UBOGON,UBOGON }, { /* ku 0a */ UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON, UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON, UBOGON,UBOGON,UBOGON,0x492f,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,0x4931, UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,0x499c,UBOGON,UBOGON, UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON, UBOGON,0x49e6,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON, UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON, UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON, UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON, UBOGON,UBOGON,UBOGON,UBOGON }, { /* ku 0b */ UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON, UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON, UBOGON,UBOGON,UBOGON,0x4b38,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON, UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON, UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON, UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON, UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON, UBOGON,UBOGON,UBOGON,0x4c3a,UBOGON,UBOGON,0x4cb1,UBOGON,UBOGON,UBOGON, UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON, UBOGON,UBOGON,UBOGON,UBOGON }, { /* ku 0c */ UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON, UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,0x4d47,UBOGON,0x4d51,UBOGON, UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON, UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON, UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON, UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON, UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON, UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON, UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON, UBOGON,UBOGON,UBOGON,UBOGON }, { /* ku 0d */ UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON, UBOGON,UBOGON,0x3747,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON, UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON, UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON, UBOGON,UBOGON,UBOGON,0x3817,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON, UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,0x38a3,UBOGON, UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON, UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON, UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON, UBOGON,UBOGON,UBOGON,UBOGON }, { /* ku 0e */ UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON, UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON, UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON, UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON, UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON, UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,0x3b1e,UBOGON,UBOGON, UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON, UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON, UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON, UBOGON,UBOGON,UBOGON,UBOGON }, { /* ku 0f */ UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON, UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON, UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON, UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON, UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,0x71d7,UBOGON,UBOGON,UBOGON, UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON, UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON, UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON, UBOGON,UBOGON,UBOGON,0x3e9a,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON, UBOGON,UBOGON,UBOGON,UBOGON }, { /* ku 10 */ UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON, UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON, UBOGON,0x3fc2,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON, UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON, UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON, UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,0x40dc,UBOGON,UBOGON,UBOGON, UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON, UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,0x41b3,UBOGON, UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON, UBOGON,UBOGON,UBOGON,UBOGON }, { /* ku 11 */ UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON, UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON, UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON, UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON, UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON, UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON, UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON, UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON, UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON, UBOGON,UBOGON,UBOGON,UBOGON }, { /* ku 12 */ UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON, UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON, UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON, UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON, UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON, UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON, UBOGON,UBOGON,UBOGON,UBOGON,0x8666,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON, UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON, UBOGON,UBOGON,0x45d9,UBOGON,0x45dd,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON, UBOGON,UBOGON,UBOGON,UBOGON }, { /* ku 13 */ UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON, UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON, UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON, UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON, UBOGON,UBOGON,UBOGON,UBOGON,0x46fc,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON, UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON, UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON, UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON, UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON, UBOGON,UBOGON,UBOGON,UBOGON }, { /* ku 14 */ UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON, UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,0x8f3a,UBOGON,UBOGON, UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON, UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON, UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON, UBOGON,0x4907,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON, UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,0x933d,UBOGON,UBOGON,UBOGON, UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON, UBOGON,UBOGON,0x49a8,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON, UBOGON,UBOGON,UBOGON,UBOGON }, { /* ku 15 */ UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON, UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON, UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON, UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON, UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,0x4aca,UBOGON, UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON, UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON, UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON, UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON, UBOGON,UBOGON,UBOGON,UBOGON }, { /* ku 16 */ UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,0x4b8d,UBOGON,UBOGON, UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON, UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON, UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON, UBOGON,0x4cc0,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,0x4cca,UBOGON, UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,0x4d25, UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,0x4d4a,UBOGON, 0x4d53,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON, UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON, UBOGON,UBOGON,UBOGON,UBOGON }, { /* ku 17 */ UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON, UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON, UBOGON,UBOGON,0x3605,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON, UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON, UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON, UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON, UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON, UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON, UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON, UBOGON,UBOGON,UBOGON,UBOGON }, { /* ku 18 */ UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON, UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON, UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON, UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON, UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON, UBOGON,UBOGON,0x3bf0,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON, UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON, UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON, UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON, UBOGON,UBOGON,UBOGON,UBOGON }, { /* ku 19 */ UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,0x3e02,UBOGON,UBOGON,UBOGON,UBOGON, UBOGON,UBOGON,0x3e23,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON, UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON, UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON, UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON, UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON, UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON, UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON, UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON, UBOGON,UBOGON,UBOGON,UBOGON }, { /* ku 1a */ UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON, UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON, UBOGON,UBOGON,UBOGON,UBOGON,0x4315,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON, UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON, UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON, UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON, UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON, UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON, UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON, UBOGON,UBOGON,UBOGON,UBOGON }, { /* ku 1b */ UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON, UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,0x455d,UBOGON,UBOGON, UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON, UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON, UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON, UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,0x465a,UBOGON,UBOGON,UBOGON, UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON, UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON, UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON, UBOGON,UBOGON,UBOGON,UBOGON }, { /* ku 1c */ UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON, UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,0x4785,UBOGON, UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON, UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON, UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON, UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON, UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON, UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,0x490b, UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,0x4939,UBOGON,UBOGON,UBOGON, 0x4937,UBOGON,UBOGON,UBOGON }, { /* ku 1d */ UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON, UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON, UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON, UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON, UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON, UBOGON,UBOGON,UBOGON,0x4a6b,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON, UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON, UBOGON,UBOGON,0x4acd,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON, UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON, UBOGON,UBOGON,UBOGON,UBOGON }, { /* ku 1e */ UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON, UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON, UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON, UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON, 0x4c4d,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON, UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON, UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON, UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON, UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON, UBOGON,UBOGON,0x3510,UBOGON }, { /* ku 1f */ UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON, UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,0x367b,UBOGON,UBOGON,UBOGON,UBOGON, UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON, UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,0x381d,UBOGON,UBOGON,UBOGON,UBOGON, UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON, UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON, UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,0x64f5,UBOGON,UBOGON,UBOGON,UBOGON, UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON, UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,0x3b27,UBOGON,UBOGON,UBOGON,UBOGON, UBOGON,UBOGON,UBOGON,UBOGON }, { /* ku 20 */ UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON, UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON, UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON, UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON, UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON, UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON, UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON, 0x3fcf,UBOGON,UBOGON,UBOGON,0x3fcd,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON, UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON, UBOGON,UBOGON,UBOGON,UBOGON }, { /* ku 21 */ UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON, UBOGON,UBOGON,UBOGON,0x4182,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON, UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON, 0x4252,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON, UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON, UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON, UBOGON,UBOGON,UBOGON,UBOGON,0x7f80,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON, UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON, UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON, UBOGON,UBOGON,UBOGON,UBOGON }, { /* ku 22 */ UBOGON,UBOGON,UBOGON,0x4451,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON, UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON, UBOGON,UBOGON,UBOGON,0x455a,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON, UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON, UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON, UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON, UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON, UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON, UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON, UBOGON,UBOGON,UBOGON,UBOGON }, { /* ku 23 */ UBOGON,0x4665,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON, UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON, UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON, UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON, UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,0x8d01, UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON, UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON, UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON, UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,0x48af,UBOGON,UBOGON,UBOGON, UBOGON,UBOGON,UBOGON,UBOGON }, { /* ku 24 */ UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON, UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON, UBOGON,UBOGON,UBOGON,UBOGON,0x4941,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON, UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON, UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON, UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,0x4a29,UBOGON,UBOGON,UBOGON,UBOGON, UBOGON,UBOGON,UBOGON,0x4a2a,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON, UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON, UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,0x4a96,UBOGON,UBOGON,UBOGON, UBOGON,UBOGON,UBOGON,0x4b12 }, { /* ku 25 */ UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON, UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON, UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON, UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON, UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON, UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON, UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON, UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON, UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON, UBOGON,UBOGON,UBOGON,UBOGON }, { /* ku 26 */ UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON, UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON, UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON, UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,0x367e,0x58e1,UBOGON,UBOGON,UBOGON, UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON, UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON, UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON, UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON, UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON, UBOGON,UBOGON,UBOGON,UBOGON }, { /* ku 27 */ UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON, UBOGON,0x39a7,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON, UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON, UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON, UBOGON,0x4320,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON, UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON, UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON, UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON, UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON, UBOGON,UBOGON,UBOGON,UBOGON }, { /* ku 28 */ UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON, UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON, UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON, UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON, UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON, UBOGON,UBOGON,UBOGON,UBOGON,0x7ce9,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON, UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON, UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON, UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON, UBOGON,0x81cb,UBOGON,UBOGON }, { /* ku 29 */ UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON, UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON, UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON, UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON, UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON, 0x4565,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON, UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON, UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON, UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON, UBOGON,UBOGON,UBOGON,UBOGON }, { /* ku 2a */ UBOGON,UBOGON,UBOGON,UBOGON,0x4704,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON, UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON, UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON, UBOGON,UBOGON,0x4764,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON, UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON, UBOGON,UBOGON,UBOGON,UBOGON,0x4823,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON, UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON, UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON, UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON, UBOGON,UBOGON,UBOGON,UBOGON }, { /* ku 2b */ UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON, UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON, UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON, UBOGON,0x95d9,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON, UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON, UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON, UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON, UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON, UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON, UBOGON,UBOGON,UBOGON,UBOGON }, { /* ku 2c */ UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON, UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON, UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON, UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON, UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON, UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON, UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON, UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON, UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON, UBOGON,UBOGON,UBOGON,UBOGON }, { /* ku 2d */ UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON, UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON, UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,0x34b9,UBOGON, UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON, UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON, UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON, UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON, UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON, UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON, UBOGON,UBOGON,UBOGON,UBOGON }, { /* ku 2e */ UBOGON,0x3c4b,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON, UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON, UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON, UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON, UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON, UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,0x40f1, UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON, UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON, UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON, UBOGON,UBOGON,UBOGON,UBOGON }, { /* ku 2f */ UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON, UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON, UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON, UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON, UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON, UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON, UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON, UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON, UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON, UBOGON,UBOGON,UBOGON,UBOGON }, { /* ku 30 */ UBOGON,UBOGON,UBOGON,UBOGON,0x4667,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON, UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,0x4714,UBOGON,UBOGON,UBOGON, UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON, UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON, UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON, UBOGON,UBOGON,UBOGON,0x4889,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON, UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON, UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON, UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON, UBOGON,UBOGON,UBOGON,UBOGON }, { /* ku 31 */ UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON, UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON, UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON, UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON, UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON, UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON, UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON, UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON, UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,0x4c0b,UBOGON, UBOGON,UBOGON,0x4c17,UBOGON }, { /* ku 32 */ UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON, UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,0x4c6d,UBOGON,0x4c70,UBOGON, UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON, UBOGON,UBOGON,UBOGON,0x4ced,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON, UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON, UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON, UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON, 0x4d8d,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON, UBOGON,UBOGON,UBOGON,0x34a7,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON, UBOGON,UBOGON,UBOGON,UBOGON }, { /* ku 33 */ UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON, UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON, UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON, UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,0x6707,UBOGON, UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON, UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON, UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON, UBOGON,UBOGON,UBOGON,UBOGON,0x3e5a,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON, UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON, UBOGON,UBOGON,UBOGON,UBOGON }, { /* ku 34 */ UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON, UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON, UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,0x42af,UBOGON,UBOGON,UBOGON,UBOGON, UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON, UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON, UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON, UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON, UBOGON,0x456b,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON, UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON, UBOGON,UBOGON,UBOGON,UBOGON }, { /* ku 35 */ UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON, UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,0x471b,UBOGON,UBOGON, UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON, UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON, UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON, UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON, UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON, UBOGON,0x4963,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON, UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON, UBOGON,UBOGON,UBOGON,UBOGON }, { /* ku 36 */ UBOGON,UBOGON,UBOGON,UBOGON,0x4a80,0x4a84,0x4a7f,UBOGON,UBOGON,UBOGON, UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,0x4af1,UBOGON,UBOGON, UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON, UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON, UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,0x9a47,UBOGON, UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON, UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON, UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON, UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON, UBOGON,UBOGON,UBOGON,UBOGON }, { /* ku 37 */ UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,0x4d1c,UBOGON, UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON, UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON, UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON, UBOGON,UBOGON,UBOGON,0x34a8,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON, UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON, UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON, UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON, UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON, UBOGON,UBOGON,UBOGON,UBOGON }, { /* ku 38 */ UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON, UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON, UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON, UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON, UBOGON,UBOGON,UBOGON,0x418b,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON, UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,0x432b,UBOGON,UBOGON,UBOGON,UBOGON, UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON, UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON, UBOGON,0x457a,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON, UBOGON,UBOGON,UBOGON,UBOGON }, { /* ku 39 */ UBOGON,UBOGON,UBOGON,UBOGON,0x4609,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON, UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,0x466d,UBOGON,UBOGON, UBOGON,UBOGON,UBOGON,0x471f,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON, UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON, UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON, UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON, UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON, 0x496a,0x496c,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON, UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON, UBOGON,UBOGON,UBOGON,UBOGON }, { /* ku 3a */ UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON, UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON, UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,0x4bb2, UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON, UBOGON,UBOGON,0x4c1d,UBOGON,UBOGON,UBOGON,0x4c2d,UBOGON,UBOGON,UBOGON, UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON, UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON, UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON, UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON, UBOGON,UBOGON,0x4d45,UBOGON }, { /* ku 3b */ UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON, UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON, UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON, UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON, UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON, UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON, UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON, UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON, UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON, UBOGON,UBOGON,UBOGON,UBOGON }, { /* ku 3c */ UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON, UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON, UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON, UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON, UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON, UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON, UBOGON,0x460a,UBOGON,UBOGON,UBOGON,UBOGON,0x460c,UBOGON,UBOGON,UBOGON, UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON, UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,0x482e,UBOGON,UBOGON,UBOGON, UBOGON,UBOGON,UBOGON,UBOGON }, { /* ku 3d */ UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON, UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON, UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON, UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON, UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON, UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON, UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON, UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON, UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON, UBOGON,UBOGON,UBOGON,UBOGON }, { /* ku 3e */ UBOGON,UBOGON,0x4c8d,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON, UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON, UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON, UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON, UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON, UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON, UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON, UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON, UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON, UBOGON,UBOGON,UBOGON,UBOGON }, { /* ku 3f */ UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON, UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,0x4331,UBOGON, UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON, UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON, UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON, UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON, UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON, UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON, UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON, UBOGON,UBOGON,UBOGON,UBOGON }, { /* ku 40 */ UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON, UBOGON,UBOGON,0x4bbc,0x4bbb,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON, UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON, UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON, UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON, UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON, UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON, UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON, UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON, UBOGON,UBOGON,UBOGON,UBOGON }, { /* ku 41 */ UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON, UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON, UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON, UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON, UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON, UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON, UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON, UBOGON,UBOGON,UBOGON,0x4c14,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON, UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON, UBOGON,UBOGON,UBOGON,UBOGON }, { /* ku 42 */ UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON, UBOGON,UBOGON,UBOGON,UBOGON,0x361c,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON, 0x3772,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON, UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON, UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON, UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON, UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON, UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON, UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON, UBOGON,UBOGON,UBOGON,UBOGON }, { /* ku 43 */ UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON, UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON, UBOGON,UBOGON,0x4d0e,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON, UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON, UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON, UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON, UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON, UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON, UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON, UBOGON,UBOGON,UBOGON,UBOGON }, { /* ku 44 */ UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON, UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON, UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON, UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON, UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,0x7674, UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON, UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON, UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON, UBOGON,UBOGON,UBOGON,UBOGON,0x4bec,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON, UBOGON,UBOGON,UBOGON,UBOGON }, { /* ku 45 */ UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON, UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON, UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON, UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON, UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON, UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON, 0x4279,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON, UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON, UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON, UBOGON,UBOGON,UBOGON,UBOGON } }; #if CNS_OBSOLETE /* CNS 11643 plane 14 conversion table */ static const unsigned short cns11643_14tab[MAX_CNS11643_KU_14][MAX_CNS11643_TEN] = { { /* ku 01 */ 0x4e28,0x4e36,0x4e3f,0x4e85,0x4e05,0x4e04,0x5182,0x5196,0x5338,0x5369, 0x53b6,0x4e2a,0x4e87,0x4e49,0x51e2,0x4e46,0x4e8f,0x4ebc,0x4ebe,0x5166, 0x51e3,0x5204,0x529c,UBOGON,0x5902,0x590a,0x5b80,0x5ddb,0x5e7a,0x5e7f, 0x5ef4,0x5f50,0x5f51,0x5f61,0x961d,UBOGON,0x4e63,0x4e62,0x4ea3,0x5185, 0x4ec5,0x4ecf,0x4ece,0x4ecc,0x5184,0x5186,UBOGON,UBOGON,0x51e4,0x5205, 0x529e,0x529d,0x52fd,0x5300,0x533a,UBOGON,0x5346,0x535d,0x5386,0x53b7, UBOGON,0x53cc,UBOGON,0x53ce,0x5721,UBOGON,0x5e00,0x5f0c,0x6237,0x6238, 0x6534,0x6535,0x65e0,UBOGON,0x738d,0x4e97,0x4ee0,UBOGON,UBOGON,0x4ee7, UBOGON,0x4ee6,UBOGON,UBOGON,UBOGON,UBOGON,0x56d8,0x518b,0x518c,0x5199, 0x51e5,UBOGON,0x520b,UBOGON }, { /* ku 02 */ UBOGON,0x5304,0x5303,0x5307,UBOGON,0x531e,0x535f,0x536d,0x5389,0x53ba, 0x53d0,UBOGON,0x53f6,0x53f7,0x53f9,UBOGON,0x53f4,UBOGON,UBOGON,0x5724, 0x5904,0x5918,0x5932,0x5930,0x5934,UBOGON,0x5975,UBOGON,0x5b82,0x5bf9, 0x5c14,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,0x5e81,0x5e83, 0x5f0d,0x5f52,UBOGON,0x5fca,0x5fc7,0x6239,UBOGON,0x624f,0x65e7,0x672f, 0x6b7a,0x6c39,UBOGON,UBOGON,0x6c37,0x6c44,0x6c45,0x738c,0x7592,0x7676, 0x9093,0x9092,UBOGON,UBOGON,0x4e21,0x4e20,0x4e22,0x4e68,0x4e89,0x4e98, 0x4ef9,0x4eef,UBOGON,UBOGON,0x4ef8,0x4f06,0x4f03,0x4efc,0x4eee,0x4f16, UBOGON,0x4f28,0x4f1c,0x4f07,0x4f1a,0x4efa,0x4f17,0x514a,UBOGON,0x5172, UBOGON,0x51b4,0x51b3,0x51b2 }, { /* ku 03 */ UBOGON,0x51e8,UBOGON,0x5214,0x520f,0x5215,0x5218,0x52a8,UBOGON,0x534b, 0x534f,UBOGON,0x5350,UBOGON,0x538b,UBOGON,0x53be,UBOGON,0x53d2,0x5416, 0x53ff,UBOGON,0x5400,UBOGON,0x5405,0x5413,0x5415,UBOGON,UBOGON,0x56e3, 0x5735,0x5736,0x5731,0x5732,0x58ee,0x5905,0x4e54,UBOGON,0x5936,UBOGON, UBOGON,UBOGON,0x597a,UBOGON,0x5986,UBOGON,UBOGON,0x5b86,0x5f53,0x5c18, UBOGON,0x5c3d,0x5c78,UBOGON,UBOGON,UBOGON,UBOGON,0x5c80,UBOGON,0x5e08, UBOGON,UBOGON,UBOGON,UBOGON,0x5ef5,0x5f0e,UBOGON,UBOGON,UBOGON,0x5fd3, 0x5fda,UBOGON,0x5fdb,UBOGON,0x620f,0x625d,0x625f,0x6267,0x6257,0x9f50, UBOGON,0x65eb,0x65ea,UBOGON,0x6737,UBOGON,0x6732,0x6736,0x6b22,0x6bce, UBOGON,0x6c58,0x6c51,0x6c77 }, { /* ku 04 */ 0x6c3c,UBOGON,0x6c5a,UBOGON,0x6c53,0x706f,0x7072,0x706e,UBOGON,UBOGON, 0x7073,0x72b1,0x72b2,UBOGON,0x738f,UBOGON,UBOGON,UBOGON,0x793c,UBOGON, 0x808d,0x808e,UBOGON,0x827b,UBOGON,0x8d71,0x8fb9,0x9096,0x909a,UBOGON, 0x4e24,0x4e71,UBOGON,0x4e9c,0x4f45,0x4f4a,0x4f39,0x4f37,UBOGON,0x4f32, 0x4f42,UBOGON,0x4f44,0x4f4b,UBOGON,0x4f40,0x4f35,0x4f31,0x5151,UBOGON, 0x5150,0x514e,UBOGON,UBOGON,0x519d,UBOGON,0x51b5,0x51b8,0x51ec,0x5223, 0x5227,0x5226,0x521f,0x522b,0x5220,0x52b4,0x52b3,UBOGON,0x5325,0x533b, 0x5374,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,0x544d,UBOGON,UBOGON,0x543a, UBOGON,UBOGON,0x5444,0x544c,0x5423,0x541a,0x5432,0x544b,0x5421,UBOGON, 0x5434,0x5449,0x5450,0x5422 }, { /* ku 05 */ 0x543f,0x5451,0x545a,0x542f,UBOGON,0x56e9,0x56f2,0x56f3,0x56ef,0x56ed, 0x56ec,0x56e6,0x5748,UBOGON,0x5744,0x573f,0x573c,0x5753,0x5756,UBOGON, 0x575f,0x5743,0x5758,0x5757,UBOGON,UBOGON,UBOGON,0x5746,UBOGON,0x573d, UBOGON,0x5742,0x5754,0x5755,0x58f1,0x58f2,0x58f0,0x590b,0x9ea6,0x56f1, 0x593d,UBOGON,0x5994,0x598c,UBOGON,0x599c,UBOGON,UBOGON,0x599f,UBOGON, 0x599b,UBOGON,0x5989,0x599a,UBOGON,0x6588,UBOGON,0x5b8d,UBOGON,0x5bfe, 0x5bff,0x5bfd,0x5c2b,UBOGON,0x5c84,0x5c8e,0x5c9c,UBOGON,UBOGON,0x5c85, 0x5df5,0x5e09,UBOGON,UBOGON,0x5e0b,UBOGON,0x5e92,0x5e90,0x5f03,UBOGON, 0x5f1e,0x5f63,UBOGON,0x5fe7,0x5ffe,0x5fe6,0x5fdc,0x5fce,UBOGON,0x5ffc, 0x5fdf,0x5fec,0x5ff6,UBOGON }, { /* ku 06 */ 0x5ff2,0x5ff0,0x5ff9,UBOGON,0x6213,UBOGON,UBOGON,0x623b,0x623c,0x6282, UBOGON,UBOGON,UBOGON,0x6278,0x628b,UBOGON,0x629e,0x62a5,0x629b,0x629c, 0x6299,0x628d,0x6285,0x629d,0x6275,UBOGON,UBOGON,UBOGON,0x65f6,UBOGON, UBOGON,UBOGON,0x66f5,0x675b,UBOGON,0x6754,0x6752,UBOGON,0x6758,0x6744, 0x674a,0x6761,UBOGON,0x6c7f,0x6c91,0x6c9e,UBOGON,0x6c6e,0x6c7c,0x6c9f, 0x6c75,UBOGON,0x6c56,0x6ca2,0x6c79,UBOGON,0x6ca1,UBOGON,0x6caa,0x6ca0, UBOGON,0x7079,0x7077,0x707e,UBOGON,0x7075,0x707b,0x7264,UBOGON,0x72bb, 0x72bc,0x72c7,0x72b9,0x72be,0x72b6,UBOGON,UBOGON,0x7398,UBOGON,UBOGON, UBOGON,UBOGON,0x7593,0x7680,UBOGON,0x7683,0x76c0,0x76c1,UBOGON,UBOGON, 0x77f4,0x77f5,UBOGON,0x7acc }, { /* ku 07 */ 0x7acd,0x7cfa,0x809f,0x8091,0x8097,0x8094,UBOGON,0x8286,0x828c,UBOGON, 0x8295,UBOGON,0x866c,UBOGON,0x8fb5,0x8fbe,0x8fc7,UBOGON,0x8fc1,0x90a9, 0x90a4,UBOGON,UBOGON,UBOGON,0x90a8,0x9627,0x9626,0x962b,0x9633,0x9634, 0x9629,0x4e3d,UBOGON,0x4e9d,0x4f93,0x4f8a,UBOGON,UBOGON,0x4f6d,0x4f8e, 0x4fa0,0x4fa2,0x4fa1,0x4f9f,0x4fa3,UBOGON,0x4f72,UBOGON,0x4f8c,0x5156, UBOGON,UBOGON,0x5190,UBOGON,UBOGON,UBOGON,0x51ed,0x51fe,0x522f,UBOGON, 0x523c,0x5234,0x5239,0x52b9,0x52b5,0x52bf,0x5355,UBOGON,0x5376,0x537a, 0x5393,UBOGON,0x53c1,0x53c2,0x53d5,0x5485,UBOGON,0x545f,0x5493,0x5489, 0x5479,0x9efe,0x548f,0x5469,0x546d,UBOGON,0x5494,0x546a,0x548a,UBOGON, 0x56fd,0x56fb,0x56f8,UBOGON }, { /* ku 08 */ 0x56fc,0x56f6,0x5765,0x5781,0x5763,0x5767,UBOGON,0x576e,0x5778,0x577f, UBOGON,UBOGON,0x58f3,0x594b,0x594c,UBOGON,UBOGON,UBOGON,0x59ad,UBOGON, 0x59c4,UBOGON,0x59c2,0x59b0,UBOGON,UBOGON,UBOGON,UBOGON,0x59bf,UBOGON, 0x59c9,0x59b8,0x59ac,UBOGON,UBOGON,UBOGON,0x59b7,0x59d7,UBOGON,0x5b60, UBOGON,0x5b96,0x5b9e,0x5b94,0x5b9f,0x5b9d,UBOGON,0x5c00,0x5c19,UBOGON, UBOGON,0x5c49,0x5c4a,UBOGON,0x5cbb,0x5cc1,UBOGON,UBOGON,UBOGON,0x5cb9, 0x5c9e,0x5cb4,0x5cba,0x5df6,0x5e13,0x5e12,0x5e77,UBOGON,0x5e98,UBOGON, 0x5e99,0x5e9d,0x5ef8,UBOGON,0x5ef9,UBOGON,0x5f06,0x5f21,UBOGON,0x5f25, 0x5f55,UBOGON,UBOGON,UBOGON,0x5f84,0x5f83,0x6030,0x6007,UBOGON,0x6036, UBOGON,UBOGON,UBOGON,0x5fe9 }, { /* ku 09 */ 0x603d,0x6008,UBOGON,UBOGON,0x62ba,0x62b2,UBOGON,0x62b7,0x62e4,0x62a7, UBOGON,UBOGON,UBOGON,0x62d5,0x62e1,0x62dd,0x62a6,0x62c1,0x62c5,0x62c0, 0x62df,0x62e0,0x62de,UBOGON,0x6589,UBOGON,0x65a6,0x65ba,UBOGON,0x65ff, UBOGON,0x6617,0x6618,0x6601,0x65fe,UBOGON,0x670c,UBOGON,0x676b,0x6796, 0x6782,0x678a,UBOGON,0x67a3,UBOGON,0x67a2,0x678f,UBOGON,0x67f9,0x6780, 0x6b26,0x6b27,0x6b68,0x6b69,UBOGON,0x6b81,0x6bb4,0x6bd1,UBOGON,UBOGON, 0x6c1c,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,0x6c97,0x6c6c,0x6cdf,UBOGON, 0x6cea,UBOGON,0x6ce4,0x6cd8,0x6cb2,0x6cce,0x6cc8,UBOGON,0x708b,0x7088, 0x7090,0x708f,UBOGON,0x7087,0x7089,0x708d,0x7081,UBOGON,0x708c,UBOGON, UBOGON,0x7240,UBOGON,UBOGON }, { /* ku 0a */ 0x7265,0x7266,0x7268,UBOGON,UBOGON,0x72cd,0x72d3,0x72db,UBOGON,0x72cf, 0x73a7,0x73a3,0x739e,UBOGON,0x73af,UBOGON,UBOGON,0x73aa,0x739c,UBOGON, 0x7542,0x7544,0x753b,0x7541,UBOGON,0x759b,0x759e,UBOGON,0x79c4,0x79c3, 0x79c6,UBOGON,UBOGON,0x79c7,UBOGON,0x79ca,UBOGON,UBOGON,0x7acf,0x7c76, 0x7c74,0x7cff,0x7cfc,UBOGON,UBOGON,0x7f59,0x80a8,UBOGON,UBOGON,0x80b0, UBOGON,0x80b3,UBOGON,0x80a4,0x80b6,0x80a7,0x80ac,UBOGON,0x80a6,0x5367, 0x820e,0x82c4,0x833e,0x829c,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,0x82aa, UBOGON,0x82c9,UBOGON,UBOGON,0x82a6,0x82b2,UBOGON,UBOGON,UBOGON,0x8fcc, 0x8fd9,0x8fca,0x8fd8,0x8fcf,0x90b7,UBOGON,0x90ad,0x90b9,0x9637,UBOGON, 0x9641,0x963e,0x96b6,0x9751 }, { /* ku 0b */ 0x9763,0x4e57,0x4e79,0x4eb2,0x4eb0,0x4eaf,0x4eb1,0x4fd2,0x4fd5,UBOGON, 0x4fbe,0x4fb8,0x4fb0,0x4fb1,0x4fc8,UBOGON,UBOGON,0x4fc6,0x4fcc,0x4fe5, 0x4fe3,0x4fb4,0x516a,UBOGON,0x519f,UBOGON,0x51c1,UBOGON,0x51c2,0x51c3, 0x5245,0x5248,UBOGON,UBOGON,0x524f,UBOGON,UBOGON,0x52c5,0x52ca,0x52c4, 0x5327,0x5358,0x537d,UBOGON,0x53dd,0x53dc,0x53da,0x53d9,0x54b9,UBOGON, 0x54d0,0x54b4,0x54ca,UBOGON,0x54a3,0x54da,0x54a4,UBOGON,0x54b2,0x549e, 0x549f,0x54b5,UBOGON,UBOGON,0x54cd,UBOGON,0x54cc,UBOGON,0x5700,0x57ac, 0x5791,0x578e,0x578d,0x5792,0x57a1,0x5790,0x57a6,0x57a8,UBOGON,0x579c, 0x5796,0x57a7,UBOGON,UBOGON,UBOGON,UBOGON,0x58f5,UBOGON,0x5909,0x5908, UBOGON,0x5952,UBOGON,UBOGON }, { /* ku 0c */ 0x59df,UBOGON,0x59eb,0x59ef,0x59f0,0x59d5,0x5a0d,0x5a04,0x59f9,0x5a02, 0x59f8,0x59e2,0x59d9,0x59e7,0x5b6a,UBOGON,UBOGON,0x5bab,UBOGON,0x5c1b, 0x5c2f,UBOGON,0x663c,UBOGON,UBOGON,UBOGON,0x5cd1,0x5cdc,0x5ce6,0x5ce1, 0x5ccd,UBOGON,0x5ce2,0x5cdd,0x5ce5,0x5dfb,0x5dfa,0x5e1e,UBOGON,0x5ea1, UBOGON,UBOGON,0x5efc,0x5efb,0x5f2f,UBOGON,UBOGON,0x5f66,UBOGON,UBOGON, UBOGON,0x605c,UBOGON,0x604e,0x6051,UBOGON,UBOGON,0x6023,0x6031,0x607c, 0x6052,UBOGON,0x6060,0x604a,0x6061,UBOGON,0x6218,UBOGON,UBOGON,UBOGON, UBOGON,UBOGON,UBOGON,UBOGON,0x631f,0x6317,0x62ea,0x6321,0x6304,0x6305, UBOGON,0x6531,0x6544,0x6540,UBOGON,0x6542,0x65be,UBOGON,0x6629,0x661b, UBOGON,0x6623,0x662c,0x661a }, { /* ku 0d */ 0x6630,0x663b,0x661e,0x6637,0x6638,UBOGON,0x670e,UBOGON,UBOGON,0x67e8, 0x67d6,UBOGON,0x67c7,0x67bc,0x6852,0x67bf,0x67d5,0x67fe,0x8363,0x67fb, UBOGON,0x67b1,0x6801,0x6805,0x6800,0x67d7,UBOGON,0x6b2a,0x6b6b,UBOGON, UBOGON,UBOGON,UBOGON,0x6be1,UBOGON,UBOGON,0x6d23,0x6cff,0x6d14,0x6d05, 0x6d13,0x6d06,0x6d21,UBOGON,0x6d15,0x6caf,0x6cf4,0x6d02,0x6d45,UBOGON, 0x6d26,UBOGON,0x6d44,UBOGON,0x6d24,0x70a5,UBOGON,0x70a3,UBOGON,0x70a2, 0x70bb,0x70a0,0x70aa,UBOGON,UBOGON,0x70a8,0x70b6,0x70b2,0x70a7,UBOGON, UBOGON,0x70b9,0x722e,UBOGON,0x723c,UBOGON,0x726d,UBOGON,UBOGON,0x72e7, 0x72ed,UBOGON,0x72ec,0x72e5,0x72e2,UBOGON,0x73c4,0x73bd,0x73cf,0x73c9, 0x73c1,0x73d0,UBOGON,0x73ce }, { /* ku 0e */ 0x74ed,0x74eb,UBOGON,0x74ef,0x7549,0x7550,0x7546,0x754a,UBOGON,0x754d, 0x75a6,UBOGON,UBOGON,UBOGON,0x75a8,UBOGON,UBOGON,0x76c7,0x76ff,UBOGON, 0x76fd,0x77e6,0x780a,UBOGON,0x7804,0x780b,0x7807,UBOGON,0x7815,0x7808, UBOGON,0x79d3,0x79d4,0x79d0,0x79d7,0x7a7c,UBOGON,UBOGON,0x7a7d,0x7a83, 0x7a82,UBOGON,0x7ad4,0x7ad5,0x7ad3,0x7ad0,0x7ad2,0x7afe,0x7afc,0x7c77, 0x7c7c,0x7c7b,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON, 0x7f8f,0x80d3,UBOGON,0x80cb,0x80d2,UBOGON,0x8109,0x80e2,0x80df,0x80c6, UBOGON,0x8224,0x82f7,0x82d8,0x82dd,UBOGON,UBOGON,0x82f8,0x82fc,UBOGON, UBOGON,0x82e9,UBOGON,0x82ee,UBOGON,0x82d0,0x830e,0x82e2,0x830b,0x82fd, 0x5179,0x8676,UBOGON,0x8678 }, { /* ku 0f */ UBOGON,UBOGON,0x8675,0x867d,UBOGON,0x8842,0x8866,UBOGON,0x898c,0x8a05, UBOGON,0x8a06,UBOGON,0x8c9f,UBOGON,0x8ff1,0x8fe7,0x8fe9,0x8fef,0x90c2, 0x90bc,UBOGON,0x90c6,0x90c0,UBOGON,UBOGON,0x90cd,0x90c9,UBOGON,0x90c4, UBOGON,0x9581,UBOGON,0x9cec,0x5032,0x4ff9,0x501d,0x4fff,0x5004,0x4ff0, 0x5003,UBOGON,0x5002,0x4ffc,0x4ff2,0x5024,0x5008,0x5036,0x502e,UBOGON, 0x5010,0x5038,0x5039,0x4ffd,0x5056,0x4ffb,0x51a3,0x51a6,0x51a1,UBOGON, UBOGON,0x51c7,0x51c9,0x5260,0x5264,0x5259,0x5265,0x5267,0x5257,0x5263, UBOGON,0x5253,UBOGON,0x52cf,UBOGON,0x52ce,0x52d0,0x52d1,0x52cc,UBOGON, UBOGON,UBOGON,0x550d,0x54f4,UBOGON,0x5513,0x54ef,0x54f5,0x54f9,0x5502, 0x5500,UBOGON,UBOGON,0x5518 }, { /* ku 10 */ 0x54f0,0x54f6,UBOGON,UBOGON,0x5519,UBOGON,0x5705,0x57c9,UBOGON,0x57b7, 0x57cd,UBOGON,UBOGON,UBOGON,0x57be,0x57bb,UBOGON,0x57db,0x57c8,0x57c4, 0x57c5,0x57d1,0x57ca,0x57c0,UBOGON,UBOGON,0x5a21,0x5a2a,UBOGON,0x5a1d, UBOGON,0x5a0b,UBOGON,UBOGON,UBOGON,UBOGON,0x5a22,UBOGON,UBOGON,0x5a24, UBOGON,0x5a14,0x5a31,UBOGON,0x5a2f,0x5a1a,0x5a12,UBOGON,UBOGON,0x5a26, UBOGON,UBOGON,0x5bbc,0x5bbb,0x5bb7,0x5c05,0x5c06,0x5c52,0x5c53,UBOGON, UBOGON,0x5cfa,0x5ceb,UBOGON,0x5cf3,0x5cf5,0x5ce9,0x5cef,UBOGON,0x5e2a, 0x5e30,0x5e2e,0x5e2c,0x5e2f,0x5eaf,0x5ea9,UBOGON,0x5efd,0x5f32,0x5f8e, 0x5f93,0x5f8f,0x604f,0x6099,UBOGON,0x607e,UBOGON,0x6074,0x604b,0x6073, 0x6075,UBOGON,UBOGON,0x6056 }, { /* ku 11 */ 0x60a9,0x608b,0x60a6,UBOGON,0x6093,0x60ae,0x609e,0x60a7,0x6245,UBOGON, UBOGON,0x632e,UBOGON,0x6352,0x6330,0x635b,UBOGON,0x6319,0x631b,UBOGON, 0x6331,0x635d,0x6337,0x6335,0x6353,UBOGON,0x635c,0x633f,0x654b,UBOGON, UBOGON,0x658b,UBOGON,0x659a,0x6650,0x6646,0x664e,0x6640,UBOGON,0x664b, 0x6648,UBOGON,0x6660,0x6644,0x664d,UBOGON,0x6837,0x6824,UBOGON,UBOGON, 0x681b,0x6836,UBOGON,0x682c,0x6819,0x6856,0x6847,0x683e,0x681e,UBOGON, 0x6815,0x6822,0x6827,0x6859,0x6858,0x6855,0x6830,0x6823,0x6b2e,0x6b2b, 0x6b30,0x6b6c,UBOGON,0x6b8b,UBOGON,0x6be9,0x6bea,0x6be5,0x6d6b,UBOGON, UBOGON,0x6d73,0x6d57,UBOGON,UBOGON,0x6d5d,0x6d56,0x6d8f,0x6d5b,0x6d1c, 0x6d9a,0x6d9b,0x6d99,UBOGON }, { /* ku 12 */ 0x6d81,0x6d71,UBOGON,UBOGON,0x6d72,0x6d5c,0x6d96,0x70c4,0x70db,0x70cc, 0x70d0,0x70e3,0x70df,UBOGON,0x70d6,0x70ee,0x70d5,UBOGON,UBOGON,UBOGON, UBOGON,0x727a,UBOGON,0x72f5,0x7302,UBOGON,UBOGON,0x73e2,0x73ec,0x73d5, 0x73f9,0x73df,0x73e6,UBOGON,UBOGON,UBOGON,UBOGON,0x73e4,0x73e1,0x74f3, UBOGON,UBOGON,UBOGON,UBOGON,0x7556,0x7555,0x7558,0x7557,0x755e,0x75c3, UBOGON,UBOGON,0x75b4,UBOGON,0x75b1,UBOGON,UBOGON,0x76cb,0x76cc,0x772a, UBOGON,0x7716,0x770f,UBOGON,UBOGON,0x773f,0x772b,0x770e,0x7724,UBOGON, 0x7721,0x7718,0x77dd,UBOGON,UBOGON,0x7824,0x7836,UBOGON,0x7958,0x7959, UBOGON,0x7962,0x79da,0x79d9,UBOGON,0x79e1,0x79e5,0x79e8,0x79db,UBOGON, 0x79e2,0x79f0,UBOGON,UBOGON }, { /* ku 13 */ UBOGON,UBOGON,0x7ada,0x7add,UBOGON,0x7adb,0x7adc,UBOGON,UBOGON,0x7b0d, 0x7b0b,0x7b14,0x7c8e,0x7c86,UBOGON,0x7c87,0x7c83,0x7c8b,UBOGON,UBOGON, UBOGON,UBOGON,0x7d24,UBOGON,UBOGON,UBOGON,0x7d25,0x7f62,0x7f93,0x7f99, 0x7f97,UBOGON,UBOGON,0x7fc4,0x7fc6,0x800a,UBOGON,UBOGON,0x8040,0x803c, 0x803b,0x80f6,0x80ff,0x80ee,0x8104,0x8103,0x8107,UBOGON,UBOGON,0x80f7, UBOGON,UBOGON,0x822d,UBOGON,0x8227,0x8229,0x831f,0x8357,UBOGON,UBOGON, UBOGON,UBOGON,0x8321,UBOGON,UBOGON,0x8318,0x8358,UBOGON,UBOGON,UBOGON, UBOGON,UBOGON,0x8684,0x869f,0x869b,0x8689,0x86a6,0x8692,0x868f,0x86a0, 0x884f,0x8878,0x887a,0x886e,0x887b,0x8884,0x8873,UBOGON,UBOGON,0x8a0d, 0x8a0b,0x8a19,UBOGON,UBOGON }, { /* ku 14 */ UBOGON,UBOGON,UBOGON,UBOGON,0x8ff9,0x9009,0x9008,UBOGON,0x90de,0x9151, UBOGON,UBOGON,0x91db,0x91df,0x91de,0x91d6,0x91e0,0x9585,0x9660,0x9659, UBOGON,0x9656,UBOGON,UBOGON,0x96bd,UBOGON,UBOGON,0x5042,0x5059,UBOGON, 0x5044,0x5066,0x5052,0x5054,0x5071,0x5050,0x507b,0x507c,0x5058,UBOGON, UBOGON,0x5079,0x506c,0x5078,0x51a8,0x51d1,0x51cf,0x5268,0x5276,0x52d4, UBOGON,0x53a0,0x53c4,UBOGON,0x5558,0x554c,0x5568,UBOGON,0x5549,UBOGON, UBOGON,0x555d,0x5529,UBOGON,0x5554,0x5553,UBOGON,0x555a,UBOGON,0x553a, 0x553f,0x552b,0x57ea,UBOGON,0x57ef,UBOGON,UBOGON,0x57dd,0x57fe,UBOGON, 0x57de,0x57e6,UBOGON,0x57e8,0x57ff,0x5803,0x58f7,0x68a6,0x591f,UBOGON, 0x595b,0x595d,0x595e,UBOGON }, { /* ku 15 */ UBOGON,0x5a2b,UBOGON,0x5a3b,UBOGON,UBOGON,0x5a61,0x5a3a,0x5a6e,0x5a4b, 0x5a6b,UBOGON,UBOGON,0x5a45,0x5a4e,0x5a68,0x5a3d,0x5a71,0x5a3f,0x5a6f, 0x5a75,UBOGON,0x5a73,0x5a2c,0x5a59,0x5a54,0x5a4f,0x5a63,UBOGON,UBOGON, 0x5bc8,UBOGON,0x5bc3,UBOGON,0x5c5b,0x5c61,UBOGON,0x5d21,0x5d0a,0x5d09, UBOGON,0x5d2c,0x5d08,UBOGON,UBOGON,0x5d2a,0x5d15,UBOGON,0x5d10,0x5d13, UBOGON,0x5d2f,0x5d18,UBOGON,0x5de3,0x5e39,0x5e35,0x5e3a,0x5e32,UBOGON, UBOGON,UBOGON,UBOGON,0x5ebb,0x5eba,0x5f34,0x5f39,UBOGON,UBOGON,UBOGON, UBOGON,0x6098,UBOGON,0x60d0,UBOGON,UBOGON,UBOGON,0x60d7,0x60aa,UBOGON, 0x60a1,0x60a4,UBOGON,0x60ee,UBOGON,0x60e7,UBOGON,UBOGON,0x60de,UBOGON, UBOGON,0x637e,0x638b,UBOGON }, { /* ku 16 */ UBOGON,0x6379,0x6386,0x6393,UBOGON,0x6373,0x636a,UBOGON,0x636c,UBOGON, 0x637f,UBOGON,0x63b2,0x63ba,UBOGON,UBOGON,0x6366,0x6374,UBOGON,0x655a, UBOGON,0x654e,0x654d,0x658d,0x658e,0x65ad,UBOGON,0x65c7,0x65ca,UBOGON, 0x65c9,UBOGON,0x65e3,0x6657,UBOGON,0x6663,0x6667,0x671a,0x6719,0x6716, UBOGON,UBOGON,0x689e,0x68b6,0x6898,0x6873,UBOGON,0x689a,0x688e,0x68b7, 0x68db,0x68a5,0x686c,0x68c1,0x6884,UBOGON,UBOGON,0x6895,0x687a,0x6899, UBOGON,0x68b8,0x68b9,0x6870,UBOGON,0x6b35,UBOGON,0x6b90,0x6bbb,0x6bed, UBOGON,UBOGON,UBOGON,0x6dc1,0x6dc3,0x6dce,UBOGON,UBOGON,0x6dad,0x6e04, UBOGON,0x6db9,UBOGON,0x6de7,UBOGON,0x6e08,0x6e06,UBOGON,0x6e0a,0x6db0, UBOGON,0x6df8,0x6e0c,UBOGON }, { /* ku 17 */ 0x6db1,UBOGON,0x6e02,0x6e07,0x6e09,0x6e01,0x6e17,0x6dff,0x6e12,UBOGON, UBOGON,0x7103,0x7107,0x7101,0x70f5,0x70f1,0x7108,0x70f2,0x710f,UBOGON, 0x70fe,UBOGON,UBOGON,UBOGON,0x731a,0x7310,0x730e,0x7402,0x73f3,UBOGON, UBOGON,0x73fb,UBOGON,UBOGON,UBOGON,0x751b,0x7523,0x7561,0x7568,UBOGON, 0x7567,0x75d3,UBOGON,UBOGON,0x7690,UBOGON,UBOGON,0x76d5,0x76d7,0x76d6, 0x7730,UBOGON,0x7726,UBOGON,0x7740,UBOGON,0x771e,UBOGON,UBOGON,UBOGON, 0x7847,UBOGON,0x784b,0x7851,0x784f,0x7842,0x7846,UBOGON,0x796e,0x796c, 0x79f2,UBOGON,0x79f1,0x79f5,0x79f3,0x79f9,UBOGON,UBOGON,UBOGON,0x7a9a, 0x7a93,0x7a91,0x7ae1,UBOGON,UBOGON,0x7b21,0x7b1c,0x7b16,0x7b17,0x7b36, 0x7b1f,UBOGON,0x7c93,0x7c99 }, { /* ku 18 */ 0x7c9a,0x7c9c,UBOGON,0x7d49,UBOGON,0x7d34,0x7d37,UBOGON,0x7d2d,UBOGON, 0x7d4c,UBOGON,UBOGON,0x7d48,UBOGON,UBOGON,0x7f3b,UBOGON,UBOGON,UBOGON, UBOGON,0x8008,0x801a,UBOGON,0x801d,UBOGON,0x8049,0x8045,0x8044,0x7c9b, UBOGON,UBOGON,0x812a,0x812e,UBOGON,UBOGON,0x8131,UBOGON,0x811a,0x8134, 0x8117,UBOGON,UBOGON,UBOGON,0x831d,0x8371,0x8384,0x8380,0x8372,0x83a1, UBOGON,0x8379,0x8391,UBOGON,0x839f,0x83ad,UBOGON,UBOGON,0x8323,UBOGON, 0x8385,0x839c,0x83b7,0x8658,0x865a,UBOGON,0x8657,0x86b2,UBOGON,0x86ae, UBOGON,UBOGON,UBOGON,0x8845,0x889c,0x8894,0x88a3,0x888f,0x88a5,0x88a9, 0x88a6,0x888a,0x88a0,0x8890,0x8992,0x8991,0x8994,UBOGON,0x8a26,0x8a32, 0x8a28,UBOGON,UBOGON,0x8a1c }, { /* ku 19 */ UBOGON,0x8a2b,0x8a20,UBOGON,0x8a29,UBOGON,UBOGON,UBOGON,0x8a21,0x8c3a, UBOGON,0x8c5b,0x8c58,0x8c7c,UBOGON,0x8ca6,0x8cae,0x8cad,0x8d65,UBOGON, 0x8d7e,UBOGON,0x8d7c,0x8d7f,0x8d7a,0x8dbd,UBOGON,UBOGON,0x8dc0,0x8dbb, 0x8ead,0x8eaf,0x8ed6,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,0x8ed9,UBOGON, UBOGON,0x9012,0x900e,0x9025,UBOGON,0x9013,0x90ee,UBOGON,0x90ab,0x90f7, UBOGON,0x9159,0x9154,0x91f2,0x91f0,0x91e5,0x91f6,UBOGON,UBOGON,0x9587, UBOGON,0x965a,UBOGON,UBOGON,0x966e,UBOGON,UBOGON,UBOGON,0x9679,UBOGON, 0x98e1,0x98e6,UBOGON,0x9ec4,0x9ed2,0x4e80,UBOGON,0x4e81,0x508f,0x5097, 0x5088,0x5089,UBOGON,UBOGON,0x5081,0x5160,UBOGON,UBOGON,0x5e42,0x51d3, UBOGON,UBOGON,0x51d2,0x51d6 }, { /* ku 1a */ 0x5273,UBOGON,0x5270,UBOGON,UBOGON,UBOGON,0x53a8,0x53a6,0x53c5,0x5597, 0x55de,UBOGON,UBOGON,0x5596,0x55b4,UBOGON,0x5585,UBOGON,0x559b,0x55a0, UBOGON,0x5559,UBOGON,0x5586,UBOGON,UBOGON,0x55af,0x557a,UBOGON,UBOGON, UBOGON,0x559e,UBOGON,0x55a9,0x570f,0x570e,0x581a,UBOGON,0x581f,UBOGON, 0x583c,0x5818,0x583e,0x5826,UBOGON,0x583a,UBOGON,0x5822,UBOGON,0x58fb, 0x5963,0x5964,UBOGON,0x5aa8,0x5aa3,0x5a82,0x5a88,0x5aa1,0x5a85,0x5a98, UBOGON,0x5a99,UBOGON,0x5a89,0x5a81,0x5a96,0x5a80,UBOGON,UBOGON,0x5a91, UBOGON,UBOGON,UBOGON,UBOGON,0x5acf,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON, UBOGON,0x5a87,0x5aa0,UBOGON,0x5a79,UBOGON,0x5a86,0x5aab,0x5aaa,0x5aa4, 0x5a8d,0x5a7e,UBOGON,0x5bd5 }, { /* ku 1b */ UBOGON,UBOGON,UBOGON,0x5c1e,0x5c5f,0x5c5e,0x5d44,0x5d3e,UBOGON,0x5d48, 0x5d1c,UBOGON,0x5d5b,0x5d4d,UBOGON,UBOGON,0x5d57,UBOGON,0x5d53,0x5d4f, UBOGON,0x5d3b,0x5d46,UBOGON,UBOGON,0x5e46,0x5e47,UBOGON,0x5e48,0x5ec0, 0x5ebd,0x5ebf,UBOGON,0x5f11,UBOGON,0x5f3e,0x5f3b,UBOGON,0x5f3a,UBOGON, UBOGON,UBOGON,0x5fa7,UBOGON,0x60ea,UBOGON,0x6107,0x6122,0x610c,UBOGON, UBOGON,0x60b3,0x60d6,0x60d2,UBOGON,0x60e3,0x60e5,0x60e9,UBOGON,UBOGON, 0x6111,0x60fd,UBOGON,UBOGON,0x611e,0x6120,0x6121,0x621e,UBOGON,0x63e2, 0x63de,0x63e6,UBOGON,UBOGON,UBOGON,UBOGON,0x63f8,UBOGON,0x63fe,0x63c1, 0x63bf,0x63f7,0x63d1,0x655f,0x6560,0x6561,UBOGON,UBOGON,0x65d1,UBOGON, UBOGON,0x667d,0x666b,0x667f }, { /* ku 1c */ UBOGON,UBOGON,0x6673,0x6681,0x666d,0x6669,UBOGON,UBOGON,0x671e,0x68ed, UBOGON,UBOGON,UBOGON,UBOGON,0x6903,UBOGON,0x68fe,0x68e5,0x691e,0x6902, UBOGON,UBOGON,0x6909,0x68ca,0x6900,UBOGON,0x6901,0x6918,0x68e2,0x68cf, UBOGON,0x692e,0x68c5,0x68ff,UBOGON,0x691c,0x68c3,UBOGON,0x6b6f,UBOGON, 0x6b6e,UBOGON,0x6bbe,UBOGON,0x6bf4,0x6c2d,UBOGON,0x6db6,0x6e75,0x6e1e, UBOGON,0x6e18,UBOGON,0x6e48,UBOGON,0x6e4f,UBOGON,0x6e42,0x6e6a,0x6e70, 0x6dfe,UBOGON,UBOGON,0x6e6d,UBOGON,0x6e7b,0x6e7e,0x6e59,UBOGON,0x6e57, UBOGON,0x6e80,0x6e50,UBOGON,0x6e29,0x6e76,0x6e2a,0x6e4c,0x712a,UBOGON, 0x7135,0x712c,0x7137,0x711d,UBOGON,UBOGON,0x7138,UBOGON,0x7134,0x712b, 0x7133,0x7127,0x7124,UBOGON }, { /* ku 1d */ 0x712d,0x7232,0x7283,0x7282,0x7287,0x7306,0x7324,0x7338,0x732a,0x732c, 0x732b,UBOGON,0x732f,0x7328,0x7417,UBOGON,UBOGON,0x7419,0x7438,UBOGON, 0x741f,0x7414,0x743c,0x73f7,0x741c,0x7415,0x7418,0x7439,0x74f9,0x7524, UBOGON,UBOGON,UBOGON,0x756e,0x756d,0x7571,0x758e,UBOGON,0x75e5,UBOGON, UBOGON,UBOGON,UBOGON,0x7694,0x76b3,UBOGON,0x76d9,UBOGON,0x7748,0x7749, 0x7743,UBOGON,UBOGON,0x7742,0x77df,UBOGON,0x7863,0x7876,UBOGON,0x785f, 0x7866,0x7966,0x7971,UBOGON,UBOGON,0x7976,0x7984,0x7975,0x79ff,0x7a07, UBOGON,0x7a0e,0x7a09,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,0x7ae7, 0x7ae2,0x7b55,UBOGON,UBOGON,0x7b43,0x7b57,0x7b6c,0x7b42,0x7b53,UBOGON, 0x7b41,UBOGON,UBOGON,0x7ca7 }, { /* ku 1e */ 0x7ca0,0x7ca6,0x7ca4,0x7d74,UBOGON,0x7d59,UBOGON,0x7d60,0x7d57,0x7d6c, 0x7d7e,0x7d64,UBOGON,0x7d5a,0x7d5d,UBOGON,UBOGON,UBOGON,0x7d76,0x7d4d, 0x7d75,UBOGON,0x7fd3,0x7fd6,UBOGON,UBOGON,0x8060,0x804e,0x8145,0x813b, UBOGON,0x8148,0x8142,0x8149,0x8140,0x8114,0x8141,UBOGON,0x81ef,0x81f6, 0x8203,UBOGON,0x83ed,UBOGON,0x83da,0x8418,0x83d2,0x8408,UBOGON,0x8400, UBOGON,UBOGON,UBOGON,0x8417,0x8346,0x8414,0x83d3,0x8405,0x841f,0x8402, 0x8416,0x83cd,0x83e6,UBOGON,0x865d,0x86d5,0x86e1,UBOGON,UBOGON,UBOGON, UBOGON,0x86ee,0x8847,0x8846,UBOGON,UBOGON,0x88bb,UBOGON,0x88bf,0x88b4, UBOGON,0x88b5,UBOGON,0x899a,0x8a43,UBOGON,UBOGON,0x8a5a,UBOGON,UBOGON, UBOGON,0x8a35,0x8a38,0x8a42 }, { /* ku 1f */ 0x8a49,0x8a5d,0x8a4b,0x8a3d,UBOGON,UBOGON,UBOGON,UBOGON,0x8c60,0x8c5e, 0x8c7f,0x8c7e,0x8c83,UBOGON,0x8cb1,0x8d87,UBOGON,UBOGON,0x8d88,0x8d83, UBOGON,UBOGON,0x8d86,0x8d8b,0x8d82,0x8dca,0x8dd2,UBOGON,UBOGON,0x8dd4, 0x8dc9,0x8eb0,UBOGON,UBOGON,UBOGON,0x8ef2,0x8ee4,0x8ef3,0x8eea,UBOGON, 0x8efd,UBOGON,0x8f9d,0x902b,0x902a,UBOGON,0x9028,0x9029,0x902c,UBOGON, UBOGON,0x903a,0x9030,0x9037,0x903b,UBOGON,0x910a,UBOGON,UBOGON,UBOGON, 0x91fe,0x9220,UBOGON,0x920b,UBOGON,0x9218,0x9222,UBOGON,0x921b,0x9208, UBOGON,0x920e,0x9213,UBOGON,UBOGON,0x9595,UBOGON,UBOGON,UBOGON,0x968c, 0x967b,0x967f,0x9681,UBOGON,0x9682,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON, 0x96ee,0x96ed,UBOGON,0x96ec }, { /* ku 20 */ 0x975f,0x976f,UBOGON,0x976d,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON, 0x98f0,UBOGON,UBOGON,UBOGON,0x9aa9,UBOGON,UBOGON,0x9ae0,0x4eb7,UBOGON, UBOGON,0x50cc,0x50bc,UBOGON,0x50aa,0x50b9,UBOGON,0x50ab,0x50c3,0x50cd, 0x517e,0x527e,0x5279,UBOGON,UBOGON,0x52e1,0x52e0,0x52e7,0x5380,0x53ab, 0x53aa,0x53a9,0x53e0,0x55ea,UBOGON,0x55d7,UBOGON,UBOGON,0x55c1,0x5715, UBOGON,0x586c,UBOGON,0x585c,0x5850,0x5861,0x586a,0x5869,0x5856,0x5860, 0x5866,0x585f,0x5923,0x5966,0x5968,UBOGON,UBOGON,0x5ace,UBOGON,0x5ac5, 0x5ac3,UBOGON,UBOGON,0x5ad0,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON, 0x5b74,0x5b76,0x5bdc,0x5bd7,0x5bda,0x5bdb,UBOGON,0x5c20,0x5d6d,0x5d66, UBOGON,0x5d64,0x5d6e,UBOGON }, { /* ku 21 */ 0x5d60,0x5f42,0x5f5a,0x5f6e,UBOGON,UBOGON,0x6130,0x613a,0x612a,0x6143, 0x6119,0x6131,UBOGON,0x613d,UBOGON,UBOGON,UBOGON,0x6408,0x6432,0x6438, UBOGON,0x6431,UBOGON,0x6419,UBOGON,0x6411,UBOGON,UBOGON,0x6429,0x641d, UBOGON,UBOGON,UBOGON,0x643c,UBOGON,0x6446,0x6447,UBOGON,UBOGON,0x643a, 0x6407,UBOGON,0x656b,UBOGON,0x6570,0x656d,UBOGON,0x65e4,0x6693,UBOGON, UBOGON,UBOGON,UBOGON,0x668f,UBOGON,UBOGON,0x6692,UBOGON,0x668e,UBOGON, 0x6946,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,0x6931,UBOGON, UBOGON,0x693e,UBOGON,0x697c,0x6943,UBOGON,0x6973,UBOGON,0x6955,UBOGON, UBOGON,0x6985,0x694d,0x6950,0x6947,0x6967,0x6936,0x6964,0x6961,UBOGON, 0x697d,0x6b44,0x6b40,0x6b71 }, { /* ku 22 */ 0x6b73,0x6b9c,UBOGON,UBOGON,UBOGON,0x6bc1,UBOGON,0x6bfa,0x6c31,0x6c32, UBOGON,UBOGON,0x6eb8,0x6ea8,UBOGON,0x6e91,0x6ebb,UBOGON,0x6e9a,UBOGON, UBOGON,0x6ea9,UBOGON,UBOGON,0x6eb5,0x6e6c,0x6ee8,UBOGON,0x6edd,0x6eda, 0x6ee6,0x6eac,UBOGON,UBOGON,UBOGON,0x6ed9,0x6ee3,0x6ee9,0x6edb,UBOGON, 0x716f,UBOGON,UBOGON,0x7148,UBOGON,0x714a,0x716b,UBOGON,0x714f,0x7157, 0x7174,UBOGON,UBOGON,UBOGON,0x7145,0x7151,0x716d,UBOGON,0x7251,0x7250, 0x724e,UBOGON,0x7341,UBOGON,0x732e,0x7346,UBOGON,0x7427,UBOGON,0x7448, 0x7453,0x743d,UBOGON,0x745d,0x7456,UBOGON,0x741e,0x7447,0x7443,0x7458, 0x7449,UBOGON,0x744c,0x7445,0x743e,UBOGON,0x7501,0x751e,UBOGON,UBOGON, 0x757a,0x75ee,0x7602,0x7697 }, { /* ku 23 */ 0x7698,UBOGON,UBOGON,UBOGON,0x775d,0x7764,0x7753,0x7758,0x7882,0x7890, 0x788a,UBOGON,0x787a,0x787d,UBOGON,0x788b,0x7878,UBOGON,UBOGON,0x788d, 0x7888,0x7892,0x7881,0x797e,0x7983,UBOGON,UBOGON,UBOGON,0x7980,UBOGON, UBOGON,UBOGON,0x7a0f,UBOGON,UBOGON,0x7a1d,UBOGON,0x7aa1,0x7aa4,UBOGON, 0x7ae9,0x7aea,UBOGON,0x7b62,0x7b6b,UBOGON,0x7b5e,UBOGON,0x7b79,UBOGON, UBOGON,0x7b6f,0x7b68,UBOGON,UBOGON,0x7cae,UBOGON,UBOGON,UBOGON,0x7cb0, UBOGON,0x7d90,UBOGON,0x7d8a,UBOGON,0x7d8b,0x7d99,0x7d95,UBOGON,0x7d87, 0x7d78,0x7d97,0x7d89,0x7d98,UBOGON,UBOGON,UBOGON,0x7fa3,UBOGON,UBOGON, UBOGON,0x7fdd,0x8057,UBOGON,0x8163,0x816a,0x816c,UBOGON,UBOGON,UBOGON, 0x815d,0x8175,UBOGON,0x815f }, { /* ku 24 */ UBOGON,0x817d,0x816d,UBOGON,UBOGON,0x8241,0x844f,0x8484,UBOGON,0x847f, UBOGON,0x8448,0x842a,0x847b,0x8472,0x8464,0x842e,0x845c,0x8453,UBOGON, 0x8441,0x84c8,UBOGON,0x8462,0x8480,0x843e,0x8483,0x8471,UBOGON,0x844a, 0x8455,0x8458,UBOGON,UBOGON,UBOGON,0x86fc,0x86fd,0x8715,UBOGON,0x8716, 0x86ff,UBOGON,UBOGON,UBOGON,0x8858,0x88cf,0x88e0,UBOGON,UBOGON,UBOGON, UBOGON,0x89e7,0x8a6a,0x8a80,UBOGON,0x8a6f,0x8a65,UBOGON,0x8a78,0x8a7d, 0x8a88,UBOGON,UBOGON,0x8a64,0x8a7e,UBOGON,0x8a67,0x8c63,0x8c88,UBOGON, 0x8ccd,UBOGON,0x8cc9,UBOGON,0x8ded,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON, UBOGON,UBOGON,0x8eb1,UBOGON,UBOGON,0x8f04,0x8f9e,0x8fa0,0x9043,0x9046, 0x9048,0x9045,0x9040,0x904c }, { /* ku 25 */ UBOGON,UBOGON,0x910c,0x9113,0x9115,UBOGON,0x916b,0x9167,0x925d,0x9255, 0x9235,UBOGON,0x9259,0x922f,0x923c,0x928f,0x925c,0x926a,0x9262,0x925f, 0x926b,0x926e,0x923b,0x9244,0x9241,0x959a,UBOGON,0x9599,UBOGON,UBOGON, UBOGON,0x968f,UBOGON,0x9696,UBOGON,UBOGON,UBOGON,0x96f4,0x96fc,UBOGON, 0x9755,UBOGON,0x9779,UBOGON,UBOGON,UBOGON,0x97ee,0x97f5,UBOGON,0x980b, UBOGON,0x98f3,UBOGON,UBOGON,0x98f7,0x98ff,0x98f5,UBOGON,0x98ec,0x98f1, UBOGON,UBOGON,0x999a,UBOGON,0x9ae2,0x9b3d,0x9b5d,0x9ce8,UBOGON,0x9ceb, 0x9cef,0x9cee,0x9e81,0x9f14,0x50d0,0x50d9,0x50dc,0x50d8,UBOGON,0x50e1, 0x50eb,UBOGON,UBOGON,0x50f4,0x50e2,0x50de,UBOGON,UBOGON,UBOGON,0x51f4, UBOGON,UBOGON,UBOGON,0x52ed }, { /* ku 26 */ 0x52ea,UBOGON,0x5332,UBOGON,0x53ae,0x53b0,UBOGON,0x55fb,0x5603,0x560b, UBOGON,0x5607,UBOGON,0x55f8,UBOGON,0x5628,0x561e,UBOGON,0x5618,0x5611, 0x5651,0x5605,0x5717,0x5892,UBOGON,0x588c,UBOGON,0x5878,0x5884,0x5873, 0x58ad,0x5897,0x5895,0x5877,0x5872,0x5896,0x588d,0x5910,UBOGON,0x596c, UBOGON,0x5ae7,UBOGON,0x5ae4,UBOGON,UBOGON,0x5aef,0x5626,UBOGON,UBOGON, 0x5af0,0x5d7b,UBOGON,0x5d83,UBOGON,UBOGON,0x5d8b,0x5d8c,UBOGON,0x5d78, 0x5e52,UBOGON,UBOGON,0x5ed0,0x5ecf,UBOGON,0x5fb3,0x5fb4,UBOGON,UBOGON, UBOGON,0x617b,UBOGON,0x616f,0x6181,0x613c,0x6142,0x6138,0x6133,UBOGON, 0x6160,0x6169,0x617d,0x6186,0x622c,0x6228,UBOGON,0x644c,UBOGON,0x6457, 0x647c,UBOGON,UBOGON,0x6455 }, { /* ku 27 */ 0x6462,0x6471,0x646a,0x6456,0x643b,0x6481,UBOGON,0x644f,0x647e,0x6464, UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,0x6571,UBOGON,UBOGON,0x66a5,0x669a, 0x669c,UBOGON,0x66a6,UBOGON,0x66a4,0x698f,0x69c5,0x69c8,0x6992,0x69b2, UBOGON,UBOGON,UBOGON,0x69e3,0x69c0,0x69d6,0x69d1,0x699f,0x69a2,0x69d2, UBOGON,UBOGON,UBOGON,0x69e1,0x69d5,0x699d,UBOGON,UBOGON,0x6998,UBOGON, 0x6b74,0x6ba1,UBOGON,0x6ef0,0x6ef3,UBOGON,UBOGON,0x6f1b,0x6f0c,0x6f1d, 0x6f34,0x6f28,0x6f17,UBOGON,0x6f44,0x6f42,0x6f04,0x6f11,0x6efa,0x6f4a, 0x7191,0x718e,UBOGON,0x718b,0x718d,0x717f,0x718c,0x717e,0x717c,0x7183, UBOGON,0x7188,UBOGON,UBOGON,0x7294,UBOGON,0x7355,0x7353,0x734f,0x7354, 0x746c,0x7465,0x7466,0x7461 }, { /* ku 28 */ 0x746b,0x7468,0x7476,UBOGON,0x7460,UBOGON,0x7474,0x7506,0x760e,UBOGON, 0x7607,UBOGON,UBOGON,0x76b9,UBOGON,0x76b7,0x76e2,UBOGON,0x7774,0x7777, 0x7776,0x7775,UBOGON,0x7778,0x7771,UBOGON,0x777a,0x715b,0x777b,0x78a6, 0x78ae,0x78b8,UBOGON,UBOGON,UBOGON,0x78b1,0x78af,UBOGON,0x7989,0x7987, UBOGON,UBOGON,0x7a29,UBOGON,0x7a2a,UBOGON,0x7a2d,0x7a2c,UBOGON,0x7a32, UBOGON,0x7aec,0x7af0,0x7b81,0x7b9e,0x7b83,UBOGON,0x7b92,UBOGON,0x7ba3, 0x7b9f,0x7b93,UBOGON,0x7b86,0x7cb8,0x7cb7,UBOGON,UBOGON,UBOGON,UBOGON, UBOGON,0x7dc8,0x7db6,UBOGON,0x7dd1,UBOGON,0x7da8,0x7dab,UBOGON,0x7db3, 0x7dcd,UBOGON,0x7dcf,0x7da4,UBOGON,UBOGON,0x7f41,0x7f6f,0x7f71,UBOGON, UBOGON,UBOGON,UBOGON,UBOGON }, { /* ku 29 */ UBOGON,0x8023,0x805b,UBOGON,0x8061,0x805f,0x8181,UBOGON,UBOGON,0x8184, 0x8213,UBOGON,0x824a,0x824c,UBOGON,UBOGON,UBOGON,0x84bd,0x8495,UBOGON, 0x8492,0x84c3,UBOGON,0x8496,0x84a5,0x84b5,0x84b3,0x84a3,0x84e4,0x84d8, 0x84d5,UBOGON,0x84b7,0x84ad,0x84da,0x8493,0x8736,UBOGON,UBOGON,UBOGON, 0x873d,0x872b,0x8747,0x8739,UBOGON,0x8745,0x871d,UBOGON,0x88ff,0x88ea, UBOGON,0x88f5,UBOGON,0x8900,0x88ed,0x8903,0x88e9,UBOGON,UBOGON,0x89ea, UBOGON,0x8a9b,0x8a8e,0x8aa2,UBOGON,0x8a9c,0x8a94,0x8a90,0x8aa9,0x8aac, UBOGON,0x8a9f,UBOGON,UBOGON,0x8a9d,UBOGON,0x8c67,UBOGON,UBOGON,0x8cd0, 0x8cd6,0x8cd4,0x8d98,0x8d9a,0x8d97,UBOGON,UBOGON,UBOGON,0x8e0b,0x8e08, 0x8e01,0x8eb4,0x8eb3,UBOGON }, { /* ku 2a */ 0x8fa1,0x8fa2,UBOGON,0x905a,UBOGON,0x9061,0x905f,UBOGON,UBOGON,0x9125, 0x917b,0x9176,0x917c,UBOGON,0x9289,0x92f6,0x92b1,0x92ad,0x9292,0x9281, 0x9284,UBOGON,0x92ae,0x9290,0x929e,UBOGON,UBOGON,UBOGON,0x95a2,0x95a7, UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,0x96a0,0x969d,0x969f,0x96d0,UBOGON, 0x96d1,UBOGON,UBOGON,0x9759,UBOGON,0x9764,UBOGON,UBOGON,UBOGON,0x9819, UBOGON,0x9814,0x9815,0x981a,UBOGON,UBOGON,UBOGON,UBOGON,0x9906,UBOGON, 0x98f8,0x9901,UBOGON,0x99be,0x99bc,0x99b7,0x99b6,0x99c0,UBOGON,0x99b8, UBOGON,UBOGON,UBOGON,0x99c4,UBOGON,0x99bf,UBOGON,0x9ada,0x9ae4,0x9ae9, 0x9ae8,0x9aea,0x9ae5,UBOGON,0x9b26,UBOGON,UBOGON,0x9b40,UBOGON,UBOGON, UBOGON,UBOGON,UBOGON,UBOGON }, { /* ku 2b */ UBOGON,0x9ebd,UBOGON,UBOGON,UBOGON,UBOGON,0x510e,UBOGON,0x50f7,UBOGON, 0x50fc,0x510d,0x5101,0x51da,0x51d9,0x51db,0x5286,0x528e,0x52ee,0x5333, 0x53b1,UBOGON,0x5647,0x562d,0x5654,UBOGON,0x564b,0x5652,0x5631,0x5644, 0x5656,0x5650,0x562b,UBOGON,0x564d,0x5637,0x564f,0x58a2,0x58b7,UBOGON, 0x58b2,UBOGON,0x58aa,0x58b5,0x58b0,UBOGON,0x58b4,0x58a4,0x58a7,UBOGON, 0x5926,0x5afe,UBOGON,0x5b04,UBOGON,0x5afc,UBOGON,0x5b06,0x5b0a,0x5afa, 0x5b0d,0x5b00,0x5b0e,UBOGON,UBOGON,UBOGON,0x5d91,UBOGON,0x5d8f,0x5d90, 0x5d98,0x5da4,0x5d9b,0x5da3,0x5d96,0x5de4,0x5e5a,UBOGON,UBOGON,0x5e5e, UBOGON,0x5fb8,0x6157,0x615c,0x61a6,0x6195,0x6188,UBOGON,0x61a3,0x618f, UBOGON,0x6164,UBOGON,0x6159 }, { /* ku 2c */ 0x6178,UBOGON,0x6185,0x6187,0x619e,UBOGON,UBOGON,0x6198,0x619c,UBOGON, UBOGON,0x622f,0x6480,0x649b,0x648e,0x648d,0x6494,0x64c6,UBOGON,0x64a8, 0x6483,UBOGON,0x64b9,0x6486,0x64b4,0x64af,0x6491,UBOGON,0x64aa,0x64a1, 0x64a7,0x66b6,0x66b3,UBOGON,0x66bc,0x66ac,UBOGON,0x66ad,0x6a0e,UBOGON, 0x6a1c,0x6a1a,UBOGON,UBOGON,0x6a0b,UBOGON,0x69ef,0x6a0c,0x69f0,0x6a22, UBOGON,0x69d8,UBOGON,0x6a12,0x69fa,UBOGON,0x6a2a,UBOGON,0x6a10,UBOGON, UBOGON,0x6a29,0x69f9,0x69ea,0x6a2c,0x6a24,UBOGON,0x69e9,0x6b52,0x6b4f, 0x6b53,UBOGON,UBOGON,0x6f10,0x6f65,0x6f75,UBOGON,UBOGON,UBOGON,UBOGON, 0x6fd0,UBOGON,0x6f5c,0x6f3d,0x6f71,UBOGON,0x6f91,0x6f0b,0x6f79,0x6f81, 0x6f8f,UBOGON,0x6f59,0x6f74 }, { /* ku 2d */ UBOGON,0x71ae,UBOGON,0x71a3,0x71ad,UBOGON,UBOGON,0x71ab,0x71a6,0x71a2, UBOGON,0x52f2,0x7257,0x7255,0x7299,0x734b,0x747a,UBOGON,UBOGON,UBOGON, 0x748c,0x7484,UBOGON,UBOGON,0x7482,0x7493,0x747b,UBOGON,0x7509,UBOGON, UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,0x778a,UBOGON,0x7790,UBOGON,0x78c6, 0x78d3,0x78c0,0x78d2,0x78c7,0x78c2,UBOGON,0x799f,0x799d,0x799e,UBOGON, 0x7a41,UBOGON,0x7a38,0x7a3a,0x7a42,UBOGON,UBOGON,0x7a3e,0x7ab0,0x7bae, 0x7bb3,UBOGON,UBOGON,0x7bbf,UBOGON,UBOGON,0x7bcd,UBOGON,0x7bb2,UBOGON, UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,0x7cc4,0x7ccd,0x7cc2,0x7cc6, 0x7cc3,0x7cc9,0x7cc7,UBOGON,0x7df8,UBOGON,0x7ded,0x7de2,UBOGON,UBOGON, UBOGON,0x7ddc,0x7e02,0x7e01 }, { /* ku 2e */ UBOGON,0x7dd6,UBOGON,0x7de4,0x7dfe,UBOGON,0x7e00,0x7dfc,0x7dfd,UBOGON, 0x7df5,0x7dff,UBOGON,0x7deb,0x7de5,0x7f78,0x7fae,0x7fe7,UBOGON,0x8065, 0x806a,0x8066,0x8068,0x806b,0x8194,0x81a1,0x8192,0x8196,0x8193,UBOGON, UBOGON,0x8501,UBOGON,0x84f8,UBOGON,0x84f5,UBOGON,0x8504,UBOGON,UBOGON, UBOGON,UBOGON,0x851b,0x8503,0x8533,0x8534,0x84ed,UBOGON,UBOGON,0x8535, UBOGON,0x8505,UBOGON,UBOGON,UBOGON,UBOGON,0x877d,UBOGON,UBOGON,UBOGON, 0x8771,UBOGON,0x885c,0x88e6,0x890f,0x891b,UBOGON,0x89a9,0x89a5,0x89ee, 0x8ab1,UBOGON,0x8acc,0x8ace,UBOGON,0x8ab7,UBOGON,0x8ab5,0x8ae9,0x8ab4, UBOGON,0x8ab3,0x8ac1,0x8aaf,0x8aca,0x8ad0,UBOGON,UBOGON,UBOGON,0x8c8e, UBOGON,UBOGON,0x8ce9,0x8cdb }, { /* ku 2f */ UBOGON,0x8ceb,0x8da4,UBOGON,0x8da2,0x8d9d,UBOGON,UBOGON,UBOGON,UBOGON, 0x8e2a,0x8e28,UBOGON,UBOGON,0x8eb8,0x8eb6,0x8eb9,0x8eb7,0x8f22,0x8f2b, 0x8f27,0x8f19,0x8fa4,UBOGON,0x8fb3,UBOGON,0x9071,0x906a,UBOGON,UBOGON, 0x9188,0x918c,0x92bf,0x92b8,0x92be,0x92dc,0x92e5,UBOGON,UBOGON,0x92d4, 0x92d6,UBOGON,0x92da,0x92ed,0x92f3,0x92db,UBOGON,0x92b9,0x92e2,0x92eb, 0x95af,UBOGON,0x95b2,0x95b3,UBOGON,UBOGON,UBOGON,0x96a3,0x96a5,UBOGON, UBOGON,UBOGON,UBOGON,0x970a,UBOGON,0x9787,0x9789,0x978c,0x97ef,0x982a, 0x9822,UBOGON,0x981f,UBOGON,0x9919,UBOGON,0x99ca,0x99da,UBOGON,UBOGON, UBOGON,0x99de,0x99c8,0x99e0,UBOGON,0x9ab6,0x9ab5,UBOGON,0x9af4,UBOGON, 0x9b6b,0x9b69,0x9b72,0x9b63 }, { /* ku 30 */ UBOGON,0x9d0d,UBOGON,0x9d01,0x9d0c,UBOGON,0x9cf8,UBOGON,UBOGON,0x9cfe, 0x9d02,0x9e84,UBOGON,0x9eab,0x9eaa,0x511d,0x5116,UBOGON,0x512b,0x511e, 0x511b,0x5290,0x5294,0x5314,UBOGON,UBOGON,0x5667,UBOGON,0x567b,UBOGON, 0x565f,0x5661,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,0x58c3, 0x58ca,0x58bb,0x58c0,0x58c4,0x5901,0x5b1f,0x5b18,0x5b11,0x5b15,UBOGON, 0x5b12,0x5b1c,UBOGON,0x5b22,0x5b79,0x5da6,UBOGON,0x5db3,0x5dab,0x5eea, UBOGON,0x5f5b,UBOGON,UBOGON,0x61b7,0x61ce,0x61b9,0x61bd,0x61cf,0x61c0, 0x6199,0x6197,UBOGON,0x61bb,0x61d0,0x61c4,0x6231,UBOGON,0x64d3,0x64c0, UBOGON,UBOGON,UBOGON,UBOGON,0x64dc,0x64d1,0x64c8,UBOGON,0x64d5,0x66c3, UBOGON,UBOGON,0x66bf,0x66c5 }, { /* ku 31 */ UBOGON,0x66cd,0x66c1,0x6706,UBOGON,0x6724,0x6a63,0x6a42,0x6a52,UBOGON, 0x6a43,0x6a33,UBOGON,0x6a6c,0x6a57,UBOGON,0x6a4c,0x6a6e,UBOGON,UBOGON, UBOGON,UBOGON,UBOGON,0x6a37,UBOGON,0x6a71,0x6a4a,0x6a36,UBOGON,0x6a53, UBOGON,0x6a45,0x6a70,UBOGON,UBOGON,0x6a5c,0x6b58,0x6b57,UBOGON,UBOGON, UBOGON,UBOGON,UBOGON,UBOGON,0x6fbb,UBOGON,UBOGON,0x6fbe,UBOGON,UBOGON, UBOGON,0x6fb5,0x6fd3,0x6f9f,UBOGON,0x6fb7,0x6ff5,0x71b7,UBOGON,0x71bb, UBOGON,0x71d1,UBOGON,0x71ba,UBOGON,0x71b6,0x71cc,UBOGON,UBOGON,0x71d3, 0x749b,UBOGON,UBOGON,0x7496,0x74a2,0x749d,0x750a,0x750e,UBOGON,0x7581, 0x762c,0x7637,0x7636,0x763b,UBOGON,0x76a1,UBOGON,UBOGON,0x7798,UBOGON, 0x7796,UBOGON,UBOGON,UBOGON }, { /* ku 32 */ 0x78d6,0x78eb,UBOGON,0x78dc,UBOGON,0x79a5,0x79a9,0x9834,0x7a53,0x7a45, UBOGON,0x7a4f,UBOGON,0x7abd,0x7abb,0x7af1,UBOGON,UBOGON,0x7bec,0x7bed, UBOGON,UBOGON,0x7cd3,UBOGON,0x7ce1,UBOGON,0x7e19,UBOGON,UBOGON,UBOGON, 0x7e27,0x7e26,UBOGON,UBOGON,0x806e,0x81af,UBOGON,UBOGON,0x81ad,UBOGON, 0x81aa,0x8218,UBOGON,UBOGON,UBOGON,UBOGON,0x856f,0x854c,UBOGON,0x8542, UBOGON,0x855c,0x8570,0x855f,UBOGON,0x855a,0x854b,0x853f,0x878a,UBOGON, 0x878b,0x87a1,0x878e,UBOGON,UBOGON,0x8799,0x885e,0x885f,0x8924,0x89a7, 0x8aea,0x8afd,0x8af9,0x8ae3,0x8ae5,UBOGON,UBOGON,0x8aec,UBOGON,UBOGON, UBOGON,UBOGON,0x8cf2,UBOGON,0x8cef,UBOGON,0x8da6,UBOGON,UBOGON,UBOGON, 0x8e3b,0x8e43,UBOGON,0x8e32 }, { /* ku 33 */ 0x8f31,0x8f30,UBOGON,0x8f2d,0x8f3c,0x8fa7,0x8fa5,UBOGON,UBOGON,UBOGON, 0x9137,0x9195,0x918e,UBOGON,0x9196,UBOGON,0x9345,0x930a,UBOGON,UBOGON, 0x92fd,0x9317,0x931c,0x9307,0x9331,0x9332,0x932c,0x9330,0x9303,0x9305, UBOGON,0x95c2,UBOGON,0x95b8,UBOGON,0x95c1,UBOGON,UBOGON,UBOGON,0x96ab, 0x96b7,UBOGON,UBOGON,0x9715,0x9714,UBOGON,UBOGON,0x970c,0x9717,UBOGON, 0x9793,UBOGON,0x97d2,UBOGON,UBOGON,0x9836,0x9831,0x9833,0x983c,0x982e, 0x983a,UBOGON,0x983d,UBOGON,0x98b5,0x9922,0x9923,0x9920,0x991c,0x991d, UBOGON,0x99a0,UBOGON,0x99ef,0x99e8,0x99eb,UBOGON,UBOGON,UBOGON,0x99e1, 0x99e6,UBOGON,UBOGON,0x9af8,0x9af5,UBOGON,UBOGON,0x9b83,0x9b94,0x9b84, UBOGON,0x9b8b,0x9b8f,UBOGON }, { /* ku 34 */ 0x9b8c,UBOGON,0x9b89,UBOGON,0x9b8e,UBOGON,UBOGON,UBOGON,0x9d24,0x9d0f, UBOGON,0x9d13,0x9d0a,UBOGON,UBOGON,UBOGON,UBOGON,0x9d2a,0x9d1a,UBOGON, 0x9d27,0x9d16,0x9d21,UBOGON,0x9e85,0x9eac,0x9ec6,0x9ec5,0x9ed7,0x9f53, UBOGON,0x5128,0x5127,0x51df,UBOGON,0x5335,0x53b3,UBOGON,0x568a,0x567d, 0x5689,UBOGON,0x58cd,0x58d0,UBOGON,0x5b2b,0x5b33,0x5b29,0x5b35,0x5b31, 0x5b37,0x5c36,0x5dbe,UBOGON,0x5db9,UBOGON,0x5dbb,UBOGON,0x61e2,0x61db, 0x61dd,0x61dc,0x61da,UBOGON,0x61d9,UBOGON,UBOGON,0x64df,UBOGON,UBOGON, 0x64e1,UBOGON,0x64ee,UBOGON,0x65b5,0x66d4,0x66d5,UBOGON,0x66d0,0x66d1, 0x66ce,0x66d7,UBOGON,UBOGON,0x6a7d,0x6a8a,UBOGON,0x6aa7,UBOGON,0x6a99, 0x6a82,0x6a88,UBOGON,UBOGON }, { /* ku 35 */ 0x6a86,UBOGON,0x6a98,0x6a9d,UBOGON,UBOGON,0x6a8f,UBOGON,0x6aaa,UBOGON, 0x6b5d,UBOGON,0x6c0a,UBOGON,0x6fd7,0x6fd6,0x6fe5,UBOGON,UBOGON,UBOGON, 0x6fd9,0x6fda,0x6fea,UBOGON,0x6ff6,UBOGON,UBOGON,0x71e3,UBOGON,0x71e9, UBOGON,0x71eb,0x71ef,0x71f3,0x71ea,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON, 0x7371,UBOGON,0x74ae,UBOGON,0x74b3,UBOGON,0x74ac,UBOGON,UBOGON,0x7583, 0x7645,0x764e,0x7644,0x76a3,0x76a5,0x77a6,0x77a4,UBOGON,0x77a9,0x77af, UBOGON,UBOGON,UBOGON,0x78f0,0x78f8,0x78f1,UBOGON,0x7a49,UBOGON,UBOGON, UBOGON,0x7ac2,0x7af2,0x7af3,0x7bfa,UBOGON,0x7bf6,0x7bfc,0x7c18,0x7c08, 0x7c12,UBOGON,UBOGON,0x7cdb,0x7cda,UBOGON,UBOGON,UBOGON,0x7e2c,0x7e4d, UBOGON,UBOGON,0x7f46,0x7ff6 }, { /* ku 36 */ 0x802b,0x8074,0x81b8,0x81c8,UBOGON,UBOGON,UBOGON,0x8592,0x8593,UBOGON, 0x857f,0x85ab,0x8597,UBOGON,UBOGON,0x85ac,UBOGON,UBOGON,UBOGON,0x87ce, UBOGON,0x87cd,UBOGON,UBOGON,0x87c1,0x87b1,0x87c7,UBOGON,0x8940,UBOGON, 0x893f,0x8939,UBOGON,0x8943,UBOGON,UBOGON,UBOGON,0x89ab,UBOGON,0x8b1f, 0x8b09,0x8b0c,UBOGON,UBOGON,0x8c40,UBOGON,0x8c96,UBOGON,0x8cf6,0x8cf7, UBOGON,0x8e46,0x8e4f,UBOGON,UBOGON,UBOGON,0x8f3d,0x8f41,0x9366,0x9378, 0x935d,0x9369,0x9374,0x937d,0x936e,0x9372,0x9373,0x9362,0x9348,0x9353, 0x935f,0x9368,UBOGON,0x937f,0x936b,UBOGON,0x95c4,UBOGON,0x96af,0x96ad, 0x96b2,UBOGON,UBOGON,0x971a,0x971b,UBOGON,UBOGON,UBOGON,UBOGON,0x979b, 0x979f,UBOGON,UBOGON,UBOGON }, { /* ku 37 */ UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,0x9840,UBOGON,0x9847,UBOGON,0x98b7, UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,0x99a2,UBOGON,UBOGON,0x9a00,0x99f3, UBOGON,UBOGON,0x99f5,UBOGON,UBOGON,0x9abd,0x9b00,0x9b02,UBOGON,0x9b34, 0x9b49,0x9b9f,UBOGON,0x9ba3,0x9bcd,0x9b99,0x9b9d,UBOGON,UBOGON,0x9d39, UBOGON,0x9d44,UBOGON,UBOGON,0x9d35,UBOGON,UBOGON,0x9eaf,UBOGON,0x512f, UBOGON,UBOGON,0x9f8e,UBOGON,0x569f,0x569b,0x569e,0x5696,0x5694,0x56a0, UBOGON,0x5b3b,UBOGON,UBOGON,0x5b3a,0x5dc1,0x5f4d,0x5f5d,0x61f3,UBOGON, UBOGON,UBOGON,UBOGON,0x64f6,0x64e5,0x64ea,0x64e7,0x6505,UBOGON,0x64f9, UBOGON,UBOGON,UBOGON,0x6aab,0x6aed,0x6ab2,0x6ab0,0x6ab5,0x6abe,0x6ac1, 0x6ac8,UBOGON,0x6ac0,0x6abc }, { /* ku 38 */ 0x6ab1,0x6ac4,0x6abf,UBOGON,UBOGON,0x7008,0x7003,0x6ffd,0x7010,0x7002, 0x7013,UBOGON,0x71fa,0x7200,0x74b9,0x74bc,UBOGON,0x765b,0x7651,0x764f, 0x76eb,0x77b8,UBOGON,0x77b9,0x77c1,0x77c0,0x77be,0x790b,UBOGON,0x7907, 0x790a,0x7908,UBOGON,0x790d,0x7906,0x7915,0x79af,UBOGON,UBOGON,UBOGON, 0x7af5,UBOGON,UBOGON,0x7c2e,UBOGON,0x7c1b,UBOGON,0x7c1a,0x7c24,UBOGON, UBOGON,0x7ce6,0x7ce3,UBOGON,UBOGON,0x7e5d,0x7e4f,0x7e66,0x7e5b,0x7f47, 0x7fb4,UBOGON,UBOGON,UBOGON,0x7ffa,0x802e,UBOGON,UBOGON,0x81ce,UBOGON, UBOGON,0x8219,UBOGON,UBOGON,0x85cc,0x85b2,UBOGON,0x85bb,0x85c1,UBOGON, UBOGON,UBOGON,0x87e9,0x87ee,0x87f0,0x87d6,0x880e,0x87da,0x8948,0x894a, 0x894e,0x894d,0x89b1,0x89b0 }, { /* ku 39 */ 0x89b3,UBOGON,0x8b38,0x8b32,UBOGON,0x8b2d,UBOGON,0x8b34,UBOGON,0x8b29, 0x8c74,UBOGON,UBOGON,0x8d03,UBOGON,UBOGON,0x8da9,0x8e58,UBOGON,UBOGON, 0x8ebf,0x8ec1,0x8f4a,0x8fac,UBOGON,0x9089,0x913d,0x913c,0x91a9,0x93a0, UBOGON,0x9390,UBOGON,0x9393,0x938b,0x93ad,0x93bb,0x93b8,UBOGON,UBOGON, 0x939c,0x95d8,0x95d7,UBOGON,UBOGON,UBOGON,0x975d,0x97a9,0x97da,UBOGON, UBOGON,UBOGON,UBOGON,0x9854,UBOGON,0x9855,0x984b,UBOGON,0x983f,0x98b9, UBOGON,UBOGON,UBOGON,UBOGON,0x9938,0x9936,0x9940,UBOGON,0x993b,0x9939, 0x99a4,UBOGON,UBOGON,0x9a08,0x9a0c,UBOGON,0x9a10,UBOGON,0x9b07,UBOGON, 0x9bd2,UBOGON,0x9bc2,0x9bbb,0x9bcc,0x9bcb,UBOGON,UBOGON,0x9d4d,0x9d63, 0x9d4e,UBOGON,0x9d50,0x9d55 }, { /* ku 3a */ UBOGON,0x9d5e,UBOGON,0x9e90,0x9eb2,0x9eb1,UBOGON,0x9eca,0x9f02,0x9f27, 0x9f26,UBOGON,0x56af,0x58e0,0x58dc,UBOGON,0x5b39,UBOGON,UBOGON,0x5b7c, 0x5bf3,UBOGON,UBOGON,0x5c6b,0x5dc4,0x650b,0x6508,0x650a,UBOGON,UBOGON, 0x65dc,UBOGON,UBOGON,0x66e1,0x66df,0x6ace,0x6ad4,0x6ae3,0x6ad7,0x6ae2, UBOGON,UBOGON,UBOGON,UBOGON,0x6ad8,0x6ad5,0x6ad2,UBOGON,UBOGON,0x701e, 0x702c,0x7025,0x6ff3,0x7204,0x7208,0x7215,UBOGON,0x74c4,0x74c9,0x74c7, 0x74c8,0x76a9,0x77c6,0x77c5,0x7918,0x791a,0x7920,UBOGON,0x7a66,0x7a64, 0x7a6a,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,0x7c35,0x7c34,UBOGON, UBOGON,0x7e6c,UBOGON,0x7e6e,0x7e71,UBOGON,0x81d4,0x81d6,0x821a,0x8262, 0x8265,0x8276,0x85db,0x85d6 }, { /* ku 3b */ UBOGON,0x85e7,UBOGON,UBOGON,0x85f4,UBOGON,0x87fd,0x87d5,0x8807,UBOGON, 0x880f,0x87f8,UBOGON,UBOGON,0x8987,UBOGON,0x89b5,0x89f5,UBOGON,0x8b3f, 0x8b43,0x8b4c,UBOGON,0x8d0b,0x8e6b,0x8e68,0x8e70,0x8e75,0x8e77,UBOGON, 0x8ec3,UBOGON,0x93e9,0x93ea,0x93cb,0x93c5,0x93c6,UBOGON,0x93ed,0x93d3, UBOGON,0x93e5,UBOGON,UBOGON,0x93db,0x93eb,0x93e0,0x93c1,UBOGON,UBOGON, 0x95dd,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON, 0x97b2,0x97b4,0x97b1,0x97b5,0x97f2,UBOGON,UBOGON,UBOGON,0x9856,UBOGON, UBOGON,UBOGON,0x9944,UBOGON,0x9a26,0x9a1f,0x9a18,0x9a21,0x9a17,UBOGON, 0x9b09,UBOGON,UBOGON,0x9bc5,0x9bdf,UBOGON,0x9be3,UBOGON,0x9be9,0x9bee, UBOGON,UBOGON,0x9d66,0x9d7a }, { /* ku 3c */ UBOGON,0x9d6e,0x9d91,0x9d83,0x9d76,0x9d7e,0x9d6d,UBOGON,0x9e95,0x9ee3, UBOGON,UBOGON,0x9f03,0x9f04,UBOGON,0x9f17,UBOGON,0x5136,UBOGON,0x5336, UBOGON,0x5b42,UBOGON,UBOGON,0x5b44,0x5b46,0x5b7e,0x5dca,0x5dc8,0x5dcc, 0x5ef0,UBOGON,0x6585,0x66e5,0x66e7,UBOGON,UBOGON,UBOGON,0x6af4,UBOGON, 0x6ae9,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,0x703d,UBOGON,0x7036,UBOGON, 0x7216,UBOGON,0x7212,0x720f,0x7217,0x7211,0x720b,UBOGON,UBOGON,0x74cd, 0x74d0,0x74cc,0x74ce,0x74d1,UBOGON,0x7589,UBOGON,0x7a6f,0x7c4b,0x7c44, UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,0x7e7f,0x8b71,UBOGON,0x802f,0x807a, 0x807b,0x807c,UBOGON,UBOGON,UBOGON,0x85fc,0x8610,0x8602,UBOGON,UBOGON, 0x85ee,0x8603,UBOGON,0x860d }, { /* ku 3d */ 0x8613,0x8608,0x860f,0x8818,0x8812,UBOGON,UBOGON,0x8967,0x8965,0x89bb, 0x8b69,0x8b62,UBOGON,0x8b6e,UBOGON,0x8b61,UBOGON,0x8b64,0x8b4d,0x8c51, UBOGON,UBOGON,0x8e83,0x8ec6,UBOGON,0x941f,UBOGON,0x9404,0x9417,0x9408, 0x9405,UBOGON,0x93f3,0x941e,0x9402,0x941a,0x941b,0x9427,0x941c,UBOGON, 0x96b5,UBOGON,UBOGON,0x9733,UBOGON,0x9734,0x9731,0x97b8,0x97ba,UBOGON, 0x97fc,UBOGON,UBOGON,0x98c3,UBOGON,0x994d,UBOGON,0x9a2f,UBOGON,UBOGON, UBOGON,0x9ac9,UBOGON,0x9ac8,0x9ac4,0x9b2a,0x9b38,0x9b50,UBOGON,0x9c0a, 0x9bfb,0x9c04,0x9bfc,0x9bfe,UBOGON,UBOGON,UBOGON,0x9c02,0x9bf6,0x9c1b, 0x9bf9,0x9c15,0x9c10,0x9bff,0x9c00,0x9c0c,UBOGON,UBOGON,0x9d95,0x9da5, UBOGON,UBOGON,UBOGON,UBOGON }, { /* ku 3e */ 0x9e98,0x9ec1,UBOGON,0x9f5a,0x5164,0x56bb,UBOGON,0x58e6,0x5b49,0x5bf7, UBOGON,UBOGON,0x5dd0,UBOGON,0x5fc2,UBOGON,0x6511,UBOGON,0x6aff,0x6afe, 0x6afd,UBOGON,0x6b01,UBOGON,UBOGON,0x704b,0x704d,0x7047,0x74d3,0x7668, 0x7667,UBOGON,UBOGON,0x77d1,0x7930,0x7932,0x792e,UBOGON,0x9f9d,0x7ac9, 0x7ac8,UBOGON,0x7c56,0x7c51,UBOGON,UBOGON,UBOGON,0x7e85,0x7e89,0x7e8e, 0x7e84,UBOGON,0x826a,0x862b,0x862f,0x8628,UBOGON,0x8616,0x8615,0x861d, 0x881a,UBOGON,UBOGON,UBOGON,0x89bc,0x8b75,0x8b7c,UBOGON,0x8d11,0x8d12, 0x8f5c,0x91bb,UBOGON,0x93f4,UBOGON,UBOGON,0x942d,UBOGON,UBOGON,0x96e4, 0x9737,0x9736,0x9767,0x97be,0x97bd,0x97e2,0x9868,0x9866,0x98c8,0x98ca, 0x98c7,0x98dc,UBOGON,0x994f }, { /* ku 3f */ 0x99a9,0x9a3c,UBOGON,0x9a3b,0x9ace,UBOGON,0x9b14,0x9b53,UBOGON,0x9c2e, UBOGON,0x9c1f,UBOGON,UBOGON,UBOGON,UBOGON,0x9db0,0x9dbd,UBOGON,UBOGON, 0x9dae,0x9dc4,0x9e7b,UBOGON,UBOGON,0x9e9e,UBOGON,0x9f05,UBOGON,0x9f69, 0x9fa1,0x56c7,0x571d,0x5b4a,0x5dd3,UBOGON,0x5f72,0x6202,UBOGON,0x6235, 0x6527,0x651e,0x651f,UBOGON,UBOGON,0x6b07,0x6b06,UBOGON,UBOGON,0x7054, 0x721c,0x7220,0x7af8,UBOGON,0x7c5d,0x7c58,UBOGON,0x7e92,0x7f4e,UBOGON, UBOGON,UBOGON,0x8827,UBOGON,0x8b81,0x8b83,UBOGON,0x8c44,UBOGON,UBOGON, UBOGON,UBOGON,0x9442,0x944d,0x9454,0x944e,UBOGON,0x9443,UBOGON,UBOGON, 0x973c,0x9740,0x97c0,UBOGON,UBOGON,UBOGON,UBOGON,0x995a,0x9a51,UBOGON, 0x9add,UBOGON,UBOGON,0x9c38 }, { /* ku 40 */ UBOGON,0x9c45,0x9c3a,UBOGON,0x9c35,UBOGON,UBOGON,UBOGON,0x9ef1,UBOGON, 0x9f93,0x529a,UBOGON,UBOGON,0x8641,0x5dd7,UBOGON,0x6528,UBOGON,UBOGON, UBOGON,0x7053,0x7059,UBOGON,0x7221,UBOGON,0x766f,0x7937,0x79b5,0x7c62, 0x7c5e,0x7cf5,UBOGON,UBOGON,0x863d,UBOGON,0x882d,0x8989,0x8b8d,0x8b87, 0x8b90,0x8d1a,0x8e99,UBOGON,UBOGON,UBOGON,0x945f,UBOGON,UBOGON,0x9456, 0x9461,0x945b,0x945a,0x945c,0x9465,UBOGON,0x9741,UBOGON,UBOGON,0x986e, 0x986c,0x986d,UBOGON,0x99aa,0x9a5c,0x9a58,0x9ade,UBOGON,0x9c4f,0x9c51, UBOGON,0x9c53,UBOGON,UBOGON,UBOGON,0x9dfc,0x9f39,UBOGON,0x513e,UBOGON, 0x56d2,UBOGON,0x5b4f,0x6b14,UBOGON,0x7a72,0x7a73,UBOGON,UBOGON,UBOGON, 0x8b91,UBOGON,UBOGON,0x91bf }, { /* ku 41 */ UBOGON,0x946c,UBOGON,UBOGON,0x96e6,0x9745,UBOGON,0x97c8,0x97e4,0x995d, UBOGON,0x9b21,UBOGON,0x9b2c,0x9b57,UBOGON,UBOGON,0x9c5d,0x9c61,0x9c65, 0x9e08,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,0x9f45,UBOGON,UBOGON,0x6205, 0x66ef,0x6b1b,0x6b1d,0x7225,0x7224,0x7c6d,UBOGON,0x8642,0x8649,UBOGON, 0x8978,0x898a,0x8b97,UBOGON,0x8c9b,0x8d1c,UBOGON,0x8ea2,UBOGON,UBOGON, UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,0x9c6c,UBOGON,0x9c6f,UBOGON, 0x9e0e,UBOGON,0x9f08,0x9f1d,0x9fa3,UBOGON,UBOGON,0x5f60,0x6b1c,UBOGON, UBOGON,UBOGON,0x7cf3,UBOGON,0x8b9b,0x8ea7,0x91c4,UBOGON,0x947a,UBOGON, UBOGON,0x9a61,0x9a63,0x9ad7,0x9c76,UBOGON,0x9fa5,UBOGON,0x7067,UBOGON, 0x72ab,0x864a,0x897d,0x8b9d }, { /* ku 42 */ 0x8c53,0x8f65,0x947b,UBOGON,0x98cd,0x98dd,UBOGON,0x9b30,0x9e16,UBOGON, UBOGON,UBOGON,UBOGON,UBOGON,0x96e7,0x9e18,0x9ea2,UBOGON,0x9f7c,UBOGON, 0x7e9e,0x9484,UBOGON,0x9e1c,UBOGON,0x7c71,0x97ca,UBOGON,UBOGON,UBOGON, 0x9ea3,UBOGON,0x9c7b,0x9f97,UBOGON,UBOGON,0x9750,UBOGON,UBOGON,UBOGON, 0x5727,0x5c13,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,0x5fc8,UBOGON, UBOGON,UBOGON,UBOGON,UBOGON,0x6765,UBOGON,UBOGON,0x52bd,UBOGON,0x5b66, UBOGON,0x65f9,0x6788,0x6ce6,0x6ccb,UBOGON,0x4fbd,0x5f8d,UBOGON,0x6018, 0x6048,UBOGON,0x6b29,0x70a6,UBOGON,0x7706,UBOGON,UBOGON,UBOGON,0x5a10, 0x5cfc,0x5cfe,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,0x70c9,UBOGON, UBOGON,UBOGON,UBOGON,UBOGON }, { /* ku 43 */ UBOGON,UBOGON,0x9579,UBOGON,0x96ba,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON, UBOGON,UBOGON,0x7b29,0x8128,UBOGON,0x8a2e,UBOGON,UBOGON,UBOGON,0x9ad9, UBOGON,0x582b,0x5845,UBOGON,0x63fa,UBOGON,UBOGON,UBOGON,0x6e86,UBOGON, UBOGON,UBOGON,UBOGON,UBOGON,0x5867,UBOGON,0x5bdd,0x656e,UBOGON,UBOGON, UBOGON,0x8c87,UBOGON,0x50d2,0x50df,UBOGON,UBOGON,UBOGON,UBOGON,0x69ba, UBOGON,0x6b9d,UBOGON,0x8059,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON, UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,0x6f8a,UBOGON,UBOGON,0x7bc3, 0x7bc2,UBOGON,UBOGON,UBOGON,UBOGON,0x90f6,UBOGON,0x9823,UBOGON,UBOGON, UBOGON,UBOGON,UBOGON,0x71cd,0x7499,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON, 0x9842,UBOGON,UBOGON,UBOGON }, { /* ku 44 */ UBOGON,0x7f84,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,0x8d0e,UBOGON,0x9861, UBOGON,UBOGON,0x8b73,UBOGON,0x9c27,UBOGON,0x9458,0x77d6,0x9b2d,UBOGON, UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON, UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,0x4f66, 0x4f68,0x4fe7,0x503f,UBOGON,0x50a6,0x510f,0x523e,0x5324,0x5365,0x539b, 0x517f,0x54cb,0x5573,0x5571,0x556b,0x55f4,0x5622,0x5620,0x5692,0x56ba, 0x5691,0x56b0,0x5759,0x578a,0x580f,0x5812,0x5813,0x5847,0x589b,0x5900, 0x594d,0x5ad1,0x5ad3,0x5b67,0x5c57,0x5c77,0x5cd5,0x5d75,0x5d8e,0x5da5, 0x5db6,0x5dbf,0x5e65,0x5ecd,0x5eed,0x5f94,0x5f9a,0x5fba,0x6125,0x6150, 0x62a3,0x6360,0x6364,0x63b6 }, { /* ku 45 */ 0x6403,0x64b6,0x651a,0x7a25,0x5c21,0x66e2,0x6702,0x67a4,0x67ac,0x6810, 0x6806,0x685e,0x685a,0x692c,0x6929,0x6a2d,0x6a77,0x6a7a,0x6aca,0x6ae6, 0x6af5,0x6b0d,0x6b0e,0x6bdc,0x6bdd,0x6bf6,0x6c1e,0x6c63,0x6da5,0x6e0f, 0x6e8a,0x6e84,0x6e8b,0x6e7c,0x6f4c,0x6f48,0x6f49,0x6f9d,0x6f99,0x6ff8, 0x702e,0x702d,0x705c,0x79cc,0x70bf,0x70ea,0x70e5,0x7111,0x7112,0x713f, 0x7139,0x713b,0x713d,0x7177,0x7175,0x7176,0x7171,0x7196,0x7193,0x71b4, 0x71dd,0x71de,0x720e,0x5911,0x7218,0x7347,0x7348,0x73ef,0x7412,0x743b, 0x74a4,0x748d,0x74b4,0x7673,0x7677,0x76bc,0x7819,0x781b,0x783d,0x7853, 0x7854,0x7858,0x78b7,0x78d8,0x78ee,0x7922,0x794d,0x7986,0x7999,0x79a3, 0x79bc,0x7aa7,0x7b37,0x7b59 }, { /* ku 46 */ 0x7bd0,0x7c2f,0x7c32,0x7c42,0x7c4e,0x7c68,0x7ca9,0x7ced,0x7dd0,0x7e07, 0x7dd3,0x7e64,0x7f40,UBOGON,0x8041,0x8063,0x80bb,0x6711,0x6725,0x8248, 0x8310,0x8362,0x8312,0x8421,0x841e,0x84e2,0x84de,0x84e1,0x8573,0x85d4, 0x85f5,0x8637,0x8645,0x8672,0x874a,0x87a9,0x87a5,0x87f5,0x8834,0x8850, 0x8887,0x8954,0x8984,0x8b03,0x8c52,0x8cd8,0x8d0c,0x8d18,0x8db0,0x8ebc, 0x8ed5,0x8faa,0x909c,UBOGON,0x915c,0x922b,0x9221,0x9273,0x92f4,0x92f5, 0x933f,0x9342,0x9386,0x93be,0x93bc,0x93bd,0x93f1,0x93f2,0x93ef,0x9422, 0x9423,0x9424,0x9467,0x9466,0x9597,0x95ce,0x95e7,0x973b,0x974d,0x98e4, 0x9942,0x9b1d,0x9b98,UBOGON,0x9d49,0x6449,0x5e71,0x5e85,0x61d3,0x990e, 0x8002,0x781e,UBOGON,UBOGON }, { /* ku 47 */ 0x5528,0x5572,0x55ba,0x55f0,0x55ee,0x56b8,0x56b9,0x56c4,0x8053,0x92b0, UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON, UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON, UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON, UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON, UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON, UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON, UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON, UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON, UBOGON,UBOGON,UBOGON,UBOGON } }; #endif #if CNS_EXTENSION /* CNS 11643 plane 15 conversion table */ static const unsigned short cns11643_15tab[MAX_CNS11643_KU_15][MAX_CNS11643_TEN] = { { /* ku 01 */ UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON, UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,0x5301,UBOGON,UBOGON,UBOGON,UBOGON, UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON, UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,0x3436,UBOGON,UBOGON,UBOGON,UBOGON, UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,0x53fa,UBOGON,UBOGON, UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,0x9f99,UBOGON,UBOGON,UBOGON, UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,0x6c49, UBOGON,UBOGON,UBOGON,0x8fb7,UBOGON,0x3406,UBOGON,UBOGON,UBOGON,UBOGON, 0x4f29,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON, UBOGON,UBOGON,UBOGON,UBOGON }, { /* ku 02 */ UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON, UBOGON,0x534e,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON, UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON, UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,0x5c81,UBOGON, UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,0x5f10,UBOGON,UBOGON,0x6268,UBOGON, UBOGON,UBOGON,UBOGON,UBOGON,0x6742,0x6740,0x51ea,UBOGON,UBOGON,UBOGON, 0x6c62,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,0x7391, UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON, 0x8fbb,0x8fbc,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON, UBOGON,UBOGON,UBOGON,UBOGON }, { /* ku 03 */ UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON, UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON, UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON, UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON, 0x3575,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,0x56e8,UBOGON,0x575b, UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON, UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON, UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON, UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON, UBOGON,0x5c97,UBOGON,UBOGON }, { /* ku 04 */ UBOGON,0x6762,UBOGON,UBOGON,0x383c,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON, UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON, UBOGON,UBOGON,UBOGON,UBOGON,0x62a4,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON, UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON, UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON, 0x6766,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON, UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON, UBOGON,0x6ca3,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON, 0x707f,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON, UBOGON,UBOGON,UBOGON,UBOGON }, { /* ku 05 */ UBOGON,UBOGON,0x77f6,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON, UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,0x8fc8,UBOGON,UBOGON, UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON, UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,0x4fab,UBOGON,UBOGON,UBOGON,UBOGON, UBOGON,0x3453,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON, UBOGON,0x5c2d,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON, UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON, UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON, 0x549c,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON, UBOGON,UBOGON,UBOGON,UBOGON }, { /* ku 06 */ UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON, UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,0x5788,UBOGON, UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON, UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON, UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON, UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,0x34ac,UBOGON,UBOGON, UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON, UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON, UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON, UBOGON,UBOGON,UBOGON,UBOGON }, { /* ku 07 */ UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON, UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,0x62c3,UBOGON,UBOGON,UBOGON,UBOGON, UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,0x6619, UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON, UBOGON,UBOGON,UBOGON,0x3b49,UBOGON,0x67a1,UBOGON,0x67a6,UBOGON,UBOGON, UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,0x3c91,UBOGON, UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,0x3cd3, UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON, UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON, UBOGON,UBOGON,UBOGON,UBOGON }, { /* ku 08 */ UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON, UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,0x77fe, UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON, UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON, UBOGON,0x7f57,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,0x43d5, UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON, UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,0x82c5,UBOGON,UBOGON,UBOGON, UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,0x8fdf,UBOGON,UBOGON, 0x8fdc,0x488c,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON, UBOGON,UBOGON,UBOGON,UBOGON }, { /* ku 09 */ UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON, UBOGON,UBOGON,0x4fe4,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON, UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON, UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON, UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON, UBOGON,0x551b,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,0x3588, UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON, UBOGON,UBOGON,UBOGON,0x57aa,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON, 0x57ab,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON, UBOGON,UBOGON,UBOGON,UBOGON }, { /* ku 0a */ UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,0x36c9, UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON, UBOGON,UBOGON,UBOGON,UBOGON,0x5ba9,UBOGON,UBOGON,UBOGON,UBOGON,0x3917, UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON, UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON, UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON, UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON, UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON, UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON, UBOGON,UBOGON,UBOGON,UBOGON }, { /* ku 0b */ UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON, UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON, UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON, UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,0x6811, UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON, UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON, UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON, UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON, UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,0x7551, UBOGON,UBOGON,UBOGON,UBOGON }, { /* ku 0c */ UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON, UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,0x3ebd,UBOGON,UBOGON, UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON, UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON, UBOGON,0x7553,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON, UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,0x7818, UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON, UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,0x4133,UBOGON,UBOGON,UBOGON, UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,0x7ad7,UBOGON,UBOGON,UBOGON,UBOGON, UBOGON,UBOGON,UBOGON,UBOGON }, { /* ku 0d */ 0x7c7e,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON, UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON, UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,0x867e, UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON, UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON, 0x4844,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON, UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON, UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON, UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON, UBOGON,UBOGON,UBOGON,UBOGON }, { /* ku 0e */ UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON, UBOGON,UBOGON,0x5266,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON, UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON, UBOGON,UBOGON,UBOGON,0x5520,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON, UBOGON,0x5521,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON, UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,0x57d7, UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON, UBOGON,UBOGON,UBOGON,UBOGON,0x36e1,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON, UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,0x36e2,UBOGON,UBOGON, UBOGON,UBOGON,UBOGON,0x5bbe }, { /* ku 0f */ UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON, UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON, UBOGON,UBOGON,UBOGON,0x387c,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,0x38e3, UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON, UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON, UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON, UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON, UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,0x3aec,UBOGON,UBOGON, UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON, UBOGON,UBOGON,UBOGON,UBOGON }, { /* ku 10 */ UBOGON,UBOGON,UBOGON,0x6857,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON, UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON, UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON, UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON, UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON, UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON, UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON, UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON, UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON, UBOGON,UBOGON,UBOGON,UBOGON }, { /* ku 11 */ UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON, UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON, UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON, UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON, UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON, UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON, UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON, UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON, UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,0x7f3c,UBOGON,UBOGON, UBOGON,UBOGON,UBOGON,UBOGON }, { /* ku 12 */ UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON, UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,0x8273,UBOGON,UBOGON, UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON, UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON, UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,0x4627,UBOGON, UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON, UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON, UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,0x96be,UBOGON, UBOGON,UBOGON,0x66fa,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON, UBOGON,UBOGON,UBOGON,UBOGON }, { /* ku 13 */ UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON, UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON, UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON, UBOGON,UBOGON,UBOGON,UBOGON,0x35ab,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON, UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON, UBOGON,UBOGON,UBOGON,UBOGON,0x364b,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON, UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON, UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON, UBOGON,UBOGON,0x5a72,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON, UBOGON,UBOGON,UBOGON,UBOGON }, { /* ku 14 */ UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON, UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON, UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON, 0x37e2,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON, UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON, UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON, UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON, UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON, UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON, UBOGON,UBOGON,UBOGON,UBOGON }, { /* ku 15 */ UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON, UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON, UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON, UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON, UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON, UBOGON,UBOGON,UBOGON,UBOGON,0x68bd,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON, UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON, UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON, UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON, UBOGON,UBOGON,UBOGON,UBOGON }, { /* ku 16 */ UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,0x6e15,UBOGON, UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON, UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON, UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,0x3dc1, UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON, UBOGON,UBOGON,UBOGON,UBOGON,0x7413,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON, UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON, 0x74f8,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON, UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON, UBOGON,UBOGON,UBOGON,0x7b3d }, { /* ku 17 */ UBOGON,UBOGON,0x76d8,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON, UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON, UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON, 0x79fc,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON, UBOGON,UBOGON,UBOGON,UBOGON,0x7b39,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON, UBOGON,0x7d4b,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON, UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON, UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON, UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,0x83b9,UBOGON,UBOGON, UBOGON,UBOGON,UBOGON,UBOGON }, { /* ku 18 */ UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON, UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON, UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,0x86cf,UBOGON,UBOGON,UBOGON,UBOGON, UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON, UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON, UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON, UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON, UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,0x8eae,UBOGON,UBOGON,UBOGON,UBOGON, UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON, UBOGON,UBOGON,UBOGON,UBOGON }, { /* ku 19 */ UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,0x96eb, UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON, UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON, UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON, UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON, UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON, UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON, UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON, 0x55b0,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON, UBOGON,UBOGON,0x5840,0x5842 }, { /* ku 1a */ UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON, UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON, UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,0x3701,UBOGON,UBOGON, UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON, UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON, UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON, UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON, UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON, UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON, UBOGON,UBOGON,UBOGON,UBOGON }, { /* ku 1b */ UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON, UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON, UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON, UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON, UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON, UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON, UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON, UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,0x692b,UBOGON,0x6916, UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON, UBOGON,UBOGON,UBOGON,UBOGON }, { /* ku 1c */ 0x691b,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,0x6927,UBOGON, UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON, UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,0x6bf5,UBOGON,UBOGON, UBOGON,UBOGON,UBOGON,UBOGON,0x3d20,UBOGON,UBOGON,UBOGON,0x6e82,UBOGON, UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON, UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,0x3d21,UBOGON,UBOGON, 0x6e7a,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON, UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON, UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON, UBOGON,UBOGON,UBOGON,0x7129 }, { /* ku 1d */ UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON, UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON, UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,0x3eda,UBOGON,UBOGON,UBOGON, UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON, UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON, UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON, UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON, UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON, UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON, UBOGON,UBOGON,UBOGON,UBOGON }, { /* ku 1e */ 0x7cab,UBOGON,0x7cac,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON, UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON, UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON, UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON, UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON, UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON, UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,0x83f7, UBOGON,UBOGON,UBOGON,UBOGON,0x44ea,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON, UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON, UBOGON,UBOGON,UBOGON,UBOGON }, { /* ku 1f */ UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON, UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON, UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON, UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON, UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON, UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON, UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON, UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON, UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,0x4989,UBOGON,UBOGON,UBOGON,UBOGON, UBOGON,UBOGON,UBOGON,0x9596 }, { /* ku 20 */ UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON, UBOGON,UBOGON,0x4ab2,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON, UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON, UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON, UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON, UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON, UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,0x55f1,UBOGON,UBOGON,UBOGON,UBOGON, UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON, UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON, UBOGON,UBOGON,UBOGON,UBOGON }, { /* ku 21 */ UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON, UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON, UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON, 0x5f41,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON, UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON, UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON, UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON, UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON, UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON, UBOGON,UBOGON,UBOGON,UBOGON }, { /* ku 22 */ UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,0x698a,UBOGON,UBOGON, UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON, UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,0x698c,UBOGON,UBOGON, UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,0x6980,UBOGON, 0x697f,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON, UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON, UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON, UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON, UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,0x3dda,UBOGON,UBOGON, UBOGON,UBOGON,UBOGON,UBOGON }, { /* ku 23 */ UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON, UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON, UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,0x3ddb,UBOGON,UBOGON, UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON, 0x3ee2,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON, UBOGON,UBOGON,UBOGON,0x3ee3,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON, UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON, UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON, UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON, UBOGON,UBOGON,UBOGON,UBOGON }, { /* ku 24 */ UBOGON,UBOGON,UBOGON,UBOGON,0x789c,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON, UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON, UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON, UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,0x7b7b,UBOGON,UBOGON,UBOGON, UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON, UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON, UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON, UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON, UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON, UBOGON,UBOGON,UBOGON,UBOGON }, { /* ku 25 */ UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON, UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON, UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON, UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON, UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON, UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,0x47f3,UBOGON,UBOGON,UBOGON,UBOGON, UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON, UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,0x90d2,UBOGON,UBOGON,UBOGON, UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON, 0x95a0,UBOGON,UBOGON,UBOGON }, { /* ku 26 */ UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON, UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,0x4a57,UBOGON,UBOGON, UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON, UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON, UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON, UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,0x51a9, UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON, UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON, UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON, UBOGON,UBOGON,UBOGON,UBOGON }, { /* ku 27 */ UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON, UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON, UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON, UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON, UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON, UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON, UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON, UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON, UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON, UBOGON,UBOGON,UBOGON,UBOGON }, { /* ku 28 */ UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON, UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON, UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON, UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON, UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,0x3bbc, UBOGON,UBOGON,0x3ba4,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON, UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON, UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON, UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON, UBOGON,UBOGON,UBOGON,UBOGON }, { /* ku 29 */ UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON, UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON, UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON, UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON, UBOGON,UBOGON,0x7195,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON, UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,0x3de8,UBOGON,UBOGON,UBOGON,UBOGON, UBOGON,UBOGON,0x7198,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON, UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON, UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,0x7478,UBOGON,UBOGON,UBOGON,UBOGON, UBOGON,UBOGON,UBOGON,UBOGON }, { /* ku 2a */ UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON, UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON, UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON, 0x78b9,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON, UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON, UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON, UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,0x7a33,UBOGON,UBOGON, UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON, UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON, UBOGON,UBOGON,UBOGON,UBOGON }, { /* ku 2b */ UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,0x7cc0,UBOGON,UBOGON,UBOGON, 0x7cc1,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON, UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON, UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON, UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON, UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON, UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON, UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON, UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON, UBOGON,UBOGON,UBOGON,UBOGON }, { /* ku 2c */ UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON, UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,0x8744,UBOGON, UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON, UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON, UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON, UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON, UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON, 0x4886,UBOGON,UBOGON,UBOGON,0x9064,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON, UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON, UBOGON,UBOGON,UBOGON,UBOGON }, { /* ku 2d */ UBOGON,0x9277,UBOGON,UBOGON,UBOGON,UBOGON,0x92af,UBOGON,UBOGON,UBOGON, UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON, UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON, UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON, UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON, UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON, UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON, UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON, UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON, UBOGON,UBOGON,UBOGON,UBOGON }, { /* ku 2e */ UBOGON,UBOGON,UBOGON,UBOGON,0x366d,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON, UBOGON,UBOGON,UBOGON,0x366e,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON, UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON, UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON, UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON, UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON, UBOGON,0x5e64,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON, UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON, UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON, UBOGON,UBOGON,UBOGON,UBOGON }, { /* ku 2f */ UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON, UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON, UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON, UBOGON,UBOGON,UBOGON,0x6a2b,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON, UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON, UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON, UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON, UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON, UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,0x6f46,UBOGON, UBOGON,UBOGON,0x6f9a,UBOGON }, { /* ku 30 */ UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON, UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON, UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON, UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON, UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,0x3f53,UBOGON,UBOGON,UBOGON,UBOGON, UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON, UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON, UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON, UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON, UBOGON,UBOGON,UBOGON,UBOGON }, { /* ku 31 */ UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON, UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON, UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON, UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON, UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON, UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON, UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,0x4526,UBOGON, UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON, UBOGON,UBOGON,0x4527,UBOGON,UBOGON,0x4528,UBOGON,UBOGON,UBOGON,UBOGON, UBOGON,UBOGON,UBOGON,UBOGON }, { /* ku 32 */ UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON, UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON, UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON, UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON, UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON, UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON, UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON, UBOGON,UBOGON,UBOGON,UBOGON,0x92f2,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON, UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON, UBOGON,UBOGON,UBOGON,UBOGON }, { /* ku 33 */ UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON, UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON, UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,0x9b79, UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON, UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON, UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON, 0x567a,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON, UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON, UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON, UBOGON,UBOGON,UBOGON,UBOGON }, { /* ku 34 */ UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,0x372c, UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON, UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON, UBOGON,UBOGON,UBOGON,UBOGON,0x5f5c,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON, UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON, UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON, UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,0x65d9,UBOGON,UBOGON, UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON, UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON, 0x6a72,UBOGON,UBOGON,UBOGON }, { /* ku 35 */ UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,0x6a78,UBOGON, UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON, UBOGON,UBOGON,UBOGON,UBOGON,0x6b5a,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON, UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON, UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON, UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON, UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON, UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON, UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,0x3efb, UBOGON,UBOGON,UBOGON,UBOGON }, { /* ku 36 */ UBOGON,0x3efc,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON, UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON, UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON, UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON, UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON, UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON, UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON, UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON, UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON, UBOGON,UBOGON,UBOGON,UBOGON }, { /* ku 37 */ UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON, UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON, UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON, UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON, UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON, UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON, UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON, UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON, UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON, UBOGON,UBOGON,UBOGON,UBOGON }, { /* ku 38 */ UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON, UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,0x8ebe,UBOGON, UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON, UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,0x933b, UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON, UBOGON,UBOGON,0x9340,UBOGON,UBOGON,UBOGON,0x933a,UBOGON,UBOGON,UBOGON, UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON, UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON, UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON, UBOGON,UBOGON,UBOGON,UBOGON }, { /* ku 39 */ UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON, UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON, UBOGON,UBOGON,UBOGON,0x9b96,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON, UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON, UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON, UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON, UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON, UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON, UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON, UBOGON,UBOGON,UBOGON,UBOGON }, { /* ku 3a */ UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,0x39a0,UBOGON, UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON, UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON, UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON, UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON, UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON, UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON, UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON, UBOGON,UBOGON,0x71f5,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON, UBOGON,UBOGON,UBOGON,UBOGON }, { /* ku 3b */ UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON, UBOGON,UBOGON,0x3f01,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON, UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON, UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON, UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON, UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,0x7a50,UBOGON,UBOGON,UBOGON, UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON, UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON, UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON, UBOGON,UBOGON,UBOGON,UBOGON }, { /* ku 3c */ UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON, UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON, UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON, UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON, UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON, UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON, UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON, UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON, UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,0x481a,UBOGON,UBOGON, UBOGON,UBOGON,UBOGON,UBOGON }, { /* ku 3d */ UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON, UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON, UBOGON,UBOGON,UBOGON,UBOGON,0x9387,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON, UBOGON,UBOGON,0x9385,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON, UBOGON,UBOGON,UBOGON,0x493c,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON, UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON, UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON, UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON, UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,0x9bb1,UBOGON,UBOGON,UBOGON,UBOGON, UBOGON,UBOGON,UBOGON,UBOGON }, { /* ku 3e */ UBOGON,UBOGON,UBOGON,0x9d47,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON, UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON, UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON, UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON, UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON, UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON, UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON, UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON, UBOGON,UBOGON,0x3a6b,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON, UBOGON,UBOGON,UBOGON,UBOGON }, { /* ku 3f */ UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON, UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON, UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON, UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON, UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON, UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON, UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON, UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON, UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON, UBOGON,UBOGON,UBOGON,UBOGON }, { /* ku 40 */ UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON, UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON, UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON, UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON, UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,0x455c,UBOGON,UBOGON,UBOGON,UBOGON, UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON, UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON, UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON, UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,0x4787, UBOGON,UBOGON,UBOGON,UBOGON }, { /* ku 41 */ UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON, UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,0x93b9,UBOGON, UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON, UBOGON,UBOGON,UBOGON,UBOGON,0x93bf,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON, UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON, UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON, UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON, UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON, UBOGON,0x9bcf,UBOGON,UBOGON,UBOGON,UBOGON,0x9d64,UBOGON,UBOGON,UBOGON, UBOGON,0x9ebf,UBOGON,UBOGON }, { /* ku 42 */ UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON, UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON, UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON, UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON, UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON, 0x3c07,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON, UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON, UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON, UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,0x3f05,UBOGON,UBOGON, UBOGON,UBOGON,UBOGON,UBOGON }, { /* ku 43 */ UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON, UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON, UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON, UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON, UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON, UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON, UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON, UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,0x45f9,UBOGON,UBOGON, UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,0x89b8,UBOGON,UBOGON,UBOGON, UBOGON,UBOGON,UBOGON,UBOGON }, { /* ku 44 */ UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON, UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,0x4953, UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON, UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON, UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON, UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON, UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON, UBOGON,UBOGON,UBOGON,UBOGON,0x9bf3,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON, UBOGON,0x4c69,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON, UBOGON,UBOGON,UBOGON,UBOGON }, { /* ku 45 */ UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON, UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON, UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,0x3c12, UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON, UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON, UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON, UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON, 0x7c4f,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON, UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON, UBOGON,UBOGON,UBOGON,UBOGON }, { /* ku 46 */ UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON, UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON, UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON, UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON, UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON, UBOGON,UBOGON,UBOGON,UBOGON,0x9425,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON, UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON, UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON, UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON, UBOGON,UBOGON,UBOGON,UBOGON }, { /* ku 47 */ UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON, UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON, UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON, UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON, UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON, UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON, UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON, UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON, UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON, UBOGON,UBOGON,UBOGON,UBOGON }, { /* ku 48 */ UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON, UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON, UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON, UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON, UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON, 0x4878,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON, UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON, UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON, UBOGON,0x95e6,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON, UBOGON,UBOGON,UBOGON,UBOGON }, { /* ku 49 */ UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,0x9c2f, UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON, UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON, UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON, UBOGON,UBOGON,UBOGON,0x6b0c,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON, UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON, UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON, UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON, UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON, UBOGON,UBOGON,UBOGON,UBOGON }, { /* ku 4a */ UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON, UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON, UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,0x9c47, 0x4c88,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON, UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON, UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON, UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,0x7936, UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON, UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON, UBOGON,UBOGON,UBOGON,UBOGON }, { /* ku 4b */ UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON, UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON, UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON, UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON, UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,0x6b15,UBOGON, UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON, UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON, UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON, UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON, UBOGON,UBOGON,UBOGON,UBOGON }, { /* ku 4c */ UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON, UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON, UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON, UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON, UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON, UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON, UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON, UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,0x4584,UBOGON,UBOGON,UBOGON,UBOGON, UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON, UBOGON,UBOGON,UBOGON,UBOGON }, { /* ku 4d */ UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON, UBOGON,UBOGON,UBOGON,0x53b5,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON, UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON, UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON, UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON, UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON, UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON, UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON, UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON, UBOGON,UBOGON,UBOGON,UBOGON } }; #endif #endif alpine-2.10+dfsg/imap/src/charset/jis_0208.c0000600000175000017500000017543111512502123022116 0ustar paulproteuspaulproteus/* ======================================================================== * Copyright 1988-2006 University of Washington * * Licensed under the Apache License, Version 2.0 (the "License"); * you may not use this file except in compliance with the License. * You may obtain a copy of the License at * * http://www.apache.org/licenses/LICENSE-2.0 * * * ======================================================================== */ /* * Program: JIS X0208 conversion table * * Author: Mark Crispin * Networks and Distributed Computing * Computing & Communications * University of Washington * Administration Building, AG-44 * Seattle, WA 98195 * Internet: MRC@CAC.Washington.EDU * * Date: 3 July 1997 * Last Edited: 30 August 2006 */ /* JIS X0208 is the industrial standard of Japan. */ #define BASE_JIS0208_KU 0x21 #define BASE_JIS0208_TEN 0x21 #define MAX_JIS0208_KU 84 #define MAX_JIS0208_TEN 94 #define SJISTOJIS(c,c1) \ c = ((c - ((c < 0xa0) ? 0x70 : 0xb0)) << 1); \ if (c1 < 0x9f) { \ c--; \ c1 -= 0x1f + (c1 > 0x7f); \ } \ else c1 -= 0x7e; #define JISTOUNICODE(c,c1,ku,ten) \ ((((ku = (c & 0x7f) - BASE_JIS0208_KU) < MAX_JIS0208_KU) && \ ((ten = (c1 & 0x7f) - BASE_JIS0208_TEN) < MAX_JIS0208_TEN)) ? \ jis0208tab[ku][ten] : UBOGON) static const unsigned short jis0208tab[MAX_JIS0208_KU][MAX_JIS0208_TEN] = { { /* ku 01 */ 0x3000,0x3001,0x3002,0xff0c,0xff0e,0x30fb,0xff1a,0xff1b,0xff1f,0xff01, 0x309b,0x309c,0x00b4,0xff40,0x00a8,0xff3e,0xffe3,0xff3f,0x30fd,0x30fe, 0x309d,0x309e,0x3003,0x4edd,0x3005,0x3006,0x3007,0x30fc,0x2015,0x2010, /* Fullwidth/halfwidth correction: * JIS0208.TXT shows 01/32 as U+005C instead of U+FF3C. * * AOL suggests that 01/33 should be U+FF5E instead of U+301C and * 01/34 should be U+2225 instead of U+2016. * I disagree; 01/33 is JIS punctuation (not a tilde); and 01/34 is * double vertical line. */ 0xff0f,0xff3c,0x301c,0x2016,0xff5c,0x2026,0x2025,0x2018,0x2019,0x201c, 0x201d,0xff08,0xff09,0x3014,0x3015,0xff3b,0xff3d,0xff5b,0xff5d,0x3008, 0x3009,0x300a,0x300b,0x300c,0x300d,0x300e,0x300f,0x3010,0x3011,0xff0b, /* Fullwidth/halfwidth correction: * JIS0208.TXT 01/61 has U+2212 instead of U+FF0D. */ 0xff0d,0x00b1,0x00d7,0x00f7,0xff1d,0x2260,0xff1c,0xff1e,0x2266,0x2267, 0x221e,0x2234,0x2642,0x2640,0x00b0,0x2032,0x2033,0x2103,0xffe5,0xff04, /* Fullwidth/halfwidth correction: * JIS 0208 shows 01/81 as U+00A2 instead of U+FFE0, and * 01/82 as U+00A3 instead of U+FFE1. */ 0xffe0,0xffe1,0xff05,0xff03,0xff06,0xff0a,0xff20,0x00a7,0x2606,0x2605, 0x25cb,0x25cf,0x25ce,0x25c7 }, { /* ku 02 */ 0x25c6,0x25a1,0x25a0,0x25b3,0x25b2,0x25bd,0x25bc,0x203b,0x3012,0x2192, 0x2190,0x2191,0x2193,0x3013,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON, UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,0x2208,0x220b,0x2286,0x2287,0x2282, 0x2283,0x222a,0x2229,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON, /* Fullwidth/halfwidth correction: * JIS0208.TXT shows 02/44 as U+00AC instead of U+FFE2. */ UBOGON,0x2227,0x2228,0xffe2,0x21d2,0x21d4,0x2200,0x2203,UBOGON,UBOGON, UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,0x2220, 0x22a5,0x2312,0x2202,0x2207,0x2261,0x2252,0x226a,0x226b,0x221a,0x223d, 0x221d,0x2235,0x222b,0x222c,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON, UBOGON,0x212b,0x2030,0x266f,0x266d,0x266a,0x2020,0x2021,0x00b6,UBOGON, UBOGON,UBOGON,UBOGON,0x25ef }, { /* ku 03 */ UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON, UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,0xff10,0xff11,0xff12,0xff13,0xff14, 0xff15,0xff16,0xff17,0xff18,0xff19,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON, UBOGON,UBOGON,0xff21,0xff22,0xff23,0xff24,0xff25,0xff26,0xff27,0xff28, 0xff29,0xff2a,0xff2b,0xff2c,0xff2d,0xff2e,0xff2f,0xff30,0xff31,0xff32, 0xff33,0xff34,0xff35,0xff36,0xff37,0xff38,0xff39,0xff3a,UBOGON,UBOGON, UBOGON,UBOGON,UBOGON,UBOGON,0xff41,0xff42,0xff43,0xff44,0xff45,0xff46, 0xff47,0xff48,0xff49,0xff4a,0xff4b,0xff4c,0xff4d,0xff4e,0xff4f,0xff50, 0xff51,0xff52,0xff53,0xff54,0xff55,0xff56,0xff57,0xff58,0xff59,0xff5a, UBOGON,UBOGON,UBOGON,UBOGON }, { /* ku 04 */ 0x3041,0x3042,0x3043,0x3044,0x3045,0x3046,0x3047,0x3048,0x3049,0x304a, 0x304b,0x304c,0x304d,0x304e,0x304f,0x3050,0x3051,0x3052,0x3053,0x3054, 0x3055,0x3056,0x3057,0x3058,0x3059,0x305a,0x305b,0x305c,0x305d,0x305e, 0x305f,0x3060,0x3061,0x3062,0x3063,0x3064,0x3065,0x3066,0x3067,0x3068, 0x3069,0x306a,0x306b,0x306c,0x306d,0x306e,0x306f,0x3070,0x3071,0x3072, 0x3073,0x3074,0x3075,0x3076,0x3077,0x3078,0x3079,0x307a,0x307b,0x307c, 0x307d,0x307e,0x307f,0x3080,0x3081,0x3082,0x3083,0x3084,0x3085,0x3086, 0x3087,0x3088,0x3089,0x308a,0x308b,0x308c,0x308d,0x308e,0x308f,0x3090, 0x3091,0x3092,0x3093,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON, UBOGON,UBOGON,UBOGON,UBOGON }, { /* ku 05 */ 0x30a1,0x30a2,0x30a3,0x30a4,0x30a5,0x30a6,0x30a7,0x30a8,0x30a9,0x30aa, 0x30ab,0x30ac,0x30ad,0x30ae,0x30af,0x30b0,0x30b1,0x30b2,0x30b3,0x30b4, 0x30b5,0x30b6,0x30b7,0x30b8,0x30b9,0x30ba,0x30bb,0x30bc,0x30bd,0x30be, 0x30bf,0x30c0,0x30c1,0x30c2,0x30c3,0x30c4,0x30c5,0x30c6,0x30c7,0x30c8, 0x30c9,0x30ca,0x30cb,0x30cc,0x30cd,0x30ce,0x30cf,0x30d0,0x30d1,0x30d2, 0x30d3,0x30d4,0x30d5,0x30d6,0x30d7,0x30d8,0x30d9,0x30da,0x30db,0x30dc, 0x30dd,0x30de,0x30df,0x30e0,0x30e1,0x30e2,0x30e3,0x30e4,0x30e5,0x30e6, 0x30e7,0x30e8,0x30e9,0x30ea,0x30eb,0x30ec,0x30ed,0x30ee,0x30ef,0x30f0, 0x30f1,0x30f2,0x30f3,0x30f4,0x30f5,0x30f6,UBOGON,UBOGON,UBOGON,UBOGON, UBOGON,UBOGON,UBOGON,UBOGON }, { /* ku 06 */ 0x0391,0x0392,0x0393,0x0394,0x0395,0x0396,0x0397,0x0398,0x0399,0x039a, 0x039b,0x039c,0x039d,0x039e,0x039f,0x03a0,0x03a1,0x03a3,0x03a4,0x03a5, 0x03a6,0x03a7,0x03a8,0x03a9,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON, UBOGON,UBOGON,0x03b1,0x03b2,0x03b3,0x03b4,0x03b5,0x03b6,0x03b7,0x03b8, 0x03b9,0x03ba,0x03bb,0x03bc,0x03bd,0x03be,0x03bf,0x03c0,0x03c1,0x03c3, 0x03c4,0x03c5,0x03c6,0x03c7,0x03c8,0x03c9,UBOGON,UBOGON,UBOGON,UBOGON, UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON, UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON, UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON, UBOGON,UBOGON,UBOGON,UBOGON }, { /* ku 07 */ 0x0410,0x0411,0x0412,0x0413,0x0414,0x0415,0x0401,0x0416,0x0417,0x0418, 0x0419,0x041a,0x041b,0x041c,0x041d,0x041e,0x041f,0x0420,0x0421,0x0422, 0x0423,0x0424,0x0425,0x0426,0x0427,0x0428,0x0429,0x042a,0x042b,0x042c, 0x042d,0x042e,0x042f,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON, UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,0x0430,0x0431, 0x0432,0x0433,0x0434,0x0435,0x0451,0x0436,0x0437,0x0438,0x0439,0x043a, 0x043b,0x043c,0x043d,0x043e,0x043f,0x0440,0x0441,0x0442,0x0443,0x0444, 0x0445,0x0446,0x0447,0x0448,0x0449,0x044a,0x044b,0x044c,0x044d,0x044e, 0x044f,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON, UBOGON,UBOGON,UBOGON,UBOGON }, { /* ku 08 */ 0x2500,0x2502,0x250c,0x2510,0x2518,0x2514,0x251c,0x252c,0x2524,0x2534, 0x253c,0x2501,0x2503,0x250f,0x2513,0x251b,0x2517,0x2523,0x2533,0x252b, 0x253b,0x254b,0x2520,0x252f,0x2528,0x2537,0x253f,0x251d,0x2530,0x2525, 0x2538,0x2542,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON, UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON, UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON, UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON, UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON, UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON, UBOGON,UBOGON,UBOGON,UBOGON }, { /* ku 09 */ UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON, UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON, UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON, UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON, UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON, UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON, UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON, UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON, UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON, UBOGON,UBOGON,UBOGON,UBOGON }, { /* ku 0a */ UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON, UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON, UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON, UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON, UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON, UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON, UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON, UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON, UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON, UBOGON,UBOGON,UBOGON,UBOGON }, { /* ku 0b */ UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON, UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON, UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON, UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON, UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON, UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON, UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON, UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON, UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON, UBOGON,UBOGON,UBOGON,UBOGON }, { /* ku 0c */ UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON, UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON, UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON, UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON, UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON, UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON, UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON, UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON, UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON, UBOGON,UBOGON,UBOGON,UBOGON }, { /* ku 0d */ #if 0 UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON, UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON, UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON, UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON, UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON, UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON, UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON, UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON, UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON, UBOGON,UBOGON,UBOGON,UBOGON #else /* additional mappings suggested by AOL */ 0x2460,0x2461,0x2462,0x2463,0x2464,0x2465,0x2466,0x2467,0x2468,0x2469, 0x246a,0x246b,0x246c,0x246d,0x246e,0x246f,0x2470,0x2471,0x2472,0x2473, 0x2160,0x2161,0x2162,0x2163,0x2164,0x2165,0x2166,0x2167,0x2168,0x2169, UBOGON,0x3349,0x3314,0x3322,0x334d,0x3318,0x3327,0x3303,0x3336,0x3351, 0x3357,0x330d,0x3326,0x3323,0x332b,0x334a,0x333b,0x339c,0x339d,0x339e, 0x338e,0x338f,0x33c4,0x33a1,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON, UBOGON,UBOGON,0x337b,0x301d,0x301f,0x2116,0x33cd,0x2121,0x32a4,0x32a5, 0x32a6,0x32a7,0x32a8,0x3231,0x3232,0x3239,0x337e,0x337d,0x337c,UBOGON, UBOGON,UBOGON,0x222e,0x2211,UBOGON,UBOGON,UBOGON,0x221f,0x22bf,UBOGON, UBOGON,UBOGON,UBOGON,UBOGON #endif }, { /* ku 0e */ UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON, UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON, UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON, UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON, UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON, UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON, UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON, UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON, UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON, UBOGON,UBOGON,UBOGON,UBOGON }, { /* ku 0f */ UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON, UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON, UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON, UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON, UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON, UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON, UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON, UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON, UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON, UBOGON,UBOGON,UBOGON,UBOGON }, { /* ku 10 */ 0x4e9c,0x5516,0x5a03,0x963f,0x54c0,0x611b,0x6328,0x59f6,0x9022,0x8475, 0x831c,0x7a50,0x60aa,0x63e1,0x6e25,0x65ed,0x8466,0x82a6,0x9bf5,0x6893, 0x5727,0x65a1,0x6271,0x5b9b,0x59d0,0x867b,0x98f4,0x7d62,0x7dbe,0x9b8e, 0x6216,0x7c9f,0x88b7,0x5b89,0x5eb5,0x6309,0x6697,0x6848,0x95c7,0x978d, 0x674f,0x4ee5,0x4f0a,0x4f4d,0x4f9d,0x5049,0x56f2,0x5937,0x59d4,0x5a01, 0x5c09,0x60df,0x610f,0x6170,0x6613,0x6905,0x70ba,0x754f,0x7570,0x79fb, 0x7dad,0x7def,0x80c3,0x840e,0x8863,0x8b02,0x9055,0x907a,0x533b,0x4e95, 0x4ea5,0x57df,0x80b2,0x90c1,0x78ef,0x4e00,0x58f1,0x6ea2,0x9038,0x7a32, 0x8328,0x828b,0x9c2f,0x5141,0x5370,0x54bd,0x54e1,0x56e0,0x59fb,0x5f15, 0x98f2,0x6deb,0x80e4,0x852d }, { /* ku 11 */ 0x9662,0x9670,0x96a0,0x97fb,0x540b,0x53f3,0x5b87,0x70cf,0x7fbd,0x8fc2, 0x96e8,0x536f,0x9d5c,0x7aba,0x4e11,0x7893,0x81fc,0x6e26,0x5618,0x5504, 0x6b1d,0x851a,0x9c3b,0x59e5,0x53a9,0x6d66,0x74dc,0x958f,0x5642,0x4e91, 0x904b,0x96f2,0x834f,0x990c,0x53e1,0x55b6,0x5b30,0x5f71,0x6620,0x66f3, 0x6804,0x6c38,0x6cf3,0x6d29,0x745b,0x76c8,0x7a4e,0x9834,0x82f1,0x885b, 0x8a60,0x92ed,0x6db2,0x75ab,0x76ca,0x99c5,0x60a6,0x8b01,0x8d8a,0x95b2, 0x698e,0x53ad,0x5186,0x5712,0x5830,0x5944,0x5bb4,0x5ef6,0x6028,0x63a9, 0x63f4,0x6cbf,0x6f14,0x708e,0x7114,0x7159,0x71d5,0x733f,0x7e01,0x8276, 0x82d1,0x8597,0x9060,0x925b,0x9d1b,0x5869,0x65bc,0x6c5a,0x7525,0x51f9, 0x592e,0x5965,0x5f80,0x5fdc }, { /* ku 12 */ 0x62bc,0x65fa,0x6a2a,0x6b27,0x6bb4,0x738b,0x7fc1,0x8956,0x9d2c,0x9d0e, 0x9ec4,0x5ca1,0x6c96,0x837b,0x5104,0x5c4b,0x61b6,0x81c6,0x6876,0x7261, 0x4e59,0x4ffa,0x5378,0x6069,0x6e29,0x7a4f,0x97f3,0x4e0b,0x5316,0x4eee, 0x4f55,0x4f3d,0x4fa1,0x4f73,0x52a0,0x53ef,0x5609,0x590f,0x5ac1,0x5bb6, 0x5be1,0x79d1,0x6687,0x679c,0x67b6,0x6b4c,0x6cb3,0x706b,0x73c2,0x798d, 0x79be,0x7a3c,0x7b87,0x82b1,0x82db,0x8304,0x8377,0x83ef,0x83d3,0x8766, 0x8ab2,0x5629,0x8ca8,0x8fe6,0x904e,0x971e,0x868a,0x4fc4,0x5ce8,0x6211, 0x7259,0x753b,0x81e5,0x82bd,0x86fe,0x8cc0,0x96c5,0x9913,0x99d5,0x4ecb, 0x4f1a,0x89e3,0x56de,0x584a,0x58ca,0x5efb,0x5feb,0x602a,0x6094,0x6062, 0x61d0,0x6212,0x62d0,0x6539 }, { /* ku 13 */ 0x9b41,0x6666,0x68b0,0x6d77,0x7070,0x754c,0x7686,0x7d75,0x82a5,0x87f9, 0x958b,0x968e,0x8c9d,0x51f1,0x52be,0x5916,0x54b3,0x5bb3,0x5d16,0x6168, 0x6982,0x6daf,0x788d,0x84cb,0x8857,0x8a72,0x93a7,0x9ab8,0x6d6c,0x99a8, 0x86d9,0x57a3,0x67ff,0x86ce,0x920e,0x5283,0x5687,0x5404,0x5ed3,0x62e1, 0x64b9,0x683c,0x6838,0x6bbb,0x7372,0x78ba,0x7a6b,0x899a,0x89d2,0x8d6b, 0x8f03,0x90ed,0x95a3,0x9694,0x9769,0x5b66,0x5cb3,0x697d,0x984d,0x984e, 0x639b,0x7b20,0x6a2b,0x6a7f,0x68b6,0x9c0d,0x6f5f,0x5272,0x559d,0x6070, 0x62ec,0x6d3b,0x6e07,0x6ed1,0x845b,0x8910,0x8f44,0x4e14,0x9c39,0x53f6, 0x691b,0x6a3a,0x9784,0x682a,0x515c,0x7ac3,0x84b2,0x91dc,0x938c,0x565b, 0x9d28,0x6822,0x8305,0x8431 }, { /* ku 14 */ 0x7ca5,0x5208,0x82c5,0x74e6,0x4e7e,0x4f83,0x51a0,0x5bd2,0x520a,0x52d8, 0x52e7,0x5dfb,0x559a,0x582a,0x59e6,0x5b8c,0x5b98,0x5bdb,0x5e72,0x5e79, 0x60a3,0x611f,0x6163,0x61be,0x63db,0x6562,0x67d1,0x6853,0x68fa,0x6b3e, 0x6b53,0x6c57,0x6f22,0x6f97,0x6f45,0x74b0,0x7518,0x76e3,0x770b,0x7aff, 0x7ba1,0x7c21,0x7de9,0x7f36,0x7ff0,0x809d,0x8266,0x839e,0x89b3,0x8acc, 0x8cab,0x9084,0x9451,0x9593,0x9591,0x95a2,0x9665,0x97d3,0x9928,0x8218, 0x4e38,0x542b,0x5cb8,0x5dcc,0x73a9,0x764c,0x773c,0x5ca9,0x7feb,0x8d0b, 0x96c1,0x9811,0x9854,0x9858,0x4f01,0x4f0e,0x5371,0x559c,0x5668,0x57fa, 0x5947,0x5b09,0x5bc4,0x5c90,0x5e0c,0x5e7e,0x5fcc,0x63ee,0x673a,0x65d7, 0x65e2,0x671f,0x68cb,0x68c4 }, { /* ku 15 */ 0x6a5f,0x5e30,0x6bc5,0x6c17,0x6c7d,0x757f,0x7948,0x5b63,0x7a00,0x7d00, 0x5fbd,0x898f,0x8a18,0x8cb4,0x8d77,0x8ecc,0x8f1d,0x98e2,0x9a0e,0x9b3c, 0x4e80,0x507d,0x5100,0x5993,0x5b9c,0x622f,0x6280,0x64ec,0x6b3a,0x72a0, 0x7591,0x7947,0x7fa9,0x87fb,0x8abc,0x8b70,0x63ac,0x83ca,0x97a0,0x5409, 0x5403,0x55ab,0x6854,0x6a58,0x8a70,0x7827,0x6775,0x9ecd,0x5374,0x5ba2, 0x811a,0x8650,0x9006,0x4e18,0x4e45,0x4ec7,0x4f11,0x53ca,0x5438,0x5bae, 0x5f13,0x6025,0x6551,0x673d,0x6c42,0x6c72,0x6ce3,0x7078,0x7403,0x7a76, 0x7aae,0x7b08,0x7d1a,0x7cfe,0x7d66,0x65e7,0x725b,0x53bb,0x5c45,0x5de8, 0x62d2,0x62e0,0x6319,0x6e20,0x865a,0x8a31,0x8ddd,0x92f8,0x6f01,0x79a6, 0x9b5a,0x4ea8,0x4eab,0x4eac }, { /* ku 16 */ 0x4f9b,0x4fa0,0x50d1,0x5147,0x7af6,0x5171,0x51f6,0x5354,0x5321,0x537f, 0x53eb,0x55ac,0x5883,0x5ce1,0x5f37,0x5f4a,0x602f,0x6050,0x606d,0x631f, 0x6559,0x6a4b,0x6cc1,0x72c2,0x72ed,0x77ef,0x80f8,0x8105,0x8208,0x854e, 0x90f7,0x93e1,0x97ff,0x9957,0x9a5a,0x4ef0,0x51dd,0x5c2d,0x6681,0x696d, 0x5c40,0x66f2,0x6975,0x7389,0x6850,0x7c81,0x50c5,0x52e4,0x5747,0x5dfe, 0x9326,0x65a4,0x6b23,0x6b3d,0x7434,0x7981,0x79bd,0x7b4b,0x7dca,0x82b9, 0x83cc,0x887f,0x895f,0x8b39,0x8fd1,0x91d1,0x541f,0x9280,0x4e5d,0x5036, 0x53e5,0x533a,0x72d7,0x7396,0x77e9,0x82e6,0x8eaf,0x99c6,0x99c8,0x99d2, 0x5177,0x611a,0x865e,0x55b0,0x7a7a,0x5076,0x5bd3,0x9047,0x9685,0x4e32, 0x6adb,0x91e7,0x5c51,0x5c48 }, { /* ku 17 */ 0x6398,0x7a9f,0x6c93,0x9774,0x8f61,0x7aaa,0x718a,0x9688,0x7c82,0x6817, 0x7e70,0x6851,0x936c,0x52f2,0x541b,0x85ab,0x8a13,0x7fa4,0x8ecd,0x90e1, 0x5366,0x8888,0x7941,0x4fc2,0x50be,0x5211,0x5144,0x5553,0x572d,0x73ea, 0x578b,0x5951,0x5f62,0x5f84,0x6075,0x6176,0x6167,0x61a9,0x63b2,0x643a, 0x656c,0x666f,0x6842,0x6e13,0x7566,0x7a3d,0x7cfb,0x7d4c,0x7d99,0x7e4b, 0x7f6b,0x830e,0x834a,0x86cd,0x8a08,0x8a63,0x8b66,0x8efd,0x981a,0x9d8f, 0x82b8,0x8fce,0x9be8,0x5287,0x621f,0x6483,0x6fc0,0x9699,0x6841,0x5091, 0x6b20,0x6c7a,0x6f54,0x7a74,0x7d50,0x8840,0x8a23,0x6708,0x4ef6,0x5039, 0x5026,0x5065,0x517c,0x5238,0x5263,0x55a7,0x570f,0x5805,0x5acc,0x5efa, 0x61b2,0x61f8,0x62f3,0x6372 }, { /* ku 18 */ 0x691c,0x6a29,0x727d,0x72ac,0x732e,0x7814,0x786f,0x7d79,0x770c,0x80a9, 0x898b,0x8b19,0x8ce2,0x8ed2,0x9063,0x9375,0x967a,0x9855,0x9a13,0x9e78, 0x5143,0x539f,0x53b3,0x5e7b,0x5f26,0x6e1b,0x6e90,0x7384,0x73fe,0x7d43, 0x8237,0x8a00,0x8afa,0x9650,0x4e4e,0x500b,0x53e4,0x547c,0x56fa,0x59d1, 0x5b64,0x5df1,0x5eab,0x5f27,0x6238,0x6545,0x67af,0x6e56,0x72d0,0x7cca, 0x88b4,0x80a1,0x80e1,0x83f0,0x864e,0x8a87,0x8de8,0x9237,0x96c7,0x9867, 0x9f13,0x4e94,0x4e92,0x4f0d,0x5348,0x5449,0x543e,0x5a2f,0x5f8c,0x5fa1, 0x609f,0x68a7,0x6a8e,0x745a,0x7881,0x8a9e,0x8aa4,0x8b77,0x9190,0x4e5e, 0x9bc9,0x4ea4,0x4f7c,0x4faf,0x5019,0x5016,0x5149,0x516c,0x529f,0x52b9, 0x52fe,0x539a,0x53e3,0x5411 }, { /* ku 19 */ 0x540e,0x5589,0x5751,0x57a2,0x597d,0x5b54,0x5b5d,0x5b8f,0x5de5,0x5de7, 0x5df7,0x5e78,0x5e83,0x5e9a,0x5eb7,0x5f18,0x6052,0x614c,0x6297,0x62d8, 0x63a7,0x653b,0x6602,0x6643,0x66f4,0x676d,0x6821,0x6897,0x69cb,0x6c5f, 0x6d2a,0x6d69,0x6e2f,0x6e9d,0x7532,0x7687,0x786c,0x7a3f,0x7ce0,0x7d05, 0x7d18,0x7d5e,0x7db1,0x8015,0x8003,0x80af,0x80b1,0x8154,0x818f,0x822a, 0x8352,0x884c,0x8861,0x8b1b,0x8ca2,0x8cfc,0x90ca,0x9175,0x9271,0x783f, 0x92fc,0x95a4,0x964d,0x9805,0x9999,0x9ad8,0x9d3b,0x525b,0x52ab,0x53f7, 0x5408,0x58d5,0x62f7,0x6fe0,0x8c6a,0x8f5f,0x9eb9,0x514b,0x523b,0x544a, 0x56fd,0x7a40,0x9177,0x9d60,0x9ed2,0x7344,0x6f09,0x8170,0x7511,0x5ffd, 0x60da,0x9aa8,0x72db,0x8fbc }, { /* ku 1a */ 0x6b64,0x9803,0x4eca,0x56f0,0x5764,0x58be,0x5a5a,0x6068,0x61c7,0x660f, 0x6606,0x6839,0x68b1,0x6df7,0x75d5,0x7d3a,0x826e,0x9b42,0x4e9b,0x4f50, 0x53c9,0x5506,0x5d6f,0x5de6,0x5dee,0x67fb,0x6c99,0x7473,0x7802,0x8a50, 0x9396,0x88df,0x5750,0x5ea7,0x632b,0x50b5,0x50ac,0x518d,0x6700,0x54c9, 0x585e,0x59bb,0x5bb0,0x5f69,0x624d,0x63a1,0x683d,0x6b73,0x6e08,0x707d, 0x91c7,0x7280,0x7815,0x7826,0x796d,0x658e,0x7d30,0x83dc,0x88c1,0x8f09, 0x969b,0x5264,0x5728,0x6750,0x7f6a,0x8ca1,0x51b4,0x5742,0x962a,0x583a, 0x698a,0x80b4,0x54b2,0x5d0e,0x57fc,0x7895,0x9dfa,0x4f5c,0x524a,0x548b, 0x643e,0x6628,0x6714,0x67f5,0x7a84,0x7b56,0x7d22,0x932f,0x685c,0x9bad, 0x7b39,0x5319,0x518a,0x5237 }, { /* ku 1b */ 0x5bdf,0x62f6,0x64ae,0x64e6,0x672d,0x6bba,0x85a9,0x96d1,0x7690,0x9bd6, 0x634c,0x9306,0x9bab,0x76bf,0x6652,0x4e09,0x5098,0x53c2,0x5c71,0x60e8, 0x6492,0x6563,0x685f,0x71e6,0x73ca,0x7523,0x7b97,0x7e82,0x8695,0x8b83, 0x8cdb,0x9178,0x9910,0x65ac,0x66ab,0x6b8b,0x4ed5,0x4ed4,0x4f3a,0x4f7f, 0x523a,0x53f8,0x53f2,0x55e3,0x56db,0x58eb,0x59cb,0x59c9,0x59ff,0x5b50, 0x5c4d,0x5e02,0x5e2b,0x5fd7,0x601d,0x6307,0x652f,0x5b5c,0x65af,0x65bd, 0x65e8,0x679d,0x6b62,0x6b7b,0x6c0f,0x7345,0x7949,0x79c1,0x7cf8,0x7d19, 0x7d2b,0x80a2,0x8102,0x81f3,0x8996,0x8a5e,0x8a69,0x8a66,0x8a8c,0x8aee, 0x8cc7,0x8cdc,0x96cc,0x98fc,0x6b6f,0x4e8b,0x4f3c,0x4f8d,0x5150,0x5b57, 0x5bfa,0x6148,0x6301,0x6642 }, { /* ku 1c */ 0x6b21,0x6ecb,0x6cbb,0x723e,0x74bd,0x75d4,0x78c1,0x793a,0x800c,0x8033, 0x81ea,0x8494,0x8f9e,0x6c50,0x9e7f,0x5f0f,0x8b58,0x9d2b,0x7afa,0x8ef8, 0x5b8d,0x96eb,0x4e03,0x53f1,0x57f7,0x5931,0x5ac9,0x5ba4,0x6089,0x6e7f, 0x6f06,0x75be,0x8cea,0x5b9f,0x8500,0x7be0,0x5072,0x67f4,0x829d,0x5c61, 0x854a,0x7e1e,0x820e,0x5199,0x5c04,0x6368,0x8d66,0x659c,0x716e,0x793e, 0x7d17,0x8005,0x8b1d,0x8eca,0x906e,0x86c7,0x90aa,0x501f,0x52fa,0x5c3a, 0x6753,0x707c,0x7235,0x914c,0x91c8,0x932b,0x82e5,0x5bc2,0x5f31,0x60f9, 0x4e3b,0x53d6,0x5b88,0x624b,0x6731,0x6b8a,0x72e9,0x73e0,0x7a2e,0x816b, 0x8da3,0x9152,0x9996,0x5112,0x53d7,0x546a,0x5bff,0x6388,0x6a39,0x7dac, 0x9700,0x56da,0x53ce,0x5468 }, { /* ku 1d */ 0x5b97,0x5c31,0x5dde,0x4fee,0x6101,0x62fe,0x6d32,0x79c0,0x79cb,0x7d42, 0x7e4d,0x7fd2,0x81ed,0x821f,0x8490,0x8846,0x8972,0x8b90,0x8e74,0x8f2f, 0x9031,0x914b,0x916c,0x96c6,0x919c,0x4ec0,0x4f4f,0x5145,0x5341,0x5f93, 0x620e,0x67d4,0x6c41,0x6e0b,0x7363,0x7e26,0x91cd,0x9283,0x53d4,0x5919, 0x5bbf,0x6dd1,0x795d,0x7e2e,0x7c9b,0x587e,0x719f,0x51fa,0x8853,0x8ff0, 0x4fca,0x5cfb,0x6625,0x77ac,0x7ae3,0x821c,0x99ff,0x51c6,0x5faa,0x65ec, 0x696f,0x6b89,0x6df3,0x6e96,0x6f64,0x76fe,0x7d14,0x5de1,0x9075,0x9187, 0x9806,0x51e6,0x521d,0x6240,0x6691,0x66d9,0x6e1a,0x5eb6,0x7dd2,0x7f72, 0x66f8,0x85af,0x85f7,0x8af8,0x52a9,0x53d9,0x5973,0x5e8f,0x5f90,0x6055, 0x92e4,0x9664,0x50b7,0x511f }, { /* ku 1e */ 0x52dd,0x5320,0x5347,0x53ec,0x54e8,0x5546,0x5531,0x5617,0x5968,0x59be, 0x5a3c,0x5bb5,0x5c06,0x5c0f,0x5c11,0x5c1a,0x5e84,0x5e8a,0x5ee0,0x5f70, 0x627f,0x6284,0x62db,0x638c,0x6377,0x6607,0x660c,0x662d,0x6676,0x677e, 0x68a2,0x6a1f,0x6a35,0x6cbc,0x6d88,0x6e09,0x6e58,0x713c,0x7126,0x7167, 0x75c7,0x7701,0x785d,0x7901,0x7965,0x79f0,0x7ae0,0x7b11,0x7ca7,0x7d39, 0x8096,0x83d6,0x848b,0x8549,0x885d,0x88f3,0x8a1f,0x8a3c,0x8a54,0x8a73, 0x8c61,0x8cde,0x91a4,0x9266,0x937e,0x9418,0x969c,0x9798,0x4e0a,0x4e08, 0x4e1e,0x4e57,0x5197,0x5270,0x57ce,0x5834,0x58cc,0x5b22,0x5e38,0x60c5, 0x64fe,0x6761,0x6756,0x6d44,0x72b6,0x7573,0x7a63,0x84b8,0x8b72,0x91b8, 0x9320,0x5631,0x57f4,0x98fe }, { /* ku 1f */ 0x62ed,0x690d,0x6b96,0x71ed,0x7e54,0x8077,0x8272,0x89e6,0x98df,0x8755, 0x8fb1,0x5c3b,0x4f38,0x4fe1,0x4fb5,0x5507,0x5a20,0x5bdd,0x5be9,0x5fc3, 0x614e,0x632f,0x65b0,0x664b,0x68ee,0x699b,0x6d78,0x6df1,0x7533,0x75b9, 0x771f,0x795e,0x79e6,0x7d33,0x81e3,0x82af,0x85aa,0x89aa,0x8a3a,0x8eab, 0x8f9b,0x9032,0x91dd,0x9707,0x4eba,0x4ec1,0x5203,0x5875,0x58ec,0x5c0b, 0x751a,0x5c3d,0x814e,0x8a0a,0x8fc5,0x9663,0x976d,0x7b25,0x8acf,0x9808, 0x9162,0x56f3,0x53a8,0x9017,0x5439,0x5782,0x5e25,0x63a8,0x6c34,0x708a, 0x7761,0x7c8b,0x7fe0,0x8870,0x9042,0x9154,0x9310,0x9318,0x968f,0x745e, 0x9ac4,0x5d07,0x5d69,0x6570,0x67a2,0x8da8,0x96db,0x636e,0x6749,0x6919, 0x83c5,0x9817,0x96c0,0x88fe }, { /* ku 20 */ 0x6f84,0x647a,0x5bf8,0x4e16,0x702c,0x755d,0x662f,0x51c4,0x5236,0x52e2, 0x59d3,0x5f81,0x6027,0x6210,0x653f,0x6574,0x661f,0x6674,0x68f2,0x6816, 0x6b63,0x6e05,0x7272,0x751f,0x76db,0x7cbe,0x8056,0x58f0,0x88fd,0x897f, 0x8aa0,0x8a93,0x8acb,0x901d,0x9192,0x9752,0x9759,0x6589,0x7a0e,0x8106, 0x96bb,0x5e2d,0x60dc,0x621a,0x65a5,0x6614,0x6790,0x77f3,0x7a4d,0x7c4d, 0x7e3e,0x810a,0x8cac,0x8d64,0x8de1,0x8e5f,0x78a9,0x5207,0x62d9,0x63a5, 0x6442,0x6298,0x8a2d,0x7a83,0x7bc0,0x8aac,0x96ea,0x7d76,0x820c,0x8749, 0x4ed9,0x5148,0x5343,0x5360,0x5ba3,0x5c02,0x5c16,0x5ddd,0x6226,0x6247, 0x64b0,0x6813,0x6834,0x6cc9,0x6d45,0x6d17,0x67d3,0x6f5c,0x714e,0x717d, 0x65cb,0x7a7f,0x7bad,0x7dda }, { /* ku 21 */ 0x7e4a,0x7fa8,0x817a,0x821b,0x8239,0x85a6,0x8a6e,0x8cce,0x8df5,0x9078, 0x9077,0x92ad,0x9291,0x9583,0x9bae,0x524d,0x5584,0x6f38,0x7136,0x5168, 0x7985,0x7e55,0x81b3,0x7cce,0x564c,0x5851,0x5ca8,0x63aa,0x66fe,0x66fd, 0x695a,0x72d9,0x758f,0x758e,0x790e,0x7956,0x79df,0x7c97,0x7d20,0x7d44, 0x8607,0x8a34,0x963b,0x9061,0x9f20,0x50e7,0x5275,0x53cc,0x53e2,0x5009, 0x55aa,0x58ee,0x594f,0x723d,0x5b8b,0x5c64,0x531d,0x60e3,0x60f3,0x635c, 0x6383,0x633f,0x63bb,0x64cd,0x65e9,0x66f9,0x5de3,0x69cd,0x69fd,0x6f15, 0x71e5,0x4e89,0x75e9,0x76f8,0x7a93,0x7cdf,0x7dcf,0x7d9c,0x8061,0x8349, 0x8358,0x846c,0x84bc,0x85fb,0x88c5,0x8d70,0x9001,0x906d,0x9397,0x971c, 0x9a12,0x50cf,0x5897,0x618e }, { /* ku 22 */ 0x81d3,0x8535,0x8d08,0x9020,0x4fc3,0x5074,0x5247,0x5373,0x606f,0x6349, 0x675f,0x6e2c,0x8db3,0x901f,0x4fd7,0x5c5e,0x8cca,0x65cf,0x7d9a,0x5352, 0x8896,0x5176,0x63c3,0x5b58,0x5b6b,0x5c0a,0x640d,0x6751,0x905c,0x4ed6, 0x591a,0x592a,0x6c70,0x8a51,0x553e,0x5815,0x59a5,0x60f0,0x6253,0x67c1, 0x8235,0x6955,0x9640,0x99c4,0x9a28,0x4f53,0x5806,0x5bfe,0x8010,0x5cb1, 0x5e2f,0x5f85,0x6020,0x614b,0x6234,0x66ff,0x6cf0,0x6ede,0x80ce,0x817f, 0x82d4,0x888b,0x8cb8,0x9000,0x902e,0x968a,0x9edb,0x9bdb,0x4ee3,0x53f0, 0x5927,0x7b2c,0x918d,0x984c,0x9df9,0x6edd,0x7027,0x5353,0x5544,0x5b85, 0x6258,0x629e,0x62d3,0x6ca2,0x6fef,0x7422,0x8a17,0x9438,0x6fc1,0x8afe, 0x8338,0x51e7,0x86f8,0x53ea }, { /* ku 23 */ 0x53e9,0x4f46,0x9054,0x8fb0,0x596a,0x8131,0x5dfd,0x7aea,0x8fbf,0x68da, 0x8c37,0x72f8,0x9c48,0x6a3d,0x8ab0,0x4e39,0x5358,0x5606,0x5766,0x62c5, 0x63a2,0x65e6,0x6b4e,0x6de1,0x6e5b,0x70ad,0x77ed,0x7aef,0x7baa,0x7dbb, 0x803d,0x80c6,0x86cb,0x8a95,0x935b,0x56e3,0x58c7,0x5f3e,0x65ad,0x6696, 0x6a80,0x6bb5,0x7537,0x8ac7,0x5024,0x77e5,0x5730,0x5f1b,0x6065,0x667a, 0x6c60,0x75f4,0x7a1a,0x7f6e,0x81f4,0x8718,0x9045,0x99b3,0x7bc9,0x755c, 0x7af9,0x7b51,0x84c4,0x9010,0x79e9,0x7a92,0x8336,0x5ae1,0x7740,0x4e2d, 0x4ef2,0x5b99,0x5fe0,0x62bd,0x663c,0x67f1,0x6ce8,0x866b,0x8877,0x8a3b, 0x914e,0x92f3,0x99d0,0x6a17,0x7026,0x732a,0x82e7,0x8457,0x8caf,0x4e01, 0x5146,0x51cb,0x558b,0x5bf5 }, { /* ku 24 */ 0x5e16,0x5e33,0x5e81,0x5f14,0x5f35,0x5f6b,0x5fb4,0x61f2,0x6311,0x66a2, 0x671d,0x6f6e,0x7252,0x753a,0x773a,0x8074,0x8139,0x8178,0x8776,0x8abf, 0x8adc,0x8d85,0x8df3,0x929a,0x9577,0x9802,0x9ce5,0x52c5,0x6357,0x76f4, 0x6715,0x6c88,0x73cd,0x8cc3,0x93ae,0x9673,0x6d25,0x589c,0x690e,0x69cc, 0x8ffd,0x939a,0x75db,0x901a,0x585a,0x6802,0x63b4,0x69fb,0x4f43,0x6f2c, 0x67d8,0x8fbb,0x8526,0x7db4,0x9354,0x693f,0x6f70,0x576a,0x58f7,0x5b2c, 0x7d2c,0x722a,0x540a,0x91e3,0x9db4,0x4ead,0x4f4e,0x505c,0x5075,0x5243, 0x8c9e,0x5448,0x5824,0x5b9a,0x5e1d,0x5e95,0x5ead,0x5ef7,0x5f1f,0x608c, 0x62b5,0x633a,0x63d0,0x68af,0x6c40,0x7887,0x798e,0x7a0b,0x7de0,0x8247, 0x8a02,0x8ae6,0x8e44,0x9013 }, { /* ku 25 */ 0x90b8,0x912d,0x91d8,0x9f0e,0x6ce5,0x6458,0x64e2,0x6575,0x6ef4,0x7684, 0x7b1b,0x9069,0x93d1,0x6eba,0x54f2,0x5fb9,0x64a4,0x8f4d,0x8fed,0x9244, 0x5178,0x586b,0x5929,0x5c55,0x5e97,0x6dfb,0x7e8f,0x751c,0x8cbc,0x8ee2, 0x985b,0x70b9,0x4f1d,0x6bbf,0x6fb1,0x7530,0x96fb,0x514e,0x5410,0x5835, 0x5857,0x59ac,0x5c60,0x5f92,0x6597,0x675c,0x6e21,0x767b,0x83df,0x8ced, 0x9014,0x90fd,0x934d,0x7825,0x783a,0x52aa,0x5ea6,0x571f,0x5974,0x6012, 0x5012,0x515a,0x51ac,0x51cd,0x5200,0x5510,0x5854,0x5858,0x5957,0x5b95, 0x5cf6,0x5d8b,0x60bc,0x6295,0x642d,0x6771,0x6843,0x68bc,0x68df,0x76d7, 0x6dd8,0x6e6f,0x6d9b,0x706f,0x71c8,0x5f53,0x75d8,0x7977,0x7b49,0x7b54, 0x7b52,0x7cd6,0x7d71,0x5230 }, { /* ku 26 */ 0x8463,0x8569,0x85e4,0x8a0e,0x8b04,0x8c46,0x8e0f,0x9003,0x900f,0x9419, 0x9676,0x982d,0x9a30,0x95d8,0x50cd,0x52d5,0x540c,0x5802,0x5c0e,0x61a7, 0x649e,0x6d1e,0x77b3,0x7ae5,0x80f4,0x8404,0x9053,0x9285,0x5ce0,0x9d07, 0x533f,0x5f97,0x5fb3,0x6d9c,0x7279,0x7763,0x79bf,0x7be4,0x6bd2,0x72ec, 0x8aad,0x6803,0x6a61,0x51f8,0x7a81,0x6934,0x5c4a,0x9cf6,0x82eb,0x5bc5, 0x9149,0x701e,0x5678,0x5c6f,0x60c7,0x6566,0x6c8c,0x8c5a,0x9041,0x9813, 0x5451,0x66c7,0x920d,0x5948,0x90a3,0x5185,0x4e4d,0x51ea,0x8599,0x8b0e, 0x7058,0x637a,0x934b,0x6962,0x99b4,0x7e04,0x7577,0x5357,0x6960,0x8edf, 0x96e3,0x6c5d,0x4e8c,0x5c3c,0x5f10,0x8fe9,0x5302,0x8cd1,0x8089,0x8679, 0x5eff,0x65e5,0x4e73,0x5165 }, { /* ku 27 */ 0x5982,0x5c3f,0x97ee,0x4efb,0x598a,0x5fcd,0x8a8d,0x6fe1,0x79b0,0x7962, 0x5be7,0x8471,0x732b,0x71b1,0x5e74,0x5ff5,0x637b,0x649a,0x71c3,0x7c98, 0x4e43,0x5efc,0x4e4b,0x57dc,0x56a2,0x60a9,0x6fc3,0x7d0d,0x80fd,0x8133, 0x81bf,0x8fb2,0x8997,0x86a4,0x5df4,0x628a,0x64ad,0x8987,0x6777,0x6ce2, 0x6d3e,0x7436,0x7834,0x5a46,0x7f75,0x82ad,0x99ac,0x4ff3,0x5ec3,0x62dd, 0x6392,0x6557,0x676f,0x76c3,0x724c,0x80cc,0x80ba,0x8f29,0x914d,0x500d, 0x57f9,0x5a92,0x6885,0x6973,0x7164,0x72fd,0x8cb7,0x58f2,0x8ce0,0x966a, 0x9019,0x877f,0x79e4,0x77e7,0x8429,0x4f2f,0x5265,0x535a,0x62cd,0x67cf, 0x6cca,0x767d,0x7b94,0x7c95,0x8236,0x8584,0x8feb,0x66dd,0x6f20,0x7206, 0x7e1b,0x83ab,0x99c1,0x9ea6 }, { /* ku 28 */ 0x51fd,0x7bb1,0x7872,0x7bb8,0x8087,0x7b48,0x6ae8,0x5e61,0x808c,0x7551, 0x7560,0x516b,0x9262,0x6e8c,0x767a,0x9197,0x9aea,0x4f10,0x7f70,0x629c, 0x7b4f,0x95a5,0x9ce9,0x567a,0x5859,0x86e4,0x96bc,0x4f34,0x5224,0x534a, 0x53cd,0x53db,0x5e06,0x642c,0x6591,0x677f,0x6c3e,0x6c4e,0x7248,0x72af, 0x73ed,0x7554,0x7e41,0x822c,0x85e9,0x8ca9,0x7bc4,0x91c6,0x7169,0x9812, 0x98ef,0x633d,0x6669,0x756a,0x76e4,0x78d0,0x8543,0x86ee,0x532a,0x5351, 0x5426,0x5983,0x5e87,0x5f7c,0x60b2,0x6249,0x6279,0x62ab,0x6590,0x6bd4, 0x6ccc,0x75b2,0x76ae,0x7891,0x79d8,0x7dcb,0x7f77,0x80a5,0x88ab,0x8ab9, 0x8cbb,0x907f,0x975e,0x98db,0x6a0b,0x7c38,0x5099,0x5c3e,0x5fae,0x6787, 0x6bd8,0x7435,0x7709,0x7f8e }, { /* ku 29 */ 0x9f3b,0x67ca,0x7a17,0x5339,0x758b,0x9aed,0x5f66,0x819d,0x83f1,0x8098, 0x5f3c,0x5fc5,0x7562,0x7b46,0x903c,0x6867,0x59eb,0x5a9b,0x7d10,0x767e, 0x8b2c,0x4ff5,0x5f6a,0x6a19,0x6c37,0x6f02,0x74e2,0x7968,0x8868,0x8a55, 0x8c79,0x5edf,0x63cf,0x75c5,0x79d2,0x82d7,0x9328,0x92f2,0x849c,0x86ed, 0x9c2d,0x54c1,0x5f6c,0x658c,0x6d5c,0x7015,0x8ca7,0x8cd3,0x983b,0x654f, 0x74f6,0x4e0d,0x4ed8,0x57e0,0x592b,0x5a66,0x5bcc,0x51a8,0x5e03,0x5e9c, 0x6016,0x6276,0x6577,0x65a7,0x666e,0x6d6e,0x7236,0x7b26,0x8150,0x819a, 0x8299,0x8b5c,0x8ca0,0x8ce6,0x8d74,0x961c,0x9644,0x4fae,0x64ab,0x6b66, 0x821e,0x8461,0x856a,0x90e8,0x5c01,0x6953,0x98a8,0x847a,0x8557,0x4f0f, 0x526f,0x5fa9,0x5e45,0x670d }, { /* ku 2a */ 0x798f,0x8179,0x8907,0x8986,0x6df5,0x5f17,0x6255,0x6cb8,0x4ecf,0x7269, 0x9b92,0x5206,0x543b,0x5674,0x58b3,0x61a4,0x626e,0x711a,0x596e,0x7c89, 0x7cde,0x7d1b,0x96f0,0x6587,0x805e,0x4e19,0x4f75,0x5175,0x5840,0x5e63, 0x5e73,0x5f0a,0x67c4,0x4e26,0x853d,0x9589,0x965b,0x7c73,0x9801,0x50fb, 0x58c1,0x7656,0x78a7,0x5225,0x77a5,0x8511,0x7b86,0x504f,0x5909,0x7247, 0x7bc7,0x7de8,0x8fba,0x8fd4,0x904d,0x4fbf,0x52c9,0x5a29,0x5f01,0x97ad, 0x4fdd,0x8217,0x92ea,0x5703,0x6355,0x6b69,0x752b,0x88dc,0x8f14,0x7a42, 0x52df,0x5893,0x6155,0x620a,0x66ae,0x6bcd,0x7c3f,0x83e9,0x5023,0x4ff8, 0x5305,0x5446,0x5831,0x5949,0x5b9d,0x5cf0,0x5cef,0x5d29,0x5e96,0x62b1, 0x6367,0x653e,0x65b9,0x670b }, { /* ku 2b */ 0x6cd5,0x6ce1,0x70f9,0x7832,0x7e2b,0x80de,0x82b3,0x840c,0x84ec,0x8702, 0x8912,0x8a2a,0x8c4a,0x90a6,0x92d2,0x98fd,0x9cf3,0x9d6c,0x4e4f,0x4ea1, 0x508d,0x5256,0x574a,0x59a8,0x5e3d,0x5fd8,0x5fd9,0x623f,0x66b4,0x671b, 0x67d0,0x68d2,0x5192,0x7d21,0x80aa,0x81a8,0x8b00,0x8c8c,0x8cbf,0x927e, 0x9632,0x5420,0x982c,0x5317,0x50d5,0x535c,0x58a8,0x64b2,0x6734,0x7267, 0x7766,0x7a46,0x91e6,0x52c3,0x6ca1,0x6b86,0x5800,0x5e4c,0x5954,0x672c, 0x7ffb,0x51e1,0x76c6,0x6469,0x78e8,0x9b54,0x9ebb,0x57cb,0x59b9,0x6627, 0x679a,0x6bce,0x54e9,0x69d9,0x5e55,0x819c,0x6795,0x9baa,0x67fe,0x9c52, 0x685d,0x4ea6,0x4fe3,0x53c8,0x62b9,0x672b,0x6cab,0x8fc4,0x4fad,0x7e6d, 0x9ebf,0x4e07,0x6162,0x6e80 }, { /* ku 2c */ 0x6f2b,0x8513,0x5473,0x672a,0x9b45,0x5df3,0x7b95,0x5cac,0x5bc6,0x871c, 0x6e4a,0x84d1,0x7a14,0x8108,0x5999,0x7c8d,0x6c11,0x7720,0x52d9,0x5922, 0x7121,0x725f,0x77db,0x9727,0x9d61,0x690b,0x5a7f,0x5a18,0x51a5,0x540d, 0x547d,0x660e,0x76df,0x8ff7,0x9298,0x9cf4,0x59ea,0x725d,0x6ec5,0x514d, 0x68c9,0x7dbf,0x7dec,0x9762,0x9eba,0x6478,0x6a21,0x8302,0x5984,0x5b5f, 0x6bdb,0x731b,0x76f2,0x7db2,0x8017,0x8499,0x5132,0x6728,0x9ed9,0x76ee, 0x6762,0x52ff,0x9905,0x5c24,0x623b,0x7c7e,0x8cb0,0x554f,0x60b6,0x7d0b, 0x9580,0x5301,0x4e5f,0x51b6,0x591c,0x723a,0x8036,0x91ce,0x5f25,0x77e2, 0x5384,0x5f79,0x7d04,0x85ac,0x8a33,0x8e8d,0x9756,0x67f3,0x85ae,0x9453, 0x6109,0x6108,0x6cb9,0x7652 }, { /* ku 2d */ 0x8aed,0x8f38,0x552f,0x4f51,0x512a,0x52c7,0x53cb,0x5ba5,0x5e7d,0x60a0, 0x6182,0x63d6,0x6709,0x67da,0x6e67,0x6d8c,0x7336,0x7337,0x7531,0x7950, 0x88d5,0x8a98,0x904a,0x9091,0x90f5,0x96c4,0x878d,0x5915,0x4e88,0x4f59, 0x4e0e,0x8a89,0x8f3f,0x9810,0x50ad,0x5e7c,0x5996,0x5bb9,0x5eb8,0x63da, 0x63fa,0x64c1,0x66dc,0x694a,0x69d8,0x6d0b,0x6eb6,0x7194,0x7528,0x7aaf, 0x7f8a,0x8000,0x8449,0x84c9,0x8981,0x8b21,0x8e0a,0x9065,0x967d,0x990a, 0x617e,0x6291,0x6b32,0x6c83,0x6d74,0x7fcc,0x7ffc,0x6dc0,0x7f85,0x87ba, 0x88f8,0x6765,0x83b1,0x983c,0x96f7,0x6d1b,0x7d61,0x843d,0x916a,0x4e71, 0x5375,0x5d50,0x6b04,0x6feb,0x85cd,0x862d,0x89a7,0x5229,0x540f,0x5c65, 0x674e,0x68a8,0x7406,0x7483 }, { /* ku 2e */ 0x75e2,0x88cf,0x88e1,0x91cc,0x96e2,0x9678,0x5f8b,0x7387,0x7acb,0x844e, 0x63a0,0x7565,0x5289,0x6d41,0x6e9c,0x7409,0x7559,0x786b,0x7c92,0x9686, 0x7adc,0x9f8d,0x4fb6,0x616e,0x65c5,0x865c,0x4e86,0x4eae,0x50da,0x4e21, 0x51cc,0x5bee,0x6599,0x6881,0x6dbc,0x731f,0x7642,0x77ad,0x7a1c,0x7ce7, 0x826f,0x8ad2,0x907c,0x91cf,0x9675,0x9818,0x529b,0x7dd1,0x502b,0x5398, 0x6797,0x6dcb,0x71d0,0x7433,0x81e8,0x8f2a,0x96a3,0x9c57,0x9e9f,0x7460, 0x5841,0x6d99,0x7d2f,0x985e,0x4ee4,0x4f36,0x4f8b,0x51b7,0x52b1,0x5dba, 0x601c,0x73b2,0x793c,0x82d3,0x9234,0x96b7,0x96f6,0x970a,0x9e97,0x9f62, 0x66a6,0x6b74,0x5217,0x52a3,0x70c8,0x88c2,0x5ec9,0x604b,0x6190,0x6f23, 0x7149,0x7c3e,0x7df4,0x806f }, { /* ku 2f */ 0x84ee,0x9023,0x932c,0x5442,0x9b6f,0x6ad3,0x7089,0x8cc2,0x8def,0x9732, 0x52b4,0x5a41,0x5eca,0x5f04,0x6717,0x697c,0x6994,0x6d6a,0x6f0f,0x7262, 0x72fc,0x7bed,0x8001,0x807e,0x874b,0x90ce,0x516d,0x9e93,0x7984,0x808b, 0x9332,0x8ad6,0x502d,0x548c,0x8a71,0x6b6a,0x8cc4,0x8107,0x60d1,0x67a0, 0x9df2,0x4e99,0x4e98,0x9c10,0x8a6b,0x85c1,0x8568,0x6900,0x6e7e,0x7897, 0x8155,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON, UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON, UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON, UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON, UBOGON,UBOGON,UBOGON,UBOGON }, { /* ku 30 */ 0x5f0c,0x4e10,0x4e15,0x4e2a,0x4e31,0x4e36,0x4e3c,0x4e3f,0x4e42,0x4e56, 0x4e58,0x4e82,0x4e85,0x8c6b,0x4e8a,0x8212,0x5f0d,0x4e8e,0x4e9e,0x4e9f, 0x4ea0,0x4ea2,0x4eb0,0x4eb3,0x4eb6,0x4ece,0x4ecd,0x4ec4,0x4ec6,0x4ec2, 0x4ed7,0x4ede,0x4eed,0x4edf,0x4ef7,0x4f09,0x4f5a,0x4f30,0x4f5b,0x4f5d, 0x4f57,0x4f47,0x4f76,0x4f88,0x4f8f,0x4f98,0x4f7b,0x4f69,0x4f70,0x4f91, 0x4f6f,0x4f86,0x4f96,0x5118,0x4fd4,0x4fdf,0x4fce,0x4fd8,0x4fdb,0x4fd1, 0x4fda,0x4fd0,0x4fe4,0x4fe5,0x501a,0x5028,0x5014,0x502a,0x5025,0x5005, 0x4f1c,0x4ff6,0x5021,0x5029,0x502c,0x4ffe,0x4fef,0x5011,0x5006,0x5043, 0x5047,0x6703,0x5055,0x5050,0x5048,0x505a,0x5056,0x506c,0x5078,0x5080, 0x509a,0x5085,0x50b4,0x50b2 }, { /* ku 31 */ 0x50c9,0x50ca,0x50b3,0x50c2,0x50d6,0x50de,0x50e5,0x50ed,0x50e3,0x50ee, 0x50f9,0x50f5,0x5109,0x5101,0x5102,0x5116,0x5115,0x5114,0x511a,0x5121, 0x513a,0x5137,0x513c,0x513b,0x513f,0x5140,0x5152,0x514c,0x5154,0x5162, 0x7af8,0x5169,0x516a,0x516e,0x5180,0x5182,0x56d8,0x518c,0x5189,0x518f, 0x5191,0x5193,0x5195,0x5196,0x51a4,0x51a6,0x51a2,0x51a9,0x51aa,0x51ab, 0x51b3,0x51b1,0x51b2,0x51b0,0x51b5,0x51bd,0x51c5,0x51c9,0x51db,0x51e0, 0x8655,0x51e9,0x51ed,0x51f0,0x51f5,0x51fe,0x5204,0x520b,0x5214,0x520e, 0x5227,0x522a,0x522e,0x5233,0x5239,0x524f,0x5244,0x524b,0x524c,0x525e, 0x5254,0x526a,0x5274,0x5269,0x5273,0x527f,0x527d,0x528d,0x5294,0x5292, 0x5271,0x5288,0x5291,0x8fa8 }, { /* ku 32 */ 0x8fa7,0x52ac,0x52ad,0x52bc,0x52b5,0x52c1,0x52cd,0x52d7,0x52de,0x52e3, 0x52e6,0x98ed,0x52e0,0x52f3,0x52f5,0x52f8,0x52f9,0x5306,0x5308,0x7538, 0x530d,0x5310,0x530f,0x5315,0x531a,0x5323,0x532f,0x5331,0x5333,0x5338, 0x5340,0x5346,0x5345,0x4e17,0x5349,0x534d,0x51d6,0x535e,0x5369,0x536e, 0x5918,0x537b,0x5377,0x5382,0x5396,0x53a0,0x53a6,0x53a5,0x53ae,0x53b0, 0x53b6,0x53c3,0x7c12,0x96d9,0x53df,0x66fc,0x71ee,0x53ee,0x53e8,0x53ed, 0x53fa,0x5401,0x543d,0x5440,0x542c,0x542d,0x543c,0x542e,0x5436,0x5429, 0x541d,0x544e,0x548f,0x5475,0x548e,0x545f,0x5471,0x5477,0x5470,0x5492, 0x547b,0x5480,0x5476,0x5484,0x5490,0x5486,0x54c7,0x54a2,0x54b8,0x54a5, 0x54ac,0x54c4,0x54c8,0x54a8 }, { /* ku 33 */ 0x54ab,0x54c2,0x54a4,0x54be,0x54bc,0x54d8,0x54e5,0x54e6,0x550f,0x5514, 0x54fd,0x54ee,0x54ed,0x54fa,0x54e2,0x5539,0x5540,0x5563,0x554c,0x552e, 0x555c,0x5545,0x5556,0x5557,0x5538,0x5533,0x555d,0x5599,0x5580,0x54af, 0x558a,0x559f,0x557b,0x557e,0x5598,0x559e,0x55ae,0x557c,0x5583,0x55a9, 0x5587,0x55a8,0x55da,0x55c5,0x55df,0x55c4,0x55dc,0x55e4,0x55d4,0x5614, 0x55f7,0x5616,0x55fe,0x55fd,0x561b,0x55f9,0x564e,0x5650,0x71df,0x5634, 0x5636,0x5632,0x5638,0x566b,0x5664,0x562f,0x566c,0x566a,0x5686,0x5680, 0x568a,0x56a0,0x5694,0x568f,0x56a5,0x56ae,0x56b6,0x56b4,0x56c2,0x56bc, 0x56c1,0x56c3,0x56c0,0x56c8,0x56ce,0x56d1,0x56d3,0x56d7,0x56ee,0x56f9, 0x5700,0x56ff,0x5704,0x5709 }, { /* ku 34 */ 0x5708,0x570b,0x570d,0x5713,0x5718,0x5716,0x55c7,0x571c,0x5726,0x5737, 0x5738,0x574e,0x573b,0x5740,0x574f,0x5769,0x57c0,0x5788,0x5761,0x577f, 0x5789,0x5793,0x57a0,0x57b3,0x57a4,0x57aa,0x57b0,0x57c3,0x57c6,0x57d4, 0x57d2,0x57d3,0x580a,0x57d6,0x57e3,0x580b,0x5819,0x581d,0x5872,0x5821, 0x5862,0x584b,0x5870,0x6bc0,0x5852,0x583d,0x5879,0x5885,0x58b9,0x589f, 0x58ab,0x58ba,0x58de,0x58bb,0x58b8,0x58ae,0x58c5,0x58d3,0x58d1,0x58d7, 0x58d9,0x58d8,0x58e5,0x58dc,0x58e4,0x58df,0x58ef,0x58fa,0x58f9,0x58fb, 0x58fc,0x58fd,0x5902,0x590a,0x5910,0x591b,0x68a6,0x5925,0x592c,0x592d, 0x5932,0x5938,0x593e,0x7ad2,0x5955,0x5950,0x594e,0x595a,0x5958,0x5962, 0x5960,0x5967,0x596c,0x5969 }, { /* ku 35 */ 0x5978,0x5981,0x599d,0x4f5e,0x4fab,0x59a3,0x59b2,0x59c6,0x59e8,0x59dc, 0x598d,0x59d9,0x59da,0x5a25,0x5a1f,0x5a11,0x5a1c,0x5a09,0x5a1a,0x5a40, 0x5a6c,0x5a49,0x5a35,0x5a36,0x5a62,0x5a6a,0x5a9a,0x5abc,0x5abe,0x5acb, 0x5ac2,0x5abd,0x5ae3,0x5ad7,0x5ae6,0x5ae9,0x5ad6,0x5afa,0x5afb,0x5b0c, 0x5b0b,0x5b16,0x5b32,0x5ad0,0x5b2a,0x5b36,0x5b3e,0x5b43,0x5b45,0x5b40, 0x5b51,0x5b55,0x5b5a,0x5b5b,0x5b65,0x5b69,0x5b70,0x5b73,0x5b75,0x5b78, 0x6588,0x5b7a,0x5b80,0x5b83,0x5ba6,0x5bb8,0x5bc3,0x5bc7,0x5bc9,0x5bd4, 0x5bd0,0x5be4,0x5be6,0x5be2,0x5bde,0x5be5,0x5beb,0x5bf0,0x5bf6,0x5bf3, 0x5c05,0x5c07,0x5c08,0x5c0d,0x5c13,0x5c20,0x5c22,0x5c28,0x5c38,0x5c39, 0x5c41,0x5c46,0x5c4e,0x5c53 }, { /* ku 36 */ 0x5c50,0x5c4f,0x5b71,0x5c6c,0x5c6e,0x4e62,0x5c76,0x5c79,0x5c8c,0x5c91, 0x5c94,0x599b,0x5cab,0x5cbb,0x5cb6,0x5cbc,0x5cb7,0x5cc5,0x5cbe,0x5cc7, 0x5cd9,0x5ce9,0x5cfd,0x5cfa,0x5ced,0x5d8c,0x5cea,0x5d0b,0x5d15,0x5d17, 0x5d5c,0x5d1f,0x5d1b,0x5d11,0x5d14,0x5d22,0x5d1a,0x5d19,0x5d18,0x5d4c, 0x5d52,0x5d4e,0x5d4b,0x5d6c,0x5d73,0x5d76,0x5d87,0x5d84,0x5d82,0x5da2, 0x5d9d,0x5dac,0x5dae,0x5dbd,0x5d90,0x5db7,0x5dbc,0x5dc9,0x5dcd,0x5dd3, 0x5dd2,0x5dd6,0x5ddb,0x5deb,0x5df2,0x5df5,0x5e0b,0x5e1a,0x5e19,0x5e11, 0x5e1b,0x5e36,0x5e37,0x5e44,0x5e43,0x5e40,0x5e4e,0x5e57,0x5e54,0x5e5f, 0x5e62,0x5e64,0x5e47,0x5e75,0x5e76,0x5e7a,0x9ebc,0x5e7f,0x5ea0,0x5ec1, 0x5ec2,0x5ec8,0x5ed0,0x5ecf }, { /* ku 37 */ 0x5ed6,0x5ee3,0x5edd,0x5eda,0x5edb,0x5ee2,0x5ee1,0x5ee8,0x5ee9,0x5eec, 0x5ef1,0x5ef3,0x5ef0,0x5ef4,0x5ef8,0x5efe,0x5f03,0x5f09,0x5f5d,0x5f5c, 0x5f0b,0x5f11,0x5f16,0x5f29,0x5f2d,0x5f38,0x5f41,0x5f48,0x5f4c,0x5f4e, 0x5f2f,0x5f51,0x5f56,0x5f57,0x5f59,0x5f61,0x5f6d,0x5f73,0x5f77,0x5f83, 0x5f82,0x5f7f,0x5f8a,0x5f88,0x5f91,0x5f87,0x5f9e,0x5f99,0x5f98,0x5fa0, 0x5fa8,0x5fad,0x5fbc,0x5fd6,0x5ffb,0x5fe4,0x5ff8,0x5ff1,0x5fdd,0x60b3, 0x5fff,0x6021,0x6060,0x6019,0x6010,0x6029,0x600e,0x6031,0x601b,0x6015, 0x602b,0x6026,0x600f,0x603a,0x605a,0x6041,0x606a,0x6077,0x605f,0x604a, 0x6046,0x604d,0x6063,0x6043,0x6064,0x6042,0x606c,0x606b,0x6059,0x6081, 0x608d,0x60e7,0x6083,0x609a }, { /* ku 38 */ 0x6084,0x609b,0x6096,0x6097,0x6092,0x60a7,0x608b,0x60e1,0x60b8,0x60e0, 0x60d3,0x60b4,0x5ff0,0x60bd,0x60c6,0x60b5,0x60d8,0x614d,0x6115,0x6106, 0x60f6,0x60f7,0x6100,0x60f4,0x60fa,0x6103,0x6121,0x60fb,0x60f1,0x610d, 0x610e,0x6147,0x613e,0x6128,0x6127,0x614a,0x613f,0x613c,0x612c,0x6134, 0x613d,0x6142,0x6144,0x6173,0x6177,0x6158,0x6159,0x615a,0x616b,0x6174, 0x616f,0x6165,0x6171,0x615f,0x615d,0x6153,0x6175,0x6199,0x6196,0x6187, 0x61ac,0x6194,0x619a,0x618a,0x6191,0x61ab,0x61ae,0x61cc,0x61ca,0x61c9, 0x61f7,0x61c8,0x61c3,0x61c6,0x61ba,0x61cb,0x7f79,0x61cd,0x61e6,0x61e3, 0x61f6,0x61fa,0x61f4,0x61ff,0x61fd,0x61fc,0x61fe,0x6200,0x6208,0x6209, 0x620d,0x620c,0x6214,0x621b }, { /* ku 39 */ 0x621e,0x6221,0x622a,0x622e,0x6230,0x6232,0x6233,0x6241,0x624e,0x625e, 0x6263,0x625b,0x6260,0x6268,0x627c,0x6282,0x6289,0x627e,0x6292,0x6293, 0x6296,0x62d4,0x6283,0x6294,0x62d7,0x62d1,0x62bb,0x62cf,0x62ff,0x62c6, 0x64d4,0x62c8,0x62dc,0x62cc,0x62ca,0x62c2,0x62c7,0x629b,0x62c9,0x630c, 0x62ee,0x62f1,0x6327,0x6302,0x6308,0x62ef,0x62f5,0x6350,0x633e,0x634d, 0x641c,0x634f,0x6396,0x638e,0x6380,0x63ab,0x6376,0x63a3,0x638f,0x6389, 0x639f,0x63b5,0x636b,0x6369,0x63be,0x63e9,0x63c0,0x63c6,0x63e3,0x63c9, 0x63d2,0x63f6,0x63c4,0x6416,0x6434,0x6406,0x6413,0x6426,0x6436,0x651d, 0x6417,0x6428,0x640f,0x6467,0x646f,0x6476,0x644e,0x652a,0x6495,0x6493, 0x64a5,0x64a9,0x6488,0x64bc }, { /* ku 3a */ 0x64da,0x64d2,0x64c5,0x64c7,0x64bb,0x64d8,0x64c2,0x64f1,0x64e7,0x8209, 0x64e0,0x64e1,0x62ac,0x64e3,0x64ef,0x652c,0x64f6,0x64f4,0x64f2,0x64fa, 0x6500,0x64fd,0x6518,0x651c,0x6505,0x6524,0x6523,0x652b,0x6534,0x6535, 0x6537,0x6536,0x6538,0x754b,0x6548,0x6556,0x6555,0x654d,0x6558,0x655e, 0x655d,0x6572,0x6578,0x6582,0x6583,0x8b8a,0x659b,0x659f,0x65ab,0x65b7, 0x65c3,0x65c6,0x65c1,0x65c4,0x65cc,0x65d2,0x65db,0x65d9,0x65e0,0x65e1, 0x65f1,0x6772,0x660a,0x6603,0x65fb,0x6773,0x6635,0x6636,0x6634,0x661c, 0x664f,0x6644,0x6649,0x6641,0x665e,0x665d,0x6664,0x6667,0x6668,0x665f, 0x6662,0x6670,0x6683,0x6688,0x668e,0x6689,0x6684,0x6698,0x669d,0x66c1, 0x66b9,0x66c9,0x66be,0x66bc }, { /* ku 3b */ 0x66c4,0x66b8,0x66d6,0x66da,0x66e0,0x663f,0x66e6,0x66e9,0x66f0,0x66f5, 0x66f7,0x670f,0x6716,0x671e,0x6726,0x6727,0x9738,0x672e,0x673f,0x6736, 0x6741,0x6738,0x6737,0x6746,0x675e,0x6760,0x6759,0x6763,0x6764,0x6789, 0x6770,0x67a9,0x677c,0x676a,0x678c,0x678b,0x67a6,0x67a1,0x6785,0x67b7, 0x67ef,0x67b4,0x67ec,0x67b3,0x67e9,0x67b8,0x67e4,0x67de,0x67dd,0x67e2, 0x67ee,0x67b9,0x67ce,0x67c6,0x67e7,0x6a9c,0x681e,0x6846,0x6829,0x6840, 0x684d,0x6832,0x684e,0x68b3,0x682b,0x6859,0x6863,0x6877,0x687f,0x689f, 0x688f,0x68ad,0x6894,0x689d,0x689b,0x6883,0x6aae,0x68b9,0x6874,0x68b5, 0x68a0,0x68ba,0x690f,0x688d,0x687e,0x6901,0x68ca,0x6908,0x68d8,0x6922, 0x6926,0x68e1,0x690c,0x68cd }, { /* ku 3c */ 0x68d4,0x68e7,0x68d5,0x6936,0x6912,0x6904,0x68d7,0x68e3,0x6925,0x68f9, 0x68e0,0x68ef,0x6928,0x692a,0x691a,0x6923,0x6921,0x68c6,0x6979,0x6977, 0x695c,0x6978,0x696b,0x6954,0x697e,0x696e,0x6939,0x6974,0x693d,0x6959, 0x6930,0x6961,0x695e,0x695d,0x6981,0x696a,0x69b2,0x69ae,0x69d0,0x69bf, 0x69c1,0x69d3,0x69be,0x69ce,0x5be8,0x69ca,0x69dd,0x69bb,0x69c3,0x69a7, 0x6a2e,0x6991,0x69a0,0x699c,0x6995,0x69b4,0x69de,0x69e8,0x6a02,0x6a1b, 0x69ff,0x6b0a,0x69f9,0x69f2,0x69e7,0x6a05,0x69b1,0x6a1e,0x69ed,0x6a14, 0x69eb,0x6a0a,0x6a12,0x6ac1,0x6a23,0x6a13,0x6a44,0x6a0c,0x6a72,0x6a36, 0x6a78,0x6a47,0x6a62,0x6a59,0x6a66,0x6a48,0x6a38,0x6a22,0x6a90,0x6a8d, 0x6aa0,0x6a84,0x6aa2,0x6aa3 }, { /* ku 3d */ 0x6a97,0x8617,0x6abb,0x6ac3,0x6ac2,0x6ab8,0x6ab3,0x6aac,0x6ade,0x6ad1, 0x6adf,0x6aaa,0x6ada,0x6aea,0x6afb,0x6b05,0x8616,0x6afa,0x6b12,0x6b16, 0x9b31,0x6b1f,0x6b38,0x6b37,0x76dc,0x6b39,0x98ee,0x6b47,0x6b43,0x6b49, 0x6b50,0x6b59,0x6b54,0x6b5b,0x6b5f,0x6b61,0x6b78,0x6b79,0x6b7f,0x6b80, 0x6b84,0x6b83,0x6b8d,0x6b98,0x6b95,0x6b9e,0x6ba4,0x6baa,0x6bab,0x6baf, 0x6bb2,0x6bb1,0x6bb3,0x6bb7,0x6bbc,0x6bc6,0x6bcb,0x6bd3,0x6bdf,0x6bec, 0x6beb,0x6bf3,0x6bef,0x9ebe,0x6c08,0x6c13,0x6c14,0x6c1b,0x6c24,0x6c23, 0x6c5e,0x6c55,0x6c62,0x6c6a,0x6c82,0x6c8d,0x6c9a,0x6c81,0x6c9b,0x6c7e, 0x6c68,0x6c73,0x6c92,0x6c90,0x6cc4,0x6cf1,0x6cd3,0x6cbd,0x6cd7,0x6cc5, 0x6cdd,0x6cae,0x6cb1,0x6cbe }, { /* ku 3e */ 0x6cba,0x6cdb,0x6cef,0x6cd9,0x6cea,0x6d1f,0x884d,0x6d36,0x6d2b,0x6d3d, 0x6d38,0x6d19,0x6d35,0x6d33,0x6d12,0x6d0c,0x6d63,0x6d93,0x6d64,0x6d5a, 0x6d79,0x6d59,0x6d8e,0x6d95,0x6fe4,0x6d85,0x6df9,0x6e15,0x6e0a,0x6db5, 0x6dc7,0x6de6,0x6db8,0x6dc6,0x6dec,0x6dde,0x6dcc,0x6de8,0x6dd2,0x6dc5, 0x6dfa,0x6dd9,0x6de4,0x6dd5,0x6dea,0x6dee,0x6e2d,0x6e6e,0x6e2e,0x6e19, 0x6e72,0x6e5f,0x6e3e,0x6e23,0x6e6b,0x6e2b,0x6e76,0x6e4d,0x6e1f,0x6e43, 0x6e3a,0x6e4e,0x6e24,0x6eff,0x6e1d,0x6e38,0x6e82,0x6eaa,0x6e98,0x6ec9, 0x6eb7,0x6ed3,0x6ebd,0x6eaf,0x6ec4,0x6eb2,0x6ed4,0x6ed5,0x6e8f,0x6ea5, 0x6ec2,0x6e9f,0x6f41,0x6f11,0x704c,0x6eec,0x6ef8,0x6efe,0x6f3f,0x6ef2, 0x6f31,0x6eef,0x6f32,0x6ecc }, { /* ku 3f */ 0x6f3e,0x6f13,0x6ef7,0x6f86,0x6f7a,0x6f78,0x6f81,0x6f80,0x6f6f,0x6f5b, 0x6ff3,0x6f6d,0x6f82,0x6f7c,0x6f58,0x6f8e,0x6f91,0x6fc2,0x6f66,0x6fb3, 0x6fa3,0x6fa1,0x6fa4,0x6fb9,0x6fc6,0x6faa,0x6fdf,0x6fd5,0x6fec,0x6fd4, 0x6fd8,0x6ff1,0x6fee,0x6fdb,0x7009,0x700b,0x6ffa,0x7011,0x7001,0x700f, 0x6ffe,0x701b,0x701a,0x6f74,0x701d,0x7018,0x701f,0x7030,0x703e,0x7032, 0x7051,0x7063,0x7099,0x7092,0x70af,0x70f1,0x70ac,0x70b8,0x70b3,0x70ae, 0x70df,0x70cb,0x70dd,0x70d9,0x7109,0x70fd,0x711c,0x7119,0x7165,0x7155, 0x7188,0x7166,0x7162,0x714c,0x7156,0x716c,0x718f,0x71fb,0x7184,0x7195, 0x71a8,0x71ac,0x71d7,0x71b9,0x71be,0x71d2,0x71c9,0x71d4,0x71ce,0x71e0, 0x71ec,0x71e7,0x71f5,0x71fc }, { /* ku 40 */ 0x71f9,0x71ff,0x720d,0x7210,0x721b,0x7228,0x722d,0x722c,0x7230,0x7232, 0x723b,0x723c,0x723f,0x7240,0x7246,0x724b,0x7258,0x7274,0x727e,0x7282, 0x7281,0x7287,0x7292,0x7296,0x72a2,0x72a7,0x72b9,0x72b2,0x72c3,0x72c6, 0x72c4,0x72ce,0x72d2,0x72e2,0x72e0,0x72e1,0x72f9,0x72f7,0x500f,0x7317, 0x730a,0x731c,0x7316,0x731d,0x7334,0x732f,0x7329,0x7325,0x733e,0x734e, 0x734f,0x9ed8,0x7357,0x736a,0x7368,0x7370,0x7378,0x7375,0x737b,0x737a, 0x73c8,0x73b3,0x73ce,0x73bb,0x73c0,0x73e5,0x73ee,0x73de,0x74a2,0x7405, 0x746f,0x7425,0x73f8,0x7432,0x743a,0x7455,0x743f,0x745f,0x7459,0x7441, 0x745c,0x7469,0x7470,0x7463,0x746a,0x7476,0x747e,0x748b,0x749e,0x74a7, 0x74ca,0x74cf,0x74d4,0x73f1 }, { /* ku 41 */ 0x74e0,0x74e3,0x74e7,0x74e9,0x74ee,0x74f2,0x74f0,0x74f1,0x74f8,0x74f7, 0x7504,0x7503,0x7505,0x750c,0x750e,0x750d,0x7515,0x7513,0x751e,0x7526, 0x752c,0x753c,0x7544,0x754d,0x754a,0x7549,0x755b,0x7546,0x755a,0x7569, 0x7564,0x7567,0x756b,0x756d,0x7578,0x7576,0x7586,0x7587,0x7574,0x758a, 0x7589,0x7582,0x7594,0x759a,0x759d,0x75a5,0x75a3,0x75c2,0x75b3,0x75c3, 0x75b5,0x75bd,0x75b8,0x75bc,0x75b1,0x75cd,0x75ca,0x75d2,0x75d9,0x75e3, 0x75de,0x75fe,0x75ff,0x75fc,0x7601,0x75f0,0x75fa,0x75f2,0x75f3,0x760b, 0x760d,0x7609,0x761f,0x7627,0x7620,0x7621,0x7622,0x7624,0x7634,0x7630, 0x763b,0x7647,0x7648,0x7646,0x765c,0x7658,0x7661,0x7662,0x7668,0x7669, 0x766a,0x7667,0x766c,0x7670 }, { /* ku 42 */ 0x7672,0x7676,0x7678,0x767c,0x7680,0x7683,0x7688,0x768b,0x768e,0x7696, 0x7693,0x7699,0x769a,0x76b0,0x76b4,0x76b8,0x76b9,0x76ba,0x76c2,0x76cd, 0x76d6,0x76d2,0x76de,0x76e1,0x76e5,0x76e7,0x76ea,0x862f,0x76fb,0x7708, 0x7707,0x7704,0x7729,0x7724,0x771e,0x7725,0x7726,0x771b,0x7737,0x7738, 0x7747,0x775a,0x7768,0x776b,0x775b,0x7765,0x777f,0x777e,0x7779,0x778e, 0x778b,0x7791,0x77a0,0x779e,0x77b0,0x77b6,0x77b9,0x77bf,0x77bc,0x77bd, 0x77bb,0x77c7,0x77cd,0x77d7,0x77da,0x77dc,0x77e3,0x77ee,0x77fc,0x780c, 0x7812,0x7926,0x7820,0x792a,0x7845,0x788e,0x7874,0x7886,0x787c,0x789a, 0x788c,0x78a3,0x78b5,0x78aa,0x78af,0x78d1,0x78c6,0x78cb,0x78d4,0x78be, 0x78bc,0x78c5,0x78ca,0x78ec }, { /* ku 43 */ 0x78e7,0x78da,0x78fd,0x78f4,0x7907,0x7912,0x7911,0x7919,0x792c,0x792b, 0x7940,0x7960,0x7957,0x795f,0x795a,0x7955,0x7953,0x797a,0x797f,0x798a, 0x799d,0x79a7,0x9f4b,0x79aa,0x79ae,0x79b3,0x79b9,0x79ba,0x79c9,0x79d5, 0x79e7,0x79ec,0x79e1,0x79e3,0x7a08,0x7a0d,0x7a18,0x7a19,0x7a20,0x7a1f, 0x7980,0x7a31,0x7a3b,0x7a3e,0x7a37,0x7a43,0x7a57,0x7a49,0x7a61,0x7a62, 0x7a69,0x9f9d,0x7a70,0x7a79,0x7a7d,0x7a88,0x7a97,0x7a95,0x7a98,0x7a96, 0x7aa9,0x7ac8,0x7ab0,0x7ab6,0x7ac5,0x7ac4,0x7abf,0x9083,0x7ac7,0x7aca, 0x7acd,0x7acf,0x7ad5,0x7ad3,0x7ad9,0x7ada,0x7add,0x7ae1,0x7ae2,0x7ae6, 0x7aed,0x7af0,0x7b02,0x7b0f,0x7b0a,0x7b06,0x7b33,0x7b18,0x7b19,0x7b1e, 0x7b35,0x7b28,0x7b36,0x7b50 }, { /* ku 44 */ 0x7b7a,0x7b04,0x7b4d,0x7b0b,0x7b4c,0x7b45,0x7b75,0x7b65,0x7b74,0x7b67, 0x7b70,0x7b71,0x7b6c,0x7b6e,0x7b9d,0x7b98,0x7b9f,0x7b8d,0x7b9c,0x7b9a, 0x7b8b,0x7b92,0x7b8f,0x7b5d,0x7b99,0x7bcb,0x7bc1,0x7bcc,0x7bcf,0x7bb4, 0x7bc6,0x7bdd,0x7be9,0x7c11,0x7c14,0x7be6,0x7be5,0x7c60,0x7c00,0x7c07, 0x7c13,0x7bf3,0x7bf7,0x7c17,0x7c0d,0x7bf6,0x7c23,0x7c27,0x7c2a,0x7c1f, 0x7c37,0x7c2b,0x7c3d,0x7c4c,0x7c43,0x7c54,0x7c4f,0x7c40,0x7c50,0x7c58, 0x7c5f,0x7c64,0x7c56,0x7c65,0x7c6c,0x7c75,0x7c83,0x7c90,0x7ca4,0x7cad, 0x7ca2,0x7cab,0x7ca1,0x7ca8,0x7cb3,0x7cb2,0x7cb1,0x7cae,0x7cb9,0x7cbd, 0x7cc0,0x7cc5,0x7cc2,0x7cd8,0x7cd2,0x7cdc,0x7ce2,0x9b3b,0x7cef,0x7cf2, 0x7cf4,0x7cf6,0x7cfa,0x7d06 }, { /* ku 45 */ 0x7d02,0x7d1c,0x7d15,0x7d0a,0x7d45,0x7d4b,0x7d2e,0x7d32,0x7d3f,0x7d35, 0x7d46,0x7d73,0x7d56,0x7d4e,0x7d72,0x7d68,0x7d6e,0x7d4f,0x7d63,0x7d93, 0x7d89,0x7d5b,0x7d8f,0x7d7d,0x7d9b,0x7dba,0x7dae,0x7da3,0x7db5,0x7dc7, 0x7dbd,0x7dab,0x7e3d,0x7da2,0x7daf,0x7ddc,0x7db8,0x7d9f,0x7db0,0x7dd8, 0x7ddd,0x7de4,0x7dde,0x7dfb,0x7df2,0x7de1,0x7e05,0x7e0a,0x7e23,0x7e21, 0x7e12,0x7e31,0x7e1f,0x7e09,0x7e0b,0x7e22,0x7e46,0x7e66,0x7e3b,0x7e35, 0x7e39,0x7e43,0x7e37,0x7e32,0x7e3a,0x7e67,0x7e5d,0x7e56,0x7e5e,0x7e59, 0x7e5a,0x7e79,0x7e6a,0x7e69,0x7e7c,0x7e7b,0x7e83,0x7dd5,0x7e7d,0x8fae, 0x7e7f,0x7e88,0x7e89,0x7e8c,0x7e92,0x7e90,0x7e93,0x7e94,0x7e96,0x7e8e, 0x7e9b,0x7e9c,0x7f38,0x7f3a }, { /* ku 46 */ 0x7f45,0x7f4c,0x7f4d,0x7f4e,0x7f50,0x7f51,0x7f55,0x7f54,0x7f58,0x7f5f, 0x7f60,0x7f68,0x7f69,0x7f67,0x7f78,0x7f82,0x7f86,0x7f83,0x7f88,0x7f87, 0x7f8c,0x7f94,0x7f9e,0x7f9d,0x7f9a,0x7fa3,0x7faf,0x7fb2,0x7fb9,0x7fae, 0x7fb6,0x7fb8,0x8b71,0x7fc5,0x7fc6,0x7fca,0x7fd5,0x7fd4,0x7fe1,0x7fe6, 0x7fe9,0x7ff3,0x7ff9,0x98dc,0x8006,0x8004,0x800b,0x8012,0x8018,0x8019, 0x801c,0x8021,0x8028,0x803f,0x803b,0x804a,0x8046,0x8052,0x8058,0x805a, 0x805f,0x8062,0x8068,0x8073,0x8072,0x8070,0x8076,0x8079,0x807d,0x807f, 0x8084,0x8086,0x8085,0x809b,0x8093,0x809a,0x80ad,0x5190,0x80ac,0x80db, 0x80e5,0x80d9,0x80dd,0x80c4,0x80da,0x80d6,0x8109,0x80ef,0x80f1,0x811b, 0x8129,0x8123,0x812f,0x814b }, { /* ku 47 */ 0x968b,0x8146,0x813e,0x8153,0x8151,0x80fc,0x8171,0x816e,0x8165,0x8166, 0x8174,0x8183,0x8188,0x818a,0x8180,0x8182,0x81a0,0x8195,0x81a4,0x81a3, 0x815f,0x8193,0x81a9,0x81b0,0x81b5,0x81be,0x81b8,0x81bd,0x81c0,0x81c2, 0x81ba,0x81c9,0x81cd,0x81d1,0x81d9,0x81d8,0x81c8,0x81da,0x81df,0x81e0, 0x81e7,0x81fa,0x81fb,0x81fe,0x8201,0x8202,0x8205,0x8207,0x820a,0x820d, 0x8210,0x8216,0x8229,0x822b,0x8238,0x8233,0x8240,0x8259,0x8258,0x825d, 0x825a,0x825f,0x8264,0x8262,0x8268,0x826a,0x826b,0x822e,0x8271,0x8277, 0x8278,0x827e,0x828d,0x8292,0x82ab,0x829f,0x82bb,0x82ac,0x82e1,0x82e3, 0x82df,0x82d2,0x82f4,0x82f3,0x82fa,0x8393,0x8303,0x82fb,0x82f9,0x82de, 0x8306,0x82dc,0x8309,0x82d9 }, { /* ku 48 */ 0x8335,0x8334,0x8316,0x8332,0x8331,0x8340,0x8339,0x8350,0x8345,0x832f, 0x832b,0x8317,0x8318,0x8385,0x839a,0x83aa,0x839f,0x83a2,0x8396,0x8323, 0x838e,0x8387,0x838a,0x837c,0x83b5,0x8373,0x8375,0x83a0,0x8389,0x83a8, 0x83f4,0x8413,0x83eb,0x83ce,0x83fd,0x8403,0x83d8,0x840b,0x83c1,0x83f7, 0x8407,0x83e0,0x83f2,0x840d,0x8422,0x8420,0x83bd,0x8438,0x8506,0x83fb, 0x846d,0x842a,0x843c,0x855a,0x8484,0x8477,0x846b,0x84ad,0x846e,0x8482, 0x8469,0x8446,0x842c,0x846f,0x8479,0x8435,0x84ca,0x8462,0x84b9,0x84bf, 0x849f,0x84d9,0x84cd,0x84bb,0x84da,0x84d0,0x84c1,0x84c6,0x84d6,0x84a1, 0x8521,0x84ff,0x84f4,0x8517,0x8518,0x852c,0x851f,0x8515,0x8514,0x84fc, 0x8540,0x8563,0x8558,0x8548 }, { /* ku 49 */ 0x8541,0x8602,0x854b,0x8555,0x8580,0x85a4,0x8588,0x8591,0x858a,0x85a8, 0x856d,0x8594,0x859b,0x85ea,0x8587,0x859c,0x8577,0x857e,0x8590,0x85c9, 0x85ba,0x85cf,0x85b9,0x85d0,0x85d5,0x85dd,0x85e5,0x85dc,0x85f9,0x860a, 0x8613,0x860b,0x85fe,0x85fa,0x8606,0x8622,0x861a,0x8630,0x863f,0x864d, 0x4e55,0x8654,0x865f,0x8667,0x8671,0x8693,0x86a3,0x86a9,0x86aa,0x868b, 0x868c,0x86b6,0x86af,0x86c4,0x86c6,0x86b0,0x86c9,0x8823,0x86ab,0x86d4, 0x86de,0x86e9,0x86ec,0x86df,0x86db,0x86ef,0x8712,0x8706,0x8708,0x8700, 0x8703,0x86fb,0x8711,0x8709,0x870d,0x86f9,0x870a,0x8734,0x873f,0x8737, 0x873b,0x8725,0x8729,0x871a,0x8760,0x875f,0x8778,0x874c,0x874e,0x8774, 0x8757,0x8768,0x876e,0x8759 }, { /* ku 4a */ 0x8753,0x8763,0x876a,0x8805,0x87a2,0x879f,0x8782,0x87af,0x87cb,0x87bd, 0x87c0,0x87d0,0x96d6,0x87ab,0x87c4,0x87b3,0x87c7,0x87c6,0x87bb,0x87ef, 0x87f2,0x87e0,0x880f,0x880d,0x87fe,0x87f6,0x87f7,0x880e,0x87d2,0x8811, 0x8816,0x8815,0x8822,0x8821,0x8831,0x8836,0x8839,0x8827,0x883b,0x8844, 0x8842,0x8852,0x8859,0x885e,0x8862,0x886b,0x8881,0x887e,0x889e,0x8875, 0x887d,0x88b5,0x8872,0x8882,0x8897,0x8892,0x88ae,0x8899,0x88a2,0x888d, 0x88a4,0x88b0,0x88bf,0x88b1,0x88c3,0x88c4,0x88d4,0x88d8,0x88d9,0x88dd, 0x88f9,0x8902,0x88fc,0x88f4,0x88e8,0x88f2,0x8904,0x890c,0x890a,0x8913, 0x8943,0x891e,0x8925,0x892a,0x892b,0x8941,0x8944,0x893b,0x8936,0x8938, 0x894c,0x891d,0x8960,0x895e }, { /* ku 4b */ 0x8966,0x8964,0x896d,0x896a,0x896f,0x8974,0x8977,0x897e,0x8983,0x8988, 0x898a,0x8993,0x8998,0x89a1,0x89a9,0x89a6,0x89ac,0x89af,0x89b2,0x89ba, 0x89bd,0x89bf,0x89c0,0x89da,0x89dc,0x89dd,0x89e7,0x89f4,0x89f8,0x8a03, 0x8a16,0x8a10,0x8a0c,0x8a1b,0x8a1d,0x8a25,0x8a36,0x8a41,0x8a5b,0x8a52, 0x8a46,0x8a48,0x8a7c,0x8a6d,0x8a6c,0x8a62,0x8a85,0x8a82,0x8a84,0x8aa8, 0x8aa1,0x8a91,0x8aa5,0x8aa6,0x8a9a,0x8aa3,0x8ac4,0x8acd,0x8ac2,0x8ada, 0x8aeb,0x8af3,0x8ae7,0x8ae4,0x8af1,0x8b14,0x8ae0,0x8ae2,0x8af7,0x8ade, 0x8adb,0x8b0c,0x8b07,0x8b1a,0x8ae1,0x8b16,0x8b10,0x8b17,0x8b20,0x8b33, 0x97ab,0x8b26,0x8b2b,0x8b3e,0x8b28,0x8b41,0x8b4c,0x8b4f,0x8b4e,0x8b49, 0x8b56,0x8b5b,0x8b5a,0x8b6b }, { /* ku 4c */ 0x8b5f,0x8b6c,0x8b6f,0x8b74,0x8b7d,0x8b80,0x8b8c,0x8b8e,0x8b92,0x8b93, 0x8b96,0x8b99,0x8b9a,0x8c3a,0x8c41,0x8c3f,0x8c48,0x8c4c,0x8c4e,0x8c50, 0x8c55,0x8c62,0x8c6c,0x8c78,0x8c7a,0x8c82,0x8c89,0x8c85,0x8c8a,0x8c8d, 0x8c8e,0x8c94,0x8c7c,0x8c98,0x621d,0x8cad,0x8caa,0x8cbd,0x8cb2,0x8cb3, 0x8cae,0x8cb6,0x8cc8,0x8cc1,0x8ce4,0x8ce3,0x8cda,0x8cfd,0x8cfa,0x8cfb, 0x8d04,0x8d05,0x8d0a,0x8d07,0x8d0f,0x8d0d,0x8d10,0x9f4e,0x8d13,0x8ccd, 0x8d14,0x8d16,0x8d67,0x8d6d,0x8d71,0x8d73,0x8d81,0x8d99,0x8dc2,0x8dbe, 0x8dba,0x8dcf,0x8dda,0x8dd6,0x8dcc,0x8ddb,0x8dcb,0x8dea,0x8deb,0x8ddf, 0x8de3,0x8dfc,0x8e08,0x8e09,0x8dff,0x8e1d,0x8e1e,0x8e10,0x8e1f,0x8e42, 0x8e35,0x8e30,0x8e34,0x8e4a }, { /* ku 4d */ 0x8e47,0x8e49,0x8e4c,0x8e50,0x8e48,0x8e59,0x8e64,0x8e60,0x8e2a,0x8e63, 0x8e55,0x8e76,0x8e72,0x8e7c,0x8e81,0x8e87,0x8e85,0x8e84,0x8e8b,0x8e8a, 0x8e93,0x8e91,0x8e94,0x8e99,0x8eaa,0x8ea1,0x8eac,0x8eb0,0x8ec6,0x8eb1, 0x8ebe,0x8ec5,0x8ec8,0x8ecb,0x8edb,0x8ee3,0x8efc,0x8efb,0x8eeb,0x8efe, 0x8f0a,0x8f05,0x8f15,0x8f12,0x8f19,0x8f13,0x8f1c,0x8f1f,0x8f1b,0x8f0c, 0x8f26,0x8f33,0x8f3b,0x8f39,0x8f45,0x8f42,0x8f3e,0x8f4c,0x8f49,0x8f46, 0x8f4e,0x8f57,0x8f5c,0x8f62,0x8f63,0x8f64,0x8f9c,0x8f9f,0x8fa3,0x8fad, 0x8faf,0x8fb7,0x8fda,0x8fe5,0x8fe2,0x8fea,0x8fef,0x9087,0x8ff4,0x9005, 0x8ff9,0x8ffa,0x9011,0x9015,0x9021,0x900d,0x901e,0x9016,0x900b,0x9027, 0x9036,0x9035,0x9039,0x8ff8 }, { /* ku 4e */ 0x904f,0x9050,0x9051,0x9052,0x900e,0x9049,0x903e,0x9056,0x9058,0x905e, 0x9068,0x906f,0x9076,0x96a8,0x9072,0x9082,0x907d,0x9081,0x9080,0x908a, 0x9089,0x908f,0x90a8,0x90af,0x90b1,0x90b5,0x90e2,0x90e4,0x6248,0x90db, 0x9102,0x9112,0x9119,0x9132,0x9130,0x914a,0x9156,0x9158,0x9163,0x9165, 0x9169,0x9173,0x9172,0x918b,0x9189,0x9182,0x91a2,0x91ab,0x91af,0x91aa, 0x91b5,0x91b4,0x91ba,0x91c0,0x91c1,0x91c9,0x91cb,0x91d0,0x91d6,0x91df, 0x91e1,0x91db,0x91fc,0x91f5,0x91f6,0x921e,0x91ff,0x9214,0x922c,0x9215, 0x9211,0x925e,0x9257,0x9245,0x9249,0x9264,0x9248,0x9295,0x923f,0x924b, 0x9250,0x929c,0x9296,0x9293,0x929b,0x925a,0x92cf,0x92b9,0x92b7,0x92e9, 0x930f,0x92fa,0x9344,0x932e }, { /* ku 4f */ 0x9319,0x9322,0x931a,0x9323,0x933a,0x9335,0x933b,0x935c,0x9360,0x937c, 0x936e,0x9356,0x93b0,0x93ac,0x93ad,0x9394,0x93b9,0x93d6,0x93d7,0x93e8, 0x93e5,0x93d8,0x93c3,0x93dd,0x93d0,0x93c8,0x93e4,0x941a,0x9414,0x9413, 0x9403,0x9407,0x9410,0x9436,0x942b,0x9435,0x9421,0x943a,0x9441,0x9452, 0x9444,0x945b,0x9460,0x9462,0x945e,0x946a,0x9229,0x9470,0x9475,0x9477, 0x947d,0x945a,0x947c,0x947e,0x9481,0x947f,0x9582,0x9587,0x958a,0x9594, 0x9596,0x9598,0x9599,0x95a0,0x95a8,0x95a7,0x95ad,0x95bc,0x95bb,0x95b9, 0x95be,0x95ca,0x6ff6,0x95c3,0x95cd,0x95cc,0x95d5,0x95d4,0x95d6,0x95dc, 0x95e1,0x95e5,0x95e2,0x9621,0x9628,0x962e,0x962f,0x9642,0x964c,0x964f, 0x964b,0x9677,0x965c,0x965e }, { /* ku 50 */ 0x965d,0x965f,0x9666,0x9672,0x966c,0x968d,0x9698,0x9695,0x9697,0x96aa, 0x96a7,0x96b1,0x96b2,0x96b0,0x96b4,0x96b6,0x96b8,0x96b9,0x96ce,0x96cb, 0x96c9,0x96cd,0x894d,0x96dc,0x970d,0x96d5,0x96f9,0x9704,0x9706,0x9708, 0x9713,0x970e,0x9711,0x970f,0x9716,0x9719,0x9724,0x972a,0x9730,0x9739, 0x973d,0x973e,0x9744,0x9746,0x9748,0x9742,0x9749,0x975c,0x9760,0x9764, 0x9766,0x9768,0x52d2,0x976b,0x9771,0x9779,0x9785,0x977c,0x9781,0x977a, 0x9786,0x978b,0x978f,0x9790,0x979c,0x97a8,0x97a6,0x97a3,0x97b3,0x97b4, 0x97c3,0x97c6,0x97c8,0x97cb,0x97dc,0x97ed,0x9f4f,0x97f2,0x7adf,0x97f6, 0x97f5,0x980f,0x980c,0x9838,0x9824,0x9821,0x9837,0x983d,0x9846,0x984f, 0x984b,0x986b,0x986f,0x9870 }, { /* ku 51 */ 0x9871,0x9874,0x9873,0x98aa,0x98af,0x98b1,0x98b6,0x98c4,0x98c3,0x98c6, 0x98e9,0x98eb,0x9903,0x9909,0x9912,0x9914,0x9918,0x9921,0x991d,0x991e, 0x9924,0x9920,0x992c,0x992e,0x993d,0x993e,0x9942,0x9949,0x9945,0x9950, 0x994b,0x9951,0x9952,0x994c,0x9955,0x9997,0x9998,0x99a5,0x99ad,0x99ae, 0x99bc,0x99df,0x99db,0x99dd,0x99d8,0x99d1,0x99ed,0x99ee,0x99f1,0x99f2, 0x99fb,0x99f8,0x9a01,0x9a0f,0x9a05,0x99e2,0x9a19,0x9a2b,0x9a37,0x9a45, 0x9a42,0x9a40,0x9a43,0x9a3e,0x9a55,0x9a4d,0x9a5b,0x9a57,0x9a5f,0x9a62, 0x9a65,0x9a64,0x9a69,0x9a6b,0x9a6a,0x9aad,0x9ab0,0x9abc,0x9ac0,0x9acf, 0x9ad1,0x9ad3,0x9ad4,0x9ade,0x9adf,0x9ae2,0x9ae3,0x9ae6,0x9aef,0x9aeb, 0x9aee,0x9af4,0x9af1,0x9af7 }, { /* ku 52 */ 0x9afb,0x9b06,0x9b18,0x9b1a,0x9b1f,0x9b22,0x9b23,0x9b25,0x9b27,0x9b28, 0x9b29,0x9b2a,0x9b2e,0x9b2f,0x9b32,0x9b44,0x9b43,0x9b4f,0x9b4d,0x9b4e, 0x9b51,0x9b58,0x9b74,0x9b93,0x9b83,0x9b91,0x9b96,0x9b97,0x9b9f,0x9ba0, 0x9ba8,0x9bb4,0x9bc0,0x9bca,0x9bb9,0x9bc6,0x9bcf,0x9bd1,0x9bd2,0x9be3, 0x9be2,0x9be4,0x9bd4,0x9be1,0x9c3a,0x9bf2,0x9bf1,0x9bf0,0x9c15,0x9c14, 0x9c09,0x9c13,0x9c0c,0x9c06,0x9c08,0x9c12,0x9c0a,0x9c04,0x9c2e,0x9c1b, 0x9c25,0x9c24,0x9c21,0x9c30,0x9c47,0x9c32,0x9c46,0x9c3e,0x9c5a,0x9c60, 0x9c67,0x9c76,0x9c78,0x9ce7,0x9cec,0x9cf0,0x9d09,0x9d08,0x9ceb,0x9d03, 0x9d06,0x9d2a,0x9d26,0x9daf,0x9d23,0x9d1f,0x9d44,0x9d15,0x9d12,0x9d41, 0x9d3f,0x9d3e,0x9d46,0x9d48 }, { /* ku 53 */ 0x9d5d,0x9d5e,0x9d64,0x9d51,0x9d50,0x9d59,0x9d72,0x9d89,0x9d87,0x9dab, 0x9d6f,0x9d7a,0x9d9a,0x9da4,0x9da9,0x9db2,0x9dc4,0x9dc1,0x9dbb,0x9db8, 0x9dba,0x9dc6,0x9dcf,0x9dc2,0x9dd9,0x9dd3,0x9df8,0x9de6,0x9ded,0x9def, 0x9dfd,0x9e1a,0x9e1b,0x9e1e,0x9e75,0x9e79,0x9e7d,0x9e81,0x9e88,0x9e8b, 0x9e8c,0x9e92,0x9e95,0x9e91,0x9e9d,0x9ea5,0x9ea9,0x9eb8,0x9eaa,0x9ead, 0x9761,0x9ecc,0x9ece,0x9ecf,0x9ed0,0x9ed4,0x9edc,0x9ede,0x9edd,0x9ee0, 0x9ee5,0x9ee8,0x9eef,0x9ef4,0x9ef6,0x9ef7,0x9ef9,0x9efb,0x9efc,0x9efd, 0x9f07,0x9f08,0x76b7,0x9f15,0x9f21,0x9f2c,0x9f3e,0x9f4a,0x9f52,0x9f54, 0x9f63,0x9f5f,0x9f60,0x9f61,0x9f66,0x9f67,0x9f6c,0x9f6a,0x9f77,0x9f72, 0x9f76,0x9f95,0x9f9c,0x9fa0 }, { /* ku 54 */ 0x582f,0x69c7,0x9059,0x7464,0x51dc,0x7199,UBOGON,UBOGON,UBOGON,UBOGON, UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON, UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON, UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON, UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON, UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON, UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON, UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON, UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON, UBOGON,UBOGON,UBOGON,UBOGON } }; alpine-2.10+dfsg/imap/src/charset/windows.c0000600000175000017500000002542411512502123022346 0ustar paulproteuspaulproteus/* ======================================================================== * Copyright 1988-2006 University of Washington * * Licensed under the Apache License, Version 2.0 (the "License"); * you may not use this file except in compliance with the License. * You may obtain a copy of the License at * * http://www.apache.org/licenses/LICENSE-2.0 * * * ======================================================================== */ /* * Program: Windows conversion tables * * Author: Mark Crispin * Networks and Distributed Computing * Computing & Communications * University of Washington * Administration Building, AG-44 * Seattle, WA 98195 * Internet: MRC@CAC.Washington.EDU * * Date: 16 October 2000 * Last Edited: 30 August 2006 */ /* Windows Thai */ static const unsigned short windows_874tab[128] = { 0x20ac,UBOGON,UBOGON,UBOGON,UBOGON,0x2026,UBOGON,UBOGON, UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON, UBOGON,0x2018,0x2019,0x201c,0x201d,0x2022,0x2013,0x2014, UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON, 0x00a0,0x0e01,0x0e02,0x0e03,0x0e04,0x0e05,0x0e06,0x0e07, 0x0e08,0x0e09,0x0e0a,0x0e0b,0x0e0c,0x0e0d,0x0e0e,0x0e0f, 0x0e10,0x0e11,0x0e12,0x0e13,0x0e14,0x0e15,0x0e16,0x0e17, 0x0e18,0x0e19,0x0e1a,0x0e1b,0x0e1c,0x0e1d,0x0e1e,0x0e1f, 0x0e20,0x0e21,0x0e22,0x0e23,0x0e24,0x0e25,0x0e26,0x0e27, 0x0e28,0x0e29,0x0e2a,0x0e2b,0x0e2c,0x0e2d,0x0e2e,0x0e2f, 0x0e30,0x0e31,0x0e32,0x0e33,0x0e34,0x0e35,0x0e36,0x0e37, 0x0e38,0x0e39,0x0e3a,UBOGON,UBOGON,UBOGON,UBOGON,0x0e3f, 0x0e40,0x0e41,0x0e42,0x0e43,0x0e44,0x0e45,0x0e46,0x0e47, 0x0e48,0x0e49,0x0e4a,0x0e4b,0x0e4c,0x0e4d,0x0e4e,0x0e4f, 0x0e50,0x0e51,0x0e52,0x0e53,0x0e54,0x0e55,0x0e56,0x0e57, 0x0e58,0x0e59,0x0e5a,0x0e5b,UBOGON,UBOGON,UBOGON,UBOGON }; /* Windows Latin-2 */ static const unsigned short windows_1250tab[128] = { 0x20ac,UBOGON,0x201a,UBOGON,0x201e,0x2026,0x2020,0x2021, UBOGON,0x2030,0x0160,0x2039,0x015a,0x0164,0x017d,0x0179, UBOGON,0x2018,0x2019,0x201c,0x201d,0x2022,0x2013,0x2014, UBOGON,0x2122,0x0161,0x203a,0x015b,0x0165,0x017e,0x017a, 0x00a0,0x02c7,0x02d8,0x0141,0x00a4,0x0104,0x00a6,0x00a7, 0x00a8,0x00a9,0x015e,0x00ab,0x00ac,0x00ad,0x00ae,0x017b, 0x00b0,0x00b1,0x02db,0x0142,0x00b4,0x00b5,0x00b6,0x00b7, 0x00b8,0x0105,0x015f,0x00bb,0x013d,0x02dd,0x013e,0x017c, 0x0154,0x00c1,0x00c2,0x0102,0x00c4,0x0139,0x0106,0x00c7, 0x010c,0x00c9,0x0118,0x00cb,0x011a,0x00cd,0x00ce,0x010e, 0x0110,0x0143,0x0147,0x00d3,0x00d4,0x0150,0x00d6,0x00d7, 0x0158,0x016e,0x00da,0x0170,0x00dc,0x00dd,0x0162,0x00df, 0x0155,0x00e1,0x00e2,0x0103,0x00e4,0x013a,0x0107,0x00e7, 0x010d,0x00e9,0x0119,0x00eb,0x011b,0x00ed,0x00ee,0x010f, 0x0111,0x0144,0x0148,0x00f3,0x00f4,0x0151,0x00f6,0x00f7, 0x0159,0x016f,0x00fa,0x0171,0x00fc,0x00fd,0x0163,0x02d9 }; /* Windows Cyrillic */ static const unsigned short windows_1251tab[128] = { 0x0402,0x0403,0x201a,0x0453,0x201e,0x2026,0x2020,0x2021, 0x20ac,0x2030,0x0409,0x2039,0x040a,0x040c,0x040b,0x040f, 0x0452,0x2018,0x2019,0x201c,0x201d,0x2022,0x2013,0x2014, UBOGON,0x2122,0x0459,0x203a,0x045a,0x045c,0x045b,0x045f, 0x00a0,0x040e,0x045e,0x0408,0x00a4,0x0490,0x00a6,0x00a7, 0x0401,0x00a9,0x0404,0x00ab,0x00ac,0x00ad,0x00ae,0x0407, 0x00b0,0x00b1,0x0406,0x0456,0x0491,0x00b5,0x00b6,0x00b7, 0x0451,0x2116,0x0454,0x00bb,0x0458,0x0405,0x0455,0x0457, 0x0410,0x0411,0x0412,0x0413,0x0414,0x0415,0x0416,0x0417, 0x0418,0x0419,0x041a,0x041b,0x041c,0x041d,0x041e,0x041f, 0x0420,0x0421,0x0422,0x0423,0x0424,0x0425,0x0426,0x0427, 0x0428,0x0429,0x042a,0x042b,0x042c,0x042d,0x042e,0x042f, 0x0430,0x0431,0x0432,0x0433,0x0434,0x0435,0x0436,0x0437, 0x0438,0x0439,0x043a,0x043b,0x043c,0x043d,0x043e,0x043f, 0x0440,0x0441,0x0442,0x0443,0x0444,0x0445,0x0446,0x0447, 0x0448,0x0449,0x044a,0x044b,0x044c,0x044d,0x044e,0x044f }; /* Windows Latin-1 */ static const unsigned short windows_1252tab[128] = { 0x20ac,UBOGON,0x201a,0x0192,0x201e,0x2026,0x2020,0x2021, 0x02c6,0x2030,0x0160,0x2039,0x0152,UBOGON,0x017d,UBOGON, UBOGON,0x2018,0x2019,0x201c,0x201d,0x2022,0x2013,0x2014, 0x02dc,0x2122,0x0161,0x203a,0x0153,UBOGON,0x017e,0x0178, 0x00a0,0x00a1,0x00a2,0x00a3,0x00a4,0x00a5,0x00a6,0x00a7, 0x00a8,0x00a9,0x00aa,0x00ab,0x00ac,0x00ad,0x00ae,0x00af, 0x00b0,0x00b1,0x00b2,0x00b3,0x00b4,0x00b5,0x00b6,0x00b7, 0x00b8,0x00b9,0x00ba,0x00bb,0x00bc,0x00bd,0x00be,0x00bf, 0x00c0,0x00c1,0x00c2,0x00c3,0x00c4,0x00c5,0x00c6,0x00c7, 0x00c8,0x00c9,0x00ca,0x00cb,0x00cc,0x00cd,0x00ce,0x00cf, 0x00d0,0x00d1,0x00d2,0x00d3,0x00d4,0x00d5,0x00d6,0x00d7, 0x00d8,0x00d9,0x00da,0x00db,0x00dc,0x00dd,0x00de,0x00df, 0x00e0,0x00e1,0x00e2,0x00e3,0x00e4,0x00e5,0x00e6,0x00e7, 0x00e8,0x00e9,0x00ea,0x00eb,0x00ec,0x00ed,0x00ee,0x00ef, 0x00f0,0x00f1,0x00f2,0x00f3,0x00f4,0x00f5,0x00f6,0x00f7, 0x00f8,0x00f9,0x00fa,0x00fb,0x00fc,0x00fd,0x00fe,0x00ff }; /* Windows Greek */ static const unsigned short windows_1253tab[128] = { 0x20ac,UBOGON,0x201a,0x0192,0x201e,0x2026,0x2020,0x2021, UBOGON,0x2030,UBOGON,0x2039,UBOGON,UBOGON,UBOGON,UBOGON, UBOGON,0x2018,0x2019,0x201c,0x201d,0x2022,0x2013,0x2014, UBOGON,0x2122,UBOGON,0x203a,UBOGON,UBOGON,UBOGON,UBOGON, 0x00a0,0x0385,0x0386,0x00a3,0x00a4,0x00a5,0x00a6,0x00a7, 0x00a8,0x00a9,UBOGON,0x00ab,0x00ac,0x00ad,0x00ae,0x2015, 0x00b0,0x00b1,0x00b2,0x00b3,0x0384,0x00b5,0x00b6,0x00b7, 0x0388,0x0389,0x038a,0x00bb,0x038c,0x00bd,0x038e,0x038f, 0x0390,0x0391,0x0392,0x0393,0x0394,0x0395,0x0396,0x0397, 0x0398,0x0399,0x039a,0x039b,0x039c,0x039d,0x039e,0x039f, 0x03a0,0x03a1,UBOGON,0x03a3,0x03a4,0x03a5,0x03a6,0x03a7, 0x03a8,0x03a9,0x03aa,0x03ab,0x03ac,0x03ad,0x03ae,0x03af, 0x03b0,0x03b1,0x03b2,0x03b3,0x03b4,0x03b5,0x03b6,0x03b7, 0x03b8,0x03b9,0x03ba,0x03bb,0x03bc,0x03bd,0x03be,0x03bf, 0x03c0,0x03c1,0x03c2,0x03c3,0x03c4,0x03c5,0x03c6,0x03c7, 0x03c8,0x03c9,0x03ca,0x03cb,0x03cc,0x03cd,0x03ce,UBOGON }; /* Windows Turkish */ static const unsigned short windows_1254tab[128] = { 0x20ac,UBOGON,0x201a,0x0192,0x201e,0x2026,0x2020,0x2021, 0x02c6,0x2030,0x0160,0x2039,0x0152,UBOGON,UBOGON,UBOGON, UBOGON,0x2018,0x2019,0x201c,0x201d,0x2022,0x2013,0x2014, 0x02dc,0x2122,0x0161,0x203a,0x0153,UBOGON,UBOGON,0x0178, 0x00a0,0x00a1,0x00a2,0x00a3,0x00a4,0x00a5,0x00a6,0x00a7, 0x00a8,0x00a9,0x00aa,0x00ab,0x00ac,0x00ad,0x00ae,0x00af, 0x00b0,0x00b1,0x00b2,0x00b3,0x00b4,0x00b5,0x00b6,0x00b7, 0x00b8,0x00b9,0x00ba,0x00bb,0x00bc,0x00bd,0x00be,0x00bf, 0x00c0,0x00c1,0x00c2,0x00c3,0x00c4,0x00c5,0x00c6,0x00c7, 0x00c8,0x00c9,0x00ca,0x00cb,0x00cc,0x00cd,0x00ce,0x00cf, 0x011e,0x00d1,0x00d2,0x00d3,0x00d4,0x00d5,0x00d6,0x00d7, 0x00d8,0x00d9,0x00da,0x00db,0x00dc,0x0130,0x015e,0x00df, 0x00e0,0x00e1,0x00e2,0x00e3,0x00e4,0x00e5,0x00e6,0x00e7, 0x00e8,0x00e9,0x00ea,0x00eb,0x00ec,0x00ed,0x00ee,0x00ef, 0x011f,0x00f1,0x00f2,0x00f3,0x00f4,0x00f5,0x00f6,0x00f7, 0x00f8,0x00f9,0x00fa,0x00fb,0x00fc,0x0131,0x015f,0x00ff }; /* Windows Hebrew */ static const unsigned short windows_1255tab[128] = { 0x20ac,UBOGON,0x201a,0x0192,0x201e,0x2026,0x2020,0x2021, 0x02c6,0x2030,UBOGON,0x2039,UBOGON,UBOGON,UBOGON,UBOGON, UBOGON,0x2018,0x2019,0x201c,0x201d,0x2022,0x2013,0x2014, 0x02dc,0x2122,UBOGON,0x203a,UBOGON,UBOGON,UBOGON,UBOGON, 0x00a0,0x00a1,0x00a2,0x00a3,0x20aa,0x00a5,0x00a6,0x00a7, 0x00a8,0x00a9,0x00d7,0x00ab,0x00ac,0x00ad,0x00ae,0x00af, 0x00b0,0x00b1,0x00b2,0x00b3,0x00b4,0x00b5,0x00b6,0x00b7, 0x00b8,0x00b9,0x00f7,0x00bb,0x00bc,0x00bd,0x00be,0x00bf, 0x05b0,0x05b1,0x05b2,0x05b3,0x05b4,0x05b5,0x05b6,0x05b7, 0x05b8,0x05b9,UBOGON,0x05bb,0x05bc,0x05bd,0x05be,0x05bf, 0x05c0,0x05c1,0x05c2,0x05c3,0x05f0,0x05f1,0x05f2,0x05f3, 0x05f4,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON, 0x05d0,0x05d1,0x05d2,0x05d3,0x05d4,0x05d5,0x05d6,0x05d7, 0x05d8,0x05d9,0x05da,0x05db,0x05dc,0x05dd,0x05de,0x05df, 0x05e0,0x05e1,0x05e2,0x05e3,0x05e4,0x05e5,0x05e6,0x05e7, 0x05e8,0x05e9,0x05ea,UBOGON,UBOGON,0x200e,0x200f,UBOGON }; /* Windows Arabic */ static const unsigned short windows_1256tab[128] = { 0x20ac,0x067e,0x201a,0x0192,0x201e,0x2026,0x2020,0x2021, 0x02c6,0x2030,0x0679,0x2039,0x0152,0x0686,0x0698,0x0688, 0x06af,0x2018,0x2019,0x201c,0x201d,0x2022,0x2013,0x2014, 0x06a9,0x2122,0x0691,0x203a,0x0153,0x200c,0x200d,0x06ba, 0x00a0,0x060c,0x00a2,0x00a3,0x00a4,0x00a5,0x00a6,0x00a7, 0x00a8,0x00a9,0x06be,0x00ab,0x00ac,0x00ad,0x00ae,0x00af, 0x00b0,0x00b1,0x00b2,0x00b3,0x00b4,0x00b5,0x00b6,0x00b7, 0x00b8,0x00b9,0x061b,0x00bb,0x00bc,0x00bd,0x00be,0x061f, 0x06c1,0x0621,0x0622,0x0623,0x0624,0x0625,0x0626,0x0627, 0x0628,0x0629,0x062a,0x062b,0x062c,0x062d,0x062e,0x062f, 0x0630,0x0631,0x0632,0x0633,0x0634,0x0635,0x0636,0x00d7, 0x0637,0x0638,0x0639,0x063a,0x0640,0x0641,0x0642,0x0643, 0x00e0,0x0644,0x00e2,0x0645,0x0646,0x0647,0x0648,0x00e7, 0x00e8,0x00e9,0x00ea,0x00eb,0x0649,0x064a,0x00ee,0x00ef, 0x064b,0x064c,0x064d,0x064e,0x00f4,0x064f,0x0650,0x00f7, 0x0651,0x00f9,0x0652,0x00fb,0x00fc,0x200e,0x200f,0x06d2 }; /* Windows Baltic */ static const unsigned short windows_1257tab[128] = { 0x20ac,UBOGON,0x201a,UBOGON,0x201e,0x2026,0x2020,0x2021, UBOGON,0x2030,UBOGON,0x2039,UBOGON,0x00a8,0x02c7,0x00b8, UBOGON,0x2018,0x2019,0x201c,0x201d,0x2022,0x2013,0x2014, UBOGON,0x2122,UBOGON,0x203a,UBOGON,0x00af,0x02db,UBOGON, 0x00a0,UBOGON,0x00a2,0x00a3,0x00a4,UBOGON,0x00a6,0x00a7, 0x00d8,0x00a9,0x0156,0x00ab,0x00ac,0x00ad,0x00ae,0x00c6, 0x00b0,0x00b1,0x00b2,0x00b3,0x00b4,0x00b5,0x00b6,0x00b7, 0x00f8,0x00b9,0x0157,0x00bb,0x00bc,0x00bd,0x00be,0x00e6, 0x0104,0x012e,0x0100,0x0106,0x00c4,0x00c5,0x0118,0x0112, 0x010c,0x00c9,0x0179,0x0116,0x0122,0x0136,0x012a,0x013b, 0x0160,0x0143,0x0145,0x00d3,0x014c,0x00d5,0x00d6,0x00d7, 0x0172,0x0141,0x015a,0x016a,0x00dc,0x017b,0x017d,0x00df, 0x0105,0x012f,0x0101,0x0107,0x00e4,0x00e5,0x0119,0x0113, 0x010d,0x00e9,0x017a,0x0117,0x0123,0x0137,0x012b,0x013c, 0x0161,0x0144,0x0146,0x00f3,0x014d,0x00f5,0x00f6,0x00f7, 0x0173,0x0142,0x015b,0x016b,0x00fc,0x017c,0x017e,0x02d9 }; /* Windows Vietnamese */ static const unsigned short windows_1258tab[128] = { 0x20ac,UBOGON,0x201a,0x0192,0x201e,0x2026,0x2020,0x2021, 0x02c6,0x2030,UBOGON,0x2039,0x0152,UBOGON,UBOGON,UBOGON, UBOGON,0x2018,0x2019,0x201c,0x201d,0x2022,0x2013,0x2014, 0x02dc,0x2122,UBOGON,0x203a,0x0153,UBOGON,UBOGON,0x0178, 0x00a0,0x00a1,0x00a2,0x00a3,0x00a4,0x00a5,0x00a6,0x00a7, 0x00a8,0x00a9,0x00aa,0x00ab,0x00ac,0x00ad,0x00ae,0x00af, 0x00b0,0x00b1,0x00b2,0x00b3,0x00b4,0x00b5,0x00b6,0x00b7, 0x00b8,0x00b9,0x00ba,0x00bb,0x00bc,0x00bd,0x00be,0x00bf, 0x00c0,0x00c1,0x00c2,0x0102,0x00c4,0x00c5,0x00c6,0x00c7, 0x00c8,0x00c9,0x00ca,0x00cb,0x0300,0x00cd,0x00ce,0x00cf, 0x0110,0x00d1,0x0309,0x00d3,0x00d4,0x01a0,0x00d6,0x00d7, 0x00d8,0x00d9,0x00da,0x00db,0x00dc,0x01af,0x0303,0x00df, 0x00e0,0x00e1,0x00e2,0x0103,0x00e4,0x00e5,0x00e6,0x00e7, 0x00e8,0x00e9,0x00ea,0x00eb,0x0301,0x00ed,0x00ee,0x00ef, 0x0111,0x00f1,0x0323,0x00f3,0x00f4,0x01a1,0x00f6,0x00f7, 0x00f8,0x00f9,0x00fa,0x00fb,0x00fc,0x01b0,0x20ab,0x00ff }; alpine-2.10+dfsg/imap/src/charset/tmap.c0000600000175000017500000025071211512502123021615 0ustar paulproteuspaulproteus/* ======================================================================== * Copyright 1988-2006 University of Washington * * Licensed under the Apache License, Version 2.0 (the "License"); * you may not use this file except in compliance with the License. * You may obtain a copy of the License at * * http://www.apache.org/licenses/LICENSE-2.0 * * * ======================================================================== */ /* * Program: Unicode title case mapping table (current as of Unicode 5.0) * * Author: Mark Crispin * Networks and Distributed Computing * Computing & Communications * University of Washington * Administration Building, AG-44 * Seattle, WA 98195 * Internet: MRC@CAC.Washington.EDU * * Date: 7 April 2006 * Last Edited: 6 December 2006 */ #define UCS4_TMAPMAX 0x2d25 /* size of mapping table */ #define UCS4_TMAPHIMIN 0xff41 /* high mapping minimum */ #define UCS4_TMAPHIMAX 0xff5a /* high mapping maximum */ #define UCS4_TMAPHIMAP 0x20 /* high mapping offset */ /* Values for Deseret */ #define UCS4_TMAPDESERETMIN 0x10428 #define UCS4_TMAPDESERETMAX 0x1044f #define UCS4_TMAPDESERETMAP 0x28 static const unsigned short ucs4_tmaptab[UCS4_TMAPMAX+1] = { 0x0000,0x0001,0x0002,0x0003,0x0004,0x0005,0x0006,0x0007, 0x0008,0x0009,0x000a,0x000b,0x000c,0x000d,0x000e,0x000f, 0x0010,0x0011,0x0012,0x0013,0x0014,0x0015,0x0016,0x0017, 0x0018,0x0019,0x001a,0x001b,0x001c,0x001d,0x001e,0x001f, 0x0020,0x0021,0x0022,0x0023,0x0024,0x0025,0x0026,0x0027, 0x0028,0x0029,0x002a,0x002b,0x002c,0x002d,0x002e,0x002f, 0x0030,0x0031,0x0032,0x0033,0x0034,0x0035,0x0036,0x0037, 0x0038,0x0039,0x003a,0x003b,0x003c,0x003d,0x003e,0x003f, 0x0040,0x0041,0x0042,0x0043,0x0044,0x0045,0x0046,0x0047, 0x0048,0x0049,0x004a,0x004b,0x004c,0x004d,0x004e,0x004f, 0x0050,0x0051,0x0052,0x0053,0x0054,0x0055,0x0056,0x0057, 0x0058,0x0059,0x005a,0x005b,0x005c,0x005d,0x005e,0x005f, 0x0060,0x0041,0x0042,0x0043,0x0044,0x0045,0x0046,0x0047, 0x0048,0x0049,0x004a,0x004b,0x004c,0x004d,0x004e,0x004f, 0x0050,0x0051,0x0052,0x0053,0x0054,0x0055,0x0056,0x0057, 0x0058,0x0059,0x005a,0x007b,0x007c,0x007d,0x007e,0x007f, 0x0080,0x0081,0x0082,0x0083,0x0084,0x0085,0x0086,0x0087, 0x0088,0x0089,0x008a,0x008b,0x008c,0x008d,0x008e,0x008f, 0x0090,0x0091,0x0092,0x0093,0x0094,0x0095,0x0096,0x0097, 0x0098,0x0099,0x009a,0x009b,0x009c,0x009d,0x009e,0x009f, 0x00a0,0x00a1,0x00a2,0x00a3,0x00a4,0x00a5,0x00a6,0x00a7, 0x00a8,0x00a9,0x00aa,0x00ab,0x00ac,0x00ad,0x00ae,0x00af, 0x00b0,0x00b1,0x00b2,0x00b3,0x00b4,0x039c,0x00b6,0x00b7, 0x00b8,0x00b9,0x00ba,0x00bb,0x00bc,0x00bd,0x00be,0x00bf, 0x00c0,0x00c1,0x00c2,0x00c3,0x00c4,0x00c5,0x00c6,0x00c7, 0x00c8,0x00c9,0x00ca,0x00cb,0x00cc,0x00cd,0x00ce,0x00cf, 0x00d0,0x00d1,0x00d2,0x00d3,0x00d4,0x00d5,0x00d6,0x00d7, 0x00d8,0x00d9,0x00da,0x00db,0x00dc,0x00dd,0x00de,0x00df, 0x00c0,0x00c1,0x00c2,0x00c3,0x00c4,0x00c5,0x00c6,0x00c7, 0x00c8,0x00c9,0x00ca,0x00cb,0x00cc,0x00cd,0x00ce,0x00cf, 0x00d0,0x00d1,0x00d2,0x00d3,0x00d4,0x00d5,0x00d6,0x00f7, 0x00d8,0x00d9,0x00da,0x00db,0x00dc,0x00dd,0x00de,0x0178, 0x0100,0x0100,0x0102,0x0102,0x0104,0x0104,0x0106,0x0106, 0x0108,0x0108,0x010a,0x010a,0x010c,0x010c,0x010e,0x010e, 0x0110,0x0110,0x0112,0x0112,0x0114,0x0114,0x0116,0x0116, 0x0118,0x0118,0x011a,0x011a,0x011c,0x011c,0x011e,0x011e, 0x0120,0x0120,0x0122,0x0122,0x0124,0x0124,0x0126,0x0126, 0x0128,0x0128,0x012a,0x012a,0x012c,0x012c,0x012e,0x012e, 0x0130,0x0049,0x0132,0x0132,0x0134,0x0134,0x0136,0x0136, 0x0138,0x0139,0x0139,0x013b,0x013b,0x013d,0x013d,0x013f, 0x013f,0x0141,0x0141,0x0143,0x0143,0x0145,0x0145,0x0147, 0x0147,0x0149,0x014a,0x014a,0x014c,0x014c,0x014e,0x014e, 0x0150,0x0150,0x0152,0x0152,0x0154,0x0154,0x0156,0x0156, 0x0158,0x0158,0x015a,0x015a,0x015c,0x015c,0x015e,0x015e, 0x0160,0x0160,0x0162,0x0162,0x0164,0x0164,0x0166,0x0166, 0x0168,0x0168,0x016a,0x016a,0x016c,0x016c,0x016e,0x016e, 0x0170,0x0170,0x0172,0x0172,0x0174,0x0174,0x0176,0x0176, 0x0178,0x0179,0x0179,0x017b,0x017b,0x017d,0x017d,0x0053, 0x0243,0x0181,0x0182,0x0182,0x0184,0x0184,0x0186,0x0187, 0x0187,0x0189,0x018a,0x018b,0x018b,0x018d,0x018e,0x018f, 0x0190,0x0191,0x0191,0x0193,0x0194,0x01f6,0x0196,0x0197, 0x0198,0x0198,0x023d,0x019b,0x019c,0x019d,0x0220,0x019f, 0x01a0,0x01a0,0x01a2,0x01a2,0x01a4,0x01a4,0x01a6,0x01a7, 0x01a7,0x01a9,0x01aa,0x01ab,0x01ac,0x01ac,0x01ae,0x01af, 0x01af,0x01b1,0x01b2,0x01b3,0x01b3,0x01b5,0x01b5,0x01b7, 0x01b8,0x01b8,0x01ba,0x01bb,0x01bc,0x01bc,0x01be,0x01f7, 0x01c0,0x01c1,0x01c2,0x01c3,0x01c5,0x01c5,0x01c5,0x01c8, 0x01c8,0x01c8,0x01cb,0x01cb,0x01cb,0x01cd,0x01cd,0x01cf, 0x01cf,0x01d1,0x01d1,0x01d3,0x01d3,0x01d5,0x01d5,0x01d7, 0x01d7,0x01d9,0x01d9,0x01db,0x01db,0x018e,0x01de,0x01de, 0x01e0,0x01e0,0x01e2,0x01e2,0x01e4,0x01e4,0x01e6,0x01e6, 0x01e8,0x01e8,0x01ea,0x01ea,0x01ec,0x01ec,0x01ee,0x01ee, 0x01f0,0x01f2,0x01f2,0x01f2,0x01f4,0x01f4,0x01f6,0x01f7, 0x01f8,0x01f8,0x01fa,0x01fa,0x01fc,0x01fc,0x01fe,0x01fe, 0x0200,0x0200,0x0202,0x0202,0x0204,0x0204,0x0206,0x0206, 0x0208,0x0208,0x020a,0x020a,0x020c,0x020c,0x020e,0x020e, 0x0210,0x0210,0x0212,0x0212,0x0214,0x0214,0x0216,0x0216, 0x0218,0x0218,0x021a,0x021a,0x021c,0x021c,0x021e,0x021e, 0x0220,0x0221,0x0222,0x0222,0x0224,0x0224,0x0226,0x0226, 0x0228,0x0228,0x022a,0x022a,0x022c,0x022c,0x022e,0x022e, 0x0230,0x0230,0x0232,0x0232,0x0234,0x0235,0x0236,0x0237, 0x0238,0x0239,0x023a,0x023b,0x023b,0x023d,0x023e,0x023f, 0x0240,0x0241,0x0241,0x0243,0x0244,0x0245,0x0246,0x0246, 0x0248,0x0248,0x024a,0x024a,0x024c,0x024c,0x024e,0x024e, 0x0250,0x0251,0x0252,0x0181,0x0186,0x0255,0x0189,0x018a, 0x0258,0x018f,0x025a,0x0190,0x025c,0x025d,0x025e,0x025f, 0x0193,0x0261,0x0262,0x0194,0x0264,0x0265,0x0266,0x0267, 0x0197,0x0196,0x026a,0x2c62,0x026c,0x026d,0x026e,0x019c, 0x0270,0x0271,0x019d,0x0273,0x0274,0x019f,0x0276,0x0277, 0x0278,0x0279,0x027a,0x027b,0x027c,0x2c64,0x027e,0x027f, 0x01a6,0x0281,0x0282,0x01a9,0x0284,0x0285,0x0286,0x0287, 0x01ae,0x0244,0x01b1,0x01b2,0x0245,0x028d,0x028e,0x028f, 0x0290,0x0291,0x01b7,0x0293,0x0294,0x0295,0x0296,0x0297, 0x0298,0x0299,0x029a,0x029b,0x029c,0x029d,0x029e,0x029f, 0x02a0,0x02a1,0x02a2,0x02a3,0x02a4,0x02a5,0x02a6,0x02a7, 0x02a8,0x02a9,0x02aa,0x02ab,0x02ac,0x02ad,0x02ae,0x02af, 0x02b0,0x02b1,0x02b2,0x02b3,0x02b4,0x02b5,0x02b6,0x02b7, 0x02b8,0x02b9,0x02ba,0x02bb,0x02bc,0x02bd,0x02be,0x02bf, 0x02c0,0x02c1,0x02c2,0x02c3,0x02c4,0x02c5,0x02c6,0x02c7, 0x02c8,0x02c9,0x02ca,0x02cb,0x02cc,0x02cd,0x02ce,0x02cf, 0x02d0,0x02d1,0x02d2,0x02d3,0x02d4,0x02d5,0x02d6,0x02d7, 0x02d8,0x02d9,0x02da,0x02db,0x02dc,0x02dd,0x02de,0x02df, 0x02e0,0x02e1,0x02e2,0x02e3,0x02e4,0x02e5,0x02e6,0x02e7, 0x02e8,0x02e9,0x02ea,0x02eb,0x02ec,0x02ed,0x02ee,0x02ef, 0x02f0,0x02f1,0x02f2,0x02f3,0x02f4,0x02f5,0x02f6,0x02f7, 0x02f8,0x02f9,0x02fa,0x02fb,0x02fc,0x02fd,0x02fe,0x02ff, 0x0300,0x0301,0x0302,0x0303,0x0304,0x0305,0x0306,0x0307, 0x0308,0x0309,0x030a,0x030b,0x030c,0x030d,0x030e,0x030f, 0x0310,0x0311,0x0312,0x0313,0x0314,0x0315,0x0316,0x0317, 0x0318,0x0319,0x031a,0x031b,0x031c,0x031d,0x031e,0x031f, 0x0320,0x0321,0x0322,0x0323,0x0324,0x0325,0x0326,0x0327, 0x0328,0x0329,0x032a,0x032b,0x032c,0x032d,0x032e,0x032f, 0x0330,0x0331,0x0332,0x0333,0x0334,0x0335,0x0336,0x0337, 0x0338,0x0339,0x033a,0x033b,0x033c,0x033d,0x033e,0x033f, 0x0340,0x0341,0x0342,0x0343,0x0344,0x0399,0x0346,0x0347, 0x0348,0x0349,0x034a,0x034b,0x034c,0x034d,0x034e,0x034f, 0x0350,0x0351,0x0352,0x0353,0x0354,0x0355,0x0356,0x0357, 0x0358,0x0359,0x035a,0x035b,0x035c,0x035d,0x035e,0x035f, 0x0360,0x0361,0x0362,0x0363,0x0364,0x0365,0x0366,0x0367, 0x0368,0x0369,0x036a,0x036b,0x036c,0x036d,0x036e,0x036f, 0x0370,0x0371,0x0372,0x0373,0x0374,0x0375,0x0376,0x0377, 0x0378,0x0379,0x037a,0x03fd,0x03fe,0x03ff,0x037e,0x037f, 0x0380,0x0381,0x0382,0x0383,0x0384,0x0385,0x0386,0x0387, 0x0388,0x0389,0x038a,0x038b,0x038c,0x038d,0x038e,0x038f, 0x0390,0x0391,0x0392,0x0393,0x0394,0x0395,0x0396,0x0397, 0x0398,0x0399,0x039a,0x039b,0x039c,0x039d,0x039e,0x039f, 0x03a0,0x03a1,0x03a2,0x03a3,0x03a4,0x03a5,0x03a6,0x03a7, 0x03a8,0x03a9,0x03aa,0x03ab,0x0386,0x0388,0x0389,0x038a, 0x03b0,0x0391,0x0392,0x0393,0x0394,0x0395,0x0396,0x0397, 0x0398,0x0399,0x039a,0x039b,0x039c,0x039d,0x039e,0x039f, 0x03a0,0x03a1,0x03a3,0x03a3,0x03a4,0x03a5,0x03a6,0x03a7, 0x03a8,0x03a9,0x03aa,0x03ab,0x038c,0x038e,0x038f,0x03cf, 0x0392,0x0398,0x03d2,0x03d3,0x03d4,0x03a6,0x03a0,0x03d7, 0x03d8,0x03d8,0x03da,0x03da,0x03dc,0x03dc,0x03de,0x03de, 0x03e0,0x03e0,0x03e2,0x03e2,0x03e4,0x03e4,0x03e6,0x03e6, 0x03e8,0x03e8,0x03ea,0x03ea,0x03ec,0x03ec,0x03ee,0x03ee, 0x039a,0x03a1,0x03f9,0x03f3,0x03f4,0x0395,0x03f6,0x03f7, 0x03f7,0x03f9,0x03fa,0x03fa,0x03fc,0x03fd,0x03fe,0x03ff, 0x0400,0x0401,0x0402,0x0403,0x0404,0x0405,0x0406,0x0407, 0x0408,0x0409,0x040a,0x040b,0x040c,0x040d,0x040e,0x040f, 0x0410,0x0411,0x0412,0x0413,0x0414,0x0415,0x0416,0x0417, 0x0418,0x0419,0x041a,0x041b,0x041c,0x041d,0x041e,0x041f, 0x0420,0x0421,0x0422,0x0423,0x0424,0x0425,0x0426,0x0427, 0x0428,0x0429,0x042a,0x042b,0x042c,0x042d,0x042e,0x042f, 0x0410,0x0411,0x0412,0x0413,0x0414,0x0415,0x0416,0x0417, 0x0418,0x0419,0x041a,0x041b,0x041c,0x041d,0x041e,0x041f, 0x0420,0x0421,0x0422,0x0423,0x0424,0x0425,0x0426,0x0427, 0x0428,0x0429,0x042a,0x042b,0x042c,0x042d,0x042e,0x042f, 0x0400,0x0401,0x0402,0x0403,0x0404,0x0405,0x0406,0x0407, 0x0408,0x0409,0x040a,0x040b,0x040c,0x040d,0x040e,0x040f, 0x0460,0x0460,0x0462,0x0462,0x0464,0x0464,0x0466,0x0466, 0x0468,0x0468,0x046a,0x046a,0x046c,0x046c,0x046e,0x046e, 0x0470,0x0470,0x0472,0x0472,0x0474,0x0474,0x0476,0x0476, 0x0478,0x0478,0x047a,0x047a,0x047c,0x047c,0x047e,0x047e, 0x0480,0x0480,0x0482,0x0483,0x0484,0x0485,0x0486,0x0487, 0x0488,0x0489,0x048a,0x048a,0x048c,0x048c,0x048e,0x048e, 0x0490,0x0490,0x0492,0x0492,0x0494,0x0494,0x0496,0x0496, 0x0498,0x0498,0x049a,0x049a,0x049c,0x049c,0x049e,0x049e, 0x04a0,0x04a0,0x04a2,0x04a2,0x04a4,0x04a4,0x04a6,0x04a6, 0x04a8,0x04a8,0x04aa,0x04aa,0x04ac,0x04ac,0x04ae,0x04ae, 0x04b0,0x04b0,0x04b2,0x04b2,0x04b4,0x04b4,0x04b6,0x04b6, 0x04b8,0x04b8,0x04ba,0x04ba,0x04bc,0x04bc,0x04be,0x04be, 0x04c0,0x04c1,0x04c1,0x04c3,0x04c3,0x04c5,0x04c5,0x04c7, 0x04c7,0x04c9,0x04c9,0x04cb,0x04cb,0x04cd,0x04cd,0x04c0, 0x04d0,0x04d0,0x04d2,0x04d2,0x04d4,0x04d4,0x04d6,0x04d6, 0x04d8,0x04d8,0x04da,0x04da,0x04dc,0x04dc,0x04de,0x04de, 0x04e0,0x04e0,0x04e2,0x04e2,0x04e4,0x04e4,0x04e6,0x04e6, 0x04e8,0x04e8,0x04ea,0x04ea,0x04ec,0x04ec,0x04ee,0x04ee, 0x04f0,0x04f0,0x04f2,0x04f2,0x04f4,0x04f4,0x04f6,0x04f6, 0x04f8,0x04f8,0x04fa,0x04fa,0x04fc,0x04fc,0x04fe,0x04fe, 0x0500,0x0500,0x0502,0x0502,0x0504,0x0504,0x0506,0x0506, 0x0508,0x0508,0x050a,0x050a,0x050c,0x050c,0x050e,0x050e, 0x0510,0x0510,0x0512,0x0512,0x0514,0x0515,0x0516,0x0517, 0x0518,0x0519,0x051a,0x051b,0x051c,0x051d,0x051e,0x051f, 0x0520,0x0521,0x0522,0x0523,0x0524,0x0525,0x0526,0x0527, 0x0528,0x0529,0x052a,0x052b,0x052c,0x052d,0x052e,0x052f, 0x0530,0x0531,0x0532,0x0533,0x0534,0x0535,0x0536,0x0537, 0x0538,0x0539,0x053a,0x053b,0x053c,0x053d,0x053e,0x053f, 0x0540,0x0541,0x0542,0x0543,0x0544,0x0545,0x0546,0x0547, 0x0548,0x0549,0x054a,0x054b,0x054c,0x054d,0x054e,0x054f, 0x0550,0x0551,0x0552,0x0553,0x0554,0x0555,0x0556,0x0557, 0x0558,0x0559,0x055a,0x055b,0x055c,0x055d,0x055e,0x055f, 0x0560,0x0531,0x0532,0x0533,0x0534,0x0535,0x0536,0x0537, 0x0538,0x0539,0x053a,0x053b,0x053c,0x053d,0x053e,0x053f, 0x0540,0x0541,0x0542,0x0543,0x0544,0x0545,0x0546,0x0547, 0x0548,0x0549,0x054a,0x054b,0x054c,0x054d,0x054e,0x054f, 0x0550,0x0551,0x0552,0x0553,0x0554,0x0555,0x0556,0x0587, 0x0588,0x0589,0x058a,0x058b,0x058c,0x058d,0x058e,0x058f, 0x0590,0x0591,0x0592,0x0593,0x0594,0x0595,0x0596,0x0597, 0x0598,0x0599,0x059a,0x059b,0x059c,0x059d,0x059e,0x059f, 0x05a0,0x05a1,0x05a2,0x05a3,0x05a4,0x05a5,0x05a6,0x05a7, 0x05a8,0x05a9,0x05aa,0x05ab,0x05ac,0x05ad,0x05ae,0x05af, 0x05b0,0x05b1,0x05b2,0x05b3,0x05b4,0x05b5,0x05b6,0x05b7, 0x05b8,0x05b9,0x05ba,0x05bb,0x05bc,0x05bd,0x05be,0x05bf, 0x05c0,0x05c1,0x05c2,0x05c3,0x05c4,0x05c5,0x05c6,0x05c7, 0x05c8,0x05c9,0x05ca,0x05cb,0x05cc,0x05cd,0x05ce,0x05cf, 0x05d0,0x05d1,0x05d2,0x05d3,0x05d4,0x05d5,0x05d6,0x05d7, 0x05d8,0x05d9,0x05da,0x05db,0x05dc,0x05dd,0x05de,0x05df, 0x05e0,0x05e1,0x05e2,0x05e3,0x05e4,0x05e5,0x05e6,0x05e7, 0x05e8,0x05e9,0x05ea,0x05eb,0x05ec,0x05ed,0x05ee,0x05ef, 0x05f0,0x05f1,0x05f2,0x05f3,0x05f4,0x05f5,0x05f6,0x05f7, 0x05f8,0x05f9,0x05fa,0x05fb,0x05fc,0x05fd,0x05fe,0x05ff, 0x0600,0x0601,0x0602,0x0603,0x0604,0x0605,0x0606,0x0607, 0x0608,0x0609,0x060a,0x060b,0x060c,0x060d,0x060e,0x060f, 0x0610,0x0611,0x0612,0x0613,0x0614,0x0615,0x0616,0x0617, 0x0618,0x0619,0x061a,0x061b,0x061c,0x061d,0x061e,0x061f, 0x0620,0x0621,0x0622,0x0623,0x0624,0x0625,0x0626,0x0627, 0x0628,0x0629,0x062a,0x062b,0x062c,0x062d,0x062e,0x062f, 0x0630,0x0631,0x0632,0x0633,0x0634,0x0635,0x0636,0x0637, 0x0638,0x0639,0x063a,0x063b,0x063c,0x063d,0x063e,0x063f, 0x0640,0x0641,0x0642,0x0643,0x0644,0x0645,0x0646,0x0647, 0x0648,0x0649,0x064a,0x064b,0x064c,0x064d,0x064e,0x064f, 0x0650,0x0651,0x0652,0x0653,0x0654,0x0655,0x0656,0x0657, 0x0658,0x0659,0x065a,0x065b,0x065c,0x065d,0x065e,0x065f, 0x0660,0x0661,0x0662,0x0663,0x0664,0x0665,0x0666,0x0667, 0x0668,0x0669,0x066a,0x066b,0x066c,0x066d,0x066e,0x066f, 0x0670,0x0671,0x0672,0x0673,0x0674,0x0675,0x0676,0x0677, 0x0678,0x0679,0x067a,0x067b,0x067c,0x067d,0x067e,0x067f, 0x0680,0x0681,0x0682,0x0683,0x0684,0x0685,0x0686,0x0687, 0x0688,0x0689,0x068a,0x068b,0x068c,0x068d,0x068e,0x068f, 0x0690,0x0691,0x0692,0x0693,0x0694,0x0695,0x0696,0x0697, 0x0698,0x0699,0x069a,0x069b,0x069c,0x069d,0x069e,0x069f, 0x06a0,0x06a1,0x06a2,0x06a3,0x06a4,0x06a5,0x06a6,0x06a7, 0x06a8,0x06a9,0x06aa,0x06ab,0x06ac,0x06ad,0x06ae,0x06af, 0x06b0,0x06b1,0x06b2,0x06b3,0x06b4,0x06b5,0x06b6,0x06b7, 0x06b8,0x06b9,0x06ba,0x06bb,0x06bc,0x06bd,0x06be,0x06bf, 0x06c0,0x06c1,0x06c2,0x06c3,0x06c4,0x06c5,0x06c6,0x06c7, 0x06c8,0x06c9,0x06ca,0x06cb,0x06cc,0x06cd,0x06ce,0x06cf, 0x06d0,0x06d1,0x06d2,0x06d3,0x06d4,0x06d5,0x06d6,0x06d7, 0x06d8,0x06d9,0x06da,0x06db,0x06dc,0x06dd,0x06de,0x06df, 0x06e0,0x06e1,0x06e2,0x06e3,0x06e4,0x06e5,0x06e6,0x06e7, 0x06e8,0x06e9,0x06ea,0x06eb,0x06ec,0x06ed,0x06ee,0x06ef, 0x06f0,0x06f1,0x06f2,0x06f3,0x06f4,0x06f5,0x06f6,0x06f7, 0x06f8,0x06f9,0x06fa,0x06fb,0x06fc,0x06fd,0x06fe,0x06ff, 0x0700,0x0701,0x0702,0x0703,0x0704,0x0705,0x0706,0x0707, 0x0708,0x0709,0x070a,0x070b,0x070c,0x070d,0x070e,0x070f, 0x0710,0x0711,0x0712,0x0713,0x0714,0x0715,0x0716,0x0717, 0x0718,0x0719,0x071a,0x071b,0x071c,0x071d,0x071e,0x071f, 0x0720,0x0721,0x0722,0x0723,0x0724,0x0725,0x0726,0x0727, 0x0728,0x0729,0x072a,0x072b,0x072c,0x072d,0x072e,0x072f, 0x0730,0x0731,0x0732,0x0733,0x0734,0x0735,0x0736,0x0737, 0x0738,0x0739,0x073a,0x073b,0x073c,0x073d,0x073e,0x073f, 0x0740,0x0741,0x0742,0x0743,0x0744,0x0745,0x0746,0x0747, 0x0748,0x0749,0x074a,0x074b,0x074c,0x074d,0x074e,0x074f, 0x0750,0x0751,0x0752,0x0753,0x0754,0x0755,0x0756,0x0757, 0x0758,0x0759,0x075a,0x075b,0x075c,0x075d,0x075e,0x075f, 0x0760,0x0761,0x0762,0x0763,0x0764,0x0765,0x0766,0x0767, 0x0768,0x0769,0x076a,0x076b,0x076c,0x076d,0x076e,0x076f, 0x0770,0x0771,0x0772,0x0773,0x0774,0x0775,0x0776,0x0777, 0x0778,0x0779,0x077a,0x077b,0x077c,0x077d,0x077e,0x077f, 0x0780,0x0781,0x0782,0x0783,0x0784,0x0785,0x0786,0x0787, 0x0788,0x0789,0x078a,0x078b,0x078c,0x078d,0x078e,0x078f, 0x0790,0x0791,0x0792,0x0793,0x0794,0x0795,0x0796,0x0797, 0x0798,0x0799,0x079a,0x079b,0x079c,0x079d,0x079e,0x079f, 0x07a0,0x07a1,0x07a2,0x07a3,0x07a4,0x07a5,0x07a6,0x07a7, 0x07a8,0x07a9,0x07aa,0x07ab,0x07ac,0x07ad,0x07ae,0x07af, 0x07b0,0x07b1,0x07b2,0x07b3,0x07b4,0x07b5,0x07b6,0x07b7, 0x07b8,0x07b9,0x07ba,0x07bb,0x07bc,0x07bd,0x07be,0x07bf, 0x07c0,0x07c1,0x07c2,0x07c3,0x07c4,0x07c5,0x07c6,0x07c7, 0x07c8,0x07c9,0x07ca,0x07cb,0x07cc,0x07cd,0x07ce,0x07cf, 0x07d0,0x07d1,0x07d2,0x07d3,0x07d4,0x07d5,0x07d6,0x07d7, 0x07d8,0x07d9,0x07da,0x07db,0x07dc,0x07dd,0x07de,0x07df, 0x07e0,0x07e1,0x07e2,0x07e3,0x07e4,0x07e5,0x07e6,0x07e7, 0x07e8,0x07e9,0x07ea,0x07eb,0x07ec,0x07ed,0x07ee,0x07ef, 0x07f0,0x07f1,0x07f2,0x07f3,0x07f4,0x07f5,0x07f6,0x07f7, 0x07f8,0x07f9,0x07fa,0x07fb,0x07fc,0x07fd,0x07fe,0x07ff, 0x0800,0x0801,0x0802,0x0803,0x0804,0x0805,0x0806,0x0807, 0x0808,0x0809,0x080a,0x080b,0x080c,0x080d,0x080e,0x080f, 0x0810,0x0811,0x0812,0x0813,0x0814,0x0815,0x0816,0x0817, 0x0818,0x0819,0x081a,0x081b,0x081c,0x081d,0x081e,0x081f, 0x0820,0x0821,0x0822,0x0823,0x0824,0x0825,0x0826,0x0827, 0x0828,0x0829,0x082a,0x082b,0x082c,0x082d,0x082e,0x082f, 0x0830,0x0831,0x0832,0x0833,0x0834,0x0835,0x0836,0x0837, 0x0838,0x0839,0x083a,0x083b,0x083c,0x083d,0x083e,0x083f, 0x0840,0x0841,0x0842,0x0843,0x0844,0x0845,0x0846,0x0847, 0x0848,0x0849,0x084a,0x084b,0x084c,0x084d,0x084e,0x084f, 0x0850,0x0851,0x0852,0x0853,0x0854,0x0855,0x0856,0x0857, 0x0858,0x0859,0x085a,0x085b,0x085c,0x085d,0x085e,0x085f, 0x0860,0x0861,0x0862,0x0863,0x0864,0x0865,0x0866,0x0867, 0x0868,0x0869,0x086a,0x086b,0x086c,0x086d,0x086e,0x086f, 0x0870,0x0871,0x0872,0x0873,0x0874,0x0875,0x0876,0x0877, 0x0878,0x0879,0x087a,0x087b,0x087c,0x087d,0x087e,0x087f, 0x0880,0x0881,0x0882,0x0883,0x0884,0x0885,0x0886,0x0887, 0x0888,0x0889,0x088a,0x088b,0x088c,0x088d,0x088e,0x088f, 0x0890,0x0891,0x0892,0x0893,0x0894,0x0895,0x0896,0x0897, 0x0898,0x0899,0x089a,0x089b,0x089c,0x089d,0x089e,0x089f, 0x08a0,0x08a1,0x08a2,0x08a3,0x08a4,0x08a5,0x08a6,0x08a7, 0x08a8,0x08a9,0x08aa,0x08ab,0x08ac,0x08ad,0x08ae,0x08af, 0x08b0,0x08b1,0x08b2,0x08b3,0x08b4,0x08b5,0x08b6,0x08b7, 0x08b8,0x08b9,0x08ba,0x08bb,0x08bc,0x08bd,0x08be,0x08bf, 0x08c0,0x08c1,0x08c2,0x08c3,0x08c4,0x08c5,0x08c6,0x08c7, 0x08c8,0x08c9,0x08ca,0x08cb,0x08cc,0x08cd,0x08ce,0x08cf, 0x08d0,0x08d1,0x08d2,0x08d3,0x08d4,0x08d5,0x08d6,0x08d7, 0x08d8,0x08d9,0x08da,0x08db,0x08dc,0x08dd,0x08de,0x08df, 0x08e0,0x08e1,0x08e2,0x08e3,0x08e4,0x08e5,0x08e6,0x08e7, 0x08e8,0x08e9,0x08ea,0x08eb,0x08ec,0x08ed,0x08ee,0x08ef, 0x08f0,0x08f1,0x08f2,0x08f3,0x08f4,0x08f5,0x08f6,0x08f7, 0x08f8,0x08f9,0x08fa,0x08fb,0x08fc,0x08fd,0x08fe,0x08ff, 0x0900,0x0901,0x0902,0x0903,0x0904,0x0905,0x0906,0x0907, 0x0908,0x0909,0x090a,0x090b,0x090c,0x090d,0x090e,0x090f, 0x0910,0x0911,0x0912,0x0913,0x0914,0x0915,0x0916,0x0917, 0x0918,0x0919,0x091a,0x091b,0x091c,0x091d,0x091e,0x091f, 0x0920,0x0921,0x0922,0x0923,0x0924,0x0925,0x0926,0x0927, 0x0928,0x0929,0x092a,0x092b,0x092c,0x092d,0x092e,0x092f, 0x0930,0x0931,0x0932,0x0933,0x0934,0x0935,0x0936,0x0937, 0x0938,0x0939,0x093a,0x093b,0x093c,0x093d,0x093e,0x093f, 0x0940,0x0941,0x0942,0x0943,0x0944,0x0945,0x0946,0x0947, 0x0948,0x0949,0x094a,0x094b,0x094c,0x094d,0x094e,0x094f, 0x0950,0x0951,0x0952,0x0953,0x0954,0x0955,0x0956,0x0957, 0x0958,0x0959,0x095a,0x095b,0x095c,0x095d,0x095e,0x095f, 0x0960,0x0961,0x0962,0x0963,0x0964,0x0965,0x0966,0x0967, 0x0968,0x0969,0x096a,0x096b,0x096c,0x096d,0x096e,0x096f, 0x0970,0x0971,0x0972,0x0973,0x0974,0x0975,0x0976,0x0977, 0x0978,0x0979,0x097a,0x097b,0x097c,0x097d,0x097e,0x097f, 0x0980,0x0981,0x0982,0x0983,0x0984,0x0985,0x0986,0x0987, 0x0988,0x0989,0x098a,0x098b,0x098c,0x098d,0x098e,0x098f, 0x0990,0x0991,0x0992,0x0993,0x0994,0x0995,0x0996,0x0997, 0x0998,0x0999,0x099a,0x099b,0x099c,0x099d,0x099e,0x099f, 0x09a0,0x09a1,0x09a2,0x09a3,0x09a4,0x09a5,0x09a6,0x09a7, 0x09a8,0x09a9,0x09aa,0x09ab,0x09ac,0x09ad,0x09ae,0x09af, 0x09b0,0x09b1,0x09b2,0x09b3,0x09b4,0x09b5,0x09b6,0x09b7, 0x09b8,0x09b9,0x09ba,0x09bb,0x09bc,0x09bd,0x09be,0x09bf, 0x09c0,0x09c1,0x09c2,0x09c3,0x09c4,0x09c5,0x09c6,0x09c7, 0x09c8,0x09c9,0x09ca,0x09cb,0x09cc,0x09cd,0x09ce,0x09cf, 0x09d0,0x09d1,0x09d2,0x09d3,0x09d4,0x09d5,0x09d6,0x09d7, 0x09d8,0x09d9,0x09da,0x09db,0x09dc,0x09dd,0x09de,0x09df, 0x09e0,0x09e1,0x09e2,0x09e3,0x09e4,0x09e5,0x09e6,0x09e7, 0x09e8,0x09e9,0x09ea,0x09eb,0x09ec,0x09ed,0x09ee,0x09ef, 0x09f0,0x09f1,0x09f2,0x09f3,0x09f4,0x09f5,0x09f6,0x09f7, 0x09f8,0x09f9,0x09fa,0x09fb,0x09fc,0x09fd,0x09fe,0x09ff, 0x0a00,0x0a01,0x0a02,0x0a03,0x0a04,0x0a05,0x0a06,0x0a07, 0x0a08,0x0a09,0x0a0a,0x0a0b,0x0a0c,0x0a0d,0x0a0e,0x0a0f, 0x0a10,0x0a11,0x0a12,0x0a13,0x0a14,0x0a15,0x0a16,0x0a17, 0x0a18,0x0a19,0x0a1a,0x0a1b,0x0a1c,0x0a1d,0x0a1e,0x0a1f, 0x0a20,0x0a21,0x0a22,0x0a23,0x0a24,0x0a25,0x0a26,0x0a27, 0x0a28,0x0a29,0x0a2a,0x0a2b,0x0a2c,0x0a2d,0x0a2e,0x0a2f, 0x0a30,0x0a31,0x0a32,0x0a33,0x0a34,0x0a35,0x0a36,0x0a37, 0x0a38,0x0a39,0x0a3a,0x0a3b,0x0a3c,0x0a3d,0x0a3e,0x0a3f, 0x0a40,0x0a41,0x0a42,0x0a43,0x0a44,0x0a45,0x0a46,0x0a47, 0x0a48,0x0a49,0x0a4a,0x0a4b,0x0a4c,0x0a4d,0x0a4e,0x0a4f, 0x0a50,0x0a51,0x0a52,0x0a53,0x0a54,0x0a55,0x0a56,0x0a57, 0x0a58,0x0a59,0x0a5a,0x0a5b,0x0a5c,0x0a5d,0x0a5e,0x0a5f, 0x0a60,0x0a61,0x0a62,0x0a63,0x0a64,0x0a65,0x0a66,0x0a67, 0x0a68,0x0a69,0x0a6a,0x0a6b,0x0a6c,0x0a6d,0x0a6e,0x0a6f, 0x0a70,0x0a71,0x0a72,0x0a73,0x0a74,0x0a75,0x0a76,0x0a77, 0x0a78,0x0a79,0x0a7a,0x0a7b,0x0a7c,0x0a7d,0x0a7e,0x0a7f, 0x0a80,0x0a81,0x0a82,0x0a83,0x0a84,0x0a85,0x0a86,0x0a87, 0x0a88,0x0a89,0x0a8a,0x0a8b,0x0a8c,0x0a8d,0x0a8e,0x0a8f, 0x0a90,0x0a91,0x0a92,0x0a93,0x0a94,0x0a95,0x0a96,0x0a97, 0x0a98,0x0a99,0x0a9a,0x0a9b,0x0a9c,0x0a9d,0x0a9e,0x0a9f, 0x0aa0,0x0aa1,0x0aa2,0x0aa3,0x0aa4,0x0aa5,0x0aa6,0x0aa7, 0x0aa8,0x0aa9,0x0aaa,0x0aab,0x0aac,0x0aad,0x0aae,0x0aaf, 0x0ab0,0x0ab1,0x0ab2,0x0ab3,0x0ab4,0x0ab5,0x0ab6,0x0ab7, 0x0ab8,0x0ab9,0x0aba,0x0abb,0x0abc,0x0abd,0x0abe,0x0abf, 0x0ac0,0x0ac1,0x0ac2,0x0ac3,0x0ac4,0x0ac5,0x0ac6,0x0ac7, 0x0ac8,0x0ac9,0x0aca,0x0acb,0x0acc,0x0acd,0x0ace,0x0acf, 0x0ad0,0x0ad1,0x0ad2,0x0ad3,0x0ad4,0x0ad5,0x0ad6,0x0ad7, 0x0ad8,0x0ad9,0x0ada,0x0adb,0x0adc,0x0add,0x0ade,0x0adf, 0x0ae0,0x0ae1,0x0ae2,0x0ae3,0x0ae4,0x0ae5,0x0ae6,0x0ae7, 0x0ae8,0x0ae9,0x0aea,0x0aeb,0x0aec,0x0aed,0x0aee,0x0aef, 0x0af0,0x0af1,0x0af2,0x0af3,0x0af4,0x0af5,0x0af6,0x0af7, 0x0af8,0x0af9,0x0afa,0x0afb,0x0afc,0x0afd,0x0afe,0x0aff, 0x0b00,0x0b01,0x0b02,0x0b03,0x0b04,0x0b05,0x0b06,0x0b07, 0x0b08,0x0b09,0x0b0a,0x0b0b,0x0b0c,0x0b0d,0x0b0e,0x0b0f, 0x0b10,0x0b11,0x0b12,0x0b13,0x0b14,0x0b15,0x0b16,0x0b17, 0x0b18,0x0b19,0x0b1a,0x0b1b,0x0b1c,0x0b1d,0x0b1e,0x0b1f, 0x0b20,0x0b21,0x0b22,0x0b23,0x0b24,0x0b25,0x0b26,0x0b27, 0x0b28,0x0b29,0x0b2a,0x0b2b,0x0b2c,0x0b2d,0x0b2e,0x0b2f, 0x0b30,0x0b31,0x0b32,0x0b33,0x0b34,0x0b35,0x0b36,0x0b37, 0x0b38,0x0b39,0x0b3a,0x0b3b,0x0b3c,0x0b3d,0x0b3e,0x0b3f, 0x0b40,0x0b41,0x0b42,0x0b43,0x0b44,0x0b45,0x0b46,0x0b47, 0x0b48,0x0b49,0x0b4a,0x0b4b,0x0b4c,0x0b4d,0x0b4e,0x0b4f, 0x0b50,0x0b51,0x0b52,0x0b53,0x0b54,0x0b55,0x0b56,0x0b57, 0x0b58,0x0b59,0x0b5a,0x0b5b,0x0b5c,0x0b5d,0x0b5e,0x0b5f, 0x0b60,0x0b61,0x0b62,0x0b63,0x0b64,0x0b65,0x0b66,0x0b67, 0x0b68,0x0b69,0x0b6a,0x0b6b,0x0b6c,0x0b6d,0x0b6e,0x0b6f, 0x0b70,0x0b71,0x0b72,0x0b73,0x0b74,0x0b75,0x0b76,0x0b77, 0x0b78,0x0b79,0x0b7a,0x0b7b,0x0b7c,0x0b7d,0x0b7e,0x0b7f, 0x0b80,0x0b81,0x0b82,0x0b83,0x0b84,0x0b85,0x0b86,0x0b87, 0x0b88,0x0b89,0x0b8a,0x0b8b,0x0b8c,0x0b8d,0x0b8e,0x0b8f, 0x0b90,0x0b91,0x0b92,0x0b93,0x0b94,0x0b95,0x0b96,0x0b97, 0x0b98,0x0b99,0x0b9a,0x0b9b,0x0b9c,0x0b9d,0x0b9e,0x0b9f, 0x0ba0,0x0ba1,0x0ba2,0x0ba3,0x0ba4,0x0ba5,0x0ba6,0x0ba7, 0x0ba8,0x0ba9,0x0baa,0x0bab,0x0bac,0x0bad,0x0bae,0x0baf, 0x0bb0,0x0bb1,0x0bb2,0x0bb3,0x0bb4,0x0bb5,0x0bb6,0x0bb7, 0x0bb8,0x0bb9,0x0bba,0x0bbb,0x0bbc,0x0bbd,0x0bbe,0x0bbf, 0x0bc0,0x0bc1,0x0bc2,0x0bc3,0x0bc4,0x0bc5,0x0bc6,0x0bc7, 0x0bc8,0x0bc9,0x0bca,0x0bcb,0x0bcc,0x0bcd,0x0bce,0x0bcf, 0x0bd0,0x0bd1,0x0bd2,0x0bd3,0x0bd4,0x0bd5,0x0bd6,0x0bd7, 0x0bd8,0x0bd9,0x0bda,0x0bdb,0x0bdc,0x0bdd,0x0bde,0x0bdf, 0x0be0,0x0be1,0x0be2,0x0be3,0x0be4,0x0be5,0x0be6,0x0be7, 0x0be8,0x0be9,0x0bea,0x0beb,0x0bec,0x0bed,0x0bee,0x0bef, 0x0bf0,0x0bf1,0x0bf2,0x0bf3,0x0bf4,0x0bf5,0x0bf6,0x0bf7, 0x0bf8,0x0bf9,0x0bfa,0x0bfb,0x0bfc,0x0bfd,0x0bfe,0x0bff, 0x0c00,0x0c01,0x0c02,0x0c03,0x0c04,0x0c05,0x0c06,0x0c07, 0x0c08,0x0c09,0x0c0a,0x0c0b,0x0c0c,0x0c0d,0x0c0e,0x0c0f, 0x0c10,0x0c11,0x0c12,0x0c13,0x0c14,0x0c15,0x0c16,0x0c17, 0x0c18,0x0c19,0x0c1a,0x0c1b,0x0c1c,0x0c1d,0x0c1e,0x0c1f, 0x0c20,0x0c21,0x0c22,0x0c23,0x0c24,0x0c25,0x0c26,0x0c27, 0x0c28,0x0c29,0x0c2a,0x0c2b,0x0c2c,0x0c2d,0x0c2e,0x0c2f, 0x0c30,0x0c31,0x0c32,0x0c33,0x0c34,0x0c35,0x0c36,0x0c37, 0x0c38,0x0c39,0x0c3a,0x0c3b,0x0c3c,0x0c3d,0x0c3e,0x0c3f, 0x0c40,0x0c41,0x0c42,0x0c43,0x0c44,0x0c45,0x0c46,0x0c47, 0x0c48,0x0c49,0x0c4a,0x0c4b,0x0c4c,0x0c4d,0x0c4e,0x0c4f, 0x0c50,0x0c51,0x0c52,0x0c53,0x0c54,0x0c55,0x0c56,0x0c57, 0x0c58,0x0c59,0x0c5a,0x0c5b,0x0c5c,0x0c5d,0x0c5e,0x0c5f, 0x0c60,0x0c61,0x0c62,0x0c63,0x0c64,0x0c65,0x0c66,0x0c67, 0x0c68,0x0c69,0x0c6a,0x0c6b,0x0c6c,0x0c6d,0x0c6e,0x0c6f, 0x0c70,0x0c71,0x0c72,0x0c73,0x0c74,0x0c75,0x0c76,0x0c77, 0x0c78,0x0c79,0x0c7a,0x0c7b,0x0c7c,0x0c7d,0x0c7e,0x0c7f, 0x0c80,0x0c81,0x0c82,0x0c83,0x0c84,0x0c85,0x0c86,0x0c87, 0x0c88,0x0c89,0x0c8a,0x0c8b,0x0c8c,0x0c8d,0x0c8e,0x0c8f, 0x0c90,0x0c91,0x0c92,0x0c93,0x0c94,0x0c95,0x0c96,0x0c97, 0x0c98,0x0c99,0x0c9a,0x0c9b,0x0c9c,0x0c9d,0x0c9e,0x0c9f, 0x0ca0,0x0ca1,0x0ca2,0x0ca3,0x0ca4,0x0ca5,0x0ca6,0x0ca7, 0x0ca8,0x0ca9,0x0caa,0x0cab,0x0cac,0x0cad,0x0cae,0x0caf, 0x0cb0,0x0cb1,0x0cb2,0x0cb3,0x0cb4,0x0cb5,0x0cb6,0x0cb7, 0x0cb8,0x0cb9,0x0cba,0x0cbb,0x0cbc,0x0cbd,0x0cbe,0x0cbf, 0x0cc0,0x0cc1,0x0cc2,0x0cc3,0x0cc4,0x0cc5,0x0cc6,0x0cc7, 0x0cc8,0x0cc9,0x0cca,0x0ccb,0x0ccc,0x0ccd,0x0cce,0x0ccf, 0x0cd0,0x0cd1,0x0cd2,0x0cd3,0x0cd4,0x0cd5,0x0cd6,0x0cd7, 0x0cd8,0x0cd9,0x0cda,0x0cdb,0x0cdc,0x0cdd,0x0cde,0x0cdf, 0x0ce0,0x0ce1,0x0ce2,0x0ce3,0x0ce4,0x0ce5,0x0ce6,0x0ce7, 0x0ce8,0x0ce9,0x0cea,0x0ceb,0x0cec,0x0ced,0x0cee,0x0cef, 0x0cf0,0x0cf1,0x0cf2,0x0cf3,0x0cf4,0x0cf5,0x0cf6,0x0cf7, 0x0cf8,0x0cf9,0x0cfa,0x0cfb,0x0cfc,0x0cfd,0x0cfe,0x0cff, 0x0d00,0x0d01,0x0d02,0x0d03,0x0d04,0x0d05,0x0d06,0x0d07, 0x0d08,0x0d09,0x0d0a,0x0d0b,0x0d0c,0x0d0d,0x0d0e,0x0d0f, 0x0d10,0x0d11,0x0d12,0x0d13,0x0d14,0x0d15,0x0d16,0x0d17, 0x0d18,0x0d19,0x0d1a,0x0d1b,0x0d1c,0x0d1d,0x0d1e,0x0d1f, 0x0d20,0x0d21,0x0d22,0x0d23,0x0d24,0x0d25,0x0d26,0x0d27, 0x0d28,0x0d29,0x0d2a,0x0d2b,0x0d2c,0x0d2d,0x0d2e,0x0d2f, 0x0d30,0x0d31,0x0d32,0x0d33,0x0d34,0x0d35,0x0d36,0x0d37, 0x0d38,0x0d39,0x0d3a,0x0d3b,0x0d3c,0x0d3d,0x0d3e,0x0d3f, 0x0d40,0x0d41,0x0d42,0x0d43,0x0d44,0x0d45,0x0d46,0x0d47, 0x0d48,0x0d49,0x0d4a,0x0d4b,0x0d4c,0x0d4d,0x0d4e,0x0d4f, 0x0d50,0x0d51,0x0d52,0x0d53,0x0d54,0x0d55,0x0d56,0x0d57, 0x0d58,0x0d59,0x0d5a,0x0d5b,0x0d5c,0x0d5d,0x0d5e,0x0d5f, 0x0d60,0x0d61,0x0d62,0x0d63,0x0d64,0x0d65,0x0d66,0x0d67, 0x0d68,0x0d69,0x0d6a,0x0d6b,0x0d6c,0x0d6d,0x0d6e,0x0d6f, 0x0d70,0x0d71,0x0d72,0x0d73,0x0d74,0x0d75,0x0d76,0x0d77, 0x0d78,0x0d79,0x0d7a,0x0d7b,0x0d7c,0x0d7d,0x0d7e,0x0d7f, 0x0d80,0x0d81,0x0d82,0x0d83,0x0d84,0x0d85,0x0d86,0x0d87, 0x0d88,0x0d89,0x0d8a,0x0d8b,0x0d8c,0x0d8d,0x0d8e,0x0d8f, 0x0d90,0x0d91,0x0d92,0x0d93,0x0d94,0x0d95,0x0d96,0x0d97, 0x0d98,0x0d99,0x0d9a,0x0d9b,0x0d9c,0x0d9d,0x0d9e,0x0d9f, 0x0da0,0x0da1,0x0da2,0x0da3,0x0da4,0x0da5,0x0da6,0x0da7, 0x0da8,0x0da9,0x0daa,0x0dab,0x0dac,0x0dad,0x0dae,0x0daf, 0x0db0,0x0db1,0x0db2,0x0db3,0x0db4,0x0db5,0x0db6,0x0db7, 0x0db8,0x0db9,0x0dba,0x0dbb,0x0dbc,0x0dbd,0x0dbe,0x0dbf, 0x0dc0,0x0dc1,0x0dc2,0x0dc3,0x0dc4,0x0dc5,0x0dc6,0x0dc7, 0x0dc8,0x0dc9,0x0dca,0x0dcb,0x0dcc,0x0dcd,0x0dce,0x0dcf, 0x0dd0,0x0dd1,0x0dd2,0x0dd3,0x0dd4,0x0dd5,0x0dd6,0x0dd7, 0x0dd8,0x0dd9,0x0dda,0x0ddb,0x0ddc,0x0ddd,0x0dde,0x0ddf, 0x0de0,0x0de1,0x0de2,0x0de3,0x0de4,0x0de5,0x0de6,0x0de7, 0x0de8,0x0de9,0x0dea,0x0deb,0x0dec,0x0ded,0x0dee,0x0def, 0x0df0,0x0df1,0x0df2,0x0df3,0x0df4,0x0df5,0x0df6,0x0df7, 0x0df8,0x0df9,0x0dfa,0x0dfb,0x0dfc,0x0dfd,0x0dfe,0x0dff, 0x0e00,0x0e01,0x0e02,0x0e03,0x0e04,0x0e05,0x0e06,0x0e07, 0x0e08,0x0e09,0x0e0a,0x0e0b,0x0e0c,0x0e0d,0x0e0e,0x0e0f, 0x0e10,0x0e11,0x0e12,0x0e13,0x0e14,0x0e15,0x0e16,0x0e17, 0x0e18,0x0e19,0x0e1a,0x0e1b,0x0e1c,0x0e1d,0x0e1e,0x0e1f, 0x0e20,0x0e21,0x0e22,0x0e23,0x0e24,0x0e25,0x0e26,0x0e27, 0x0e28,0x0e29,0x0e2a,0x0e2b,0x0e2c,0x0e2d,0x0e2e,0x0e2f, 0x0e30,0x0e31,0x0e32,0x0e33,0x0e34,0x0e35,0x0e36,0x0e37, 0x0e38,0x0e39,0x0e3a,0x0e3b,0x0e3c,0x0e3d,0x0e3e,0x0e3f, 0x0e40,0x0e41,0x0e42,0x0e43,0x0e44,0x0e45,0x0e46,0x0e47, 0x0e48,0x0e49,0x0e4a,0x0e4b,0x0e4c,0x0e4d,0x0e4e,0x0e4f, 0x0e50,0x0e51,0x0e52,0x0e53,0x0e54,0x0e55,0x0e56,0x0e57, 0x0e58,0x0e59,0x0e5a,0x0e5b,0x0e5c,0x0e5d,0x0e5e,0x0e5f, 0x0e60,0x0e61,0x0e62,0x0e63,0x0e64,0x0e65,0x0e66,0x0e67, 0x0e68,0x0e69,0x0e6a,0x0e6b,0x0e6c,0x0e6d,0x0e6e,0x0e6f, 0x0e70,0x0e71,0x0e72,0x0e73,0x0e74,0x0e75,0x0e76,0x0e77, 0x0e78,0x0e79,0x0e7a,0x0e7b,0x0e7c,0x0e7d,0x0e7e,0x0e7f, 0x0e80,0x0e81,0x0e82,0x0e83,0x0e84,0x0e85,0x0e86,0x0e87, 0x0e88,0x0e89,0x0e8a,0x0e8b,0x0e8c,0x0e8d,0x0e8e,0x0e8f, 0x0e90,0x0e91,0x0e92,0x0e93,0x0e94,0x0e95,0x0e96,0x0e97, 0x0e98,0x0e99,0x0e9a,0x0e9b,0x0e9c,0x0e9d,0x0e9e,0x0e9f, 0x0ea0,0x0ea1,0x0ea2,0x0ea3,0x0ea4,0x0ea5,0x0ea6,0x0ea7, 0x0ea8,0x0ea9,0x0eaa,0x0eab,0x0eac,0x0ead,0x0eae,0x0eaf, 0x0eb0,0x0eb1,0x0eb2,0x0eb3,0x0eb4,0x0eb5,0x0eb6,0x0eb7, 0x0eb8,0x0eb9,0x0eba,0x0ebb,0x0ebc,0x0ebd,0x0ebe,0x0ebf, 0x0ec0,0x0ec1,0x0ec2,0x0ec3,0x0ec4,0x0ec5,0x0ec6,0x0ec7, 0x0ec8,0x0ec9,0x0eca,0x0ecb,0x0ecc,0x0ecd,0x0ece,0x0ecf, 0x0ed0,0x0ed1,0x0ed2,0x0ed3,0x0ed4,0x0ed5,0x0ed6,0x0ed7, 0x0ed8,0x0ed9,0x0eda,0x0edb,0x0edc,0x0edd,0x0ede,0x0edf, 0x0ee0,0x0ee1,0x0ee2,0x0ee3,0x0ee4,0x0ee5,0x0ee6,0x0ee7, 0x0ee8,0x0ee9,0x0eea,0x0eeb,0x0eec,0x0eed,0x0eee,0x0eef, 0x0ef0,0x0ef1,0x0ef2,0x0ef3,0x0ef4,0x0ef5,0x0ef6,0x0ef7, 0x0ef8,0x0ef9,0x0efa,0x0efb,0x0efc,0x0efd,0x0efe,0x0eff, 0x0f00,0x0f01,0x0f02,0x0f03,0x0f04,0x0f05,0x0f06,0x0f07, 0x0f08,0x0f09,0x0f0a,0x0f0b,0x0f0c,0x0f0d,0x0f0e,0x0f0f, 0x0f10,0x0f11,0x0f12,0x0f13,0x0f14,0x0f15,0x0f16,0x0f17, 0x0f18,0x0f19,0x0f1a,0x0f1b,0x0f1c,0x0f1d,0x0f1e,0x0f1f, 0x0f20,0x0f21,0x0f22,0x0f23,0x0f24,0x0f25,0x0f26,0x0f27, 0x0f28,0x0f29,0x0f2a,0x0f2b,0x0f2c,0x0f2d,0x0f2e,0x0f2f, 0x0f30,0x0f31,0x0f32,0x0f33,0x0f34,0x0f35,0x0f36,0x0f37, 0x0f38,0x0f39,0x0f3a,0x0f3b,0x0f3c,0x0f3d,0x0f3e,0x0f3f, 0x0f40,0x0f41,0x0f42,0x0f43,0x0f44,0x0f45,0x0f46,0x0f47, 0x0f48,0x0f49,0x0f4a,0x0f4b,0x0f4c,0x0f4d,0x0f4e,0x0f4f, 0x0f50,0x0f51,0x0f52,0x0f53,0x0f54,0x0f55,0x0f56,0x0f57, 0x0f58,0x0f59,0x0f5a,0x0f5b,0x0f5c,0x0f5d,0x0f5e,0x0f5f, 0x0f60,0x0f61,0x0f62,0x0f63,0x0f64,0x0f65,0x0f66,0x0f67, 0x0f68,0x0f69,0x0f6a,0x0f6b,0x0f6c,0x0f6d,0x0f6e,0x0f6f, 0x0f70,0x0f71,0x0f72,0x0f73,0x0f74,0x0f75,0x0f76,0x0f77, 0x0f78,0x0f79,0x0f7a,0x0f7b,0x0f7c,0x0f7d,0x0f7e,0x0f7f, 0x0f80,0x0f81,0x0f82,0x0f83,0x0f84,0x0f85,0x0f86,0x0f87, 0x0f88,0x0f89,0x0f8a,0x0f8b,0x0f8c,0x0f8d,0x0f8e,0x0f8f, 0x0f90,0x0f91,0x0f92,0x0f93,0x0f94,0x0f95,0x0f96,0x0f97, 0x0f98,0x0f99,0x0f9a,0x0f9b,0x0f9c,0x0f9d,0x0f9e,0x0f9f, 0x0fa0,0x0fa1,0x0fa2,0x0fa3,0x0fa4,0x0fa5,0x0fa6,0x0fa7, 0x0fa8,0x0fa9,0x0faa,0x0fab,0x0fac,0x0fad,0x0fae,0x0faf, 0x0fb0,0x0fb1,0x0fb2,0x0fb3,0x0fb4,0x0fb5,0x0fb6,0x0fb7, 0x0fb8,0x0fb9,0x0fba,0x0fbb,0x0fbc,0x0fbd,0x0fbe,0x0fbf, 0x0fc0,0x0fc1,0x0fc2,0x0fc3,0x0fc4,0x0fc5,0x0fc6,0x0fc7, 0x0fc8,0x0fc9,0x0fca,0x0fcb,0x0fcc,0x0fcd,0x0fce,0x0fcf, 0x0fd0,0x0fd1,0x0fd2,0x0fd3,0x0fd4,0x0fd5,0x0fd6,0x0fd7, 0x0fd8,0x0fd9,0x0fda,0x0fdb,0x0fdc,0x0fdd,0x0fde,0x0fdf, 0x0fe0,0x0fe1,0x0fe2,0x0fe3,0x0fe4,0x0fe5,0x0fe6,0x0fe7, 0x0fe8,0x0fe9,0x0fea,0x0feb,0x0fec,0x0fed,0x0fee,0x0fef, 0x0ff0,0x0ff1,0x0ff2,0x0ff3,0x0ff4,0x0ff5,0x0ff6,0x0ff7, 0x0ff8,0x0ff9,0x0ffa,0x0ffb,0x0ffc,0x0ffd,0x0ffe,0x0fff, 0x1000,0x1001,0x1002,0x1003,0x1004,0x1005,0x1006,0x1007, 0x1008,0x1009,0x100a,0x100b,0x100c,0x100d,0x100e,0x100f, 0x1010,0x1011,0x1012,0x1013,0x1014,0x1015,0x1016,0x1017, 0x1018,0x1019,0x101a,0x101b,0x101c,0x101d,0x101e,0x101f, 0x1020,0x1021,0x1022,0x1023,0x1024,0x1025,0x1026,0x1027, 0x1028,0x1029,0x102a,0x102b,0x102c,0x102d,0x102e,0x102f, 0x1030,0x1031,0x1032,0x1033,0x1034,0x1035,0x1036,0x1037, 0x1038,0x1039,0x103a,0x103b,0x103c,0x103d,0x103e,0x103f, 0x1040,0x1041,0x1042,0x1043,0x1044,0x1045,0x1046,0x1047, 0x1048,0x1049,0x104a,0x104b,0x104c,0x104d,0x104e,0x104f, 0x1050,0x1051,0x1052,0x1053,0x1054,0x1055,0x1056,0x1057, 0x1058,0x1059,0x105a,0x105b,0x105c,0x105d,0x105e,0x105f, 0x1060,0x1061,0x1062,0x1063,0x1064,0x1065,0x1066,0x1067, 0x1068,0x1069,0x106a,0x106b,0x106c,0x106d,0x106e,0x106f, 0x1070,0x1071,0x1072,0x1073,0x1074,0x1075,0x1076,0x1077, 0x1078,0x1079,0x107a,0x107b,0x107c,0x107d,0x107e,0x107f, 0x1080,0x1081,0x1082,0x1083,0x1084,0x1085,0x1086,0x1087, 0x1088,0x1089,0x108a,0x108b,0x108c,0x108d,0x108e,0x108f, 0x1090,0x1091,0x1092,0x1093,0x1094,0x1095,0x1096,0x1097, 0x1098,0x1099,0x109a,0x109b,0x109c,0x109d,0x109e,0x109f, 0x10a0,0x10a1,0x10a2,0x10a3,0x10a4,0x10a5,0x10a6,0x10a7, 0x10a8,0x10a9,0x10aa,0x10ab,0x10ac,0x10ad,0x10ae,0x10af, 0x10b0,0x10b1,0x10b2,0x10b3,0x10b4,0x10b5,0x10b6,0x10b7, 0x10b8,0x10b9,0x10ba,0x10bb,0x10bc,0x10bd,0x10be,0x10bf, 0x10c0,0x10c1,0x10c2,0x10c3,0x10c4,0x10c5,0x10c6,0x10c7, 0x10c8,0x10c9,0x10ca,0x10cb,0x10cc,0x10cd,0x10ce,0x10cf, 0x10d0,0x10d1,0x10d2,0x10d3,0x10d4,0x10d5,0x10d6,0x10d7, 0x10d8,0x10d9,0x10da,0x10db,0x10dc,0x10dd,0x10de,0x10df, 0x10e0,0x10e1,0x10e2,0x10e3,0x10e4,0x10e5,0x10e6,0x10e7, 0x10e8,0x10e9,0x10ea,0x10eb,0x10ec,0x10ed,0x10ee,0x10ef, 0x10f0,0x10f1,0x10f2,0x10f3,0x10f4,0x10f5,0x10f6,0x10f7, 0x10f8,0x10f9,0x10fa,0x10fb,0x10fc,0x10fd,0x10fe,0x10ff, 0x1100,0x1101,0x1102,0x1103,0x1104,0x1105,0x1106,0x1107, 0x1108,0x1109,0x110a,0x110b,0x110c,0x110d,0x110e,0x110f, 0x1110,0x1111,0x1112,0x1113,0x1114,0x1115,0x1116,0x1117, 0x1118,0x1119,0x111a,0x111b,0x111c,0x111d,0x111e,0x111f, 0x1120,0x1121,0x1122,0x1123,0x1124,0x1125,0x1126,0x1127, 0x1128,0x1129,0x112a,0x112b,0x112c,0x112d,0x112e,0x112f, 0x1130,0x1131,0x1132,0x1133,0x1134,0x1135,0x1136,0x1137, 0x1138,0x1139,0x113a,0x113b,0x113c,0x113d,0x113e,0x113f, 0x1140,0x1141,0x1142,0x1143,0x1144,0x1145,0x1146,0x1147, 0x1148,0x1149,0x114a,0x114b,0x114c,0x114d,0x114e,0x114f, 0x1150,0x1151,0x1152,0x1153,0x1154,0x1155,0x1156,0x1157, 0x1158,0x1159,0x115a,0x115b,0x115c,0x115d,0x115e,0x115f, 0x1160,0x1161,0x1162,0x1163,0x1164,0x1165,0x1166,0x1167, 0x1168,0x1169,0x116a,0x116b,0x116c,0x116d,0x116e,0x116f, 0x1170,0x1171,0x1172,0x1173,0x1174,0x1175,0x1176,0x1177, 0x1178,0x1179,0x117a,0x117b,0x117c,0x117d,0x117e,0x117f, 0x1180,0x1181,0x1182,0x1183,0x1184,0x1185,0x1186,0x1187, 0x1188,0x1189,0x118a,0x118b,0x118c,0x118d,0x118e,0x118f, 0x1190,0x1191,0x1192,0x1193,0x1194,0x1195,0x1196,0x1197, 0x1198,0x1199,0x119a,0x119b,0x119c,0x119d,0x119e,0x119f, 0x11a0,0x11a1,0x11a2,0x11a3,0x11a4,0x11a5,0x11a6,0x11a7, 0x11a8,0x11a9,0x11aa,0x11ab,0x11ac,0x11ad,0x11ae,0x11af, 0x11b0,0x11b1,0x11b2,0x11b3,0x11b4,0x11b5,0x11b6,0x11b7, 0x11b8,0x11b9,0x11ba,0x11bb,0x11bc,0x11bd,0x11be,0x11bf, 0x11c0,0x11c1,0x11c2,0x11c3,0x11c4,0x11c5,0x11c6,0x11c7, 0x11c8,0x11c9,0x11ca,0x11cb,0x11cc,0x11cd,0x11ce,0x11cf, 0x11d0,0x11d1,0x11d2,0x11d3,0x11d4,0x11d5,0x11d6,0x11d7, 0x11d8,0x11d9,0x11da,0x11db,0x11dc,0x11dd,0x11de,0x11df, 0x11e0,0x11e1,0x11e2,0x11e3,0x11e4,0x11e5,0x11e6,0x11e7, 0x11e8,0x11e9,0x11ea,0x11eb,0x11ec,0x11ed,0x11ee,0x11ef, 0x11f0,0x11f1,0x11f2,0x11f3,0x11f4,0x11f5,0x11f6,0x11f7, 0x11f8,0x11f9,0x11fa,0x11fb,0x11fc,0x11fd,0x11fe,0x11ff, 0x1200,0x1201,0x1202,0x1203,0x1204,0x1205,0x1206,0x1207, 0x1208,0x1209,0x120a,0x120b,0x120c,0x120d,0x120e,0x120f, 0x1210,0x1211,0x1212,0x1213,0x1214,0x1215,0x1216,0x1217, 0x1218,0x1219,0x121a,0x121b,0x121c,0x121d,0x121e,0x121f, 0x1220,0x1221,0x1222,0x1223,0x1224,0x1225,0x1226,0x1227, 0x1228,0x1229,0x122a,0x122b,0x122c,0x122d,0x122e,0x122f, 0x1230,0x1231,0x1232,0x1233,0x1234,0x1235,0x1236,0x1237, 0x1238,0x1239,0x123a,0x123b,0x123c,0x123d,0x123e,0x123f, 0x1240,0x1241,0x1242,0x1243,0x1244,0x1245,0x1246,0x1247, 0x1248,0x1249,0x124a,0x124b,0x124c,0x124d,0x124e,0x124f, 0x1250,0x1251,0x1252,0x1253,0x1254,0x1255,0x1256,0x1257, 0x1258,0x1259,0x125a,0x125b,0x125c,0x125d,0x125e,0x125f, 0x1260,0x1261,0x1262,0x1263,0x1264,0x1265,0x1266,0x1267, 0x1268,0x1269,0x126a,0x126b,0x126c,0x126d,0x126e,0x126f, 0x1270,0x1271,0x1272,0x1273,0x1274,0x1275,0x1276,0x1277, 0x1278,0x1279,0x127a,0x127b,0x127c,0x127d,0x127e,0x127f, 0x1280,0x1281,0x1282,0x1283,0x1284,0x1285,0x1286,0x1287, 0x1288,0x1289,0x128a,0x128b,0x128c,0x128d,0x128e,0x128f, 0x1290,0x1291,0x1292,0x1293,0x1294,0x1295,0x1296,0x1297, 0x1298,0x1299,0x129a,0x129b,0x129c,0x129d,0x129e,0x129f, 0x12a0,0x12a1,0x12a2,0x12a3,0x12a4,0x12a5,0x12a6,0x12a7, 0x12a8,0x12a9,0x12aa,0x12ab,0x12ac,0x12ad,0x12ae,0x12af, 0x12b0,0x12b1,0x12b2,0x12b3,0x12b4,0x12b5,0x12b6,0x12b7, 0x12b8,0x12b9,0x12ba,0x12bb,0x12bc,0x12bd,0x12be,0x12bf, 0x12c0,0x12c1,0x12c2,0x12c3,0x12c4,0x12c5,0x12c6,0x12c7, 0x12c8,0x12c9,0x12ca,0x12cb,0x12cc,0x12cd,0x12ce,0x12cf, 0x12d0,0x12d1,0x12d2,0x12d3,0x12d4,0x12d5,0x12d6,0x12d7, 0x12d8,0x12d9,0x12da,0x12db,0x12dc,0x12dd,0x12de,0x12df, 0x12e0,0x12e1,0x12e2,0x12e3,0x12e4,0x12e5,0x12e6,0x12e7, 0x12e8,0x12e9,0x12ea,0x12eb,0x12ec,0x12ed,0x12ee,0x12ef, 0x12f0,0x12f1,0x12f2,0x12f3,0x12f4,0x12f5,0x12f6,0x12f7, 0x12f8,0x12f9,0x12fa,0x12fb,0x12fc,0x12fd,0x12fe,0x12ff, 0x1300,0x1301,0x1302,0x1303,0x1304,0x1305,0x1306,0x1307, 0x1308,0x1309,0x130a,0x130b,0x130c,0x130d,0x130e,0x130f, 0x1310,0x1311,0x1312,0x1313,0x1314,0x1315,0x1316,0x1317, 0x1318,0x1319,0x131a,0x131b,0x131c,0x131d,0x131e,0x131f, 0x1320,0x1321,0x1322,0x1323,0x1324,0x1325,0x1326,0x1327, 0x1328,0x1329,0x132a,0x132b,0x132c,0x132d,0x132e,0x132f, 0x1330,0x1331,0x1332,0x1333,0x1334,0x1335,0x1336,0x1337, 0x1338,0x1339,0x133a,0x133b,0x133c,0x133d,0x133e,0x133f, 0x1340,0x1341,0x1342,0x1343,0x1344,0x1345,0x1346,0x1347, 0x1348,0x1349,0x134a,0x134b,0x134c,0x134d,0x134e,0x134f, 0x1350,0x1351,0x1352,0x1353,0x1354,0x1355,0x1356,0x1357, 0x1358,0x1359,0x135a,0x135b,0x135c,0x135d,0x135e,0x135f, 0x1360,0x1361,0x1362,0x1363,0x1364,0x1365,0x1366,0x1367, 0x1368,0x1369,0x136a,0x136b,0x136c,0x136d,0x136e,0x136f, 0x1370,0x1371,0x1372,0x1373,0x1374,0x1375,0x1376,0x1377, 0x1378,0x1379,0x137a,0x137b,0x137c,0x137d,0x137e,0x137f, 0x1380,0x1381,0x1382,0x1383,0x1384,0x1385,0x1386,0x1387, 0x1388,0x1389,0x138a,0x138b,0x138c,0x138d,0x138e,0x138f, 0x1390,0x1391,0x1392,0x1393,0x1394,0x1395,0x1396,0x1397, 0x1398,0x1399,0x139a,0x139b,0x139c,0x139d,0x139e,0x139f, 0x13a0,0x13a1,0x13a2,0x13a3,0x13a4,0x13a5,0x13a6,0x13a7, 0x13a8,0x13a9,0x13aa,0x13ab,0x13ac,0x13ad,0x13ae,0x13af, 0x13b0,0x13b1,0x13b2,0x13b3,0x13b4,0x13b5,0x13b6,0x13b7, 0x13b8,0x13b9,0x13ba,0x13bb,0x13bc,0x13bd,0x13be,0x13bf, 0x13c0,0x13c1,0x13c2,0x13c3,0x13c4,0x13c5,0x13c6,0x13c7, 0x13c8,0x13c9,0x13ca,0x13cb,0x13cc,0x13cd,0x13ce,0x13cf, 0x13d0,0x13d1,0x13d2,0x13d3,0x13d4,0x13d5,0x13d6,0x13d7, 0x13d8,0x13d9,0x13da,0x13db,0x13dc,0x13dd,0x13de,0x13df, 0x13e0,0x13e1,0x13e2,0x13e3,0x13e4,0x13e5,0x13e6,0x13e7, 0x13e8,0x13e9,0x13ea,0x13eb,0x13ec,0x13ed,0x13ee,0x13ef, 0x13f0,0x13f1,0x13f2,0x13f3,0x13f4,0x13f5,0x13f6,0x13f7, 0x13f8,0x13f9,0x13fa,0x13fb,0x13fc,0x13fd,0x13fe,0x13ff, 0x1400,0x1401,0x1402,0x1403,0x1404,0x1405,0x1406,0x1407, 0x1408,0x1409,0x140a,0x140b,0x140c,0x140d,0x140e,0x140f, 0x1410,0x1411,0x1412,0x1413,0x1414,0x1415,0x1416,0x1417, 0x1418,0x1419,0x141a,0x141b,0x141c,0x141d,0x141e,0x141f, 0x1420,0x1421,0x1422,0x1423,0x1424,0x1425,0x1426,0x1427, 0x1428,0x1429,0x142a,0x142b,0x142c,0x142d,0x142e,0x142f, 0x1430,0x1431,0x1432,0x1433,0x1434,0x1435,0x1436,0x1437, 0x1438,0x1439,0x143a,0x143b,0x143c,0x143d,0x143e,0x143f, 0x1440,0x1441,0x1442,0x1443,0x1444,0x1445,0x1446,0x1447, 0x1448,0x1449,0x144a,0x144b,0x144c,0x144d,0x144e,0x144f, 0x1450,0x1451,0x1452,0x1453,0x1454,0x1455,0x1456,0x1457, 0x1458,0x1459,0x145a,0x145b,0x145c,0x145d,0x145e,0x145f, 0x1460,0x1461,0x1462,0x1463,0x1464,0x1465,0x1466,0x1467, 0x1468,0x1469,0x146a,0x146b,0x146c,0x146d,0x146e,0x146f, 0x1470,0x1471,0x1472,0x1473,0x1474,0x1475,0x1476,0x1477, 0x1478,0x1479,0x147a,0x147b,0x147c,0x147d,0x147e,0x147f, 0x1480,0x1481,0x1482,0x1483,0x1484,0x1485,0x1486,0x1487, 0x1488,0x1489,0x148a,0x148b,0x148c,0x148d,0x148e,0x148f, 0x1490,0x1491,0x1492,0x1493,0x1494,0x1495,0x1496,0x1497, 0x1498,0x1499,0x149a,0x149b,0x149c,0x149d,0x149e,0x149f, 0x14a0,0x14a1,0x14a2,0x14a3,0x14a4,0x14a5,0x14a6,0x14a7, 0x14a8,0x14a9,0x14aa,0x14ab,0x14ac,0x14ad,0x14ae,0x14af, 0x14b0,0x14b1,0x14b2,0x14b3,0x14b4,0x14b5,0x14b6,0x14b7, 0x14b8,0x14b9,0x14ba,0x14bb,0x14bc,0x14bd,0x14be,0x14bf, 0x14c0,0x14c1,0x14c2,0x14c3,0x14c4,0x14c5,0x14c6,0x14c7, 0x14c8,0x14c9,0x14ca,0x14cb,0x14cc,0x14cd,0x14ce,0x14cf, 0x14d0,0x14d1,0x14d2,0x14d3,0x14d4,0x14d5,0x14d6,0x14d7, 0x14d8,0x14d9,0x14da,0x14db,0x14dc,0x14dd,0x14de,0x14df, 0x14e0,0x14e1,0x14e2,0x14e3,0x14e4,0x14e5,0x14e6,0x14e7, 0x14e8,0x14e9,0x14ea,0x14eb,0x14ec,0x14ed,0x14ee,0x14ef, 0x14f0,0x14f1,0x14f2,0x14f3,0x14f4,0x14f5,0x14f6,0x14f7, 0x14f8,0x14f9,0x14fa,0x14fb,0x14fc,0x14fd,0x14fe,0x14ff, 0x1500,0x1501,0x1502,0x1503,0x1504,0x1505,0x1506,0x1507, 0x1508,0x1509,0x150a,0x150b,0x150c,0x150d,0x150e,0x150f, 0x1510,0x1511,0x1512,0x1513,0x1514,0x1515,0x1516,0x1517, 0x1518,0x1519,0x151a,0x151b,0x151c,0x151d,0x151e,0x151f, 0x1520,0x1521,0x1522,0x1523,0x1524,0x1525,0x1526,0x1527, 0x1528,0x1529,0x152a,0x152b,0x152c,0x152d,0x152e,0x152f, 0x1530,0x1531,0x1532,0x1533,0x1534,0x1535,0x1536,0x1537, 0x1538,0x1539,0x153a,0x153b,0x153c,0x153d,0x153e,0x153f, 0x1540,0x1541,0x1542,0x1543,0x1544,0x1545,0x1546,0x1547, 0x1548,0x1549,0x154a,0x154b,0x154c,0x154d,0x154e,0x154f, 0x1550,0x1551,0x1552,0x1553,0x1554,0x1555,0x1556,0x1557, 0x1558,0x1559,0x155a,0x155b,0x155c,0x155d,0x155e,0x155f, 0x1560,0x1561,0x1562,0x1563,0x1564,0x1565,0x1566,0x1567, 0x1568,0x1569,0x156a,0x156b,0x156c,0x156d,0x156e,0x156f, 0x1570,0x1571,0x1572,0x1573,0x1574,0x1575,0x1576,0x1577, 0x1578,0x1579,0x157a,0x157b,0x157c,0x157d,0x157e,0x157f, 0x1580,0x1581,0x1582,0x1583,0x1584,0x1585,0x1586,0x1587, 0x1588,0x1589,0x158a,0x158b,0x158c,0x158d,0x158e,0x158f, 0x1590,0x1591,0x1592,0x1593,0x1594,0x1595,0x1596,0x1597, 0x1598,0x1599,0x159a,0x159b,0x159c,0x159d,0x159e,0x159f, 0x15a0,0x15a1,0x15a2,0x15a3,0x15a4,0x15a5,0x15a6,0x15a7, 0x15a8,0x15a9,0x15aa,0x15ab,0x15ac,0x15ad,0x15ae,0x15af, 0x15b0,0x15b1,0x15b2,0x15b3,0x15b4,0x15b5,0x15b6,0x15b7, 0x15b8,0x15b9,0x15ba,0x15bb,0x15bc,0x15bd,0x15be,0x15bf, 0x15c0,0x15c1,0x15c2,0x15c3,0x15c4,0x15c5,0x15c6,0x15c7, 0x15c8,0x15c9,0x15ca,0x15cb,0x15cc,0x15cd,0x15ce,0x15cf, 0x15d0,0x15d1,0x15d2,0x15d3,0x15d4,0x15d5,0x15d6,0x15d7, 0x15d8,0x15d9,0x15da,0x15db,0x15dc,0x15dd,0x15de,0x15df, 0x15e0,0x15e1,0x15e2,0x15e3,0x15e4,0x15e5,0x15e6,0x15e7, 0x15e8,0x15e9,0x15ea,0x15eb,0x15ec,0x15ed,0x15ee,0x15ef, 0x15f0,0x15f1,0x15f2,0x15f3,0x15f4,0x15f5,0x15f6,0x15f7, 0x15f8,0x15f9,0x15fa,0x15fb,0x15fc,0x15fd,0x15fe,0x15ff, 0x1600,0x1601,0x1602,0x1603,0x1604,0x1605,0x1606,0x1607, 0x1608,0x1609,0x160a,0x160b,0x160c,0x160d,0x160e,0x160f, 0x1610,0x1611,0x1612,0x1613,0x1614,0x1615,0x1616,0x1617, 0x1618,0x1619,0x161a,0x161b,0x161c,0x161d,0x161e,0x161f, 0x1620,0x1621,0x1622,0x1623,0x1624,0x1625,0x1626,0x1627, 0x1628,0x1629,0x162a,0x162b,0x162c,0x162d,0x162e,0x162f, 0x1630,0x1631,0x1632,0x1633,0x1634,0x1635,0x1636,0x1637, 0x1638,0x1639,0x163a,0x163b,0x163c,0x163d,0x163e,0x163f, 0x1640,0x1641,0x1642,0x1643,0x1644,0x1645,0x1646,0x1647, 0x1648,0x1649,0x164a,0x164b,0x164c,0x164d,0x164e,0x164f, 0x1650,0x1651,0x1652,0x1653,0x1654,0x1655,0x1656,0x1657, 0x1658,0x1659,0x165a,0x165b,0x165c,0x165d,0x165e,0x165f, 0x1660,0x1661,0x1662,0x1663,0x1664,0x1665,0x1666,0x1667, 0x1668,0x1669,0x166a,0x166b,0x166c,0x166d,0x166e,0x166f, 0x1670,0x1671,0x1672,0x1673,0x1674,0x1675,0x1676,0x1677, 0x1678,0x1679,0x167a,0x167b,0x167c,0x167d,0x167e,0x167f, 0x1680,0x1681,0x1682,0x1683,0x1684,0x1685,0x1686,0x1687, 0x1688,0x1689,0x168a,0x168b,0x168c,0x168d,0x168e,0x168f, 0x1690,0x1691,0x1692,0x1693,0x1694,0x1695,0x1696,0x1697, 0x1698,0x1699,0x169a,0x169b,0x169c,0x169d,0x169e,0x169f, 0x16a0,0x16a1,0x16a2,0x16a3,0x16a4,0x16a5,0x16a6,0x16a7, 0x16a8,0x16a9,0x16aa,0x16ab,0x16ac,0x16ad,0x16ae,0x16af, 0x16b0,0x16b1,0x16b2,0x16b3,0x16b4,0x16b5,0x16b6,0x16b7, 0x16b8,0x16b9,0x16ba,0x16bb,0x16bc,0x16bd,0x16be,0x16bf, 0x16c0,0x16c1,0x16c2,0x16c3,0x16c4,0x16c5,0x16c6,0x16c7, 0x16c8,0x16c9,0x16ca,0x16cb,0x16cc,0x16cd,0x16ce,0x16cf, 0x16d0,0x16d1,0x16d2,0x16d3,0x16d4,0x16d5,0x16d6,0x16d7, 0x16d8,0x16d9,0x16da,0x16db,0x16dc,0x16dd,0x16de,0x16df, 0x16e0,0x16e1,0x16e2,0x16e3,0x16e4,0x16e5,0x16e6,0x16e7, 0x16e8,0x16e9,0x16ea,0x16eb,0x16ec,0x16ed,0x16ee,0x16ef, 0x16f0,0x16f1,0x16f2,0x16f3,0x16f4,0x16f5,0x16f6,0x16f7, 0x16f8,0x16f9,0x16fa,0x16fb,0x16fc,0x16fd,0x16fe,0x16ff, 0x1700,0x1701,0x1702,0x1703,0x1704,0x1705,0x1706,0x1707, 0x1708,0x1709,0x170a,0x170b,0x170c,0x170d,0x170e,0x170f, 0x1710,0x1711,0x1712,0x1713,0x1714,0x1715,0x1716,0x1717, 0x1718,0x1719,0x171a,0x171b,0x171c,0x171d,0x171e,0x171f, 0x1720,0x1721,0x1722,0x1723,0x1724,0x1725,0x1726,0x1727, 0x1728,0x1729,0x172a,0x172b,0x172c,0x172d,0x172e,0x172f, 0x1730,0x1731,0x1732,0x1733,0x1734,0x1735,0x1736,0x1737, 0x1738,0x1739,0x173a,0x173b,0x173c,0x173d,0x173e,0x173f, 0x1740,0x1741,0x1742,0x1743,0x1744,0x1745,0x1746,0x1747, 0x1748,0x1749,0x174a,0x174b,0x174c,0x174d,0x174e,0x174f, 0x1750,0x1751,0x1752,0x1753,0x1754,0x1755,0x1756,0x1757, 0x1758,0x1759,0x175a,0x175b,0x175c,0x175d,0x175e,0x175f, 0x1760,0x1761,0x1762,0x1763,0x1764,0x1765,0x1766,0x1767, 0x1768,0x1769,0x176a,0x176b,0x176c,0x176d,0x176e,0x176f, 0x1770,0x1771,0x1772,0x1773,0x1774,0x1775,0x1776,0x1777, 0x1778,0x1779,0x177a,0x177b,0x177c,0x177d,0x177e,0x177f, 0x1780,0x1781,0x1782,0x1783,0x1784,0x1785,0x1786,0x1787, 0x1788,0x1789,0x178a,0x178b,0x178c,0x178d,0x178e,0x178f, 0x1790,0x1791,0x1792,0x1793,0x1794,0x1795,0x1796,0x1797, 0x1798,0x1799,0x179a,0x179b,0x179c,0x179d,0x179e,0x179f, 0x17a0,0x17a1,0x17a2,0x17a3,0x17a4,0x17a5,0x17a6,0x17a7, 0x17a8,0x17a9,0x17aa,0x17ab,0x17ac,0x17ad,0x17ae,0x17af, 0x17b0,0x17b1,0x17b2,0x17b3,0x17b4,0x17b5,0x17b6,0x17b7, 0x17b8,0x17b9,0x17ba,0x17bb,0x17bc,0x17bd,0x17be,0x17bf, 0x17c0,0x17c1,0x17c2,0x17c3,0x17c4,0x17c5,0x17c6,0x17c7, 0x17c8,0x17c9,0x17ca,0x17cb,0x17cc,0x17cd,0x17ce,0x17cf, 0x17d0,0x17d1,0x17d2,0x17d3,0x17d4,0x17d5,0x17d6,0x17d7, 0x17d8,0x17d9,0x17da,0x17db,0x17dc,0x17dd,0x17de,0x17df, 0x17e0,0x17e1,0x17e2,0x17e3,0x17e4,0x17e5,0x17e6,0x17e7, 0x17e8,0x17e9,0x17ea,0x17eb,0x17ec,0x17ed,0x17ee,0x17ef, 0x17f0,0x17f1,0x17f2,0x17f3,0x17f4,0x17f5,0x17f6,0x17f7, 0x17f8,0x17f9,0x17fa,0x17fb,0x17fc,0x17fd,0x17fe,0x17ff, 0x1800,0x1801,0x1802,0x1803,0x1804,0x1805,0x1806,0x1807, 0x1808,0x1809,0x180a,0x180b,0x180c,0x180d,0x180e,0x180f, 0x1810,0x1811,0x1812,0x1813,0x1814,0x1815,0x1816,0x1817, 0x1818,0x1819,0x181a,0x181b,0x181c,0x181d,0x181e,0x181f, 0x1820,0x1821,0x1822,0x1823,0x1824,0x1825,0x1826,0x1827, 0x1828,0x1829,0x182a,0x182b,0x182c,0x182d,0x182e,0x182f, 0x1830,0x1831,0x1832,0x1833,0x1834,0x1835,0x1836,0x1837, 0x1838,0x1839,0x183a,0x183b,0x183c,0x183d,0x183e,0x183f, 0x1840,0x1841,0x1842,0x1843,0x1844,0x1845,0x1846,0x1847, 0x1848,0x1849,0x184a,0x184b,0x184c,0x184d,0x184e,0x184f, 0x1850,0x1851,0x1852,0x1853,0x1854,0x1855,0x1856,0x1857, 0x1858,0x1859,0x185a,0x185b,0x185c,0x185d,0x185e,0x185f, 0x1860,0x1861,0x1862,0x1863,0x1864,0x1865,0x1866,0x1867, 0x1868,0x1869,0x186a,0x186b,0x186c,0x186d,0x186e,0x186f, 0x1870,0x1871,0x1872,0x1873,0x1874,0x1875,0x1876,0x1877, 0x1878,0x1879,0x187a,0x187b,0x187c,0x187d,0x187e,0x187f, 0x1880,0x1881,0x1882,0x1883,0x1884,0x1885,0x1886,0x1887, 0x1888,0x1889,0x188a,0x188b,0x188c,0x188d,0x188e,0x188f, 0x1890,0x1891,0x1892,0x1893,0x1894,0x1895,0x1896,0x1897, 0x1898,0x1899,0x189a,0x189b,0x189c,0x189d,0x189e,0x189f, 0x18a0,0x18a1,0x18a2,0x18a3,0x18a4,0x18a5,0x18a6,0x18a7, 0x18a8,0x18a9,0x18aa,0x18ab,0x18ac,0x18ad,0x18ae,0x18af, 0x18b0,0x18b1,0x18b2,0x18b3,0x18b4,0x18b5,0x18b6,0x18b7, 0x18b8,0x18b9,0x18ba,0x18bb,0x18bc,0x18bd,0x18be,0x18bf, 0x18c0,0x18c1,0x18c2,0x18c3,0x18c4,0x18c5,0x18c6,0x18c7, 0x18c8,0x18c9,0x18ca,0x18cb,0x18cc,0x18cd,0x18ce,0x18cf, 0x18d0,0x18d1,0x18d2,0x18d3,0x18d4,0x18d5,0x18d6,0x18d7, 0x18d8,0x18d9,0x18da,0x18db,0x18dc,0x18dd,0x18de,0x18df, 0x18e0,0x18e1,0x18e2,0x18e3,0x18e4,0x18e5,0x18e6,0x18e7, 0x18e8,0x18e9,0x18ea,0x18eb,0x18ec,0x18ed,0x18ee,0x18ef, 0x18f0,0x18f1,0x18f2,0x18f3,0x18f4,0x18f5,0x18f6,0x18f7, 0x18f8,0x18f9,0x18fa,0x18fb,0x18fc,0x18fd,0x18fe,0x18ff, 0x1900,0x1901,0x1902,0x1903,0x1904,0x1905,0x1906,0x1907, 0x1908,0x1909,0x190a,0x190b,0x190c,0x190d,0x190e,0x190f, 0x1910,0x1911,0x1912,0x1913,0x1914,0x1915,0x1916,0x1917, 0x1918,0x1919,0x191a,0x191b,0x191c,0x191d,0x191e,0x191f, 0x1920,0x1921,0x1922,0x1923,0x1924,0x1925,0x1926,0x1927, 0x1928,0x1929,0x192a,0x192b,0x192c,0x192d,0x192e,0x192f, 0x1930,0x1931,0x1932,0x1933,0x1934,0x1935,0x1936,0x1937, 0x1938,0x1939,0x193a,0x193b,0x193c,0x193d,0x193e,0x193f, 0x1940,0x1941,0x1942,0x1943,0x1944,0x1945,0x1946,0x1947, 0x1948,0x1949,0x194a,0x194b,0x194c,0x194d,0x194e,0x194f, 0x1950,0x1951,0x1952,0x1953,0x1954,0x1955,0x1956,0x1957, 0x1958,0x1959,0x195a,0x195b,0x195c,0x195d,0x195e,0x195f, 0x1960,0x1961,0x1962,0x1963,0x1964,0x1965,0x1966,0x1967, 0x1968,0x1969,0x196a,0x196b,0x196c,0x196d,0x196e,0x196f, 0x1970,0x1971,0x1972,0x1973,0x1974,0x1975,0x1976,0x1977, 0x1978,0x1979,0x197a,0x197b,0x197c,0x197d,0x197e,0x197f, 0x1980,0x1981,0x1982,0x1983,0x1984,0x1985,0x1986,0x1987, 0x1988,0x1989,0x198a,0x198b,0x198c,0x198d,0x198e,0x198f, 0x1990,0x1991,0x1992,0x1993,0x1994,0x1995,0x1996,0x1997, 0x1998,0x1999,0x199a,0x199b,0x199c,0x199d,0x199e,0x199f, 0x19a0,0x19a1,0x19a2,0x19a3,0x19a4,0x19a5,0x19a6,0x19a7, 0x19a8,0x19a9,0x19aa,0x19ab,0x19ac,0x19ad,0x19ae,0x19af, 0x19b0,0x19b1,0x19b2,0x19b3,0x19b4,0x19b5,0x19b6,0x19b7, 0x19b8,0x19b9,0x19ba,0x19bb,0x19bc,0x19bd,0x19be,0x19bf, 0x19c0,0x19c1,0x19c2,0x19c3,0x19c4,0x19c5,0x19c6,0x19c7, 0x19c8,0x19c9,0x19ca,0x19cb,0x19cc,0x19cd,0x19ce,0x19cf, 0x19d0,0x19d1,0x19d2,0x19d3,0x19d4,0x19d5,0x19d6,0x19d7, 0x19d8,0x19d9,0x19da,0x19db,0x19dc,0x19dd,0x19de,0x19df, 0x19e0,0x19e1,0x19e2,0x19e3,0x19e4,0x19e5,0x19e6,0x19e7, 0x19e8,0x19e9,0x19ea,0x19eb,0x19ec,0x19ed,0x19ee,0x19ef, 0x19f0,0x19f1,0x19f2,0x19f3,0x19f4,0x19f5,0x19f6,0x19f7, 0x19f8,0x19f9,0x19fa,0x19fb,0x19fc,0x19fd,0x19fe,0x19ff, 0x1a00,0x1a01,0x1a02,0x1a03,0x1a04,0x1a05,0x1a06,0x1a07, 0x1a08,0x1a09,0x1a0a,0x1a0b,0x1a0c,0x1a0d,0x1a0e,0x1a0f, 0x1a10,0x1a11,0x1a12,0x1a13,0x1a14,0x1a15,0x1a16,0x1a17, 0x1a18,0x1a19,0x1a1a,0x1a1b,0x1a1c,0x1a1d,0x1a1e,0x1a1f, 0x1a20,0x1a21,0x1a22,0x1a23,0x1a24,0x1a25,0x1a26,0x1a27, 0x1a28,0x1a29,0x1a2a,0x1a2b,0x1a2c,0x1a2d,0x1a2e,0x1a2f, 0x1a30,0x1a31,0x1a32,0x1a33,0x1a34,0x1a35,0x1a36,0x1a37, 0x1a38,0x1a39,0x1a3a,0x1a3b,0x1a3c,0x1a3d,0x1a3e,0x1a3f, 0x1a40,0x1a41,0x1a42,0x1a43,0x1a44,0x1a45,0x1a46,0x1a47, 0x1a48,0x1a49,0x1a4a,0x1a4b,0x1a4c,0x1a4d,0x1a4e,0x1a4f, 0x1a50,0x1a51,0x1a52,0x1a53,0x1a54,0x1a55,0x1a56,0x1a57, 0x1a58,0x1a59,0x1a5a,0x1a5b,0x1a5c,0x1a5d,0x1a5e,0x1a5f, 0x1a60,0x1a61,0x1a62,0x1a63,0x1a64,0x1a65,0x1a66,0x1a67, 0x1a68,0x1a69,0x1a6a,0x1a6b,0x1a6c,0x1a6d,0x1a6e,0x1a6f, 0x1a70,0x1a71,0x1a72,0x1a73,0x1a74,0x1a75,0x1a76,0x1a77, 0x1a78,0x1a79,0x1a7a,0x1a7b,0x1a7c,0x1a7d,0x1a7e,0x1a7f, 0x1a80,0x1a81,0x1a82,0x1a83,0x1a84,0x1a85,0x1a86,0x1a87, 0x1a88,0x1a89,0x1a8a,0x1a8b,0x1a8c,0x1a8d,0x1a8e,0x1a8f, 0x1a90,0x1a91,0x1a92,0x1a93,0x1a94,0x1a95,0x1a96,0x1a97, 0x1a98,0x1a99,0x1a9a,0x1a9b,0x1a9c,0x1a9d,0x1a9e,0x1a9f, 0x1aa0,0x1aa1,0x1aa2,0x1aa3,0x1aa4,0x1aa5,0x1aa6,0x1aa7, 0x1aa8,0x1aa9,0x1aaa,0x1aab,0x1aac,0x1aad,0x1aae,0x1aaf, 0x1ab0,0x1ab1,0x1ab2,0x1ab3,0x1ab4,0x1ab5,0x1ab6,0x1ab7, 0x1ab8,0x1ab9,0x1aba,0x1abb,0x1abc,0x1abd,0x1abe,0x1abf, 0x1ac0,0x1ac1,0x1ac2,0x1ac3,0x1ac4,0x1ac5,0x1ac6,0x1ac7, 0x1ac8,0x1ac9,0x1aca,0x1acb,0x1acc,0x1acd,0x1ace,0x1acf, 0x1ad0,0x1ad1,0x1ad2,0x1ad3,0x1ad4,0x1ad5,0x1ad6,0x1ad7, 0x1ad8,0x1ad9,0x1ada,0x1adb,0x1adc,0x1add,0x1ade,0x1adf, 0x1ae0,0x1ae1,0x1ae2,0x1ae3,0x1ae4,0x1ae5,0x1ae6,0x1ae7, 0x1ae8,0x1ae9,0x1aea,0x1aeb,0x1aec,0x1aed,0x1aee,0x1aef, 0x1af0,0x1af1,0x1af2,0x1af3,0x1af4,0x1af5,0x1af6,0x1af7, 0x1af8,0x1af9,0x1afa,0x1afb,0x1afc,0x1afd,0x1afe,0x1aff, 0x1b00,0x1b01,0x1b02,0x1b03,0x1b04,0x1b05,0x1b06,0x1b07, 0x1b08,0x1b09,0x1b0a,0x1b0b,0x1b0c,0x1b0d,0x1b0e,0x1b0f, 0x1b10,0x1b11,0x1b12,0x1b13,0x1b14,0x1b15,0x1b16,0x1b17, 0x1b18,0x1b19,0x1b1a,0x1b1b,0x1b1c,0x1b1d,0x1b1e,0x1b1f, 0x1b20,0x1b21,0x1b22,0x1b23,0x1b24,0x1b25,0x1b26,0x1b27, 0x1b28,0x1b29,0x1b2a,0x1b2b,0x1b2c,0x1b2d,0x1b2e,0x1b2f, 0x1b30,0x1b31,0x1b32,0x1b33,0x1b34,0x1b35,0x1b36,0x1b37, 0x1b38,0x1b39,0x1b3a,0x1b3b,0x1b3c,0x1b3d,0x1b3e,0x1b3f, 0x1b40,0x1b41,0x1b42,0x1b43,0x1b44,0x1b45,0x1b46,0x1b47, 0x1b48,0x1b49,0x1b4a,0x1b4b,0x1b4c,0x1b4d,0x1b4e,0x1b4f, 0x1b50,0x1b51,0x1b52,0x1b53,0x1b54,0x1b55,0x1b56,0x1b57, 0x1b58,0x1b59,0x1b5a,0x1b5b,0x1b5c,0x1b5d,0x1b5e,0x1b5f, 0x1b60,0x1b61,0x1b62,0x1b63,0x1b64,0x1b65,0x1b66,0x1b67, 0x1b68,0x1b69,0x1b6a,0x1b6b,0x1b6c,0x1b6d,0x1b6e,0x1b6f, 0x1b70,0x1b71,0x1b72,0x1b73,0x1b74,0x1b75,0x1b76,0x1b77, 0x1b78,0x1b79,0x1b7a,0x1b7b,0x1b7c,0x1b7d,0x1b7e,0x1b7f, 0x1b80,0x1b81,0x1b82,0x1b83,0x1b84,0x1b85,0x1b86,0x1b87, 0x1b88,0x1b89,0x1b8a,0x1b8b,0x1b8c,0x1b8d,0x1b8e,0x1b8f, 0x1b90,0x1b91,0x1b92,0x1b93,0x1b94,0x1b95,0x1b96,0x1b97, 0x1b98,0x1b99,0x1b9a,0x1b9b,0x1b9c,0x1b9d,0x1b9e,0x1b9f, 0x1ba0,0x1ba1,0x1ba2,0x1ba3,0x1ba4,0x1ba5,0x1ba6,0x1ba7, 0x1ba8,0x1ba9,0x1baa,0x1bab,0x1bac,0x1bad,0x1bae,0x1baf, 0x1bb0,0x1bb1,0x1bb2,0x1bb3,0x1bb4,0x1bb5,0x1bb6,0x1bb7, 0x1bb8,0x1bb9,0x1bba,0x1bbb,0x1bbc,0x1bbd,0x1bbe,0x1bbf, 0x1bc0,0x1bc1,0x1bc2,0x1bc3,0x1bc4,0x1bc5,0x1bc6,0x1bc7, 0x1bc8,0x1bc9,0x1bca,0x1bcb,0x1bcc,0x1bcd,0x1bce,0x1bcf, 0x1bd0,0x1bd1,0x1bd2,0x1bd3,0x1bd4,0x1bd5,0x1bd6,0x1bd7, 0x1bd8,0x1bd9,0x1bda,0x1bdb,0x1bdc,0x1bdd,0x1bde,0x1bdf, 0x1be0,0x1be1,0x1be2,0x1be3,0x1be4,0x1be5,0x1be6,0x1be7, 0x1be8,0x1be9,0x1bea,0x1beb,0x1bec,0x1bed,0x1bee,0x1bef, 0x1bf0,0x1bf1,0x1bf2,0x1bf3,0x1bf4,0x1bf5,0x1bf6,0x1bf7, 0x1bf8,0x1bf9,0x1bfa,0x1bfb,0x1bfc,0x1bfd,0x1bfe,0x1bff, 0x1c00,0x1c01,0x1c02,0x1c03,0x1c04,0x1c05,0x1c06,0x1c07, 0x1c08,0x1c09,0x1c0a,0x1c0b,0x1c0c,0x1c0d,0x1c0e,0x1c0f, 0x1c10,0x1c11,0x1c12,0x1c13,0x1c14,0x1c15,0x1c16,0x1c17, 0x1c18,0x1c19,0x1c1a,0x1c1b,0x1c1c,0x1c1d,0x1c1e,0x1c1f, 0x1c20,0x1c21,0x1c22,0x1c23,0x1c24,0x1c25,0x1c26,0x1c27, 0x1c28,0x1c29,0x1c2a,0x1c2b,0x1c2c,0x1c2d,0x1c2e,0x1c2f, 0x1c30,0x1c31,0x1c32,0x1c33,0x1c34,0x1c35,0x1c36,0x1c37, 0x1c38,0x1c39,0x1c3a,0x1c3b,0x1c3c,0x1c3d,0x1c3e,0x1c3f, 0x1c40,0x1c41,0x1c42,0x1c43,0x1c44,0x1c45,0x1c46,0x1c47, 0x1c48,0x1c49,0x1c4a,0x1c4b,0x1c4c,0x1c4d,0x1c4e,0x1c4f, 0x1c50,0x1c51,0x1c52,0x1c53,0x1c54,0x1c55,0x1c56,0x1c57, 0x1c58,0x1c59,0x1c5a,0x1c5b,0x1c5c,0x1c5d,0x1c5e,0x1c5f, 0x1c60,0x1c61,0x1c62,0x1c63,0x1c64,0x1c65,0x1c66,0x1c67, 0x1c68,0x1c69,0x1c6a,0x1c6b,0x1c6c,0x1c6d,0x1c6e,0x1c6f, 0x1c70,0x1c71,0x1c72,0x1c73,0x1c74,0x1c75,0x1c76,0x1c77, 0x1c78,0x1c79,0x1c7a,0x1c7b,0x1c7c,0x1c7d,0x1c7e,0x1c7f, 0x1c80,0x1c81,0x1c82,0x1c83,0x1c84,0x1c85,0x1c86,0x1c87, 0x1c88,0x1c89,0x1c8a,0x1c8b,0x1c8c,0x1c8d,0x1c8e,0x1c8f, 0x1c90,0x1c91,0x1c92,0x1c93,0x1c94,0x1c95,0x1c96,0x1c97, 0x1c98,0x1c99,0x1c9a,0x1c9b,0x1c9c,0x1c9d,0x1c9e,0x1c9f, 0x1ca0,0x1ca1,0x1ca2,0x1ca3,0x1ca4,0x1ca5,0x1ca6,0x1ca7, 0x1ca8,0x1ca9,0x1caa,0x1cab,0x1cac,0x1cad,0x1cae,0x1caf, 0x1cb0,0x1cb1,0x1cb2,0x1cb3,0x1cb4,0x1cb5,0x1cb6,0x1cb7, 0x1cb8,0x1cb9,0x1cba,0x1cbb,0x1cbc,0x1cbd,0x1cbe,0x1cbf, 0x1cc0,0x1cc1,0x1cc2,0x1cc3,0x1cc4,0x1cc5,0x1cc6,0x1cc7, 0x1cc8,0x1cc9,0x1cca,0x1ccb,0x1ccc,0x1ccd,0x1cce,0x1ccf, 0x1cd0,0x1cd1,0x1cd2,0x1cd3,0x1cd4,0x1cd5,0x1cd6,0x1cd7, 0x1cd8,0x1cd9,0x1cda,0x1cdb,0x1cdc,0x1cdd,0x1cde,0x1cdf, 0x1ce0,0x1ce1,0x1ce2,0x1ce3,0x1ce4,0x1ce5,0x1ce6,0x1ce7, 0x1ce8,0x1ce9,0x1cea,0x1ceb,0x1cec,0x1ced,0x1cee,0x1cef, 0x1cf0,0x1cf1,0x1cf2,0x1cf3,0x1cf4,0x1cf5,0x1cf6,0x1cf7, 0x1cf8,0x1cf9,0x1cfa,0x1cfb,0x1cfc,0x1cfd,0x1cfe,0x1cff, 0x1d00,0x1d01,0x1d02,0x1d03,0x1d04,0x1d05,0x1d06,0x1d07, 0x1d08,0x1d09,0x1d0a,0x1d0b,0x1d0c,0x1d0d,0x1d0e,0x1d0f, 0x1d10,0x1d11,0x1d12,0x1d13,0x1d14,0x1d15,0x1d16,0x1d17, 0x1d18,0x1d19,0x1d1a,0x1d1b,0x1d1c,0x1d1d,0x1d1e,0x1d1f, 0x1d20,0x1d21,0x1d22,0x1d23,0x1d24,0x1d25,0x1d26,0x1d27, 0x1d28,0x1d29,0x1d2a,0x1d2b,0x1d2c,0x1d2d,0x1d2e,0x1d2f, 0x1d30,0x1d31,0x1d32,0x1d33,0x1d34,0x1d35,0x1d36,0x1d37, 0x1d38,0x1d39,0x1d3a,0x1d3b,0x1d3c,0x1d3d,0x1d3e,0x1d3f, 0x1d40,0x1d41,0x1d42,0x1d43,0x1d44,0x1d45,0x1d46,0x1d47, 0x1d48,0x1d49,0x1d4a,0x1d4b,0x1d4c,0x1d4d,0x1d4e,0x1d4f, 0x1d50,0x1d51,0x1d52,0x1d53,0x1d54,0x1d55,0x1d56,0x1d57, 0x1d58,0x1d59,0x1d5a,0x1d5b,0x1d5c,0x1d5d,0x1d5e,0x1d5f, 0x1d60,0x1d61,0x1d62,0x1d63,0x1d64,0x1d65,0x1d66,0x1d67, 0x1d68,0x1d69,0x1d6a,0x1d6b,0x1d6c,0x1d6d,0x1d6e,0x1d6f, 0x1d70,0x1d71,0x1d72,0x1d73,0x1d74,0x1d75,0x1d76,0x1d77, 0x1d78,0x1d79,0x1d7a,0x1d7b,0x1d7c,0x2c63,0x1d7e,0x1d7f, 0x1d80,0x1d81,0x1d82,0x1d83,0x1d84,0x1d85,0x1d86,0x1d87, 0x1d88,0x1d89,0x1d8a,0x1d8b,0x1d8c,0x1d8d,0x1d8e,0x1d8f, 0x1d90,0x1d91,0x1d92,0x1d93,0x1d94,0x1d95,0x1d96,0x1d97, 0x1d98,0x1d99,0x1d9a,0x1d9b,0x1d9c,0x1d9d,0x1d9e,0x1d9f, 0x1da0,0x1da1,0x1da2,0x1da3,0x1da4,0x1da5,0x1da6,0x1da7, 0x1da8,0x1da9,0x1daa,0x1dab,0x1dac,0x1dad,0x1dae,0x1daf, 0x1db0,0x1db1,0x1db2,0x1db3,0x1db4,0x1db5,0x1db6,0x1db7, 0x1db8,0x1db9,0x1dba,0x1dbb,0x1dbc,0x1dbd,0x1dbe,0x1dbf, 0x1dc0,0x1dc1,0x1dc2,0x1dc3,0x1dc4,0x1dc5,0x1dc6,0x1dc7, 0x1dc8,0x1dc9,0x1dca,0x1dcb,0x1dcc,0x1dcd,0x1dce,0x1dcf, 0x1dd0,0x1dd1,0x1dd2,0x1dd3,0x1dd4,0x1dd5,0x1dd6,0x1dd7, 0x1dd8,0x1dd9,0x1dda,0x1ddb,0x1ddc,0x1ddd,0x1dde,0x1ddf, 0x1de0,0x1de1,0x1de2,0x1de3,0x1de4,0x1de5,0x1de6,0x1de7, 0x1de8,0x1de9,0x1dea,0x1deb,0x1dec,0x1ded,0x1dee,0x1def, 0x1df0,0x1df1,0x1df2,0x1df3,0x1df4,0x1df5,0x1df6,0x1df7, 0x1df8,0x1df9,0x1dfa,0x1dfb,0x1dfc,0x1dfd,0x1dfe,0x1dff, 0x1e00,0x1e00,0x1e02,0x1e02,0x1e04,0x1e04,0x1e06,0x1e06, 0x1e08,0x1e08,0x1e0a,0x1e0a,0x1e0c,0x1e0c,0x1e0e,0x1e0e, 0x1e10,0x1e10,0x1e12,0x1e12,0x1e14,0x1e14,0x1e16,0x1e16, 0x1e18,0x1e18,0x1e1a,0x1e1a,0x1e1c,0x1e1c,0x1e1e,0x1e1e, 0x1e20,0x1e20,0x1e22,0x1e22,0x1e24,0x1e24,0x1e26,0x1e26, 0x1e28,0x1e28,0x1e2a,0x1e2a,0x1e2c,0x1e2c,0x1e2e,0x1e2e, 0x1e30,0x1e30,0x1e32,0x1e32,0x1e34,0x1e34,0x1e36,0x1e36, 0x1e38,0x1e38,0x1e3a,0x1e3a,0x1e3c,0x1e3c,0x1e3e,0x1e3e, 0x1e40,0x1e40,0x1e42,0x1e42,0x1e44,0x1e44,0x1e46,0x1e46, 0x1e48,0x1e48,0x1e4a,0x1e4a,0x1e4c,0x1e4c,0x1e4e,0x1e4e, 0x1e50,0x1e50,0x1e52,0x1e52,0x1e54,0x1e54,0x1e56,0x1e56, 0x1e58,0x1e58,0x1e5a,0x1e5a,0x1e5c,0x1e5c,0x1e5e,0x1e5e, 0x1e60,0x1e60,0x1e62,0x1e62,0x1e64,0x1e64,0x1e66,0x1e66, 0x1e68,0x1e68,0x1e6a,0x1e6a,0x1e6c,0x1e6c,0x1e6e,0x1e6e, 0x1e70,0x1e70,0x1e72,0x1e72,0x1e74,0x1e74,0x1e76,0x1e76, 0x1e78,0x1e78,0x1e7a,0x1e7a,0x1e7c,0x1e7c,0x1e7e,0x1e7e, 0x1e80,0x1e80,0x1e82,0x1e82,0x1e84,0x1e84,0x1e86,0x1e86, 0x1e88,0x1e88,0x1e8a,0x1e8a,0x1e8c,0x1e8c,0x1e8e,0x1e8e, 0x1e90,0x1e90,0x1e92,0x1e92,0x1e94,0x1e94,0x1e96,0x1e97, 0x1e98,0x1e99,0x1e9a,0x1e60,0x1e9c,0x1e9d,0x1e9e,0x1e9f, 0x1ea0,0x1ea0,0x1ea2,0x1ea2,0x1ea4,0x1ea4,0x1ea6,0x1ea6, 0x1ea8,0x1ea8,0x1eaa,0x1eaa,0x1eac,0x1eac,0x1eae,0x1eae, 0x1eb0,0x1eb0,0x1eb2,0x1eb2,0x1eb4,0x1eb4,0x1eb6,0x1eb6, 0x1eb8,0x1eb8,0x1eba,0x1eba,0x1ebc,0x1ebc,0x1ebe,0x1ebe, 0x1ec0,0x1ec0,0x1ec2,0x1ec2,0x1ec4,0x1ec4,0x1ec6,0x1ec6, 0x1ec8,0x1ec8,0x1eca,0x1eca,0x1ecc,0x1ecc,0x1ece,0x1ece, 0x1ed0,0x1ed0,0x1ed2,0x1ed2,0x1ed4,0x1ed4,0x1ed6,0x1ed6, 0x1ed8,0x1ed8,0x1eda,0x1eda,0x1edc,0x1edc,0x1ede,0x1ede, 0x1ee0,0x1ee0,0x1ee2,0x1ee2,0x1ee4,0x1ee4,0x1ee6,0x1ee6, 0x1ee8,0x1ee8,0x1eea,0x1eea,0x1eec,0x1eec,0x1eee,0x1eee, 0x1ef0,0x1ef0,0x1ef2,0x1ef2,0x1ef4,0x1ef4,0x1ef6,0x1ef6, 0x1ef8,0x1ef8,0x1efa,0x1efb,0x1efc,0x1efd,0x1efe,0x1eff, 0x1f08,0x1f09,0x1f0a,0x1f0b,0x1f0c,0x1f0d,0x1f0e,0x1f0f, 0x1f08,0x1f09,0x1f0a,0x1f0b,0x1f0c,0x1f0d,0x1f0e,0x1f0f, 0x1f18,0x1f19,0x1f1a,0x1f1b,0x1f1c,0x1f1d,0x1f16,0x1f17, 0x1f18,0x1f19,0x1f1a,0x1f1b,0x1f1c,0x1f1d,0x1f1e,0x1f1f, 0x1f28,0x1f29,0x1f2a,0x1f2b,0x1f2c,0x1f2d,0x1f2e,0x1f2f, 0x1f28,0x1f29,0x1f2a,0x1f2b,0x1f2c,0x1f2d,0x1f2e,0x1f2f, 0x1f38,0x1f39,0x1f3a,0x1f3b,0x1f3c,0x1f3d,0x1f3e,0x1f3f, 0x1f38,0x1f39,0x1f3a,0x1f3b,0x1f3c,0x1f3d,0x1f3e,0x1f3f, 0x1f48,0x1f49,0x1f4a,0x1f4b,0x1f4c,0x1f4d,0x1f46,0x1f47, 0x1f48,0x1f49,0x1f4a,0x1f4b,0x1f4c,0x1f4d,0x1f4e,0x1f4f, 0x1f50,0x1f59,0x1f52,0x1f5b,0x1f54,0x1f5d,0x1f56,0x1f5f, 0x1f58,0x1f59,0x1f5a,0x1f5b,0x1f5c,0x1f5d,0x1f5e,0x1f5f, 0x1f68,0x1f69,0x1f6a,0x1f6b,0x1f6c,0x1f6d,0x1f6e,0x1f6f, 0x1f68,0x1f69,0x1f6a,0x1f6b,0x1f6c,0x1f6d,0x1f6e,0x1f6f, 0x1fba,0x1fbb,0x1fc8,0x1fc9,0x1fca,0x1fcb,0x1fda,0x1fdb, 0x1ff8,0x1ff9,0x1fea,0x1feb,0x1ffa,0x1ffb,0x1f7e,0x1f7f, 0x1f88,0x1f89,0x1f8a,0x1f8b,0x1f8c,0x1f8d,0x1f8e,0x1f8f, 0x1f88,0x1f89,0x1f8a,0x1f8b,0x1f8c,0x1f8d,0x1f8e,0x1f8f, 0x1f98,0x1f99,0x1f9a,0x1f9b,0x1f9c,0x1f9d,0x1f9e,0x1f9f, 0x1f98,0x1f99,0x1f9a,0x1f9b,0x1f9c,0x1f9d,0x1f9e,0x1f9f, 0x1fa8,0x1fa9,0x1faa,0x1fab,0x1fac,0x1fad,0x1fae,0x1faf, 0x1fa8,0x1fa9,0x1faa,0x1fab,0x1fac,0x1fad,0x1fae,0x1faf, 0x1fb8,0x1fb9,0x1fb2,0x1fbc,0x1fb4,0x1fb5,0x1fb6,0x1fb7, 0x1fb8,0x1fb9,0x1fba,0x1fbb,0x1fbc,0x1fbd,0x0399,0x1fbf, 0x1fc0,0x1fc1,0x1fc2,0x1fcc,0x1fc4,0x1fc5,0x1fc6,0x1fc7, 0x1fc8,0x1fc9,0x1fca,0x1fcb,0x1fcc,0x1fcd,0x1fce,0x1fcf, 0x1fd8,0x1fd9,0x1fd2,0x1fd3,0x1fd4,0x1fd5,0x1fd6,0x1fd7, 0x1fd8,0x1fd9,0x1fda,0x1fdb,0x1fdc,0x1fdd,0x1fde,0x1fdf, 0x1fe8,0x1fe9,0x1fe2,0x1fe3,0x1fe4,0x1fec,0x1fe6,0x1fe7, 0x1fe8,0x1fe9,0x1fea,0x1feb,0x1fec,0x1fed,0x1fee,0x1fef, 0x1ff0,0x1ff1,0x1ff2,0x1ffc,0x1ff4,0x1ff5,0x1ff6,0x1ff7, 0x1ff8,0x1ff9,0x1ffa,0x1ffb,0x1ffc,0x1ffd,0x1ffe,0x1fff, 0x2000,0x2001,0x2002,0x2003,0x2004,0x2005,0x2006,0x2007, 0x2008,0x2009,0x200a,0x200b,0x200c,0x200d,0x200e,0x200f, 0x2010,0x2011,0x2012,0x2013,0x2014,0x2015,0x2016,0x2017, 0x2018,0x2019,0x201a,0x201b,0x201c,0x201d,0x201e,0x201f, 0x2020,0x2021,0x2022,0x2023,0x2024,0x2025,0x2026,0x2027, 0x2028,0x2029,0x202a,0x202b,0x202c,0x202d,0x202e,0x202f, 0x2030,0x2031,0x2032,0x2033,0x2034,0x2035,0x2036,0x2037, 0x2038,0x2039,0x203a,0x203b,0x203c,0x203d,0x203e,0x203f, 0x2040,0x2041,0x2042,0x2043,0x2044,0x2045,0x2046,0x2047, 0x2048,0x2049,0x204a,0x204b,0x204c,0x204d,0x204e,0x204f, 0x2050,0x2051,0x2052,0x2053,0x2054,0x2055,0x2056,0x2057, 0x2058,0x2059,0x205a,0x205b,0x205c,0x205d,0x205e,0x205f, 0x2060,0x2061,0x2062,0x2063,0x2064,0x2065,0x2066,0x2067, 0x2068,0x2069,0x206a,0x206b,0x206c,0x206d,0x206e,0x206f, 0x2070,0x2071,0x2072,0x2073,0x2074,0x2075,0x2076,0x2077, 0x2078,0x2079,0x207a,0x207b,0x207c,0x207d,0x207e,0x207f, 0x2080,0x2081,0x2082,0x2083,0x2084,0x2085,0x2086,0x2087, 0x2088,0x2089,0x208a,0x208b,0x208c,0x208d,0x208e,0x208f, 0x2090,0x2091,0x2092,0x2093,0x2094,0x2095,0x2096,0x2097, 0x2098,0x2099,0x209a,0x209b,0x209c,0x209d,0x209e,0x209f, 0x20a0,0x20a1,0x20a2,0x20a3,0x20a4,0x20a5,0x20a6,0x20a7, 0x20a8,0x20a9,0x20aa,0x20ab,0x20ac,0x20ad,0x20ae,0x20af, 0x20b0,0x20b1,0x20b2,0x20b3,0x20b4,0x20b5,0x20b6,0x20b7, 0x20b8,0x20b9,0x20ba,0x20bb,0x20bc,0x20bd,0x20be,0x20bf, 0x20c0,0x20c1,0x20c2,0x20c3,0x20c4,0x20c5,0x20c6,0x20c7, 0x20c8,0x20c9,0x20ca,0x20cb,0x20cc,0x20cd,0x20ce,0x20cf, 0x20d0,0x20d1,0x20d2,0x20d3,0x20d4,0x20d5,0x20d6,0x20d7, 0x20d8,0x20d9,0x20da,0x20db,0x20dc,0x20dd,0x20de,0x20df, 0x20e0,0x20e1,0x20e2,0x20e3,0x20e4,0x20e5,0x20e6,0x20e7, 0x20e8,0x20e9,0x20ea,0x20eb,0x20ec,0x20ed,0x20ee,0x20ef, 0x20f0,0x20f1,0x20f2,0x20f3,0x20f4,0x20f5,0x20f6,0x20f7, 0x20f8,0x20f9,0x20fa,0x20fb,0x20fc,0x20fd,0x20fe,0x20ff, 0x2100,0x2101,0x2102,0x2103,0x2104,0x2105,0x2106,0x2107, 0x2108,0x2109,0x210a,0x210b,0x210c,0x210d,0x210e,0x210f, 0x2110,0x2111,0x2112,0x2113,0x2114,0x2115,0x2116,0x2117, 0x2118,0x2119,0x211a,0x211b,0x211c,0x211d,0x211e,0x211f, 0x2120,0x2121,0x2122,0x2123,0x2124,0x2125,0x2126,0x2127, 0x2128,0x2129,0x212a,0x212b,0x212c,0x212d,0x212e,0x212f, 0x2130,0x2131,0x2132,0x2133,0x2134,0x2135,0x2136,0x2137, 0x2138,0x2139,0x213a,0x213b,0x213c,0x213d,0x213e,0x213f, 0x2140,0x2141,0x2142,0x2143,0x2144,0x2145,0x2146,0x2147, 0x2148,0x2149,0x214a,0x214b,0x214c,0x214d,0x2132,0x214f, 0x2150,0x2151,0x2152,0x2153,0x2154,0x2155,0x2156,0x2157, 0x2158,0x2159,0x215a,0x215b,0x215c,0x215d,0x215e,0x215f, 0x2160,0x2161,0x2162,0x2163,0x2164,0x2165,0x2166,0x2167, 0x2168,0x2169,0x216a,0x216b,0x216c,0x216d,0x216e,0x216f, 0x2160,0x2161,0x2162,0x2163,0x2164,0x2165,0x2166,0x2167, 0x2168,0x2169,0x216a,0x216b,0x216c,0x216d,0x216e,0x216f, 0x2180,0x2181,0x2182,0x2183,0x2183,0x2185,0x2186,0x2187, 0x2188,0x2189,0x218a,0x218b,0x218c,0x218d,0x218e,0x218f, 0x2190,0x2191,0x2192,0x2193,0x2194,0x2195,0x2196,0x2197, 0x2198,0x2199,0x219a,0x219b,0x219c,0x219d,0x219e,0x219f, 0x21a0,0x21a1,0x21a2,0x21a3,0x21a4,0x21a5,0x21a6,0x21a7, 0x21a8,0x21a9,0x21aa,0x21ab,0x21ac,0x21ad,0x21ae,0x21af, 0x21b0,0x21b1,0x21b2,0x21b3,0x21b4,0x21b5,0x21b6,0x21b7, 0x21b8,0x21b9,0x21ba,0x21bb,0x21bc,0x21bd,0x21be,0x21bf, 0x21c0,0x21c1,0x21c2,0x21c3,0x21c4,0x21c5,0x21c6,0x21c7, 0x21c8,0x21c9,0x21ca,0x21cb,0x21cc,0x21cd,0x21ce,0x21cf, 0x21d0,0x21d1,0x21d2,0x21d3,0x21d4,0x21d5,0x21d6,0x21d7, 0x21d8,0x21d9,0x21da,0x21db,0x21dc,0x21dd,0x21de,0x21df, 0x21e0,0x21e1,0x21e2,0x21e3,0x21e4,0x21e5,0x21e6,0x21e7, 0x21e8,0x21e9,0x21ea,0x21eb,0x21ec,0x21ed,0x21ee,0x21ef, 0x21f0,0x21f1,0x21f2,0x21f3,0x21f4,0x21f5,0x21f6,0x21f7, 0x21f8,0x21f9,0x21fa,0x21fb,0x21fc,0x21fd,0x21fe,0x21ff, 0x2200,0x2201,0x2202,0x2203,0x2204,0x2205,0x2206,0x2207, 0x2208,0x2209,0x220a,0x220b,0x220c,0x220d,0x220e,0x220f, 0x2210,0x2211,0x2212,0x2213,0x2214,0x2215,0x2216,0x2217, 0x2218,0x2219,0x221a,0x221b,0x221c,0x221d,0x221e,0x221f, 0x2220,0x2221,0x2222,0x2223,0x2224,0x2225,0x2226,0x2227, 0x2228,0x2229,0x222a,0x222b,0x222c,0x222d,0x222e,0x222f, 0x2230,0x2231,0x2232,0x2233,0x2234,0x2235,0x2236,0x2237, 0x2238,0x2239,0x223a,0x223b,0x223c,0x223d,0x223e,0x223f, 0x2240,0x2241,0x2242,0x2243,0x2244,0x2245,0x2246,0x2247, 0x2248,0x2249,0x224a,0x224b,0x224c,0x224d,0x224e,0x224f, 0x2250,0x2251,0x2252,0x2253,0x2254,0x2255,0x2256,0x2257, 0x2258,0x2259,0x225a,0x225b,0x225c,0x225d,0x225e,0x225f, 0x2260,0x2261,0x2262,0x2263,0x2264,0x2265,0x2266,0x2267, 0x2268,0x2269,0x226a,0x226b,0x226c,0x226d,0x226e,0x226f, 0x2270,0x2271,0x2272,0x2273,0x2274,0x2275,0x2276,0x2277, 0x2278,0x2279,0x227a,0x227b,0x227c,0x227d,0x227e,0x227f, 0x2280,0x2281,0x2282,0x2283,0x2284,0x2285,0x2286,0x2287, 0x2288,0x2289,0x228a,0x228b,0x228c,0x228d,0x228e,0x228f, 0x2290,0x2291,0x2292,0x2293,0x2294,0x2295,0x2296,0x2297, 0x2298,0x2299,0x229a,0x229b,0x229c,0x229d,0x229e,0x229f, 0x22a0,0x22a1,0x22a2,0x22a3,0x22a4,0x22a5,0x22a6,0x22a7, 0x22a8,0x22a9,0x22aa,0x22ab,0x22ac,0x22ad,0x22ae,0x22af, 0x22b0,0x22b1,0x22b2,0x22b3,0x22b4,0x22b5,0x22b6,0x22b7, 0x22b8,0x22b9,0x22ba,0x22bb,0x22bc,0x22bd,0x22be,0x22bf, 0x22c0,0x22c1,0x22c2,0x22c3,0x22c4,0x22c5,0x22c6,0x22c7, 0x22c8,0x22c9,0x22ca,0x22cb,0x22cc,0x22cd,0x22ce,0x22cf, 0x22d0,0x22d1,0x22d2,0x22d3,0x22d4,0x22d5,0x22d6,0x22d7, 0x22d8,0x22d9,0x22da,0x22db,0x22dc,0x22dd,0x22de,0x22df, 0x22e0,0x22e1,0x22e2,0x22e3,0x22e4,0x22e5,0x22e6,0x22e7, 0x22e8,0x22e9,0x22ea,0x22eb,0x22ec,0x22ed,0x22ee,0x22ef, 0x22f0,0x22f1,0x22f2,0x22f3,0x22f4,0x22f5,0x22f6,0x22f7, 0x22f8,0x22f9,0x22fa,0x22fb,0x22fc,0x22fd,0x22fe,0x22ff, 0x2300,0x2301,0x2302,0x2303,0x2304,0x2305,0x2306,0x2307, 0x2308,0x2309,0x230a,0x230b,0x230c,0x230d,0x230e,0x230f, 0x2310,0x2311,0x2312,0x2313,0x2314,0x2315,0x2316,0x2317, 0x2318,0x2319,0x231a,0x231b,0x231c,0x231d,0x231e,0x231f, 0x2320,0x2321,0x2322,0x2323,0x2324,0x2325,0x2326,0x2327, 0x2328,0x2329,0x232a,0x232b,0x232c,0x232d,0x232e,0x232f, 0x2330,0x2331,0x2332,0x2333,0x2334,0x2335,0x2336,0x2337, 0x2338,0x2339,0x233a,0x233b,0x233c,0x233d,0x233e,0x233f, 0x2340,0x2341,0x2342,0x2343,0x2344,0x2345,0x2346,0x2347, 0x2348,0x2349,0x234a,0x234b,0x234c,0x234d,0x234e,0x234f, 0x2350,0x2351,0x2352,0x2353,0x2354,0x2355,0x2356,0x2357, 0x2358,0x2359,0x235a,0x235b,0x235c,0x235d,0x235e,0x235f, 0x2360,0x2361,0x2362,0x2363,0x2364,0x2365,0x2366,0x2367, 0x2368,0x2369,0x236a,0x236b,0x236c,0x236d,0x236e,0x236f, 0x2370,0x2371,0x2372,0x2373,0x2374,0x2375,0x2376,0x2377, 0x2378,0x2379,0x237a,0x237b,0x237c,0x237d,0x237e,0x237f, 0x2380,0x2381,0x2382,0x2383,0x2384,0x2385,0x2386,0x2387, 0x2388,0x2389,0x238a,0x238b,0x238c,0x238d,0x238e,0x238f, 0x2390,0x2391,0x2392,0x2393,0x2394,0x2395,0x2396,0x2397, 0x2398,0x2399,0x239a,0x239b,0x239c,0x239d,0x239e,0x239f, 0x23a0,0x23a1,0x23a2,0x23a3,0x23a4,0x23a5,0x23a6,0x23a7, 0x23a8,0x23a9,0x23aa,0x23ab,0x23ac,0x23ad,0x23ae,0x23af, 0x23b0,0x23b1,0x23b2,0x23b3,0x23b4,0x23b5,0x23b6,0x23b7, 0x23b8,0x23b9,0x23ba,0x23bb,0x23bc,0x23bd,0x23be,0x23bf, 0x23c0,0x23c1,0x23c2,0x23c3,0x23c4,0x23c5,0x23c6,0x23c7, 0x23c8,0x23c9,0x23ca,0x23cb,0x23cc,0x23cd,0x23ce,0x23cf, 0x23d0,0x23d1,0x23d2,0x23d3,0x23d4,0x23d5,0x23d6,0x23d7, 0x23d8,0x23d9,0x23da,0x23db,0x23dc,0x23dd,0x23de,0x23df, 0x23e0,0x23e1,0x23e2,0x23e3,0x23e4,0x23e5,0x23e6,0x23e7, 0x23e8,0x23e9,0x23ea,0x23eb,0x23ec,0x23ed,0x23ee,0x23ef, 0x23f0,0x23f1,0x23f2,0x23f3,0x23f4,0x23f5,0x23f6,0x23f7, 0x23f8,0x23f9,0x23fa,0x23fb,0x23fc,0x23fd,0x23fe,0x23ff, 0x2400,0x2401,0x2402,0x2403,0x2404,0x2405,0x2406,0x2407, 0x2408,0x2409,0x240a,0x240b,0x240c,0x240d,0x240e,0x240f, 0x2410,0x2411,0x2412,0x2413,0x2414,0x2415,0x2416,0x2417, 0x2418,0x2419,0x241a,0x241b,0x241c,0x241d,0x241e,0x241f, 0x2420,0x2421,0x2422,0x2423,0x2424,0x2425,0x2426,0x2427, 0x2428,0x2429,0x242a,0x242b,0x242c,0x242d,0x242e,0x242f, 0x2430,0x2431,0x2432,0x2433,0x2434,0x2435,0x2436,0x2437, 0x2438,0x2439,0x243a,0x243b,0x243c,0x243d,0x243e,0x243f, 0x2440,0x2441,0x2442,0x2443,0x2444,0x2445,0x2446,0x2447, 0x2448,0x2449,0x244a,0x244b,0x244c,0x244d,0x244e,0x244f, 0x2450,0x2451,0x2452,0x2453,0x2454,0x2455,0x2456,0x2457, 0x2458,0x2459,0x245a,0x245b,0x245c,0x245d,0x245e,0x245f, 0x2460,0x2461,0x2462,0x2463,0x2464,0x2465,0x2466,0x2467, 0x2468,0x2469,0x246a,0x246b,0x246c,0x246d,0x246e,0x246f, 0x2470,0x2471,0x2472,0x2473,0x2474,0x2475,0x2476,0x2477, 0x2478,0x2479,0x247a,0x247b,0x247c,0x247d,0x247e,0x247f, 0x2480,0x2481,0x2482,0x2483,0x2484,0x2485,0x2486,0x2487, 0x2488,0x2489,0x248a,0x248b,0x248c,0x248d,0x248e,0x248f, 0x2490,0x2491,0x2492,0x2493,0x2494,0x2495,0x2496,0x2497, 0x2498,0x2499,0x249a,0x249b,0x249c,0x249d,0x249e,0x249f, 0x24a0,0x24a1,0x24a2,0x24a3,0x24a4,0x24a5,0x24a6,0x24a7, 0x24a8,0x24a9,0x24aa,0x24ab,0x24ac,0x24ad,0x24ae,0x24af, 0x24b0,0x24b1,0x24b2,0x24b3,0x24b4,0x24b5,0x24b6,0x24b7, 0x24b8,0x24b9,0x24ba,0x24bb,0x24bc,0x24bd,0x24be,0x24bf, 0x24c0,0x24c1,0x24c2,0x24c3,0x24c4,0x24c5,0x24c6,0x24c7, 0x24c8,0x24c9,0x24ca,0x24cb,0x24cc,0x24cd,0x24ce,0x24cf, 0x24b6,0x24b7,0x24b8,0x24b9,0x24ba,0x24bb,0x24bc,0x24bd, 0x24be,0x24bf,0x24c0,0x24c1,0x24c2,0x24c3,0x24c4,0x24c5, 0x24c6,0x24c7,0x24c8,0x24c9,0x24ca,0x24cb,0x24cc,0x24cd, 0x24ce,0x24cf,0x24ea,0x24eb,0x24ec,0x24ed,0x24ee,0x24ef, 0x24f0,0x24f1,0x24f2,0x24f3,0x24f4,0x24f5,0x24f6,0x24f7, 0x24f8,0x24f9,0x24fa,0x24fb,0x24fc,0x24fd,0x24fe,0x24ff, 0x2500,0x2501,0x2502,0x2503,0x2504,0x2505,0x2506,0x2507, 0x2508,0x2509,0x250a,0x250b,0x250c,0x250d,0x250e,0x250f, 0x2510,0x2511,0x2512,0x2513,0x2514,0x2515,0x2516,0x2517, 0x2518,0x2519,0x251a,0x251b,0x251c,0x251d,0x251e,0x251f, 0x2520,0x2521,0x2522,0x2523,0x2524,0x2525,0x2526,0x2527, 0x2528,0x2529,0x252a,0x252b,0x252c,0x252d,0x252e,0x252f, 0x2530,0x2531,0x2532,0x2533,0x2534,0x2535,0x2536,0x2537, 0x2538,0x2539,0x253a,0x253b,0x253c,0x253d,0x253e,0x253f, 0x2540,0x2541,0x2542,0x2543,0x2544,0x2545,0x2546,0x2547, 0x2548,0x2549,0x254a,0x254b,0x254c,0x254d,0x254e,0x254f, 0x2550,0x2551,0x2552,0x2553,0x2554,0x2555,0x2556,0x2557, 0x2558,0x2559,0x255a,0x255b,0x255c,0x255d,0x255e,0x255f, 0x2560,0x2561,0x2562,0x2563,0x2564,0x2565,0x2566,0x2567, 0x2568,0x2569,0x256a,0x256b,0x256c,0x256d,0x256e,0x256f, 0x2570,0x2571,0x2572,0x2573,0x2574,0x2575,0x2576,0x2577, 0x2578,0x2579,0x257a,0x257b,0x257c,0x257d,0x257e,0x257f, 0x2580,0x2581,0x2582,0x2583,0x2584,0x2585,0x2586,0x2587, 0x2588,0x2589,0x258a,0x258b,0x258c,0x258d,0x258e,0x258f, 0x2590,0x2591,0x2592,0x2593,0x2594,0x2595,0x2596,0x2597, 0x2598,0x2599,0x259a,0x259b,0x259c,0x259d,0x259e,0x259f, 0x25a0,0x25a1,0x25a2,0x25a3,0x25a4,0x25a5,0x25a6,0x25a7, 0x25a8,0x25a9,0x25aa,0x25ab,0x25ac,0x25ad,0x25ae,0x25af, 0x25b0,0x25b1,0x25b2,0x25b3,0x25b4,0x25b5,0x25b6,0x25b7, 0x25b8,0x25b9,0x25ba,0x25bb,0x25bc,0x25bd,0x25be,0x25bf, 0x25c0,0x25c1,0x25c2,0x25c3,0x25c4,0x25c5,0x25c6,0x25c7, 0x25c8,0x25c9,0x25ca,0x25cb,0x25cc,0x25cd,0x25ce,0x25cf, 0x25d0,0x25d1,0x25d2,0x25d3,0x25d4,0x25d5,0x25d6,0x25d7, 0x25d8,0x25d9,0x25da,0x25db,0x25dc,0x25dd,0x25de,0x25df, 0x25e0,0x25e1,0x25e2,0x25e3,0x25e4,0x25e5,0x25e6,0x25e7, 0x25e8,0x25e9,0x25ea,0x25eb,0x25ec,0x25ed,0x25ee,0x25ef, 0x25f0,0x25f1,0x25f2,0x25f3,0x25f4,0x25f5,0x25f6,0x25f7, 0x25f8,0x25f9,0x25fa,0x25fb,0x25fc,0x25fd,0x25fe,0x25ff, 0x2600,0x2601,0x2602,0x2603,0x2604,0x2605,0x2606,0x2607, 0x2608,0x2609,0x260a,0x260b,0x260c,0x260d,0x260e,0x260f, 0x2610,0x2611,0x2612,0x2613,0x2614,0x2615,0x2616,0x2617, 0x2618,0x2619,0x261a,0x261b,0x261c,0x261d,0x261e,0x261f, 0x2620,0x2621,0x2622,0x2623,0x2624,0x2625,0x2626,0x2627, 0x2628,0x2629,0x262a,0x262b,0x262c,0x262d,0x262e,0x262f, 0x2630,0x2631,0x2632,0x2633,0x2634,0x2635,0x2636,0x2637, 0x2638,0x2639,0x263a,0x263b,0x263c,0x263d,0x263e,0x263f, 0x2640,0x2641,0x2642,0x2643,0x2644,0x2645,0x2646,0x2647, 0x2648,0x2649,0x264a,0x264b,0x264c,0x264d,0x264e,0x264f, 0x2650,0x2651,0x2652,0x2653,0x2654,0x2655,0x2656,0x2657, 0x2658,0x2659,0x265a,0x265b,0x265c,0x265d,0x265e,0x265f, 0x2660,0x2661,0x2662,0x2663,0x2664,0x2665,0x2666,0x2667, 0x2668,0x2669,0x266a,0x266b,0x266c,0x266d,0x266e,0x266f, 0x2670,0x2671,0x2672,0x2673,0x2674,0x2675,0x2676,0x2677, 0x2678,0x2679,0x267a,0x267b,0x267c,0x267d,0x267e,0x267f, 0x2680,0x2681,0x2682,0x2683,0x2684,0x2685,0x2686,0x2687, 0x2688,0x2689,0x268a,0x268b,0x268c,0x268d,0x268e,0x268f, 0x2690,0x2691,0x2692,0x2693,0x2694,0x2695,0x2696,0x2697, 0x2698,0x2699,0x269a,0x269b,0x269c,0x269d,0x269e,0x269f, 0x26a0,0x26a1,0x26a2,0x26a3,0x26a4,0x26a5,0x26a6,0x26a7, 0x26a8,0x26a9,0x26aa,0x26ab,0x26ac,0x26ad,0x26ae,0x26af, 0x26b0,0x26b1,0x26b2,0x26b3,0x26b4,0x26b5,0x26b6,0x26b7, 0x26b8,0x26b9,0x26ba,0x26bb,0x26bc,0x26bd,0x26be,0x26bf, 0x26c0,0x26c1,0x26c2,0x26c3,0x26c4,0x26c5,0x26c6,0x26c7, 0x26c8,0x26c9,0x26ca,0x26cb,0x26cc,0x26cd,0x26ce,0x26cf, 0x26d0,0x26d1,0x26d2,0x26d3,0x26d4,0x26d5,0x26d6,0x26d7, 0x26d8,0x26d9,0x26da,0x26db,0x26dc,0x26dd,0x26de,0x26df, 0x26e0,0x26e1,0x26e2,0x26e3,0x26e4,0x26e5,0x26e6,0x26e7, 0x26e8,0x26e9,0x26ea,0x26eb,0x26ec,0x26ed,0x26ee,0x26ef, 0x26f0,0x26f1,0x26f2,0x26f3,0x26f4,0x26f5,0x26f6,0x26f7, 0x26f8,0x26f9,0x26fa,0x26fb,0x26fc,0x26fd,0x26fe,0x26ff, 0x2700,0x2701,0x2702,0x2703,0x2704,0x2705,0x2706,0x2707, 0x2708,0x2709,0x270a,0x270b,0x270c,0x270d,0x270e,0x270f, 0x2710,0x2711,0x2712,0x2713,0x2714,0x2715,0x2716,0x2717, 0x2718,0x2719,0x271a,0x271b,0x271c,0x271d,0x271e,0x271f, 0x2720,0x2721,0x2722,0x2723,0x2724,0x2725,0x2726,0x2727, 0x2728,0x2729,0x272a,0x272b,0x272c,0x272d,0x272e,0x272f, 0x2730,0x2731,0x2732,0x2733,0x2734,0x2735,0x2736,0x2737, 0x2738,0x2739,0x273a,0x273b,0x273c,0x273d,0x273e,0x273f, 0x2740,0x2741,0x2742,0x2743,0x2744,0x2745,0x2746,0x2747, 0x2748,0x2749,0x274a,0x274b,0x274c,0x274d,0x274e,0x274f, 0x2750,0x2751,0x2752,0x2753,0x2754,0x2755,0x2756,0x2757, 0x2758,0x2759,0x275a,0x275b,0x275c,0x275d,0x275e,0x275f, 0x2760,0x2761,0x2762,0x2763,0x2764,0x2765,0x2766,0x2767, 0x2768,0x2769,0x276a,0x276b,0x276c,0x276d,0x276e,0x276f, 0x2770,0x2771,0x2772,0x2773,0x2774,0x2775,0x2776,0x2777, 0x2778,0x2779,0x277a,0x277b,0x277c,0x277d,0x277e,0x277f, 0x2780,0x2781,0x2782,0x2783,0x2784,0x2785,0x2786,0x2787, 0x2788,0x2789,0x278a,0x278b,0x278c,0x278d,0x278e,0x278f, 0x2790,0x2791,0x2792,0x2793,0x2794,0x2795,0x2796,0x2797, 0x2798,0x2799,0x279a,0x279b,0x279c,0x279d,0x279e,0x279f, 0x27a0,0x27a1,0x27a2,0x27a3,0x27a4,0x27a5,0x27a6,0x27a7, 0x27a8,0x27a9,0x27aa,0x27ab,0x27ac,0x27ad,0x27ae,0x27af, 0x27b0,0x27b1,0x27b2,0x27b3,0x27b4,0x27b5,0x27b6,0x27b7, 0x27b8,0x27b9,0x27ba,0x27bb,0x27bc,0x27bd,0x27be,0x27bf, 0x27c0,0x27c1,0x27c2,0x27c3,0x27c4,0x27c5,0x27c6,0x27c7, 0x27c8,0x27c9,0x27ca,0x27cb,0x27cc,0x27cd,0x27ce,0x27cf, 0x27d0,0x27d1,0x27d2,0x27d3,0x27d4,0x27d5,0x27d6,0x27d7, 0x27d8,0x27d9,0x27da,0x27db,0x27dc,0x27dd,0x27de,0x27df, 0x27e0,0x27e1,0x27e2,0x27e3,0x27e4,0x27e5,0x27e6,0x27e7, 0x27e8,0x27e9,0x27ea,0x27eb,0x27ec,0x27ed,0x27ee,0x27ef, 0x27f0,0x27f1,0x27f2,0x27f3,0x27f4,0x27f5,0x27f6,0x27f7, 0x27f8,0x27f9,0x27fa,0x27fb,0x27fc,0x27fd,0x27fe,0x27ff, 0x2800,0x2801,0x2802,0x2803,0x2804,0x2805,0x2806,0x2807, 0x2808,0x2809,0x280a,0x280b,0x280c,0x280d,0x280e,0x280f, 0x2810,0x2811,0x2812,0x2813,0x2814,0x2815,0x2816,0x2817, 0x2818,0x2819,0x281a,0x281b,0x281c,0x281d,0x281e,0x281f, 0x2820,0x2821,0x2822,0x2823,0x2824,0x2825,0x2826,0x2827, 0x2828,0x2829,0x282a,0x282b,0x282c,0x282d,0x282e,0x282f, 0x2830,0x2831,0x2832,0x2833,0x2834,0x2835,0x2836,0x2837, 0x2838,0x2839,0x283a,0x283b,0x283c,0x283d,0x283e,0x283f, 0x2840,0x2841,0x2842,0x2843,0x2844,0x2845,0x2846,0x2847, 0x2848,0x2849,0x284a,0x284b,0x284c,0x284d,0x284e,0x284f, 0x2850,0x2851,0x2852,0x2853,0x2854,0x2855,0x2856,0x2857, 0x2858,0x2859,0x285a,0x285b,0x285c,0x285d,0x285e,0x285f, 0x2860,0x2861,0x2862,0x2863,0x2864,0x2865,0x2866,0x2867, 0x2868,0x2869,0x286a,0x286b,0x286c,0x286d,0x286e,0x286f, 0x2870,0x2871,0x2872,0x2873,0x2874,0x2875,0x2876,0x2877, 0x2878,0x2879,0x287a,0x287b,0x287c,0x287d,0x287e,0x287f, 0x2880,0x2881,0x2882,0x2883,0x2884,0x2885,0x2886,0x2887, 0x2888,0x2889,0x288a,0x288b,0x288c,0x288d,0x288e,0x288f, 0x2890,0x2891,0x2892,0x2893,0x2894,0x2895,0x2896,0x2897, 0x2898,0x2899,0x289a,0x289b,0x289c,0x289d,0x289e,0x289f, 0x28a0,0x28a1,0x28a2,0x28a3,0x28a4,0x28a5,0x28a6,0x28a7, 0x28a8,0x28a9,0x28aa,0x28ab,0x28ac,0x28ad,0x28ae,0x28af, 0x28b0,0x28b1,0x28b2,0x28b3,0x28b4,0x28b5,0x28b6,0x28b7, 0x28b8,0x28b9,0x28ba,0x28bb,0x28bc,0x28bd,0x28be,0x28bf, 0x28c0,0x28c1,0x28c2,0x28c3,0x28c4,0x28c5,0x28c6,0x28c7, 0x28c8,0x28c9,0x28ca,0x28cb,0x28cc,0x28cd,0x28ce,0x28cf, 0x28d0,0x28d1,0x28d2,0x28d3,0x28d4,0x28d5,0x28d6,0x28d7, 0x28d8,0x28d9,0x28da,0x28db,0x28dc,0x28dd,0x28de,0x28df, 0x28e0,0x28e1,0x28e2,0x28e3,0x28e4,0x28e5,0x28e6,0x28e7, 0x28e8,0x28e9,0x28ea,0x28eb,0x28ec,0x28ed,0x28ee,0x28ef, 0x28f0,0x28f1,0x28f2,0x28f3,0x28f4,0x28f5,0x28f6,0x28f7, 0x28f8,0x28f9,0x28fa,0x28fb,0x28fc,0x28fd,0x28fe,0x28ff, 0x2900,0x2901,0x2902,0x2903,0x2904,0x2905,0x2906,0x2907, 0x2908,0x2909,0x290a,0x290b,0x290c,0x290d,0x290e,0x290f, 0x2910,0x2911,0x2912,0x2913,0x2914,0x2915,0x2916,0x2917, 0x2918,0x2919,0x291a,0x291b,0x291c,0x291d,0x291e,0x291f, 0x2920,0x2921,0x2922,0x2923,0x2924,0x2925,0x2926,0x2927, 0x2928,0x2929,0x292a,0x292b,0x292c,0x292d,0x292e,0x292f, 0x2930,0x2931,0x2932,0x2933,0x2934,0x2935,0x2936,0x2937, 0x2938,0x2939,0x293a,0x293b,0x293c,0x293d,0x293e,0x293f, 0x2940,0x2941,0x2942,0x2943,0x2944,0x2945,0x2946,0x2947, 0x2948,0x2949,0x294a,0x294b,0x294c,0x294d,0x294e,0x294f, 0x2950,0x2951,0x2952,0x2953,0x2954,0x2955,0x2956,0x2957, 0x2958,0x2959,0x295a,0x295b,0x295c,0x295d,0x295e,0x295f, 0x2960,0x2961,0x2962,0x2963,0x2964,0x2965,0x2966,0x2967, 0x2968,0x2969,0x296a,0x296b,0x296c,0x296d,0x296e,0x296f, 0x2970,0x2971,0x2972,0x2973,0x2974,0x2975,0x2976,0x2977, 0x2978,0x2979,0x297a,0x297b,0x297c,0x297d,0x297e,0x297f, 0x2980,0x2981,0x2982,0x2983,0x2984,0x2985,0x2986,0x2987, 0x2988,0x2989,0x298a,0x298b,0x298c,0x298d,0x298e,0x298f, 0x2990,0x2991,0x2992,0x2993,0x2994,0x2995,0x2996,0x2997, 0x2998,0x2999,0x299a,0x299b,0x299c,0x299d,0x299e,0x299f, 0x29a0,0x29a1,0x29a2,0x29a3,0x29a4,0x29a5,0x29a6,0x29a7, 0x29a8,0x29a9,0x29aa,0x29ab,0x29ac,0x29ad,0x29ae,0x29af, 0x29b0,0x29b1,0x29b2,0x29b3,0x29b4,0x29b5,0x29b6,0x29b7, 0x29b8,0x29b9,0x29ba,0x29bb,0x29bc,0x29bd,0x29be,0x29bf, 0x29c0,0x29c1,0x29c2,0x29c3,0x29c4,0x29c5,0x29c6,0x29c7, 0x29c8,0x29c9,0x29ca,0x29cb,0x29cc,0x29cd,0x29ce,0x29cf, 0x29d0,0x29d1,0x29d2,0x29d3,0x29d4,0x29d5,0x29d6,0x29d7, 0x29d8,0x29d9,0x29da,0x29db,0x29dc,0x29dd,0x29de,0x29df, 0x29e0,0x29e1,0x29e2,0x29e3,0x29e4,0x29e5,0x29e6,0x29e7, 0x29e8,0x29e9,0x29ea,0x29eb,0x29ec,0x29ed,0x29ee,0x29ef, 0x29f0,0x29f1,0x29f2,0x29f3,0x29f4,0x29f5,0x29f6,0x29f7, 0x29f8,0x29f9,0x29fa,0x29fb,0x29fc,0x29fd,0x29fe,0x29ff, 0x2a00,0x2a01,0x2a02,0x2a03,0x2a04,0x2a05,0x2a06,0x2a07, 0x2a08,0x2a09,0x2a0a,0x2a0b,0x2a0c,0x2a0d,0x2a0e,0x2a0f, 0x2a10,0x2a11,0x2a12,0x2a13,0x2a14,0x2a15,0x2a16,0x2a17, 0x2a18,0x2a19,0x2a1a,0x2a1b,0x2a1c,0x2a1d,0x2a1e,0x2a1f, 0x2a20,0x2a21,0x2a22,0x2a23,0x2a24,0x2a25,0x2a26,0x2a27, 0x2a28,0x2a29,0x2a2a,0x2a2b,0x2a2c,0x2a2d,0x2a2e,0x2a2f, 0x2a30,0x2a31,0x2a32,0x2a33,0x2a34,0x2a35,0x2a36,0x2a37, 0x2a38,0x2a39,0x2a3a,0x2a3b,0x2a3c,0x2a3d,0x2a3e,0x2a3f, 0x2a40,0x2a41,0x2a42,0x2a43,0x2a44,0x2a45,0x2a46,0x2a47, 0x2a48,0x2a49,0x2a4a,0x2a4b,0x2a4c,0x2a4d,0x2a4e,0x2a4f, 0x2a50,0x2a51,0x2a52,0x2a53,0x2a54,0x2a55,0x2a56,0x2a57, 0x2a58,0x2a59,0x2a5a,0x2a5b,0x2a5c,0x2a5d,0x2a5e,0x2a5f, 0x2a60,0x2a61,0x2a62,0x2a63,0x2a64,0x2a65,0x2a66,0x2a67, 0x2a68,0x2a69,0x2a6a,0x2a6b,0x2a6c,0x2a6d,0x2a6e,0x2a6f, 0x2a70,0x2a71,0x2a72,0x2a73,0x2a74,0x2a75,0x2a76,0x2a77, 0x2a78,0x2a79,0x2a7a,0x2a7b,0x2a7c,0x2a7d,0x2a7e,0x2a7f, 0x2a80,0x2a81,0x2a82,0x2a83,0x2a84,0x2a85,0x2a86,0x2a87, 0x2a88,0x2a89,0x2a8a,0x2a8b,0x2a8c,0x2a8d,0x2a8e,0x2a8f, 0x2a90,0x2a91,0x2a92,0x2a93,0x2a94,0x2a95,0x2a96,0x2a97, 0x2a98,0x2a99,0x2a9a,0x2a9b,0x2a9c,0x2a9d,0x2a9e,0x2a9f, 0x2aa0,0x2aa1,0x2aa2,0x2aa3,0x2aa4,0x2aa5,0x2aa6,0x2aa7, 0x2aa8,0x2aa9,0x2aaa,0x2aab,0x2aac,0x2aad,0x2aae,0x2aaf, 0x2ab0,0x2ab1,0x2ab2,0x2ab3,0x2ab4,0x2ab5,0x2ab6,0x2ab7, 0x2ab8,0x2ab9,0x2aba,0x2abb,0x2abc,0x2abd,0x2abe,0x2abf, 0x2ac0,0x2ac1,0x2ac2,0x2ac3,0x2ac4,0x2ac5,0x2ac6,0x2ac7, 0x2ac8,0x2ac9,0x2aca,0x2acb,0x2acc,0x2acd,0x2ace,0x2acf, 0x2ad0,0x2ad1,0x2ad2,0x2ad3,0x2ad4,0x2ad5,0x2ad6,0x2ad7, 0x2ad8,0x2ad9,0x2ada,0x2adb,0x2adc,0x2add,0x2ade,0x2adf, 0x2ae0,0x2ae1,0x2ae2,0x2ae3,0x2ae4,0x2ae5,0x2ae6,0x2ae7, 0x2ae8,0x2ae9,0x2aea,0x2aeb,0x2aec,0x2aed,0x2aee,0x2aef, 0x2af0,0x2af1,0x2af2,0x2af3,0x2af4,0x2af5,0x2af6,0x2af7, 0x2af8,0x2af9,0x2afa,0x2afb,0x2afc,0x2afd,0x2afe,0x2aff, 0x2b00,0x2b01,0x2b02,0x2b03,0x2b04,0x2b05,0x2b06,0x2b07, 0x2b08,0x2b09,0x2b0a,0x2b0b,0x2b0c,0x2b0d,0x2b0e,0x2b0f, 0x2b10,0x2b11,0x2b12,0x2b13,0x2b14,0x2b15,0x2b16,0x2b17, 0x2b18,0x2b19,0x2b1a,0x2b1b,0x2b1c,0x2b1d,0x2b1e,0x2b1f, 0x2b20,0x2b21,0x2b22,0x2b23,0x2b24,0x2b25,0x2b26,0x2b27, 0x2b28,0x2b29,0x2b2a,0x2b2b,0x2b2c,0x2b2d,0x2b2e,0x2b2f, 0x2b30,0x2b31,0x2b32,0x2b33,0x2b34,0x2b35,0x2b36,0x2b37, 0x2b38,0x2b39,0x2b3a,0x2b3b,0x2b3c,0x2b3d,0x2b3e,0x2b3f, 0x2b40,0x2b41,0x2b42,0x2b43,0x2b44,0x2b45,0x2b46,0x2b47, 0x2b48,0x2b49,0x2b4a,0x2b4b,0x2b4c,0x2b4d,0x2b4e,0x2b4f, 0x2b50,0x2b51,0x2b52,0x2b53,0x2b54,0x2b55,0x2b56,0x2b57, 0x2b58,0x2b59,0x2b5a,0x2b5b,0x2b5c,0x2b5d,0x2b5e,0x2b5f, 0x2b60,0x2b61,0x2b62,0x2b63,0x2b64,0x2b65,0x2b66,0x2b67, 0x2b68,0x2b69,0x2b6a,0x2b6b,0x2b6c,0x2b6d,0x2b6e,0x2b6f, 0x2b70,0x2b71,0x2b72,0x2b73,0x2b74,0x2b75,0x2b76,0x2b77, 0x2b78,0x2b79,0x2b7a,0x2b7b,0x2b7c,0x2b7d,0x2b7e,0x2b7f, 0x2b80,0x2b81,0x2b82,0x2b83,0x2b84,0x2b85,0x2b86,0x2b87, 0x2b88,0x2b89,0x2b8a,0x2b8b,0x2b8c,0x2b8d,0x2b8e,0x2b8f, 0x2b90,0x2b91,0x2b92,0x2b93,0x2b94,0x2b95,0x2b96,0x2b97, 0x2b98,0x2b99,0x2b9a,0x2b9b,0x2b9c,0x2b9d,0x2b9e,0x2b9f, 0x2ba0,0x2ba1,0x2ba2,0x2ba3,0x2ba4,0x2ba5,0x2ba6,0x2ba7, 0x2ba8,0x2ba9,0x2baa,0x2bab,0x2bac,0x2bad,0x2bae,0x2baf, 0x2bb0,0x2bb1,0x2bb2,0x2bb3,0x2bb4,0x2bb5,0x2bb6,0x2bb7, 0x2bb8,0x2bb9,0x2bba,0x2bbb,0x2bbc,0x2bbd,0x2bbe,0x2bbf, 0x2bc0,0x2bc1,0x2bc2,0x2bc3,0x2bc4,0x2bc5,0x2bc6,0x2bc7, 0x2bc8,0x2bc9,0x2bca,0x2bcb,0x2bcc,0x2bcd,0x2bce,0x2bcf, 0x2bd0,0x2bd1,0x2bd2,0x2bd3,0x2bd4,0x2bd5,0x2bd6,0x2bd7, 0x2bd8,0x2bd9,0x2bda,0x2bdb,0x2bdc,0x2bdd,0x2bde,0x2bdf, 0x2be0,0x2be1,0x2be2,0x2be3,0x2be4,0x2be5,0x2be6,0x2be7, 0x2be8,0x2be9,0x2bea,0x2beb,0x2bec,0x2bed,0x2bee,0x2bef, 0x2bf0,0x2bf1,0x2bf2,0x2bf3,0x2bf4,0x2bf5,0x2bf6,0x2bf7, 0x2bf8,0x2bf9,0x2bfa,0x2bfb,0x2bfc,0x2bfd,0x2bfe,0x2bff, 0x2c00,0x2c01,0x2c02,0x2c03,0x2c04,0x2c05,0x2c06,0x2c07, 0x2c08,0x2c09,0x2c0a,0x2c0b,0x2c0c,0x2c0d,0x2c0e,0x2c0f, 0x2c10,0x2c11,0x2c12,0x2c13,0x2c14,0x2c15,0x2c16,0x2c17, 0x2c18,0x2c19,0x2c1a,0x2c1b,0x2c1c,0x2c1d,0x2c1e,0x2c1f, 0x2c20,0x2c21,0x2c22,0x2c23,0x2c24,0x2c25,0x2c26,0x2c27, 0x2c28,0x2c29,0x2c2a,0x2c2b,0x2c2c,0x2c2d,0x2c2e,0x2c2f, 0x2c00,0x2c01,0x2c02,0x2c03,0x2c04,0x2c05,0x2c06,0x2c07, 0x2c08,0x2c09,0x2c0a,0x2c0b,0x2c0c,0x2c0d,0x2c0e,0x2c0f, 0x2c10,0x2c11,0x2c12,0x2c13,0x2c14,0x2c15,0x2c16,0x2c17, 0x2c18,0x2c19,0x2c1a,0x2c1b,0x2c1c,0x2c1d,0x2c1e,0x2c1f, 0x2c20,0x2c21,0x2c22,0x2c23,0x2c24,0x2c25,0x2c26,0x2c27, 0x2c28,0x2c29,0x2c2a,0x2c2b,0x2c2c,0x2c2d,0x2c2e,0x2c5f, 0x2c60,0x2c60,0x2c62,0x2c63,0x2c64,0x023a,0x023e,0x2c67, 0x2c67,0x2c69,0x2c69,0x2c6b,0x2c6b,0x2c6d,0x2c6e,0x2c6f, 0x2c70,0x2c71,0x2c72,0x2c73,0x2c74,0x2c75,0x2c75,0x2c77, 0x2c78,0x2c79,0x2c7a,0x2c7b,0x2c7c,0x2c7d,0x2c7e,0x2c7f, 0x2c80,0x2c80,0x2c82,0x2c82,0x2c84,0x2c84,0x2c86,0x2c86, 0x2c88,0x2c88,0x2c8a,0x2c8a,0x2c8c,0x2c8c,0x2c8e,0x2c8e, 0x2c90,0x2c90,0x2c92,0x2c92,0x2c94,0x2c94,0x2c96,0x2c96, 0x2c98,0x2c98,0x2c9a,0x2c9a,0x2c9c,0x2c9c,0x2c9e,0x2c9e, 0x2ca0,0x2ca0,0x2ca2,0x2ca2,0x2ca4,0x2ca4,0x2ca6,0x2ca6, 0x2ca8,0x2ca8,0x2caa,0x2caa,0x2cac,0x2cac,0x2cae,0x2cae, 0x2cb0,0x2cb0,0x2cb2,0x2cb2,0x2cb4,0x2cb4,0x2cb6,0x2cb6, 0x2cb8,0x2cb8,0x2cba,0x2cba,0x2cbc,0x2cbc,0x2cbe,0x2cbe, 0x2cc0,0x2cc0,0x2cc2,0x2cc2,0x2cc4,0x2cc4,0x2cc6,0x2cc6, 0x2cc8,0x2cc8,0x2cca,0x2cca,0x2ccc,0x2ccc,0x2cce,0x2cce, 0x2cd0,0x2cd0,0x2cd2,0x2cd2,0x2cd4,0x2cd4,0x2cd6,0x2cd6, 0x2cd8,0x2cd8,0x2cda,0x2cda,0x2cdc,0x2cdc,0x2cde,0x2cde, 0x2ce0,0x2ce0,0x2ce2,0x2ce2,0x2ce4,0x2ce5,0x2ce6,0x2ce7, 0x2ce8,0x2ce9,0x2cea,0x2ceb,0x2cec,0x2ced,0x2cee,0x2cef, 0x2cf0,0x2cf1,0x2cf2,0x2cf3,0x2cf4,0x2cf5,0x2cf6,0x2cf7, 0x2cf8,0x2cf9,0x2cfa,0x2cfb,0x2cfc,0x2cfd,0x2cfe,0x2cff, 0x10a0,0x10a1,0x10a2,0x10a3,0x10a4,0x10a5,0x10a6,0x10a7, 0x10a8,0x10a9,0x10aa,0x10ab,0x10ac,0x10ad,0x10ae,0x10af, 0x10b0,0x10b1,0x10b2,0x10b3,0x10b4,0x10b5,0x10b6,0x10b7, 0x10b8,0x10b9,0x10ba,0x10bb,0x10bc,0x10bd,0x10be,0x10bf, 0x10c0,0x10c1,0x10c2,0x10c3,0x10c4,0x10c5 }; alpine-2.10+dfsg/imap/src/charset/viscii.c0000600000175000017500000000545711512502123022146 0ustar paulproteuspaulproteus/* ======================================================================== * Copyright 1988-2006 University of Washington * * Licensed under the Apache License, Version 2.0 (the "License"); * you may not use this file except in compliance with the License. * You may obtain a copy of the License at * * http://www.apache.org/licenses/LICENSE-2.0 * * * ======================================================================== */ /* * Program: VISCII conversion table * * Author: Mark Crispin * Networks and Distributed Computing * Computing & Communications * University of Washington * Administration Building, AG-44 * Seattle, WA 98195 * Internet: MRC@CAC.Washington.EDU * * Date: 2 June 1998 * Last Edited: 30 August 2006 */ /* VISCII is the VIetnamese Standard Code for Information Interchange, * defined by the Vietnamese Standardization Working Group, RFC-1456, * May 1993. */ static const unsigned short visciitab[256] = { 0x0000,0x0001,0x1eb2,0x0003,0x0004,0x1eb4,0x1eaa,0x0007, 0x0008,0x0009,0x000a,0x000b,0x000c,0x000d,0x000e,0x000f, 0x0010,0x0011,0x0012,0x0013,0x1ef6,0x0015,0x0016,0x0017, 0x0018,0x1ef8,0x001a,0x001b,0x001c,0x001d,0x1ef4,0x001f, 0x0020,0x0021,0x0022,0x0023,0x0024,0x0025,0x0026,0x0027, 0x0028,0x0029,0x002a,0x002b,0x002c,0x002d,0x002e,0x002f, 0x0030,0x0031,0x0032,0x0033,0x0034,0x0035,0x0036,0x0037, 0x0038,0x0039,0x003a,0x003b,0x003c,0x003d,0x003e,0x003f, 0x0040,0x0041,0x0042,0x0043,0x0044,0x0045,0x0046,0x0047, 0x0048,0x0049,0x004a,0x004b,0x004c,0x004d,0x004e,0x004f, 0x0050,0x0051,0x0052,0x0053,0x0054,0x0055,0x0056,0x0057, 0x0058,0x0059,0x005a,0x005b,0x005c,0x005d,0x005e,0x005f, 0x0060,0x0061,0x0062,0x0063,0x0064,0x0065,0x0066,0x0067, 0x0068,0x0069,0x006a,0x006b,0x006c,0x006d,0x006e,0x006f, 0x0070,0x0071,0x0072,0x0073,0x0074,0x0075,0x0076,0x0077, 0x0078,0x0079,0x007a,0x007b,0x007c,0x007d,0x007e,0x007f, 0x1ea0,0x1eae,0x1eb0,0x1eb6,0x1ea4,0x1ea6,0x1ea8,0x1eac, 0x1ebc,0x1eb8,0x1ebe,0x1ec0,0x1ec2,0x1ec4,0x1ec6,0x1ed0, 0x1ed2,0x1ed4,0x1ed6,0x1ed8,0x1ee2,0x1eda,0x1edc,0x1ede, 0x1eca,0x1ece,0x1ecc,0x1ec8,0x1ee6,0x0168,0x1ee4,0x1ef2, 0x00d5,0x1eaf,0x1eb1,0x1eb7,0x1ea5,0x1ea7,0x1ea9,0x1ead, 0x1ebd,0x1eb9,0x1ebf,0x1ec1,0x1ec3,0x1ec5,0x1ec7,0x1ed1, 0x1ed3,0x1ed5,0x1ed7,0x1ee0,0x01a0,0x1ed9,0x1edd,0x1edf, 0x1ecb,0x1ef0,0x1ee8,0x1eea,0x1eec,0x01a1,0x1edb,0x01af, 0x00c0,0x00c1,0x00c2,0x00c3,0x1ea2,0x0102,0x1eb3,0x1eb5, 0x00c8,0x00c9,0x00ca,0x1eba,0x00cc,0x00cd,0x0128,0x1ef3, 0x0110,0x1ee9,0x00d2,0x00d3,0x00d4,0x1ea1,0x1ef7,0x1eeb, 0x1eed,0x00d9,0x00da,0x1ef9,0x1ef5,0x00dd,0x1ee1,0x01b0, 0x00e0,0x00e1,0x00e2,0x00e3,0x1ea3,0x0103,0x1eef,0x1eab, 0x00e8,0x00e9,0x00ea,0x1ebb,0x00ec,0x00ed,0x0129,0x1ec9, 0x0111,0x1ef1,0x00f2,0x00f3,0x00f4,0x00f5,0x1ecf,0x1ecd, 0x1ee5,0x00f9,0x00fa,0x0169,0x1ee7,0x00fd,0x1ee3,0x1eee }; alpine-2.10+dfsg/imap/src/charset/big5.c0000600000175000017500000033614111512502123021503 0ustar paulproteuspaulproteus/* ======================================================================== * Copyright 1988-2006 University of Washington * * Licensed under the Apache License, Version 2.0 (the "License"); * you may not use this file except in compliance with the License. * You may obtain a copy of the License at * * http://www.apache.org/licenses/LICENSE-2.0 * * * ======================================================================== */ /* * Program: BIG-5 conversion table * * Author: Mark Crispin * Networks and Distributed Computing * Computing & Communications * University of Washington * Administration Building, AG-44 * Seattle, WA 98195 * Internet: MRC@CAC.Washington.EDU * * Date: 3 July 1997 * Last Edited: 30 August 2006 */ /* Big-5 is the de-facto industrial standard of the Republic of China * (Taiwan), and is commonly used in the Hong Kong Special Administrative * Region of the People's Republic of China (mainland China). */ #define BASE_BIG5_KU 0xa1 #define BASE_BIG5_TEN_0 0x40 #define BASE_BIG5_TEN_1 0xa1 #define MAX_BIG5_KU 89 #define MAX_BIG5_TEN_0 63 #define MAX_BIG5_TEN_1 94 #define BIG5TOUNICODE(c,c1,ku,ten) \ (((ku = c - BASE_BIG5_KU) < MAX_BIG5_KU) ? \ ((c1 & 0x80) ? \ (((ten = c1 - BASE_BIG5_TEN_1) < MAX_BIG5_TEN_1) ? \ big5tab[ku].plane1[ten] : UBOGON) : \ (((ten = c1 - BASE_BIG5_TEN_0) < MAX_BIG5_TEN_0) ? \ big5tab[ku].plane0[ten] : UBOGON)) : UBOGON) typedef struct big5_ku { unsigned short plane0[MAX_BIG5_TEN_0]; unsigned short plane1[MAX_BIG5_TEN_1]; } BIG5; static const BIG5 big5tab[MAX_BIG5_KU] = { { /* ku 01 */ { 0x3000,0xff0c,0x3001,0x3002,0xff0e,0x2022,0xff1b,0xff1a,0xff1f,0xff01, 0xfe30,0x2026,0x2025,0xfe50,0xff64,0xfe52,0x00b7,0xfe54,0xfe55,0xfe56, 0xfe57,0xff5c,0x2013,0xfe31,0x2014,0xfe33,0xfffd,0xfe34,0xfe4f,0xff08, 0xff09,0xfe35,0xfe36,0xff5b,0xff5d,0xfe37,0xfe38,0x3014,0x3015,0xfe39, 0xfe3a,0x3010,0x3011,0xfe3b,0xfe3c,0x300a,0x300b,0xfe3d,0xfe3e,0x3008, 0x3009,0xfe3f,0xfe40,0x300c,0x300d,0xfe41,0xfe42,0x300e,0x300f,0xfe43, 0xfe44,0xfe59,0xfe5a },{ 0xfe5b,0xfe5c,0xfe5d,0xfe5e,0x2018,0x2019,0x201c,0x201d,0x301d,0x301e, 0x2035,0x2032,0xff03,0xff06,0xff0a,0x203b,0x00a7,0x3003,0x25cb,0x25cf, 0x25b3,0x25b2,0x25ce,0x2606,0x2605,0x25c7,0x25c6,0x25a1,0x25a0,0x25bd, 0x25bc,0x32a3,0x2105,0x203e,0xfffd,0xff3f,0xfffd,0xfe49,0xfe4a,0xfe4d, 0xfe4e,0xfe4b,0xfe4c,0xfe5f,0xfe60,0xfe61,0xff0b,0xff0d,0x00d7,0x00f7, 0x00b1,0x221a,0xff1c,0xff1e,0xff1d,0x2266,0x2267,0x2260,0x221e,0x2252, 0x2261,0xfe62,0xfe63,0xfe64,0xfe65,0xfe66,0x223c,0x2229,0x222a,0x22a5, 0x2220,0x221f,0x22bf,0x33d2,0x33d1,0x222b,0x222e,0x2235,0x2234,0x2640, 0x2642,0x2641,0x2609,0x2191,0x2193,0x2190,0x2192,0x2196,0x2197,0x2199, 0x2198,0x2225,0x2223,0xfffd } }, { /* ku 02 */ { 0xfffd,0xff0f,0xff3c,0xff04,0x00a5,0x3012,0x00a2,0x00a3,0xff05,0xff20, 0x2103,0x2109,0xfe69,0xfe6a,0xfe6b,0x33d5,0x339c,0x339d,0x339e,0x33ce, 0x33a1,0x338e,0x338f,0x33c4,0x00b0,0x5159,0x515b,0x515e,0x515d,0x5161, 0x5163,0x55e7,0x74e9,0x7cce,0x2581,0x2582,0x2583,0x2584,0x2585,0x2586, 0x2587,0x2588,0x258f,0x258e,0x258d,0x258c,0x258b,0x258a,0x2589,0x253c, 0x2534,0x252c,0x2524,0x251c,0x2594,0x2500,0x2502,0x2595,0x250c,0x2510, 0x2514,0x2518,0x256d },{ 0x256e,0x2570,0x256f,0x2550,0x255e,0x256a,0x2561,0x25e2,0x25e3,0x25e5, 0x25e4,0x2571,0x2572,0x2573,0xff10,0xff11,0xff12,0xff13,0xff14,0xff15, 0xff16,0xff17,0xff18,0xff19,0x2160,0x2161,0x2162,0x2163,0x2164,0x2165, 0x2166,0x2167,0x2168,0x2169,0x3021,0x3022,0x3023,0x3024,0x3025,0x3026, 0x3027,0x3028,0x3029,0xfffd,0x5344,0xfffd,0xff21,0xff22,0xff23,0xff24, 0xff25,0xff26,0xff27,0xff28,0xff29,0xff2a,0xff2b,0xff2c,0xff2d,0xff2e, 0xff2f,0xff30,0xff31,0xff32,0xff33,0xff34,0xff35,0xff36,0xff37,0xff38, 0xff39,0xff3a,0xff41,0xff42,0xff43,0xff44,0xff45,0xff46,0xff47,0xff48, 0xff49,0xff4a,0xff4b,0xff4c,0xff4d,0xff4e,0xff4f,0xff50,0xff51,0xff52, 0xff53,0xff54,0xff55,0xff56 } }, { /* ku 03 */ { 0xff57,0xff58,0xff59,0xff5a,0x0391,0x0392,0x0393,0x0394,0x0395,0x0396, 0x0397,0x0398,0x0399,0x039a,0x039b,0x039c,0x039d,0x039e,0x039f,0x03a0, 0x03a1,0x03a3,0x03a4,0x03a5,0x03a6,0x03a7,0x03a8,0x03a9,0x03b1,0x03b2, 0x03b3,0x03b4,0x03b5,0x03b6,0x03b7,0x03b8,0x03b9,0x03ba,0x03bb,0x03bc, 0x03bd,0x03be,0x03bf,0x03c0,0x03c1,0x03c3,0x03c4,0x03c5,0x03c6,0x03c7, 0x03c8,0x03c9,0x3105,0x3106,0x3107,0x3108,0x3109,0x310a,0x310b,0x310c, 0x310d,0x310e,0x310f },{ 0x3110,0x3111,0x3112,0x3113,0x3114,0x3115,0x3116,0x3117,0x3118,0x3119, 0x311a,0x311b,0x311c,0x311d,0x311e,0x311f,0x3120,0x3121,0x3122,0x3123, 0x3124,0x3125,0x3126,0x3127,0x3128,0x3129,0x02d9,0x02c9,0x02ca,0x02c7, 0x02cb,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON, UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON, UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON, UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON, UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON, UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON, UBOGON,UBOGON,UBOGON,UBOGON } }, { /* ku 04 */ { 0x4e00,0x4e59,0x4e01,0x4e03,0x4e43,0x4e5d,0x4e86,0x4e8c,0x4eba,0x513f, 0x5165,0x516b,0x51e0,0x5200,0x5201,0x529b,0x5315,0x5341,0x535c,0x53c8, 0x4e09,0x4e0b,0x4e08,0x4e0a,0x4e2b,0x4e38,0x51e1,0x4e45,0x4e48,0x4e5f, 0x4e5e,0x4e8e,0x4ea1,0x5140,0x5203,0x52fa,0x5343,0x53c9,0x53e3,0x571f, 0x58eb,0x5915,0x5927,0x5973,0x5b50,0x5b51,0x5b53,0x5bf8,0x5c0f,0x5c22, 0x5c38,0x5c71,0x5ddd,0x5de5,0x5df1,0x5df2,0x5df3,0x5dfe,0x5e72,0x5efe, 0x5f0b,0x5f13,0x624d },{ 0x4e11,0x4e10,0x4e0d,0x4e2d,0x4e30,0x4e39,0x4e4b,0x5c39,0x4e88,0x4e91, 0x4e95,0x4e92,0x4e94,0x4ea2,0x4ec1,0x4ec0,0x4ec3,0x4ec6,0x4ec7,0x4ecd, 0x4eca,0x4ecb,0x4ec4,0x5143,0x5141,0x5167,0x516d,0x516e,0x516c,0x5197, 0x51f6,0x5206,0x5207,0x5208,0x52fb,0x52fe,0x52ff,0x5316,0x5339,0x5348, 0x5347,0x5345,0x535e,0x5384,0x53cb,0x53ca,0x53cd,0x58ec,0x5929,0x592b, 0x592a,0x592d,0x5b54,0x5c11,0x5c24,0x5c3a,0x5c6f,0x5df4,0x5e7b,0x5eff, 0x5f14,0x5f15,0x5fc3,0x6208,0x6236,0x624b,0x624e,0x652f,0x6587,0x6597, 0x65a4,0x65b9,0x65e5,0x66f0,0x6708,0x6728,0x6b20,0x6b62,0x6b79,0x6bcb, 0x6bd4,0x6bdb,0x6c0f,0x6c34,0x706b,0x722a,0x7236,0x723b,0x7247,0x7259, 0x725b,0x72ac,0x738b,0x4e19 } }, { /* ku 05 */ { 0x4e16,0x4e15,0x4e14,0x4e18,0x4e3b,0x4e4d,0x4e4f,0x4e4e,0x4ee5,0x4ed8, 0x4ed4,0x4ed5,0x4ed6,0x4ed7,0x4ee3,0x4ee4,0x4ed9,0x4ede,0x5145,0x5144, 0x5189,0x518a,0x51ac,0x51f9,0x51fa,0x51f8,0x520a,0x52a0,0x529f,0x5305, 0x5306,0x5317,0x531d,0x4edf,0x534a,0x5349,0x5361,0x5360,0x536f,0x536e, 0x53bb,0x53ef,0x53e4,0x53f3,0x53ec,0x53ee,0x53e9,0x53e8,0x53fc,0x53f8, 0x53f5,0x53eb,0x53e6,0x53ea,0x53f2,0x53f1,0x53f0,0x53e5,0x53ed,0x53fb, 0x56db,0x56da,0x5916 },{ 0x592e,0x5931,0x5974,0x5976,0x5b55,0x5b83,0x5c3c,0x5de8,0x5de7,0x5de6, 0x5e02,0x5e03,0x5e73,0x5e7c,0x5f01,0x5f18,0x5f17,0x5fc5,0x620a,0x6253, 0x6254,0x6252,0x6251,0x65a5,0x65e6,0x672e,0x672c,0x672a,0x672b,0x672d, 0x6b63,0x6bcd,0x6c11,0x6c10,0x6c38,0x6c41,0x6c40,0x6c3e,0x72af,0x7384, 0x7389,0x74dc,0x74e6,0x7518,0x751f,0x7528,0x7529,0x7530,0x7531,0x7532, 0x7533,0x758b,0x767d,0x76ae,0x76bf,0x76ee,0x77db,0x77e2,0x77f3,0x793a, 0x79be,0x7a74,0x7acb,0x4e1e,0x4e1f,0x4e52,0x4e53,0x4e69,0x4e99,0x4ea4, 0x4ea6,0x4ea5,0x4eff,0x4f09,0x4f19,0x4f0a,0x4f15,0x4f0d,0x4f10,0x4f11, 0x4f0f,0x4ef2,0x4ef6,0x4efb,0x4ef0,0x4ef3,0x4efd,0x4f01,0x4f0b,0x5149, 0x5147,0x5146,0x5148,0x5168 } }, { /* ku 06 */ { 0x5171,0x518d,0x51b0,0x5217,0x5211,0x5212,0x520e,0x5216,0x52a3,0x5308, 0x5321,0x5320,0x5370,0x5371,0x5409,0x540f,0x540c,0x540a,0x5410,0x5401, 0x540b,0x5404,0x5411,0x540d,0x5408,0x5403,0x540e,0x5406,0x5412,0x56e0, 0x56de,0x56dd,0x5733,0x5730,0x5728,0x572d,0x572c,0x572f,0x5729,0x5919, 0x591a,0x5937,0x5938,0x5984,0x5978,0x5983,0x597d,0x5979,0x5982,0x5981, 0x5b57,0x5b58,0x5b87,0x5b88,0x5b85,0x5b89,0x5bfa,0x5c16,0x5c79,0x5dde, 0x5e06,0x5e76,0x5e74 },{ 0x5f0f,0x5f1b,0x5fd9,0x5fd6,0x620e,0x620c,0x620d,0x6210,0x6263,0x625b, 0x6258,0x6536,0x65e9,0x65e8,0x65ec,0x65ed,0x66f2,0x66f3,0x6709,0x673d, 0x6734,0x6731,0x6735,0x6b21,0x6b64,0x6b7b,0x6c16,0x6c5d,0x6c57,0x6c59, 0x6c5f,0x6c60,0x6c50,0x6c55,0x6c61,0x6c5b,0x6c4d,0x6c4e,0x7070,0x725f, 0x725d,0x767e,0x7af9,0x7c73,0x7cf8,0x7f36,0x7f8a,0x7fbd,0x8001,0x8003, 0x800c,0x8012,0x8033,0x807f,0x8089,0x808b,0x808c,0x81e3,0x81ea,0x81f3, 0x81fc,0x820c,0x821b,0x821f,0x826e,0x8272,0x827e,0x866b,0x8840,0x884c, 0x8863,0x897f,0x9621,0x4e32,0x4ea8,0x4f4d,0x4f4f,0x4f47,0x4f57,0x4f5e, 0x4f34,0x4f5b,0x4f55,0x4f30,0x4f50,0x4f51,0x4f3d,0x4f3a,0x4f38,0x4f43, 0x4f54,0x4f3c,0x4f46,0x4f63 } }, { /* ku 07 */ { 0x4f5c,0x4f60,0x4f2f,0x4f4e,0x4f36,0x4f59,0x4f5d,0x4f48,0x4f5a,0x514c, 0x514b,0x514d,0x5175,0x51b6,0x51b7,0x5225,0x5224,0x5229,0x522a,0x5228, 0x52ab,0x52a9,0x52aa,0x52ac,0x5323,0x5373,0x5375,0x541d,0x542d,0x541e, 0x543e,0x5426,0x544e,0x5427,0x5446,0x5443,0x5433,0x5448,0x5442,0x541b, 0x5429,0x544a,0x5439,0x543b,0x5438,0x542e,0x5435,0x5436,0x5420,0x543c, 0x5440,0x5431,0x542b,0x541f,0x542c,0x56ea,0x56f0,0x56e4,0x56eb,0x574a, 0x5751,0x5740,0x574d },{ 0x5747,0x574e,0x573e,0x5750,0x574f,0x573b,0x58ef,0x593e,0x599d,0x5992, 0x59a8,0x599e,0x59a3,0x5999,0x5996,0x598d,0x59a4,0x5993,0x598a,0x59a5, 0x5b5d,0x5b5c,0x5b5a,0x5b5b,0x5b8c,0x5b8b,0x5b8f,0x5c2c,0x5c40,0x5c41, 0x5c3f,0x5c3e,0x5c90,0x5c91,0x5c94,0x5c8c,0x5deb,0x5e0c,0x5e8f,0x5e87, 0x5e8a,0x5ef7,0x5f04,0x5f1f,0x5f64,0x5f62,0x5f77,0x5f79,0x5fd8,0x5fcc, 0x5fd7,0x5fcd,0x5ff1,0x5feb,0x5ff8,0x5fea,0x6212,0x6211,0x6284,0x6297, 0x6296,0x6280,0x6276,0x6289,0x626d,0x628a,0x627c,0x627e,0x6279,0x6273, 0x6292,0x626f,0x6298,0x626e,0x6295,0x6293,0x6291,0x6286,0x6539,0x653b, 0x6538,0x65f1,0x66f4,0x675f,0x674e,0x674f,0x6750,0x6751,0x675c,0x6756, 0x675e,0x6749,0x6746,0x6760 } }, { /* ku 08 */ { 0x6753,0x6757,0x6b65,0x6bcf,0x6c42,0x6c5e,0x6c99,0x6c81,0x6c88,0x6c89, 0x6c85,0x6c9b,0x6c6a,0x6c7a,0x6c90,0x6c70,0x6c8c,0x6c68,0x6c96,0x6c92, 0x6c7d,0x6c83,0x6c72,0x6c7e,0x6c74,0x6c86,0x6c76,0x6c8d,0x6c94,0x6c98, 0x6c82,0x7076,0x707c,0x707d,0x7078,0x7262,0x7261,0x7260,0x72c4,0x72c2, 0x7396,0x752c,0x752b,0x7537,0x7538,0x7682,0x76ef,0x77e3,0x79c1,0x79c0, 0x79bf,0x7a76,0x7cfb,0x7f55,0x8096,0x8093,0x809d,0x8098,0x809b,0x809a, 0x80b2,0x826f,0x8292 },{ 0x828b,0x828d,0x898b,0x89d2,0x8a00,0x8c37,0x8c46,0x8c55,0x8c9d,0x8d64, 0x8d70,0x8db3,0x8eab,0x8eca,0x8f9b,0x8fb0,0x8fc2,0x8fc6,0x8fc5,0x8fc4, 0x5de1,0x9091,0x90a2,0x90aa,0x90a6,0x90a3,0x9149,0x91c6,0x91cc,0x9632, 0x962e,0x9631,0x962a,0x962c,0x4e26,0x4e56,0x4e73,0x4e8b,0x4e9b,0x4e9e, 0x4eab,0x4eac,0x4f6f,0x4f9d,0x4f8d,0x4f73,0x4f7f,0x4f6c,0x4f9b,0x4f8b, 0x4f86,0x4f83,0x4f70,0x4f75,0x4f88,0x4f69,0x4f7b,0x4f96,0x4f7e,0x4f8f, 0x4f91,0x4f7a,0x5154,0x5152,0x5155,0x5169,0x5177,0x5176,0x5178,0x51bd, 0x51fd,0x523b,0x5238,0x5237,0x523a,0x5230,0x522e,0x5236,0x5241,0x52be, 0x52bb,0x5352,0x5354,0x5353,0x5351,0x5366,0x5377,0x5378,0x5379,0x53d6, 0x53d4,0x53d7,0x5473,0x5475 } }, { /* ku 09 */ { 0x5496,0x5478,0x5495,0x5480,0x547b,0x5477,0x5484,0x5492,0x5486,0x547c, 0x5490,0x5471,0x5476,0x548c,0x549a,0x5462,0x5468,0x548b,0x547d,0x548e, 0x56fa,0x5783,0x5777,0x576a,0x5769,0x5761,0x5766,0x5764,0x577c,0x591c, 0x5949,0x5947,0x5948,0x5944,0x5954,0x59be,0x59bb,0x59d4,0x59b9,0x59ae, 0x59d1,0x59c6,0x59d0,0x59cd,0x59cb,0x59d3,0x59ca,0x59af,0x59b3,0x59d2, 0x59c5,0x5b5f,0x5b64,0x5b63,0x5b97,0x5b9a,0x5b98,0x5b9c,0x5b99,0x5b9b, 0x5c1a,0x5c48,0x5c45 },{ 0x5c46,0x5cb7,0x5ca1,0x5cb8,0x5ca9,0x5cab,0x5cb1,0x5cb3,0x5e18,0x5e1a, 0x5e16,0x5e15,0x5e1b,0x5e11,0x5e78,0x5e9a,0x5e97,0x5e9c,0x5e95,0x5e96, 0x5ef6,0x5f26,0x5f27,0x5f29,0x5f80,0x5f81,0x5f7f,0x5f7c,0x5fdd,0x5fe0, 0x5ffd,0x5ff5,0x5fff,0x600f,0x6014,0x602f,0x6035,0x6016,0x602a,0x6015, 0x6021,0x6027,0x6029,0x602b,0x601b,0x6216,0x6215,0x623f,0x623e,0x6240, 0x627f,0x62c9,0x62cc,0x62c4,0x62bf,0x62c2,0x62b9,0x62d2,0x62db,0x62ab, 0x62d3,0x62d4,0x62cb,0x62c8,0x62a8,0x62bd,0x62bc,0x62d0,0x62d9,0x62c7, 0x62cd,0x62b5,0x62da,0x62b1,0x62d8,0x62d6,0x62d7,0x62c6,0x62ac,0x62ce, 0x653e,0x65a7,0x65bc,0x65fa,0x6614,0x6613,0x660c,0x6606,0x6602,0x660e, 0x6600,0x660f,0x6615,0x660a } }, { /* ku 0a */ { 0x6607,0x670d,0x670b,0x676d,0x678b,0x6795,0x6771,0x679c,0x6773,0x6777, 0x6787,0x679d,0x6797,0x676f,0x6770,0x677f,0x6789,0x677e,0x6790,0x6775, 0x679a,0x6793,0x677c,0x676a,0x6772,0x6b23,0x6b66,0x6b67,0x6b7f,0x6c13, 0x6c1b,0x6ce3,0x6ce8,0x6cf3,0x6cb1,0x6ccc,0x6ce5,0x6cb3,0x6cbd,0x6cbe, 0x6cbc,0x6ce2,0x6cab,0x6cd5,0x6cd3,0x6cb8,0x6cc4,0x6cb9,0x6cc1,0x6cae, 0x6cd7,0x6cc5,0x6cf1,0x6cbf,0x6cbb,0x6ce1,0x6cdb,0x6cca,0x6cac,0x6cef, 0x6cdc,0x6cd6,0x6ce0 },{ 0x7095,0x708e,0x7092,0x708a,0x7099,0x722c,0x722d,0x7238,0x7248,0x7267, 0x7269,0x72c0,0x72ce,0x72d9,0x72d7,0x72d0,0x73a9,0x73a8,0x739f,0x73ab, 0x73a5,0x753d,0x759d,0x7599,0x759a,0x7684,0x76c2,0x76f2,0x76f4,0x77e5, 0x77fd,0x793e,0x7940,0x7941,0x79c9,0x79c8,0x7a7a,0x7a79,0x7afa,0x7cfe, 0x7f54,0x7f8c,0x7f8b,0x8005,0x80ba,0x80a5,0x80a2,0x80b1,0x80a1,0x80ab, 0x80a9,0x80b4,0x80aa,0x80af,0x81e5,0x81fe,0x820d,0x82b3,0x829d,0x8299, 0x82ad,0x82bd,0x829f,0x82b9,0x82b1,0x82ac,0x82a5,0x82af,0x82b8,0x82a3, 0x82b0,0x82be,0x82b7,0x864e,0x8671,0x521d,0x8868,0x8ecb,0x8fce,0x8fd4, 0x8fd1,0x90b5,0x90b8,0x90b1,0x90b6,0x91c7,0x91d1,0x9577,0x9580,0x961c, 0x9640,0x963f,0x963b,0x9644 } }, { /* ku 0b */ { 0x9642,0x96b9,0x96e8,0x9752,0x975e,0x4e9f,0x4ead,0x4eae,0x4fe1,0x4fb5, 0x4faf,0x4fbf,0x4fe0,0x4fd1,0x4fcf,0x4fdd,0x4fc3,0x4fb6,0x4fd8,0x4fdf, 0x4fca,0x4fd7,0x4fae,0x4fd0,0x4fc4,0x4fc2,0x4fda,0x4fce,0x4fde,0x4fb7, 0x5157,0x5192,0x5191,0x51a0,0x524e,0x5243,0x524a,0x524d,0x524c,0x524b, 0x5247,0x52c7,0x52c9,0x52c3,0x52c1,0x530d,0x5357,0x537b,0x539a,0x53db, 0x54ac,0x54c0,0x54a8,0x54ce,0x54c9,0x54b8,0x54a6,0x54b3,0x54c7,0x54c2, 0x54bd,0x54aa,0x54c1 },{ 0x54c4,0x54c8,0x54af,0x54ab,0x54b1,0x54bb,0x54a9,0x54a7,0x54bf,0x56ff, 0x5782,0x578b,0x57a0,0x57a3,0x57a2,0x57ce,0x57ae,0x5793,0x5955,0x5951, 0x594f,0x594e,0x5950,0x59dc,0x59d8,0x59ff,0x59e3,0x59e8,0x5a03,0x59e5, 0x59ea,0x59da,0x59e6,0x5a01,0x59fb,0x5b69,0x5ba3,0x5ba6,0x5ba4,0x5ba2, 0x5ba5,0x5c01,0x5c4e,0x5c4f,0x5c4d,0x5c4b,0x5cd9,0x5cd2,0x5df7,0x5e1d, 0x5e25,0x5e1f,0x5e7d,0x5ea0,0x5ea6,0x5efa,0x5f08,0x5f2d,0x5f65,0x5f88, 0x5f85,0x5f8a,0x5f8b,0x5f87,0x5f8c,0x5f89,0x6012,0x601d,0x6020,0x6025, 0x600e,0x6028,0x604d,0x6070,0x6068,0x6062,0x6046,0x6043,0x606c,0x606b, 0x606a,0x6064,0x6241,0x62dc,0x6316,0x6309,0x62fc,0x62ed,0x6301,0x62ee, 0x62fd,0x6307,0x62f1,0x62f7 } }, { /* ku 0c */ { 0x62ef,0x62ec,0x62fe,0x62f4,0x6311,0x6302,0x653f,0x6545,0x65ab,0x65bd, 0x65e2,0x6625,0x662d,0x6620,0x6627,0x662f,0x661f,0x6628,0x6631,0x6624, 0x66f7,0x67ff,0x67d3,0x67f1,0x67d4,0x67d0,0x67ec,0x67b6,0x67af,0x67f5, 0x67e9,0x67ef,0x67c4,0x67d1,0x67b4,0x67da,0x67e5,0x67b8,0x67cf,0x67de, 0x67f3,0x67b0,0x67d9,0x67e2,0x67dd,0x67d2,0x6b6a,0x6b83,0x6b86,0x6bb5, 0x6bd2,0x6bd7,0x6c1f,0x6cc9,0x6d0b,0x6d32,0x6d2a,0x6d41,0x6d25,0x6d0c, 0x6d31,0x6d1e,0x6d17 },{ 0x6d3b,0x6d3d,0x6d3e,0x6d36,0x6d1b,0x6cf5,0x6d39,0x6d27,0x6d38,0x6d29, 0x6d2e,0x6d35,0x6d0e,0x6d2b,0x70ab,0x70ba,0x70b3,0x70ac,0x70af,0x70ad, 0x70b8,0x70ae,0x70a4,0x7230,0x7272,0x726f,0x7274,0x72e9,0x72e0,0x72e1, 0x73b7,0x73ca,0x73bb,0x73b2,0x73cd,0x73c0,0x73b3,0x751a,0x752d,0x754f, 0x754c,0x754e,0x754b,0x75ab,0x75a4,0x75a5,0x75a2,0x75a3,0x7678,0x7686, 0x7687,0x7688,0x76c8,0x76c6,0x76c3,0x76c5,0x7701,0x76f9,0x76f8,0x7709, 0x770b,0x76fe,0x76fc,0x7707,0x77dc,0x7802,0x7814,0x780c,0x780d,0x7946, 0x7949,0x7948,0x7947,0x79b9,0x79ba,0x79d1,0x79d2,0x79cb,0x7a7f,0x7a81, 0x7aff,0x7afd,0x7c7d,0x7d02,0x7d05,0x7d00,0x7d09,0x7d07,0x7d04,0x7d06, 0x7f38,0x7f8e,0x7fbf,0x8004 } }, { /* ku 0d */ { 0x8010,0x800d,0x8011,0x8036,0x80d6,0x80e5,0x80da,0x80c3,0x80c4,0x80cc, 0x80e1,0x80db,0x80ce,0x80de,0x80e4,0x80dd,0x81f4,0x8222,0x82e7,0x8303, 0x8305,0x82e3,0x82db,0x82e6,0x8304,0x82e5,0x8302,0x8309,0x82d2,0x82d7, 0x82f1,0x8301,0x82dc,0x82d4,0x82d1,0x82de,0x82d3,0x82df,0x82ef,0x8306, 0x8650,0x8679,0x867b,0x867a,0x884d,0x886b,0x8981,0x89d4,0x8a08,0x8a02, 0x8a03,0x8c9e,0x8ca0,0x8d74,0x8d73,0x8db4,0x8ecd,0x8ecc,0x8ff0,0x8fe6, 0x8fe2,0x8fea,0x8fe5 },{ 0x8fed,0x8feb,0x8fe4,0x8fe8,0x90ca,0x90ce,0x90c1,0x90c3,0x914b,0x914a, 0x91cd,0x9582,0x9650,0x964b,0x964c,0x964d,0x9762,0x9769,0x97cb,0x97ed, 0x97f3,0x9801,0x98a8,0x98db,0x98df,0x9996,0x9999,0x4e58,0x4eb3,0x500c, 0x500d,0x5023,0x4fef,0x5026,0x5025,0x4ff8,0x5029,0x5016,0x5006,0x503c, 0x501f,0x501a,0x5012,0x5011,0x4ffa,0x5000,0x5014,0x5028,0x4ff1,0x5021, 0x500b,0x5019,0x5018,0x4ff3,0x4fee,0x502d,0x502a,0x4ffe,0x502b,0x5009, 0x517c,0x51a4,0x51a5,0x51a2,0x51cd,0x51cc,0x51c6,0x51cb,0x5256,0x525c, 0x5254,0x525b,0x525d,0x532a,0x537f,0x539f,0x539d,0x53df,0x54e8,0x5510, 0x5501,0x5537,0x54fc,0x54e5,0x54f2,0x5506,0x54fa,0x5514,0x54e9,0x54ed, 0x54e1,0x5509,0x54ee,0x54ea } }, { /* ku 0e */ { 0x54e6,0x5527,0x5507,0x54fd,0x550f,0x5703,0x5704,0x57c2,0x57d4,0x57cb, 0x57c3,0x5809,0x590f,0x5957,0x5958,0x595a,0x5a11,0x5a18,0x5a1c,0x5a1f, 0x5a1b,0x5a13,0x59ec,0x5a20,0x5a23,0x5a29,0x5a25,0x5a0c,0x5a09,0x5b6b, 0x5c58,0x5bb0,0x5bb3,0x5bb6,0x5bb4,0x5bae,0x5bb5,0x5bb9,0x5bb8,0x5c04, 0x5c51,0x5c55,0x5c50,0x5ced,0x5cfd,0x5cfb,0x5cea,0x5ce8,0x5cf0,0x5cf6, 0x5d01,0x5cf4,0x5dee,0x5e2d,0x5e2b,0x5eab,0x5ead,0x5ea7,0x5f31,0x5f92, 0x5f91,0x5f90,0x6059 },{ 0x6063,0x6065,0x6050,0x6055,0x606d,0x6069,0x606f,0x6084,0x609f,0x609a, 0x608d,0x6094,0x608c,0x6085,0x6096,0x6247,0x62f3,0x6308,0x62ff,0x634e, 0x633e,0x632f,0x6355,0x6342,0x6346,0x634f,0x6349,0x633a,0x6350,0x633d, 0x632a,0x632b,0x6328,0x634d,0x634c,0x6548,0x6549,0x6599,0x65c1,0x65c5, 0x6642,0x6649,0x664f,0x6643,0x6652,0x664c,0x6645,0x6641,0x66f8,0x6714, 0x6715,0x6717,0x6821,0x6838,0x6848,0x6846,0x6853,0x6839,0x6842,0x6854, 0x6829,0x68b3,0x6817,0x684c,0x6851,0x683d,0x67f4,0x6850,0x6840,0x683c, 0x6843,0x682a,0x6845,0x6813,0x6818,0x6841,0x6b8a,0x6b89,0x6bb7,0x6c23, 0x6c27,0x6c28,0x6c26,0x6c24,0x6cf0,0x6d6a,0x6d95,0x6d88,0x6d87,0x6d66, 0x6d78,0x6d77,0x6d59,0x6d93 } }, { /* ku 0f */ { 0x6d6c,0x6d89,0x6d6e,0x6d5a,0x6d74,0x6d69,0x6d8c,0x6d8a,0x6d79,0x6d85, 0x6d65,0x6d94,0x70ca,0x70d8,0x70e4,0x70d9,0x70c8,0x70cf,0x7239,0x7279, 0x72fc,0x72f9,0x72fd,0x72f8,0x72f7,0x7386,0x73ed,0x7409,0x73ee,0x73e0, 0x73ea,0x73de,0x7554,0x755d,0x755c,0x755a,0x7559,0x75be,0x75c5,0x75c7, 0x75b2,0x75b3,0x75bd,0x75bc,0x75b9,0x75c2,0x75b8,0x768b,0x76b0,0x76ca, 0x76cd,0x76ce,0x7729,0x771f,0x7720,0x7728,0x77e9,0x7830,0x7827,0x7838, 0x781d,0x7834,0x7837 },{ 0x7825,0x782d,0x7820,0x781f,0x7832,0x7955,0x7950,0x7960,0x795f,0x7956, 0x795e,0x795d,0x7957,0x795a,0x79e4,0x79e3,0x79e7,0x79df,0x79e6,0x79e9, 0x79d8,0x7a84,0x7a88,0x7ad9,0x7b06,0x7b11,0x7c89,0x7d21,0x7d17,0x7d0b, 0x7d0a,0x7d20,0x7d22,0x7d14,0x7d10,0x7d15,0x7d1a,0x7d1c,0x7d0d,0x7d19, 0x7d1b,0x7f3a,0x7f5f,0x7f94,0x7fc5,0x7fc1,0x8006,0x8018,0x8015,0x8019, 0x8017,0x803d,0x803f,0x80f1,0x8102,0x80f0,0x8105,0x80ed,0x80f4,0x8106, 0x80f8,0x80f3,0x8108,0x80fd,0x810a,0x80fc,0x80ef,0x81ed,0x81ec,0x8200, 0x8210,0x822a,0x822b,0x8228,0x822c,0x82bb,0x832b,0x8352,0x8354,0x834a, 0x8338,0x8350,0x8349,0x8335,0x8334,0x834f,0x8332,0x8339,0x8336,0x8317, 0x8340,0x8331,0x8328,0x8343 } }, { /* ku 10 */ { 0x8654,0x868a,0x86aa,0x8693,0x86a4,0x86a9,0x868c,0x86a3,0x869c,0x8870, 0x8877,0x8881,0x8882,0x887d,0x8879,0x8a18,0x8a10,0x8a0e,0x8a0c,0x8a15, 0x8a0a,0x8a17,0x8a13,0x8a16,0x8a0f,0x8a11,0x8c48,0x8c7a,0x8c79,0x8ca1, 0x8ca2,0x8d77,0x8eac,0x8ed2,0x8ed4,0x8ecf,0x8fb1,0x9001,0x9006,0x8ff7, 0x9000,0x8ffa,0x8ff4,0x9003,0x8ffd,0x9005,0x8ff8,0x9095,0x90e1,0x90dd, 0x90e2,0x9152,0x914d,0x914c,0x91d8,0x91dd,0x91d7,0x91dc,0x91d9,0x9583, 0x9662,0x9663,0x9661 },{ 0x965b,0x965d,0x9664,0x9658,0x965e,0x96bb,0x98e2,0x99ac,0x9aa8,0x9ad8, 0x9b25,0x9b32,0x9b3c,0x4e7e,0x507a,0x507d,0x505c,0x5047,0x5043,0x504c, 0x505a,0x5049,0x5065,0x5076,0x504e,0x5055,0x5075,0x5074,0x5077,0x504f, 0x500f,0x506f,0x506d,0x515c,0x5195,0x51f0,0x526a,0x526f,0x52d2,0x52d9, 0x52d8,0x52d5,0x5310,0x530f,0x5319,0x533f,0x5340,0x533e,0x53c3,0x66fc, 0x5546,0x556a,0x5566,0x5544,0x555e,0x5561,0x5543,0x554a,0x5531,0x5556, 0x554f,0x5555,0x552f,0x5564,0x5538,0x552e,0x555c,0x552c,0x5563,0x5533, 0x5541,0x5557,0x5708,0x570b,0x5709,0x57df,0x5805,0x580a,0x5806,0x57e0, 0x57e4,0x57fa,0x5802,0x5835,0x57f7,0x57f9,0x5920,0x5962,0x5a36,0x5a41, 0x5a49,0x5a66,0x5a6a,0x5a40 } }, { /* ku 11 */ { 0x5a3c,0x5a62,0x5a5a,0x5a46,0x5a4a,0x5b70,0x5bc7,0x5bc5,0x5bc4,0x5bc2, 0x5bbf,0x5bc6,0x5c09,0x5c08,0x5c07,0x5c60,0x5c5c,0x5c5d,0x5d07,0x5d06, 0x5d0e,0x5d1b,0x5d16,0x5d22,0x5d11,0x5d29,0x5d14,0x5d19,0x5d24,0x5d27, 0x5d17,0x5de2,0x5e38,0x5e36,0x5e33,0x5e37,0x5eb7,0x5eb8,0x5eb6,0x5eb5, 0x5ebe,0x5f35,0x5f37,0x5f57,0x5f6c,0x5f69,0x5f6b,0x5f97,0x5f99,0x5f9e, 0x5f98,0x5fa1,0x5fa0,0x5f9c,0x607f,0x60a3,0x6089,0x60a0,0x60a8,0x60cb, 0x60b4,0x60e6,0x60bd },{ 0x60c5,0x60bb,0x60b5,0x60dc,0x60bc,0x60d8,0x60d5,0x60c6,0x60df,0x60b8, 0x60da,0x60c7,0x621a,0x621b,0x6248,0x63a0,0x63a7,0x6372,0x6396,0x63a2, 0x63a5,0x6377,0x6367,0x6398,0x63aa,0x6371,0x63a9,0x6389,0x6383,0x639b, 0x636b,0x63a8,0x6384,0x6388,0x6399,0x63a1,0x63ac,0x6392,0x638f,0x6380, 0x637b,0x6369,0x6368,0x637a,0x655d,0x6556,0x6551,0x6559,0x6557,0x555f, 0x654f,0x6558,0x6555,0x6554,0x659c,0x659b,0x65ac,0x65cf,0x65cb,0x65cc, 0x65ce,0x665d,0x665a,0x6664,0x6668,0x6666,0x665e,0x66f9,0x52d7,0x671b, 0x6881,0x68af,0x68a2,0x6893,0x68b5,0x687f,0x6876,0x68b1,0x68a7,0x6897, 0x68b0,0x6883,0x68c4,0x68ad,0x6886,0x6885,0x6894,0x689d,0x68a8,0x689f, 0x68a1,0x6882,0x6b32,0x6bba } }, { /* ku 12 */ { 0x6beb,0x6bec,0x6c2b,0x6d8e,0x6dbc,0x6df3,0x6dd9,0x6db2,0x6de1,0x6dcc, 0x6de4,0x6dfb,0x6dfa,0x6e05,0x6dc7,0x6dcb,0x6daf,0x6dd1,0x6dae,0x6dde, 0x6df9,0x6db8,0x6df7,0x6df5,0x6dc5,0x6dd2,0x6e1a,0x6db5,0x6dda,0x6deb, 0x6dd8,0x6dea,0x6df1,0x6dee,0x6de8,0x6dc6,0x6dc4,0x6daa,0x6dec,0x6dbf, 0x6de6,0x70f9,0x7109,0x710a,0x70fd,0x70ef,0x723d,0x727d,0x7281,0x731c, 0x731b,0x7316,0x7313,0x7319,0x7387,0x7405,0x740a,0x7403,0x7406,0x73fe, 0x740d,0x74e0,0x74f6 },{ 0x74f7,0x751c,0x7522,0x7565,0x7566,0x7562,0x7570,0x758f,0x75d4,0x75d5, 0x75b5,0x75ca,0x75cd,0x768e,0x76d4,0x76d2,0x76db,0x7737,0x773e,0x773c, 0x7736,0x7738,0x773a,0x786b,0x7843,0x784e,0x7965,0x7968,0x796d,0x79fb, 0x7a92,0x7a95,0x7b20,0x7b28,0x7b1b,0x7b2c,0x7b26,0x7b19,0x7b1e,0x7b2e, 0x7c92,0x7c97,0x7c95,0x7d46,0x7d43,0x7d71,0x7d2e,0x7d39,0x7d3c,0x7d40, 0x7d30,0x7d33,0x7d44,0x7d2f,0x7d42,0x7d32,0x7d31,0x7f3d,0x7f9e,0x7f9a, 0x7fcc,0x7fce,0x7fd2,0x801c,0x804a,0x8046,0x812f,0x8116,0x8123,0x812b, 0x8129,0x8130,0x8124,0x8202,0x8235,0x8237,0x8236,0x8239,0x838e,0x839e, 0x8398,0x8378,0x83a2,0x8396,0x83bd,0x83ab,0x8392,0x838a,0x8393,0x8389, 0x83a0,0x8377,0x837b,0x837c } }, { /* ku 13 */ { 0x8386,0x83a7,0x8655,0x5f6a,0x86c7,0x86c0,0x86b6,0x86c4,0x86b5,0x86c6, 0x86cb,0x86b1,0x86af,0x86c9,0x8853,0x889e,0x8888,0x88ab,0x8892,0x8896, 0x888d,0x888b,0x8993,0x898f,0x8a2a,0x8a1d,0x8a23,0x8a25,0x8a31,0x8a2d, 0x8a1f,0x8a1b,0x8a22,0x8c49,0x8c5a,0x8ca9,0x8cac,0x8cab,0x8ca8,0x8caa, 0x8ca7,0x8d67,0x8d66,0x8dbe,0x8dba,0x8edb,0x8edf,0x9019,0x900d,0x901a, 0x9017,0x9023,0x901f,0x901d,0x9010,0x9015,0x901e,0x9020,0x900f,0x9022, 0x9016,0x901b,0x9014 },{ 0x90e8,0x90ed,0x90fd,0x9157,0x91ce,0x91f5,0x91e6,0x91e3,0x91e7,0x91ed, 0x91e9,0x9589,0x966a,0x9675,0x9673,0x9678,0x9670,0x9674,0x9676,0x9677, 0x966c,0x96c0,0x96ea,0x96e9,0x7ae0,0x7adf,0x9802,0x9803,0x9b5a,0x9ce5, 0x9e75,0x9e7f,0x9ea5,0x9ebb,0x50a2,0x508d,0x5085,0x5099,0x5091,0x5080, 0x5096,0x5098,0x509a,0x6700,0x51f1,0x5272,0x5274,0x5275,0x5269,0x52de, 0x52dd,0x52db,0x535a,0x53a5,0x557b,0x5580,0x55a7,0x557c,0x558a,0x559d, 0x5598,0x5582,0x559c,0x55aa,0x5594,0x5587,0x558b,0x5583,0x55b3,0x55ae, 0x559f,0x553e,0x55b2,0x559a,0x55bb,0x55ac,0x55b1,0x557e,0x5589,0x55ab, 0x5599,0x570d,0x582f,0x582a,0x5834,0x5824,0x5830,0x5831,0x5821,0x581d, 0x5820,0x58f9,0x58fa,0x5960 } }, { /* ku 14 */ { 0x5a77,0x5a9a,0x5a7f,0x5a92,0x5a9b,0x5aa7,0x5b73,0x5b71,0x5bd2,0x5bcc, 0x5bd3,0x5bd0,0x5c0a,0x5c0b,0x5c31,0x5d4c,0x5d50,0x5d34,0x5d47,0x5dfd, 0x5e45,0x5e3d,0x5e40,0x5e43,0x5e7e,0x5eca,0x5ec1,0x5ec2,0x5ec4,0x5f3c, 0x5f6d,0x5fa9,0x5faa,0x5fa8,0x60d1,0x60e1,0x60b2,0x60b6,0x60e0,0x611c, 0x6123,0x60fa,0x6115,0x60f0,0x60fb,0x60f4,0x6168,0x60f1,0x610e,0x60f6, 0x6109,0x6100,0x6112,0x621f,0x6249,0x63a3,0x638c,0x63cf,0x63c0,0x63e9, 0x63c9,0x63c6,0x63cd },{ 0x63d2,0x63e3,0x63d0,0x63e1,0x63d6,0x63ed,0x63ee,0x6376,0x63f4,0x63ea, 0x63db,0x6452,0x63da,0x63f9,0x655e,0x6566,0x6562,0x6563,0x6591,0x6590, 0x65af,0x666e,0x6670,0x6674,0x6676,0x666f,0x6691,0x667a,0x667e,0x6677, 0x66fe,0x66ff,0x671f,0x671d,0x68fa,0x68d5,0x68e0,0x68d8,0x68d7,0x6905, 0x68df,0x68f5,0x68ee,0x68e7,0x68f9,0x68d2,0x68f2,0x68e3,0x68cb,0x68cd, 0x690d,0x6912,0x690e,0x68c9,0x68da,0x696e,0x68fb,0x6b3e,0x6b3a,0x6b3d, 0x6b98,0x6b96,0x6bbc,0x6bef,0x6c2e,0x6c2f,0x6c2c,0x6e2f,0x6e38,0x6e54, 0x6e21,0x6e32,0x6e67,0x6e4a,0x6e20,0x6e25,0x6e23,0x6e1b,0x6e5b,0x6e58, 0x6e24,0x6e56,0x6e6e,0x6e2d,0x6e26,0x6e6f,0x6e34,0x6e4d,0x6e3a,0x6e2c, 0x6e43,0x6e1d,0x6e3e,0x6ecb } }, { /* ku 15 */ { 0x6e89,0x6e19,0x6e4e,0x6e63,0x6e44,0x6e72,0x6e69,0x6e5f,0x7119,0x711a, 0x7126,0x7130,0x7121,0x7136,0x716e,0x711c,0x724c,0x7284,0x7280,0x7336, 0x7325,0x7334,0x7329,0x743a,0x742a,0x7433,0x7422,0x7425,0x7435,0x7436, 0x7434,0x742f,0x741b,0x7426,0x7428,0x7525,0x7526,0x756b,0x756a,0x75e2, 0x75db,0x75e3,0x75d9,0x75d8,0x75de,0x75e0,0x767b,0x767c,0x7696,0x7693, 0x76b4,0x76dc,0x774f,0x77ed,0x785d,0x786c,0x786f,0x7a0d,0x7a08,0x7a0b, 0x7a05,0x7a00,0x7a98 },{ 0x7a97,0x7a96,0x7ae5,0x7ae3,0x7b49,0x7b56,0x7b46,0x7b50,0x7b52,0x7b54, 0x7b4d,0x7b4b,0x7b4f,0x7b51,0x7c9f,0x7ca5,0x7d5e,0x7d50,0x7d68,0x7d55, 0x7d2b,0x7d6e,0x7d72,0x7d61,0x7d66,0x7d62,0x7d70,0x7d73,0x5584,0x7fd4, 0x7fd5,0x800b,0x8052,0x8085,0x8155,0x8154,0x814b,0x8151,0x814e,0x8139, 0x8146,0x813e,0x814c,0x8153,0x8174,0x8212,0x821c,0x83e9,0x8403,0x83f8, 0x840d,0x83e0,0x83c5,0x840b,0x83c1,0x83ef,0x83f1,0x83f4,0x8457,0x840a, 0x83f0,0x840c,0x83cc,0x83fd,0x83f2,0x83ca,0x8438,0x840e,0x8404,0x83dc, 0x8407,0x83d4,0x83df,0x865b,0x86df,0x86d9,0x86ed,0x86d4,0x86db,0x86e4, 0x86d0,0x86de,0x8857,0x88c1,0x88c2,0x88b1,0x8983,0x8996,0x8a3b,0x8a60, 0x8a55,0x8a5e,0x8a3c,0x8a41 } }, { /* ku 16 */ { 0x8a54,0x8a5b,0x8a50,0x8a46,0x8a34,0x8a3a,0x8a36,0x8a56,0x8c61,0x8c82, 0x8caf,0x8cbc,0x8cb3,0x8cbd,0x8cc1,0x8cbb,0x8cc0,0x8cb4,0x8cb7,0x8cb6, 0x8cbf,0x8cb8,0x8d8a,0x8d85,0x8d81,0x8dce,0x8ddd,0x8dcb,0x8dda,0x8dd1, 0x8dcc,0x8ddb,0x8dc6,0x8efb,0x8ef8,0x8efc,0x8f9c,0x902e,0x9035,0x9031, 0x9038,0x9032,0x9036,0x9102,0x90f5,0x9109,0x90fe,0x9163,0x9165,0x91cf, 0x9214,0x9215,0x9223,0x9209,0x921e,0x920d,0x9210,0x9207,0x9211,0x9594, 0x958f,0x958b,0x9591 },{ 0x9593,0x9592,0x958e,0x968a,0x968e,0x968b,0x967d,0x9685,0x9686,0x968d, 0x9672,0x9684,0x96c1,0x96c5,0x96c4,0x96c6,0x96c7,0x96ef,0x96f2,0x97cc, 0x9805,0x9806,0x9808,0x98e7,0x98ea,0x98ef,0x98e9,0x98f2,0x98ed,0x99ae, 0x99ad,0x9ec3,0x9ecd,0x9ed1,0x4e82,0x50ad,0x50b5,0x50b2,0x50b3,0x50c5, 0x50be,0x50ac,0x50b7,0x50bb,0x50af,0x50c7,0x527f,0x5277,0x527d,0x52df, 0x52e6,0x52e4,0x52e2,0x52e3,0x532f,0x55df,0x55e8,0x55d3,0x55e6,0x55ce, 0x55dc,0x55c7,0x55d1,0x55e3,0x55e4,0x55ef,0x55da,0x55e1,0x55c5,0x55c6, 0x55e5,0x55c9,0x5712,0x5713,0x585e,0x5851,0x5858,0x5857,0x585a,0x5854, 0x586b,0x584c,0x586d,0x584a,0x5862,0x5852,0x584b,0x5967,0x5ac1,0x5ac9, 0x5acc,0x5abe,0x5abd,0x5abc } }, { /* ku 17 */ { 0x5ab3,0x5ac2,0x5ab2,0x5d69,0x5d6f,0x5e4c,0x5e79,0x5ec9,0x5ec8,0x5f12, 0x5f59,0x5fac,0x5fae,0x611a,0x610f,0x6148,0x611f,0x60f3,0x611b,0x60f9, 0x6101,0x6108,0x614e,0x614c,0x6144,0x614d,0x613e,0x6134,0x6127,0x610d, 0x6106,0x6137,0x6221,0x6222,0x6413,0x643e,0x641e,0x642a,0x642d,0x643d, 0x642c,0x640f,0x641c,0x6414,0x640d,0x6436,0x6416,0x6417,0x6406,0x656c, 0x659f,0x65b0,0x6697,0x6689,0x6687,0x6688,0x6696,0x6684,0x6698,0x668d, 0x6703,0x6994,0x696d },{ 0x695a,0x6977,0x6960,0x6954,0x6975,0x6930,0x6982,0x694a,0x6968,0x696b, 0x695e,0x6953,0x6979,0x6986,0x695d,0x6963,0x695b,0x6b47,0x6b72,0x6bc0, 0x6bbf,0x6bd3,0x6bfd,0x6ea2,0x6eaf,0x6ed3,0x6eb6,0x6ec2,0x6e90,0x6e9d, 0x6ec7,0x6ec5,0x6ea5,0x6e98,0x6ebc,0x6eba,0x6eab,0x6ed1,0x6e96,0x6e9c, 0x6ec4,0x6ed4,0x6eaa,0x6ea7,0x6eb4,0x714e,0x7159,0x7169,0x7164,0x7149, 0x7167,0x715c,0x716c,0x7166,0x714c,0x7165,0x715e,0x7146,0x7168,0x7156, 0x723a,0x7252,0x7337,0x7345,0x733f,0x733e,0x746f,0x745a,0x7455,0x745f, 0x745e,0x7441,0x743f,0x7459,0x745b,0x745c,0x7576,0x7578,0x7600,0x75f0, 0x7601,0x75f2,0x75f1,0x75fa,0x75ff,0x75f4,0x75f3,0x76de,0x76df,0x775b, 0x776b,0x7766,0x775e,0x7763 } }, { /* ku 18 */ { 0x7779,0x776a,0x776c,0x775c,0x7765,0x7768,0x7762,0x77ee,0x788e,0x78b0, 0x7897,0x7898,0x788c,0x7889,0x787c,0x7891,0x7893,0x787f,0x797a,0x797f, 0x7981,0x842c,0x79bd,0x7a1c,0x7a1a,0x7a20,0x7a14,0x7a1f,0x7a1e,0x7a9f, 0x7aa0,0x7b77,0x7bc0,0x7b60,0x7b6e,0x7b67,0x7cb1,0x7cb3,0x7cb5,0x7d93, 0x7d79,0x7d91,0x7d81,0x7d8f,0x7d5b,0x7f6e,0x7f69,0x7f6a,0x7f72,0x7fa9, 0x7fa8,0x7fa4,0x8056,0x8058,0x8086,0x8084,0x8171,0x8170,0x8178,0x8165, 0x816e,0x8173,0x816b },{ 0x8179,0x817a,0x8166,0x8205,0x8247,0x8482,0x8477,0x843d,0x8431,0x8475, 0x8466,0x846b,0x8449,0x846c,0x845b,0x843c,0x8435,0x8461,0x8463,0x8469, 0x846d,0x8446,0x865e,0x865c,0x865f,0x86f9,0x8713,0x8708,0x8707,0x8700, 0x86fe,0x86fb,0x8702,0x8703,0x8706,0x870a,0x8859,0x88df,0x88d4,0x88d9, 0x88dc,0x88d8,0x88dd,0x88e1,0x88ca,0x88d5,0x88d2,0x899c,0x89e3,0x8a6b, 0x8a72,0x8a73,0x8a66,0x8a69,0x8a70,0x8a87,0x8a7c,0x8a63,0x8aa0,0x8a71, 0x8a85,0x8a6d,0x8a62,0x8a6e,0x8a6c,0x8a79,0x8a7b,0x8a3e,0x8a68,0x8c62, 0x8c8a,0x8c89,0x8cca,0x8cc7,0x8cc8,0x8cc4,0x8cb2,0x8cc3,0x8cc2,0x8cc5, 0x8de1,0x8ddf,0x8de8,0x8def,0x8df3,0x8dfa,0x8dea,0x8de4,0x8de6,0x8eb2, 0x8f03,0x8f09,0x8efe,0x8f0a } }, { /* ku 19 */ { 0x8f9f,0x8fb2,0x904b,0x904a,0x9053,0x9042,0x9054,0x903c,0x9055,0x9050, 0x9047,0x904f,0x904e,0x904d,0x9051,0x903e,0x9041,0x9112,0x9117,0x916c, 0x916a,0x9169,0x91c9,0x9237,0x9257,0x9238,0x923d,0x9240,0x923e,0x925b, 0x924b,0x9264,0x9251,0x9234,0x9249,0x924d,0x9245,0x9239,0x923f,0x925a, 0x9598,0x9698,0x9694,0x9695,0x96cd,0x96cb,0x96c9,0x96ca,0x96f7,0x96fb, 0x96f9,0x96f6,0x9756,0x9774,0x9776,0x9810,0x9811,0x9813,0x980a,0x9812, 0x980c,0x98fc,0x98f4 },{ 0x98fd,0x98fe,0x99b3,0x99b1,0x99b4,0x9ae1,0x9ce9,0x9e82,0x9f0e,0x9f13, 0x9f20,0x50e7,0x50ee,0x50e5,0x50d6,0x50ed,0x50da,0x50d5,0x50cf,0x50d1, 0x50f1,0x50ce,0x50e9,0x5162,0x51f3,0x5283,0x5282,0x5331,0x53ad,0x55fe, 0x5600,0x561b,0x5617,0x55fd,0x5614,0x5606,0x5609,0x560d,0x560e,0x55f7, 0x5616,0x561f,0x5608,0x5610,0x55f6,0x5718,0x5716,0x5875,0x587e,0x5883, 0x5893,0x588a,0x5879,0x5885,0x587d,0x58fd,0x5925,0x5922,0x5924,0x596a, 0x5969,0x5ae1,0x5ae6,0x5ae9,0x5ad7,0x5ad6,0x5ad8,0x5ae3,0x5b75,0x5bde, 0x5be7,0x5be1,0x5be5,0x5be6,0x5be8,0x5be2,0x5be4,0x5bdf,0x5c0d,0x5c62, 0x5d84,0x5d87,0x5e5b,0x5e63,0x5e55,0x5e57,0x5e54,0x5ed3,0x5ed6,0x5f0a, 0x5f46,0x5f70,0x5fb9,0x6147 } }, { /* ku 1a */ { 0x613f,0x614b,0x6177,0x6162,0x6163,0x615f,0x615a,0x6158,0x6175,0x622a, 0x6487,0x6458,0x6454,0x64a4,0x6478,0x645f,0x647a,0x6451,0x6467,0x6434, 0x646d,0x647b,0x6572,0x65a1,0x65d7,0x65d6,0x66a2,0x66a8,0x669d,0x699c, 0x69a8,0x6995,0x69c1,0x69ae,0x69d3,0x69cb,0x699b,0x69b7,0x69bb,0x69ab, 0x69b4,0x69d0,0x69cd,0x69ad,0x69cc,0x69a6,0x69c3,0x69a3,0x6b49,0x6b4c, 0x6c33,0x6f33,0x6f14,0x6efe,0x6f13,0x6ef4,0x6f29,0x6f3e,0x6f20,0x6f2c, 0x6f0f,0x6f02,0x6f22 },{ 0x6eff,0x6eef,0x6f06,0x6f31,0x6f38,0x6f32,0x6f23,0x6f15,0x6f2b,0x6f2f, 0x6f88,0x6f2a,0x6eec,0x6f01,0x6ef2,0x6ecc,0x6ef7,0x7194,0x7199,0x717d, 0x718a,0x7184,0x7192,0x723e,0x7292,0x7296,0x7344,0x7350,0x7464,0x7463, 0x746a,0x7470,0x746d,0x7504,0x7591,0x7627,0x760d,0x760b,0x7609,0x7613, 0x76e1,0x76e3,0x7784,0x777d,0x777f,0x7761,0x78c1,0x789f,0x78a7,0x78b3, 0x78a9,0x78a3,0x798e,0x798f,0x798d,0x7a2e,0x7a31,0x7aaa,0x7aa9,0x7aed, 0x7aef,0x7ba1,0x7b95,0x7b8b,0x7b75,0x7b97,0x7b9d,0x7b94,0x7b8f,0x7bb8, 0x7b87,0x7b84,0x7cb9,0x7cbd,0x7cbe,0x7dbb,0x7db0,0x7d9c,0x7dbd,0x7dbe, 0x7da0,0x7dca,0x7db4,0x7db2,0x7db1,0x7dba,0x7da2,0x7dbf,0x7db5,0x7db8, 0x7dad,0x7dd2,0x7dc7,0x7dac } }, { /* ku 1b */ { 0x7f70,0x7fe0,0x7fe1,0x7fdf,0x805e,0x805a,0x8087,0x8150,0x8180,0x818f, 0x8188,0x818a,0x817f,0x8182,0x81e7,0x81fa,0x8207,0x8214,0x821e,0x824b, 0x84c9,0x84bf,0x84c6,0x84c4,0x8499,0x849e,0x84b2,0x849c,0x84cb,0x84b8, 0x84c0,0x84d3,0x8490,0x84bc,0x84d1,0x84ca,0x873f,0x871c,0x873b,0x8722, 0x8725,0x8734,0x8718,0x8755,0x8737,0x8729,0x88f3,0x8902,0x88f4,0x88f9, 0x88f8,0x88fd,0x88e8,0x891a,0x88ef,0x8aa6,0x8a8c,0x8a9e,0x8aa3,0x8a8d, 0x8aa1,0x8a93,0x8aa4 },{ 0x8aaa,0x8aa5,0x8aa8,0x8a98,0x8a91,0x8a9a,0x8aa7,0x8c6a,0x8c8d,0x8c8c, 0x8cd3,0x8cd1,0x8cd2,0x8d6b,0x8d99,0x8d95,0x8dfc,0x8f14,0x8f12,0x8f15, 0x8f13,0x8fa3,0x9060,0x9058,0x905c,0x9063,0x9059,0x905e,0x9062,0x905d, 0x905b,0x9119,0x9118,0x911e,0x9175,0x9178,0x9177,0x9174,0x9278,0x9280, 0x9285,0x9298,0x9296,0x927b,0x9293,0x929c,0x92a8,0x927c,0x9291,0x95a1, 0x95a8,0x95a9,0x95a3,0x95a5,0x95a4,0x9699,0x969c,0x969b,0x96cc,0x96d2, 0x9700,0x977c,0x9785,0x97f6,0x9817,0x9818,0x98af,0x98b1,0x9903,0x9905, 0x990c,0x9909,0x99c1,0x9aaf,0x9ab0,0x9ae6,0x9b41,0x9b42,0x9cf4,0x9cf6, 0x9cf3,0x9ebc,0x9f3b,0x9f4a,0x5104,0x5100,0x50fb,0x50f5,0x50f9,0x5102, 0x5108,0x5109,0x5105,0x51dc } }, { /* ku 1c */ { 0x5287,0x5288,0x5289,0x528d,0x528a,0x52f0,0x53b2,0x562e,0x563b,0x5639, 0x5632,0x563f,0x5634,0x5629,0x5653,0x564e,0x5657,0x5674,0x5636,0x562f, 0x5630,0x5880,0x589f,0x589e,0x58b3,0x589c,0x58ae,0x58a9,0x58a6,0x596d, 0x5b09,0x5afb,0x5b0b,0x5af5,0x5b0c,0x5b08,0x5bee,0x5bec,0x5be9,0x5beb, 0x5c64,0x5c65,0x5d9d,0x5d94,0x5e62,0x5e5f,0x5e61,0x5ee2,0x5eda,0x5edf, 0x5edd,0x5ee3,0x5ee0,0x5f48,0x5f71,0x5fb7,0x5fb5,0x6176,0x6167,0x616e, 0x615d,0x6155,0x6182 },{ 0x617c,0x6170,0x616b,0x617e,0x61a7,0x6190,0x61ab,0x618e,0x61ac,0x619a, 0x61a4,0x6194,0x61ae,0x622e,0x6469,0x646f,0x6479,0x649e,0x64b2,0x6488, 0x6490,0x64b0,0x64a5,0x6493,0x6495,0x64a9,0x6492,0x64ae,0x64ad,0x64ab, 0x649a,0x64ac,0x6499,0x64a2,0x64b3,0x6575,0x6577,0x6578,0x66ae,0x66ab, 0x66b4,0x66b1,0x6a23,0x6a1f,0x69e8,0x6a01,0x6a1e,0x6a19,0x69fd,0x6a21, 0x6a13,0x6a0a,0x69f3,0x6a02,0x6a05,0x69ed,0x6a11,0x6b50,0x6b4e,0x6ba4, 0x6bc5,0x6bc6,0x6f3f,0x6f7c,0x6f84,0x6f51,0x6f66,0x6f54,0x6f86,0x6f6d, 0x6f5b,0x6f78,0x6f6e,0x6f8e,0x6f7a,0x6f70,0x6f64,0x6f97,0x6f58,0x6ed5, 0x6f6f,0x6f60,0x6f5f,0x719f,0x71ac,0x71b1,0x71a8,0x7256,0x729b,0x734e, 0x7357,0x7469,0x748b,0x7483 } }, { /* ku 1d */ { 0x747e,0x7480,0x757f,0x7620,0x7629,0x761f,0x7624,0x7626,0x7621,0x7622, 0x769a,0x76ba,0x76e4,0x778e,0x7787,0x778c,0x7791,0x778b,0x78cb,0x78c5, 0x78ba,0x78ca,0x78be,0x78d5,0x78bc,0x78d0,0x7a3f,0x7a3c,0x7a40,0x7a3d, 0x7a37,0x7a3b,0x7aaf,0x7aae,0x7bad,0x7bb1,0x7bc4,0x7bb4,0x7bc6,0x7bc7, 0x7bc1,0x7ba0,0x7bcc,0x7cca,0x7de0,0x7df4,0x7def,0x7dfb,0x7dd8,0x7dec, 0x7ddd,0x7de8,0x7de3,0x7dda,0x7dde,0x7de9,0x7d9e,0x7dd9,0x7df2,0x7df9, 0x7f75,0x7f77,0x7faf },{ 0x7fe9,0x8026,0x819b,0x819c,0x819d,0x81a0,0x819a,0x8198,0x8517,0x853d, 0x851a,0x84ee,0x852c,0x852d,0x8513,0x8511,0x8523,0x8521,0x8514,0x84ec, 0x8525,0x84ff,0x8506,0x8782,0x8774,0x8776,0x8760,0x8766,0x8778,0x8768, 0x8759,0x8757,0x874c,0x8753,0x885b,0x885d,0x8910,0x8907,0x8912,0x8913, 0x8915,0x890a,0x8abc,0x8ad2,0x8ac7,0x8ac4,0x8a95,0x8acb,0x8af8,0x8ab2, 0x8ac9,0x8ac2,0x8abf,0x8ab0,0x8ad6,0x8acd,0x8ab6,0x8ab9,0x8adb,0x8c4c, 0x8c4e,0x8c6c,0x8ce0,0x8cde,0x8ce6,0x8ce4,0x8cec,0x8ced,0x8ce2,0x8ce3, 0x8cdc,0x8cea,0x8ce1,0x8d6d,0x8d9f,0x8da3,0x8e2b,0x8e10,0x8e1d,0x8e22, 0x8e0f,0x8e29,0x8e1f,0x8e21,0x8e1e,0x8eba,0x8f1d,0x8f1b,0x8f1f,0x8f29, 0x8f26,0x8f2a,0x8f1c,0x8f1e } }, { /* ku 1e */ { 0x8f25,0x9069,0x906e,0x9068,0x906d,0x9077,0x9130,0x912d,0x9127,0x9131, 0x9187,0x9189,0x918b,0x9183,0x92c5,0x92bb,0x92b7,0x92ea,0x92ac,0x92e4, 0x92c1,0x92b3,0x92bc,0x92d2,0x92c7,0x92f0,0x92b2,0x95ad,0x95b1,0x9704, 0x9706,0x9707,0x9709,0x9760,0x978d,0x978b,0x978f,0x9821,0x982b,0x981c, 0x98b3,0x990a,0x9913,0x9912,0x9918,0x99dd,0x99d0,0x99df,0x99db,0x99d1, 0x99d5,0x99d2,0x99d9,0x9ab7,0x9aee,0x9aef,0x9b27,0x9b45,0x9b44,0x9b77, 0x9b6f,0x9d06,0x9d09 },{ 0x9d03,0x9ea9,0x9ebe,0x9ece,0x58a8,0x9f52,0x5112,0x5118,0x5114,0x5110, 0x5115,0x5180,0x51aa,0x51dd,0x5291,0x5293,0x52f3,0x5659,0x566b,0x5679, 0x5669,0x5664,0x5678,0x566a,0x5668,0x5665,0x5671,0x566f,0x566c,0x5662, 0x5676,0x58c1,0x58be,0x58c7,0x58c5,0x596e,0x5b1d,0x5b34,0x5b78,0x5bf0, 0x5c0e,0x5f4a,0x61b2,0x6191,0x61a9,0x618a,0x61cd,0x61b6,0x61be,0x61ca, 0x61c8,0x6230,0x64c5,0x64c1,0x64cb,0x64bb,0x64bc,0x64da,0x64c4,0x64c7, 0x64c2,0x64cd,0x64bf,0x64d2,0x64d4,0x64be,0x6574,0x66c6,0x66c9,0x66b9, 0x66c4,0x66c7,0x66b8,0x6a3d,0x6a38,0x6a3a,0x6a59,0x6a6b,0x6a58,0x6a39, 0x6a44,0x6a62,0x6a61,0x6a4b,0x6a47,0x6a35,0x6a5f,0x6a48,0x6b59,0x6b77, 0x6c05,0x6fc2,0x6fb1,0x6fa1 } }, { /* ku 1f */ { 0x6fc3,0x6fa4,0x6fc1,0x6fa7,0x6fb3,0x6fc0,0x6fb9,0x6fb6,0x6fa6,0x6fa0, 0x6fb4,0x71be,0x71c9,0x71d0,0x71d2,0x71c8,0x71d5,0x71b9,0x71ce,0x71d9, 0x71dc,0x71c3,0x71c4,0x7368,0x749c,0x74a3,0x7498,0x749f,0x749e,0x74e2, 0x750c,0x750d,0x7634,0x7638,0x763a,0x76e7,0x76e5,0x77a0,0x779e,0x779f, 0x77a5,0x78e8,0x78da,0x78ec,0x78e7,0x79a6,0x7a4d,0x7a4e,0x7a46,0x7a4c, 0x7a4b,0x7aba,0x7bd9,0x7c11,0x7bc9,0x7be4,0x7bdb,0x7be1,0x7be9,0x7be6, 0x7cd5,0x7cd6,0x7e0a },{ 0x7e11,0x7e08,0x7e1b,0x7e23,0x7e1e,0x7e1d,0x7e09,0x7e10,0x7f79,0x7fb2, 0x7ff0,0x7ff1,0x7fee,0x8028,0x81b3,0x81a9,0x81a8,0x81fb,0x8208,0x8258, 0x8259,0x854a,0x8559,0x8548,0x8568,0x8569,0x8543,0x8549,0x856d,0x856a, 0x855e,0x8783,0x879f,0x879e,0x87a2,0x878d,0x8861,0x892a,0x8932,0x8925, 0x892b,0x8921,0x89aa,0x89a6,0x8ae6,0x8afa,0x8aeb,0x8af1,0x8b00,0x8adc, 0x8ae7,0x8aee,0x8afe,0x8b01,0x8b02,0x8af7,0x8aed,0x8af3,0x8af6,0x8afc, 0x8c6b,0x8c6d,0x8c93,0x8cf4,0x8e44,0x8e31,0x8e34,0x8e42,0x8e39,0x8e35, 0x8f3b,0x8f2f,0x8f38,0x8f33,0x8fa8,0x8fa6,0x9075,0x9074,0x9078,0x9072, 0x907c,0x907a,0x9134,0x9192,0x9320,0x9336,0x92f8,0x9333,0x932f,0x9322, 0x92fc,0x932b,0x9304,0x931a } }, { /* ku 20 */ { 0x9310,0x9326,0x9321,0x9315,0x932e,0x9319,0x95bb,0x96a7,0x96a8,0x96aa, 0x96d5,0x970e,0x9711,0x9716,0x970d,0x9713,0x970f,0x975b,0x975c,0x9766, 0x9798,0x9830,0x9838,0x983b,0x9837,0x982d,0x9839,0x9824,0x9910,0x9928, 0x991e,0x991b,0x9921,0x991a,0x99ed,0x99e2,0x99f1,0x9ab8,0x9abc,0x9afb, 0x9aed,0x9b28,0x9b91,0x9d15,0x9d23,0x9d26,0x9d28,0x9d12,0x9d1b,0x9ed8, 0x9ed4,0x9f8d,0x9f9c,0x512a,0x511f,0x5121,0x5132,0x52f5,0x568e,0x5680, 0x5690,0x5685,0x5687 },{ 0x568f,0x58d5,0x58d3,0x58d1,0x58ce,0x5b30,0x5b2a,0x5b24,0x5b7a,0x5c37, 0x5c68,0x5dbc,0x5dba,0x5dbd,0x5db8,0x5e6b,0x5f4c,0x5fbd,0x61c9,0x61c2, 0x61c7,0x61e6,0x61cb,0x6232,0x6234,0x64ce,0x64ca,0x64d8,0x64e0,0x64f0, 0x64e6,0x64ec,0x64f1,0x64e2,0x64ed,0x6582,0x6583,0x66d9,0x66d6,0x6a80, 0x6a94,0x6a84,0x6aa2,0x6a9c,0x6adb,0x6aa3,0x6a7e,0x6a97,0x6a90,0x6aa0, 0x6b5c,0x6bae,0x6bda,0x6c08,0x6fd8,0x6ff1,0x6fdf,0x6fe0,0x6fdb,0x6fe4, 0x6feb,0x6fef,0x6f80,0x6fec,0x6fe1,0x6fe9,0x6fd5,0x6fee,0x6ff0,0x71e7, 0x71df,0x71ee,0x71e6,0x71e5,0x71ed,0x71ec,0x71f4,0x71e0,0x7235,0x7246, 0x7370,0x7372,0x74a9,0x74b0,0x74a6,0x74a8,0x7646,0x7642,0x764c,0x76ea, 0x77b3,0x77aa,0x77b0,0x77ac } }, { /* ku 21 */ { 0x77a7,0x77ad,0x77ef,0x78f7,0x78fa,0x78f4,0x78ef,0x7901,0x79a7,0x79aa, 0x7a57,0x7abf,0x7c07,0x7c0d,0x7bfe,0x7bf7,0x7c0c,0x7be0,0x7ce0,0x7cdc, 0x7cde,0x7ce2,0x7cdf,0x7cd9,0x7cdd,0x7e2e,0x7e3e,0x7e46,0x7e37,0x7e32, 0x7e43,0x7e2b,0x7e3d,0x7e31,0x7e45,0x7e41,0x7e34,0x7e39,0x7e48,0x7e35, 0x7e3f,0x7e2f,0x7f44,0x7ff3,0x7ffc,0x8071,0x8072,0x8070,0x806f,0x8073, 0x81c6,0x81c3,0x81ba,0x81c2,0x81c0,0x81bf,0x81bd,0x81c9,0x81be,0x81e8, 0x8209,0x8271,0x85aa },{ 0x8584,0x857e,0x859c,0x8591,0x8594,0x85af,0x859b,0x8587,0x85a8,0x858a, 0x8667,0x87c0,0x87d1,0x87b3,0x87d2,0x87c6,0x87ab,0x87bb,0x87ba,0x87c8, 0x87cb,0x893b,0x8936,0x8944,0x8938,0x893d,0x89ac,0x8b0e,0x8b17,0x8b19, 0x8b1b,0x8b0a,0x8b20,0x8b1d,0x8b04,0x8b10,0x8c41,0x8c3f,0x8c73,0x8cfa, 0x8cfd,0x8cfc,0x8cf8,0x8cfb,0x8da8,0x8e49,0x8e4b,0x8e48,0x8e4a,0x8f44, 0x8f3e,0x8f42,0x8f45,0x8f3f,0x907f,0x907d,0x9084,0x9081,0x9082,0x9080, 0x9139,0x91a3,0x919e,0x919c,0x934d,0x9382,0x9328,0x9375,0x934a,0x9365, 0x934b,0x9318,0x937e,0x936c,0x935b,0x9370,0x935a,0x9354,0x95ca,0x95cb, 0x95cc,0x95c8,0x95c6,0x96b1,0x96b8,0x96d6,0x971c,0x971e,0x97a0,0x97d3, 0x9846,0x98b6,0x9935,0x9a01 } }, { /* ku 22 */ { 0x99ff,0x9bae,0x9bab,0x9baa,0x9bad,0x9d3b,0x9d3f,0x9e8b,0x9ecf,0x9ede, 0x9edc,0x9edd,0x9edb,0x9f3e,0x9f4b,0x53e2,0x5695,0x56ae,0x58d9,0x58d8, 0x5b38,0x5f5d,0x61e3,0x6233,0x64f4,0x64f2,0x64fe,0x6506,0x64fa,0x64fb, 0x64f7,0x65b7,0x66dc,0x6726,0x6ab3,0x6aac,0x6ac3,0x6abb,0x6ab8,0x6ac2, 0x6aae,0x6aaf,0x6b5f,0x6b78,0x6baf,0x7009,0x700b,0x6ffe,0x7006,0x6ffa, 0x7011,0x700f,0x71fb,0x71fc,0x71fe,0x71f8,0x7377,0x7375,0x74a7,0x74bf, 0x7515,0x7656,0x7658 },{ 0x7652,0x77bd,0x77bf,0x77bb,0x77bc,0x790e,0x79ae,0x7a61,0x7a62,0x7a60, 0x7ac4,0x7ac5,0x7c2b,0x7c27,0x7c2a,0x7c1e,0x7c23,0x7c21,0x7ce7,0x7e54, 0x7e55,0x7e5e,0x7e5a,0x7e61,0x7e52,0x7e59,0x7f48,0x7ff9,0x7ffb,0x8077, 0x8076,0x81cd,0x81cf,0x820a,0x85cf,0x85a9,0x85cd,0x85d0,0x85c9,0x85b0, 0x85ba,0x85b9,0x85a6,0x87ef,0x87ec,0x87f2,0x87e0,0x8986,0x89b2,0x89f4, 0x8b28,0x8b39,0x8b2c,0x8b2b,0x8c50,0x8d05,0x8e59,0x8e63,0x8e66,0x8e64, 0x8e5f,0x8e55,0x8ec0,0x8f49,0x8f4d,0x9087,0x9083,0x9088,0x91ab,0x91ac, 0x91d0,0x9394,0x938a,0x9396,0x93a2,0x93b3,0x93ae,0x93ac,0x93b0,0x9398, 0x939a,0x9397,0x95d4,0x95d6,0x95d0,0x95d5,0x96e2,0x96dc,0x96d9,0x96db, 0x96de,0x9724,0x97a3,0x97a6 } }, { /* ku 23 */ { 0x97ad,0x97f9,0x984d,0x984f,0x984c,0x984e,0x9853,0x98ba,0x993e,0x993f, 0x993d,0x992e,0x99a5,0x9a0e,0x9ac1,0x9b03,0x9b06,0x9b4f,0x9b4e,0x9b4d, 0x9bca,0x9bc9,0x9bfd,0x9bc8,0x9bc0,0x9d51,0x9d5d,0x9d60,0x9ee0,0x9f15, 0x9f2c,0x5133,0x56a5,0x58de,0x58df,0x58e2,0x5bf5,0x9f90,0x5eec,0x61f2, 0x61f7,0x61f6,0x61f5,0x6500,0x650f,0x66e0,0x66dd,0x6ae5,0x6add,0x6ada, 0x6ad3,0x701b,0x701f,0x7028,0x701a,0x701d,0x7015,0x7018,0x7206,0x720d, 0x7258,0x72a2,0x7378 },{ 0x737a,0x74bd,0x74ca,0x74e3,0x7587,0x7586,0x765f,0x7661,0x77c7,0x7919, 0x79b1,0x7a6b,0x7a69,0x7c3e,0x7c3f,0x7c38,0x7c3d,0x7c37,0x7c40,0x7e6b, 0x7e6d,0x7e79,0x7e69,0x7e6a,0x7f85,0x7e73,0x7fb6,0x7fb9,0x7fb8,0x81d8, 0x85e9,0x85dd,0x85ea,0x85d5,0x85e4,0x85e5,0x85f7,0x87fb,0x8805,0x880d, 0x87f9,0x87fe,0x8960,0x895f,0x8956,0x895e,0x8b41,0x8b5c,0x8b58,0x8b49, 0x8b5a,0x8b4e,0x8b4f,0x8b46,0x8b59,0x8d08,0x8d0a,0x8e7c,0x8e72,0x8e87, 0x8e76,0x8e6c,0x8e7a,0x8e74,0x8f54,0x8f4e,0x8fad,0x908a,0x908b,0x91b1, 0x91ae,0x93e1,0x93d1,0x93df,0x93c3,0x93c8,0x93dc,0x93dd,0x93d6,0x93e2, 0x93cd,0x93d8,0x93e4,0x93d7,0x93e8,0x95dc,0x96b4,0x96e3,0x972a,0x9727, 0x9761,0x97dc,0x97fb,0x985e } }, { /* ku 24 */ { 0x9858,0x985b,0x98bc,0x9945,0x9949,0x9a16,0x9a19,0x9b0d,0x9be8,0x9be7, 0x9bd6,0x9bdb,0x9d89,0x9d61,0x9d72,0x9d6a,0x9d6c,0x9e92,0x9e97,0x9e93, 0x9eb4,0x52f8,0x56a8,0x56b7,0x56b6,0x56b4,0x56bc,0x58e4,0x5b40,0x5b43, 0x5b7d,0x5bf6,0x5dc9,0x61f8,0x61fa,0x6518,0x6514,0x6519,0x66e6,0x6727, 0x6aec,0x703e,0x7030,0x7032,0x7210,0x737b,0x74cf,0x7662,0x7665,0x7926, 0x792a,0x792c,0x792b,0x7ac7,0x7af6,0x7c4c,0x7c43,0x7c4d,0x7cef,0x7cf0, 0x8fae,0x7e7d,0x7e7c },{ 0x7e82,0x7f4c,0x8000,0x81da,0x8266,0x85fb,0x85f9,0x8611,0x85fa,0x8606, 0x860b,0x8607,0x860a,0x8814,0x8815,0x8964,0x89ba,0x89f8,0x8b70,0x8b6c, 0x8b66,0x8b6f,0x8b5f,0x8b6b,0x8d0f,0x8d0d,0x8e89,0x8e81,0x8e85,0x8e82, 0x91b4,0x91cb,0x9418,0x9403,0x93fd,0x95e1,0x9730,0x98c4,0x9952,0x9951, 0x99a8,0x9a2b,0x9a30,0x9a37,0x9a35,0x9c13,0x9c0d,0x9e79,0x9eb5,0x9ee8, 0x9f2f,0x9f5f,0x9f63,0x9f61,0x5137,0x5138,0x56c1,0x56c0,0x56c2,0x5914, 0x5c6c,0x5dcd,0x61fc,0x61fe,0x651d,0x651c,0x6595,0x66e9,0x6afb,0x6b04, 0x6afa,0x6bb2,0x704c,0x721b,0x72a7,0x74d6,0x74d4,0x7669,0x77d3,0x7c50, 0x7e8f,0x7e8c,0x7fbc,0x8617,0x862d,0x861a,0x8823,0x8822,0x8821,0x881f, 0x896a,0x896c,0x89bd,0x8b74 } }, { /* ku 25 */ { 0x8b77,0x8b7d,0x8d13,0x8e8a,0x8e8d,0x8e8b,0x8f5f,0x8faf,0x91ba,0x942e, 0x9433,0x9435,0x943a,0x9438,0x9432,0x942b,0x95e2,0x9738,0x9739,0x9732, 0x97ff,0x9867,0x9865,0x9957,0x9a45,0x9a43,0x9a40,0x9a3e,0x9acf,0x9b54, 0x9b51,0x9c2d,0x9c25,0x9daf,0x9db4,0x9dc2,0x9db8,0x9e9d,0x9eef,0x9f19, 0x9f5c,0x9f66,0x9f67,0x513c,0x513b,0x56c8,0x56ca,0x56c9,0x5b7f,0x5dd4, 0x5dd2,0x5f4e,0x61ff,0x6524,0x6b0a,0x6b61,0x7051,0x7058,0x7380,0x74e4, 0x758a,0x766e,0x766c },{ 0x79b3,0x7c60,0x7c5f,0x807e,0x807d,0x81df,0x8972,0x896f,0x89fc,0x8b80, 0x8d16,0x8d17,0x8e91,0x8e93,0x8f61,0x9148,0x9444,0x9451,0x9452,0x973d, 0x973e,0x97c3,0x97c1,0x986b,0x9955,0x9a55,0x9a4d,0x9ad2,0x9b1a,0x9c49, 0x9c31,0x9c3e,0x9c3b,0x9dd3,0x9dd7,0x9f34,0x9f6c,0x9f6a,0x9f94,0x56cc, 0x5dd6,0x6200,0x6523,0x652b,0x652a,0x66ec,0x6b10,0x74da,0x7aca,0x7c64, 0x7c63,0x7c65,0x7e93,0x7e96,0x7e94,0x81e2,0x8638,0x863f,0x8831,0x8b8a, 0x9090,0x908f,0x9463,0x9460,0x9464,0x9768,0x986f,0x995c,0x9a5a,0x9a5b, 0x9a57,0x9ad3,0x9ad4,0x9ad1,0x9c54,0x9c57,0x9c56,0x9de5,0x9e9f,0x9ef4, 0x56d1,0x58e9,0x652c,0x705e,0x7671,0x7672,0x77d7,0x7f50,0x7f88,0x8836, 0x8839,0x8862,0x8b93,0x8b92 } }, { /* ku 26 */ { 0x8b96,0x8277,0x8d1b,0x91c0,0x946a,0x9742,0x9748,0x9744,0x97c6,0x9870, 0x9a5f,0x9b22,0x9b58,0x9c5f,0x9df9,0x9dfa,0x9e7c,0x9e7d,0x9f07,0x9f77, 0x9f72,0x5ef3,0x6b16,0x7063,0x7c6c,0x7c6e,0x883b,0x89c0,0x8ea1,0x91c1, 0x9472,0x9470,0x9871,0x995e,0x9ad6,0x9b23,0x9ecc,0x7064,0x77da,0x8b9a, 0x9477,0x97c9,0x9a62,0x9a65,0x7e9c,0x8b9c,0x8eaa,0x91c5,0x947d,0x947e, 0x947c,0x9c77,0x9c78,0x9ef7,0x8c54,0x947f,0x9e1a,0x7228,0x9a6a,0x9b31, 0x9e1b,0x9e1e,0x7c72 },{ 0x30fe,0x309d,0x309e,0x3005,0x3041,0x3042,0x3043,0x3044,0x3045,0x3046, 0x3047,0x3048,0x3049,0x304a,0x304b,0x304c,0x304d,0x304e,0x304f,0x3050, 0x3051,0x3052,0x3053,0x3054,0x3055,0x3056,0x3057,0x3058,0x3059,0x305a, 0x305b,0x305c,0x305d,0x305e,0x305f,0x3060,0x3061,0x3062,0x3063,0x3064, 0x3065,0x3066,0x3067,0x3068,0x3069,0x306a,0x306b,0x306c,0x306d,0x306e, 0x306f,0x3070,0x3071,0x3072,0x3073,0x3074,0x3075,0x3076,0x3077,0x3078, 0x3079,0x307a,0x307b,0x307c,0x307d,0x307e,0x307f,0x3080,0x3081,0x3082, 0x3083,0x3084,0x3085,0x3086,0x3087,0x3088,0x3089,0x308a,0x308b,0x308c, 0x308d,0x308e,0x308f,0x3090,0x3091,0x3092,0x3093,0x30a1,0x30a2,0x30a3, 0x30a4,0x30a5,0x30a6,0x30a7 } }, { /* ku 27 */ { 0x30a8,0x30a9,0x30aa,0x30ab,0x30ac,0x30ad,0x30ae,0x30af,0x30b0,0x30b1, 0x30b2,0x30b3,0x30b4,0x30b5,0x30b6,0x30b7,0x30b8,0x30b9,0x30ba,0x30bb, 0x30bc,0x30bd,0x30be,0x30bf,0x30c0,0x30c1,0x30c2,0x30c3,0x30c4,0x30c5, 0x30c6,0x30c7,0x30c8,0x30c9,0x30ca,0x30cb,0x30cc,0x30cd,0x30ce,0x30cf, 0x30d0,0x30d1,0x30d2,0x30d3,0x30d4,0x30d5,0x30d6,0x30d7,0x30d8,0x30d9, 0x30da,0x30db,0x30dc,0x30dd,0x30de,0x30df,0x30e0,0x30e1,0x30e2,0x30e3, 0x30e4,0x30e5,0x30e6 },{ 0x30e7,0x30e8,0x30e9,0x30ea,0x30eb,0x30ec,0x30ed,0x30ee,0x30ef,0x30f0, 0x30f1,0x30f2,0x30f3,0x30f4,0x30f5,0x30f6,0x0414,0x0415,0x0401,0x0416, 0x0417,0x0418,0x0419,0x041a,0x041b,0x041c,0x0423,0x0424,0x0425,0x0426, 0x0427,0x0428,0x0429,0x042a,0x042b,0x042c,0x042d,0x042e,0x042f,0x0430, 0x0431,0x0432,0x0433,0x0434,0x0435,0x0451,0x0436,0x0437,0x0438,0x0439, 0x043a,0x043b,0x043c,0x043d,0x043e,0x043f,0x0440,0x0441,0x0442,0x0443, 0x0444,0x0445,0x0446,0x0447,0x0448,0x0449,0x044a,0x044b,0x044c,0x044d, 0x044e,0x044f,0x2460,0x2461,0x2462,0x2463,0x2464,0x2465,0x2466,0x2467, 0x2468,0x2469,0x2474,0x2475,0x2476,0x2477,0x2478,0x2479,0x247a,0x247b, 0x247c,0x247d,UBOGON,UBOGON } }, { /* ku 28 */ { UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON, UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON, UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON, UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON, UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON, UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON, UBOGON,UBOGON,UBOGON },{ UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON, UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON, UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON, UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON, UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON, UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON, UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON, UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON, UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON, UBOGON,UBOGON,UBOGON,UBOGON } }, { /* ku 29 */ { 0x4e42,0x4e5c,0x51f5,0x531a,0x5382,0x4e07,0x4e0c,0x4e47,0x4e8d,0x56d7, 0xfa0c,0x5c6e,0x5f73,0x4e0f,0x5187,0x4e0e,0x4e2e,0x4e93,0x4ec2,0x4ec9, 0x4ec8,0x5198,0x52fc,0x536c,0x53b9,0x5720,0x5903,0x592c,0x5c10,0x5dff, 0x65e1,0x6bb3,0x6bcc,0x6c14,0x723f,0x4e31,0x4e3c,0x4ee8,0x4edc,0x4ee9, 0x4ee1,0x4edd,0x4eda,0x520c,0x531c,0x534c,0x5722,0x5723,0x5917,0x592f, 0x5b81,0x5b84,0x5c12,0x5c3b,0x5c74,0x5c73,0x5e04,0x5e80,0x5e82,0x5fc9, 0x6209,0x6250,0x6c15 },{ 0x6c36,0x6c43,0x6c3f,0x6c3b,0x72ae,0x72b0,0x738a,0x79b8,0x808a,0x961e, 0x4f0e,0x4f18,0x4f2c,0x4ef5,0x4f14,0x4ef1,0x4f00,0x4ef7,0x4f08,0x4f1d, 0x4f02,0x4f05,0x4f22,0x4f13,0x4f04,0x4ef4,0x4f12,0x51b1,0x5213,0x5209, 0x5210,0x52a6,0x5322,0x531f,0x534d,0x538a,0x5407,0x56e1,0x56df,0x572e, 0x572a,0x5734,0x593c,0x5980,0x597c,0x5985,0x597b,0x597e,0x5977,0x597f, 0x5b56,0x5c15,0x5c25,0x5c7c,0x5c7a,0x5c7b,0x5c7e,0x5ddf,0x5e75,0x5e84, 0x5f02,0x5f1a,0x5f74,0x5fd5,0x5fd4,0x5fcf,0x625c,0x625e,0x6264,0x6261, 0x6266,0x6262,0x6259,0x6260,0x625a,0x6265,0x65ef,0x65ee,0x673e,0x6739, 0x6738,0x673b,0x673a,0x673f,0x673c,0x6733,0x6c18,0x6c46,0x6c52,0x6c5c, 0x6c4f,0x6c4a,0x6c54,0x6c4b } }, { /* ku 2a */ { 0x6c4c,0x7071,0x725e,0x72b4,0x72b5,0x738e,0x752a,0x767f,0x7a75,0x7f51, 0x8278,0x827c,0x8280,0x827d,0x827f,0x864d,0x897e,0x9099,0x9097,0x9098, 0x909b,0x9094,0x9622,0x9624,0x9620,0x9623,0x4f56,0x4f3b,0x4f62,0x4f49, 0x4f53,0x4f64,0x4f3e,0x4f67,0x4f52,0x4f5f,0x4f41,0x4f58,0x4f2d,0x4f33, 0x4f3f,0x4f61,0x518f,0x51b9,0x521c,0x521e,0x5221,0x52ad,0x52ae,0x5309, 0x5363,0x5372,0x538e,0x538f,0x5430,0x5437,0x542a,0x5454,0x5445,0x5419, 0x541c,0x5425,0x5418 },{ 0x543d,0x544f,0x5441,0x5428,0x5424,0x5447,0x56ee,0x56e7,0x56e5,0x5741, 0x5745,0x574c,0x5749,0x574b,0x5752,0x5906,0x5940,0x59a6,0x5998,0x59a0, 0x5997,0x598e,0x59a2,0x5990,0x598f,0x59a7,0x59a1,0x5b8e,0x5b92,0x5c28, 0x5c2a,0x5c8d,0x5c8f,0x5c88,0x5c8b,0x5c89,0x5c92,0x5c8a,0x5c86,0x5c93, 0x5c95,0x5de0,0x5e0a,0x5e0e,0x5e8b,0x5e89,0x5e8c,0x5e88,0x5e8d,0x5f05, 0x5f1d,0x5f78,0x5f76,0x5fd2,0x5fd1,0x5fd0,0x5fed,0x5fe8,0x5fee,0x5ff3, 0x5fe1,0x5fe4,0x5fe3,0x5ffa,0x5fef,0x5ff7,0x5ffb,0x6000,0x5ff4,0x623a, 0x6283,0x628c,0x628e,0x628f,0x6294,0x6287,0x6271,0x627b,0x627a,0x6270, 0x6281,0x6288,0x6277,0x627d,0x6272,0x6274,0x6537,0x65f0,0x65f4,0x65f3, 0x65f2,0x65f5,0x6745,0x6747 } }, { /* ku 2b */ { 0x6759,0x6755,0x674c,0x6748,0x675d,0x674d,0x675a,0x674b,0x6bd0,0x6c19, 0x6c1a,0x6c78,0x6c67,0x6c6b,0x6c84,0x6c8b,0x6c8f,0x6c71,0x6c6f,0x6c69, 0x6c9a,0x6c6d,0x6c87,0x6c95,0x6c9c,0x6c66,0x6c73,0x6c65,0x6c7b,0x6c8e, 0x7074,0x707a,0x7263,0x72bf,0x72bd,0x72c3,0x72c6,0x72c1,0x72ba,0x72c5, 0x7395,0x7397,0x7393,0x7394,0x7392,0x753a,0x7539,0x7594,0x7595,0x7681, 0x793d,0x8034,0x8095,0x8099,0x8090,0x8092,0x809c,0x8290,0x828f,0x8285, 0x828e,0x8291,0x8293 },{ 0x828a,0x8283,0x8284,0x8c78,0x8fc9,0x8fbf,0x909f,0x90a1,0x90a5,0x909e, 0x90a7,0x90a0,0x9630,0x9628,0x962f,0x962d,0x4e33,0x4f98,0x4f7c,0x4f85, 0x4f7d,0x4f80,0x4f87,0x4f76,0x4f74,0x4f89,0x4f84,0x4f77,0x4f4c,0x4f97, 0x4f6a,0x4f9a,0x4f79,0x4f81,0x4f78,0x4f90,0x4f9c,0x4f94,0x4f9e,0x4f92, 0x4f82,0x4f95,0x4f6b,0x4f6e,0x519e,0x51bc,0x51be,0x5235,0x5232,0x5233, 0x5246,0x5231,0x52bc,0x530a,0x530b,0x533c,0x5392,0x5394,0x5487,0x547f, 0x5481,0x5491,0x5482,0x5488,0x546b,0x547a,0x547e,0x5465,0x546c,0x5474, 0x5466,0x548d,0x546f,0x5461,0x5460,0x5498,0x5463,0x5467,0x5464,0x56f7, 0x56f9,0x576f,0x5772,0x576d,0x576b,0x5771,0x5770,0x5776,0x5780,0x5775, 0x577b,0x5773,0x5774,0x5762 } }, { /* ku 2c */ { 0x5768,0x577d,0x590c,0x5945,0x59b5,0x59ba,0x59cf,0x59ce,0x59b2,0x59cc, 0x59c1,0x59b6,0x59bc,0x59c3,0x59d6,0x59b1,0x59bd,0x59c0,0x59c8,0x59b4, 0x59c7,0x5b62,0x5b65,0x5b93,0x5b95,0x5c44,0x5c47,0x5cae,0x5ca4,0x5ca0, 0x5cb5,0x5caf,0x5ca8,0x5cac,0x5c9f,0x5ca3,0x5cad,0x5ca2,0x5caa,0x5ca7, 0x5c9d,0x5ca5,0x5cb6,0x5cb0,0x5ca6,0x5e17,0x5e14,0x5e19,0x5f28,0x5f22, 0x5f23,0x5f24,0x5f54,0x5f82,0x5f7e,0x5f7d,0x5fde,0x5fe5,0x602d,0x6026, 0x6019,0x6032,0x600b },{ 0x6034,0x600a,0x6017,0x6033,0x601a,0x601e,0x602c,0x6022,0x600d,0x6010, 0x602e,0x6013,0x6011,0x600c,0x6009,0x601c,0x6214,0x623d,0x62ad,0x62b4, 0x62d1,0x62be,0x62aa,0x62b6,0x62ca,0x62ae,0x62b3,0x62af,0x62bb,0x62a9, 0x62b0,0x62b8,0x653d,0x65a8,0x65bb,0x6609,0x65fc,0x6604,0x6612,0x6608, 0x65fb,0x6603,0x660b,0x660d,0x6605,0x65fd,0x6611,0x6610,0x66f6,0x670a, 0x6785,0x676c,0x678e,0x6792,0x6776,0x677b,0x6798,0x6786,0x6784,0x6774, 0x678d,0x678c,0x677a,0x679f,0x6791,0x6799,0x6783,0x677d,0x6781,0x6778, 0x6779,0x6794,0x6b25,0x6b80,0x6b7e,0x6bde,0x6c1d,0x6c93,0x6cec,0x6ceb, 0x6cee,0x6cd9,0x6cb6,0x6cd4,0x6cad,0x6ce7,0x6cb7,0x6cd0,0x6cc2,0x6cba, 0x6cc3,0x6cc6,0x6ced,0x6cf2 } }, { /* ku 2d */ { 0x6cd2,0x6cdd,0x6cb4,0x6c8a,0x6c9d,0x6c80,0x6cde,0x6cc0,0x6d30,0x6ccd, 0x6cc7,0x6cb0,0x6cf9,0x6ccf,0x6ce9,0x6cd1,0x7094,0x7098,0x7085,0x7093, 0x7086,0x7084,0x7091,0x7096,0x7082,0x709a,0x7083,0x726a,0x72d6,0x72cb, 0x72d8,0x72c9,0x72dc,0x72d2,0x72d4,0x72da,0x72cc,0x72d1,0x73a4,0x73a1, 0x73ad,0x73a6,0x73a2,0x73a0,0x73ac,0x739d,0x74dd,0x74e8,0x753f,0x7540, 0x753e,0x758c,0x7598,0x76af,0x76f3,0x76f1,0x76f0,0x76f5,0x77f8,0x77fc, 0x77f9,0x77fb,0x77fa },{ 0x77f7,0x7942,0x793f,0x79c5,0x7a78,0x7a7b,0x7afb,0x7c75,0x7cfd,0x8035, 0x808f,0x80ae,0x80a3,0x80b8,0x80b5,0x80ad,0x8220,0x82a0,0x82c0,0x82ab, 0x829a,0x8298,0x829b,0x82b5,0x82a7,0x82ae,0x82bc,0x829e,0x82ba,0x82b4, 0x82a8,0x82a1,0x82a9,0x82c2,0x82a4,0x82c3,0x82b6,0x82a2,0x8670,0x866f, 0x866d,0x866e,0x8c56,0x8fd2,0x8fcb,0x8fd3,0x8fcd,0x8fd6,0x8fd5,0x8fd7, 0x90b2,0x90b4,0x90af,0x90b3,0x90b0,0x9639,0x963d,0x963c,0x963a,0x9643, 0x4fcd,0x4fc5,0x4fd3,0x4fb2,0x4fc9,0x4fcb,0x4fc1,0x4fd4,0x4fdc,0x4fd9, 0x4fbb,0x4fb3,0x4fdb,0x4fc7,0x4fd6,0x4fba,0x4fc0,0x4fb9,0x4fec,0x5244, 0x5249,0x52c0,0x52c2,0x533d,0x537c,0x5397,0x5396,0x5399,0x5398,0x54ba, 0x54a1,0x54ad,0x54a5,0x54cf } }, { /* ku 2e */ { 0x54c3,0x830d,0x54b7,0x54ae,0x54d6,0x54b6,0x54c5,0x54c6,0x54a0,0x5470, 0x54bc,0x54a2,0x54be,0x5472,0x54de,0x54b0,0x57b5,0x579e,0x579f,0x57a4, 0x578c,0x5797,0x579d,0x579b,0x5794,0x5798,0x578f,0x5799,0x57a5,0x579a, 0x5795,0x58f4,0x590d,0x5953,0x59e1,0x59de,0x59ee,0x5a00,0x59f1,0x59dd, 0x59fa,0x59fd,0x59fc,0x59f6,0x59e4,0x59f2,0x59f7,0x59db,0x59e9,0x59f3, 0x59f5,0x59e0,0x59fe,0x59f4,0x59ed,0x5ba8,0x5c4c,0x5cd0,0x5cd8,0x5ccc, 0x5cd7,0x5ccb,0x5cdb },{ 0x5cde,0x5cda,0x5cc9,0x5cc7,0x5cca,0x5cd6,0x5cd3,0x5cd4,0x5ccf,0x5cc8, 0x5cc6,0x5cce,0x5cdf,0x5cf8,0x5df9,0x5e21,0x5e22,0x5e23,0x5e20,0x5e24, 0x5eb0,0x5ea4,0x5ea2,0x5e9b,0x5ea3,0x5ea5,0x5f07,0x5f2e,0x5f56,0x5f86, 0x6037,0x6039,0x6054,0x6072,0x605e,0x6045,0x6053,0x6047,0x6049,0x605b, 0x604c,0x6040,0x6042,0x605f,0x6024,0x6044,0x6058,0x6066,0x606e,0x6242, 0x6243,0x62cf,0x630d,0x630b,0x62f5,0x630e,0x6303,0x62eb,0x62f9,0x630f, 0x630c,0x62f8,0x62f6,0x6300,0x6313,0x6314,0x62fa,0x6315,0x62fb,0x62f0, 0x6541,0x6543,0x65aa,0x65bf,0x6636,0x6621,0x6632,0x6635,0x661c,0x6626, 0x6622,0x6633,0x662b,0x663a,0x661d,0x6634,0x6639,0x662e,0x670f,0x6710, 0x67c1,0x67f2,0x67c8,0x67ba } }, { /* ku 2f */ { 0x67dc,0x67bb,0x67f8,0x67d8,0x67c0,0x67b7,0x67c5,0x67eb,0x67e4,0x67df, 0x67b5,0x67cd,0x67b3,0x67f7,0x67f6,0x67ee,0x67e3,0x67c2,0x67b9,0x67ce, 0x67e7,0x67f0,0x67b2,0x67fc,0x67c6,0x67ed,0x67cc,0x67ae,0x67e6,0x67db, 0x67fa,0x67c9,0x67ca,0x67c3,0x67ea,0x67cb,0x6b28,0x6b82,0x6b84,0x6bb6, 0x6bd6,0x6bd8,0x6be0,0x6c20,0x6c21,0x6d28,0x6d34,0x6d2d,0x6d1f,0x6d3c, 0x6d3f,0x6d12,0x6d0a,0x6cda,0x6d33,0x6d04,0x6d19,0x6d3a,0x6d1a,0x6d11, 0x6d00,0x6d1d,0x6d42 },{ 0x6d01,0x6d18,0x6d37,0x6d03,0x6d0f,0x6d40,0x6d07,0x6d20,0x6d2c,0x6d08, 0x6d22,0x6d09,0x6d10,0x70b7,0x709f,0x70be,0x70b1,0x70b0,0x70a1,0x70b4, 0x70b5,0x70a9,0x7241,0x7249,0x724a,0x726c,0x7270,0x7273,0x726e,0x72ca, 0x72e4,0x72e8,0x72eb,0x72df,0x72ea,0x72e6,0x72e3,0x7385,0x73cc,0x73c2, 0x73c8,0x73c5,0x73b9,0x73b6,0x73b5,0x73b4,0x73eb,0x73bf,0x73c7,0x73be, 0x73c3,0x73c6,0x73b8,0x73cb,0x74ec,0x74ee,0x752e,0x7547,0x7548,0x75a7, 0x75aa,0x7679,0x76c4,0x7708,0x7703,0x7704,0x7705,0x770a,0x76f7,0x76fb, 0x76fa,0x77e7,0x77e8,0x7806,0x7811,0x7812,0x7805,0x7810,0x780f,0x780e, 0x7809,0x7803,0x7813,0x794a,0x794c,0x794b,0x7945,0x7944,0x79d5,0x79cd, 0x79cf,0x79d6,0x79ce,0x7a80 } }, { /* ku 30 */ { 0x7a7e,0x7ad1,0x7b00,0x7b01,0x7c7a,0x7c78,0x7c79,0x7c7f,0x7c80,0x7c81, 0x7d03,0x7d08,0x7d01,0x7f58,0x7f91,0x7f8d,0x7fbe,0x8007,0x800e,0x800f, 0x8014,0x8037,0x80d8,0x80c7,0x80e0,0x80d1,0x80c8,0x80c2,0x80d0,0x80c5, 0x80e3,0x80d9,0x80dc,0x80ca,0x80d5,0x80c9,0x80cf,0x80d7,0x80e6,0x80cd, 0x81ff,0x8221,0x8294,0x82d9,0x82fe,0x82f9,0x8307,0x82e8,0x8300,0x82d5, 0x833a,0x82eb,0x82d6,0x82f4,0x82ec,0x82e1,0x82f2,0x82f5,0x830c,0x82fb, 0x82f6,0x82f0,0x82ea },{ 0x82e4,0x82e0,0x82fa,0x82f3,0x82ed,0x8677,0x8674,0x867c,0x8673,0x8841, 0x884e,0x8867,0x886a,0x8869,0x89d3,0x8a04,0x8a07,0x8d72,0x8fe3,0x8fe1, 0x8fee,0x8fe0,0x90f1,0x90bd,0x90bf,0x90d5,0x90c5,0x90be,0x90c7,0x90cb, 0x90c8,0x91d4,0x91d3,0x9654,0x964f,0x9651,0x9653,0x964a,0x964e,0x501e, 0x5005,0x5007,0x5013,0x5022,0x5030,0x501b,0x4ff5,0x4ff4,0x5033,0x5037, 0x502c,0x4ff6,0x4ff7,0x5017,0x501c,0x5020,0x5027,0x5035,0x502f,0x5031, 0x500e,0x515a,0x5194,0x5193,0x51ca,0x51c4,0x51c5,0x51c8,0x51ce,0x5261, 0x525a,0x5252,0x525e,0x525f,0x5255,0x5262,0x52cd,0x530e,0x539e,0x5526, 0x54e2,0x5517,0x5512,0x54e7,0x54f3,0x54e4,0x551a,0x54ff,0x5504,0x5508, 0x54eb,0x5511,0x5505,0x54f1 } }, { /* ku 31 */ { 0x550a,0x54fb,0x54f7,0x54f8,0x54e0,0x550e,0x5503,0x550b,0x5701,0x5702, 0x57cc,0x5832,0x57d5,0x57d2,0x57ba,0x57c6,0x57bd,0x57bc,0x57b8,0x57b6, 0x57bf,0x57c7,0x57d0,0x57b9,0x57c1,0x590e,0x594a,0x5a19,0x5a16,0x5a2d, 0x5a2e,0x5a15,0x5a0f,0x5a17,0x5a0a,0x5a1e,0x5a33,0x5b6c,0x5ba7,0x5bad, 0x5bac,0x5c03,0x5c56,0x5c54,0x5cec,0x5cff,0x5cee,0x5cf1,0x5cf7,0x5d00, 0x5cf9,0x5e29,0x5e28,0x5ea8,0x5eae,0x5eaa,0x5eac,0x5f33,0x5f30,0x5f67, 0x605d,0x605a,0x6067 },{ 0x6041,0x60a2,0x6088,0x6080,0x6092,0x6081,0x609d,0x6083,0x6095,0x609b, 0x6097,0x6087,0x609c,0x608e,0x6219,0x6246,0x62f2,0x6310,0x6356,0x632c, 0x6344,0x6345,0x6336,0x6343,0x63e4,0x6339,0x634b,0x634a,0x633c,0x6329, 0x6341,0x6334,0x6358,0x6354,0x6359,0x632d,0x6347,0x6333,0x635a,0x6351, 0x6338,0x6357,0x6340,0x6348,0x654a,0x6546,0x65c6,0x65c3,0x65c4,0x65c2, 0x664a,0x665f,0x6647,0x6651,0x6712,0x6713,0x681f,0x681a,0x6849,0x6832, 0x6833,0x683b,0x684b,0x684f,0x6816,0x6831,0x681c,0x6835,0x682b,0x682d, 0x682f,0x684e,0x6844,0x6834,0x681d,0x6812,0x6814,0x6826,0x6828,0x682e, 0x684d,0x683a,0x6825,0x6820,0x6b2c,0x6b2f,0x6b2d,0x6b31,0x6b34,0x6b6d, 0x8082,0x6b88,0x6be6,0x6be4 } }, { /* ku 32 */ { 0x6be8,0x6be3,0x6be2,0x6be7,0x6c25,0x6d7a,0x6d63,0x6d64,0x6d76,0x6d0d, 0x6d61,0x6d92,0x6d58,0x6d62,0x6d6d,0x6d6f,0x6d91,0x6d8d,0x6def,0x6d7f, 0x6d86,0x6d5e,0x6d67,0x6d60,0x6d97,0x6d70,0x6d7c,0x6d5f,0x6d82,0x6d98, 0x6d2f,0x6d68,0x6d8b,0x6d7e,0x6d80,0x6d84,0x6d16,0x6d83,0x6d7b,0x6d7d, 0x6d75,0x6d90,0x70dc,0x70d3,0x70d1,0x70dd,0x70cb,0x7f39,0x70e2,0x70d7, 0x70d2,0x70de,0x70e0,0x70d4,0x70cd,0x70c5,0x70c6,0x70c7,0x70da,0x70ce, 0x70e1,0x7242,0x7278 },{ 0x7277,0x7276,0x7300,0x72fa,0x72f4,0x72fe,0x72f6,0x72f3,0x72fb,0x7301, 0x73d3,0x73d9,0x73e5,0x73d6,0x73bc,0x73e7,0x73e3,0x73e9,0x73dc,0x73d2, 0x73db,0x73d4,0x73dd,0x73da,0x73d7,0x73d8,0x73e8,0x74de,0x74df,0x74f4, 0x74f5,0x7521,0x755b,0x755f,0x75b0,0x75c1,0x75bb,0x75c4,0x75c0,0x75bf, 0x75b6,0x75ba,0x768a,0x76c9,0x771d,0x771b,0x7710,0x7713,0x7712,0x7723, 0x7711,0x7715,0x7719,0x771a,0x7722,0x7727,0x7823,0x782c,0x7822,0x7835, 0x782f,0x7828,0x782e,0x782b,0x7821,0x7829,0x7833,0x782a,0x7831,0x7954, 0x795b,0x794f,0x795c,0x7953,0x7952,0x7951,0x79eb,0x79ec,0x79e0,0x79ee, 0x79ed,0x79ea,0x79dc,0x79de,0x79dd,0x7a86,0x7a89,0x7a85,0x7a8b,0x7a8c, 0x7a8a,0x7a87,0x7ad8,0x7b10 } }, { /* ku 33 */ { 0x7b04,0x7b13,0x7b05,0x7b0f,0x7b08,0x7b0a,0x7b0e,0x7b09,0x7b12,0x7c84, 0x7c91,0x7c8a,0x7c8c,0x7c88,0x7c8d,0x7c85,0x7d1e,0x7d1d,0x7d11,0x7d0e, 0x7d18,0x7d16,0x7d13,0x7d1f,0x7d12,0x7d0f,0x7d0c,0x7f5c,0x7f61,0x7f5e, 0x7f60,0x7f5d,0x7f5b,0x7f96,0x7f92,0x7fc3,0x7fc2,0x7fc0,0x8016,0x803e, 0x8039,0x80fa,0x80f2,0x80f9,0x80f5,0x8101,0x80fb,0x8100,0x8201,0x822f, 0x8225,0x8333,0x832d,0x8344,0x8319,0x8351,0x8325,0x8356,0x833f,0x8341, 0x8326,0x831c,0x8322 },{ 0x8342,0x834e,0x831b,0x832a,0x8308,0x833c,0x834d,0x8316,0x8324,0x8320, 0x8337,0x832f,0x8329,0x8347,0x8345,0x834c,0x8353,0x831e,0x832c,0x834b, 0x8327,0x8348,0x8653,0x8652,0x86a2,0x86a8,0x8696,0x868d,0x8691,0x869e, 0x8687,0x8697,0x8686,0x868b,0x869a,0x8685,0x86a5,0x8699,0x86a1,0x86a7, 0x8695,0x8698,0x868e,0x869d,0x8690,0x8694,0x8843,0x8844,0x886d,0x8875, 0x8876,0x8872,0x8880,0x8871,0x887f,0x886f,0x8883,0x887e,0x8874,0x887c, 0x8a12,0x8c47,0x8c57,0x8c7b,0x8ca4,0x8ca3,0x8d76,0x8d78,0x8db5,0x8db7, 0x8db6,0x8ed1,0x8ed3,0x8ffe,0x8ff5,0x9002,0x8fff,0x8ffb,0x9004,0x8ffc, 0x8ff6,0x90d6,0x90e0,0x90d9,0x90da,0x90e3,0x90df,0x90e5,0x90d8,0x90db, 0x90d7,0x90dc,0x90e4,0x9150 } }, { /* ku 34 */ { 0x914e,0x914f,0x91d5,0x91e2,0x91da,0x965c,0x965f,0x96bc,0x98e3,0x9adf, 0x9b2f,0x4e7f,0x5070,0x506a,0x5061,0x505e,0x5060,0x5053,0x504b,0x505d, 0x5072,0x5048,0x504d,0x5041,0x505b,0x504a,0x5062,0x5015,0x5045,0x505f, 0x5069,0x506b,0x5063,0x5064,0x5046,0x5040,0x506e,0x5073,0x5057,0x5051, 0x51d0,0x526b,0x526d,0x526c,0x526e,0x52d6,0x52d3,0x532d,0x539c,0x5575, 0x5576,0x553c,0x554d,0x5550,0x5534,0x552a,0x5551,0x5562,0x5536,0x5535, 0x5530,0x5552,0x5545 },{ 0x550c,0x5532,0x5565,0x554e,0x5539,0x5548,0x552d,0x553b,0x5540,0x554b, 0x570a,0x5707,0x57fb,0x5814,0x57e2,0x57f6,0x57dc,0x57f4,0x5800,0x57ed, 0x57fd,0x5808,0x57f8,0x580b,0x57f3,0x57cf,0x5807,0x57ee,0x57e3,0x57f2, 0x57e5,0x57ec,0x57e1,0x580e,0x57fc,0x5810,0x57e7,0x5801,0x580c,0x57f1, 0x57e9,0x57f0,0x580d,0x5804,0x595c,0x5a60,0x5a58,0x5a55,0x5a67,0x5a5e, 0x5a38,0x5a35,0x5a6d,0x5a50,0x5a5f,0x5a65,0x5a6c,0x5a53,0x5a64,0x5a57, 0x5a43,0x5a5d,0x5a52,0x5a44,0x5a5b,0x5a48,0x5a8e,0x5a3e,0x5a4d,0x5a39, 0x5a4c,0x5a70,0x5a69,0x5a47,0x5a51,0x5a56,0x5a42,0x5a5c,0x5b72,0x5b6e, 0x5bc1,0x5bc0,0x5c59,0x5d1e,0x5d0b,0x5d1d,0x5d1a,0x5d20,0x5d0c,0x5d28, 0x5d0d,0x5d26,0x5d25,0x5d0f } }, { /* ku 35 */ { 0x5d30,0x5d12,0x5d23,0x5d1f,0x5d2e,0x5e3e,0x5e34,0x5eb1,0x5eb4,0x5eb9, 0x5eb2,0x5eb3,0x5f36,0x5f38,0x5f9b,0x5f96,0x5f9f,0x608a,0x6090,0x6086, 0x60be,0x60b0,0x60ba,0x60d3,0x60d4,0x60cf,0x60e4,0x60d9,0x60dd,0x60c8, 0x60b1,0x60db,0x60b7,0x60ca,0x60bf,0x60c3,0x60cd,0x60c0,0x6332,0x6365, 0x638a,0x6382,0x637d,0x63bd,0x639e,0x63ad,0x639d,0x6397,0x63ab,0x638e, 0x636f,0x6387,0x6390,0x636e,0x63af,0x6375,0x639c,0x636d,0x63ae,0x637c, 0x63a4,0x633b,0x639f },{ 0x6378,0x6385,0x6381,0x6391,0x638d,0x6370,0x6553,0x65cd,0x6665,0x6661, 0x665b,0x6659,0x665c,0x6662,0x6718,0x6879,0x6887,0x6890,0x689c,0x686d, 0x686e,0x68ae,0x68ab,0x6956,0x686f,0x68a3,0x68ac,0x68a9,0x6875,0x6874, 0x68b2,0x688f,0x6877,0x6892,0x687c,0x686b,0x6872,0x68aa,0x6880,0x6871, 0x687e,0x689b,0x6896,0x688b,0x68a0,0x6889,0x68a4,0x6878,0x687b,0x6891, 0x688c,0x688a,0x687d,0x6b36,0x6b33,0x6b37,0x6b38,0x6b91,0x6b8f,0x6b8d, 0x6b8e,0x6b8c,0x6c2a,0x6dc0,0x6dab,0x6db4,0x6db3,0x6e74,0x6dac,0x6de9, 0x6de2,0x6db7,0x6df6,0x6dd4,0x6e00,0x6dc8,0x6de0,0x6ddf,0x6dd6,0x6dbe, 0x6de5,0x6ddc,0x6ddd,0x6ddb,0x6df4,0x6dca,0x6dbd,0x6ded,0x6df0,0x6dba, 0x6dd5,0x6dc2,0x6dcf,0x6dc9 } }, { /* ku 36 */ { 0x6dd0,0x6df2,0x6dd3,0x6dfd,0x6dd7,0x6dcd,0x6de3,0x6dbb,0x70fa,0x710d, 0x70f7,0x7117,0x70f4,0x710c,0x70f0,0x7104,0x70f3,0x7110,0x70fc,0x70ff, 0x7106,0x7113,0x7100,0x70f8,0x70f6,0x710b,0x7102,0x710e,0x727e,0x727b, 0x727c,0x727f,0x731d,0x7317,0x7307,0x7311,0x7318,0x730a,0x7308,0x72ff, 0x730f,0x731e,0x7388,0x73f6,0x73f8,0x73f5,0x7404,0x7401,0x73fd,0x7407, 0x7400,0x73fa,0x73fc,0x73ff,0x740c,0x740b,0x73f4,0x7408,0x7564,0x7563, 0x75ce,0x75d2,0x75cf },{ 0x75cb,0x75cc,0x75d1,0x75d0,0x768f,0x7689,0x76d3,0x7739,0x772f,0x772d, 0x7731,0x7732,0x7734,0x7733,0x773d,0x7725,0x773b,0x7735,0x7848,0x7852, 0x7849,0x784d,0x784a,0x784c,0x7826,0x7845,0x7850,0x7964,0x7967,0x7969, 0x796a,0x7963,0x796b,0x7961,0x79bb,0x79fa,0x79f8,0x79f6,0x79f7,0x7a8f, 0x7a94,0x7a90,0x7b35,0x7b47,0x7b34,0x7b25,0x7b30,0x7b22,0x7b24,0x7b33, 0x7b18,0x7b2a,0x7b1d,0x7b31,0x7b2b,0x7b2d,0x7b2f,0x7b32,0x7b38,0x7b1a, 0x7b23,0x7c94,0x7c98,0x7c96,0x7ca3,0x7d35,0x7d3d,0x7d38,0x7d36,0x7d3a, 0x7d45,0x7d2c,0x7d29,0x7d41,0x7d47,0x7d3e,0x7d3f,0x7d4a,0x7d3b,0x7d28, 0x7f63,0x7f95,0x7f9c,0x7f9d,0x7f9b,0x7fca,0x7fcb,0x7fcd,0x7fd0,0x7fd1, 0x7fc7,0x7fcf,0x7fc9,0x801f } }, { /* ku 37 */ { 0x801e,0x801b,0x8047,0x8043,0x8048,0x8118,0x8125,0x8119,0x811b,0x812d, 0x811f,0x812c,0x811e,0x8121,0x8115,0x8127,0x811d,0x8122,0x8211,0x8238, 0x8233,0x823a,0x8234,0x8232,0x8274,0x8390,0x83a3,0x83a8,0x838d,0x837a, 0x8373,0x83a4,0x8374,0x838f,0x8381,0x8395,0x8399,0x8375,0x8394,0x83a9, 0x837d,0x8383,0x838c,0x839d,0x839b,0x83aa,0x838b,0x837e,0x83a5,0x83af, 0x8388,0x8397,0x83b0,0x837f,0x83a6,0x8387,0x83ae,0x8376,0x839a,0x8659, 0x8656,0x86bf,0x86b7 },{ 0x86c2,0x86c1,0x86c5,0x86ba,0x86b0,0x86c8,0x86b9,0x86b3,0x86b8,0x86cc, 0x86b4,0x86bb,0x86bc,0x86c3,0x86bd,0x86be,0x8852,0x8889,0x8895,0x88a8, 0x88a2,0x88aa,0x889a,0x8891,0x88a1,0x889f,0x8898,0x88a7,0x8899,0x889b, 0x8897,0x88a4,0x88ac,0x888c,0x8893,0x888e,0x8982,0x89d6,0x89d9,0x89d5, 0x8a30,0x8a27,0x8a2c,0x8a1e,0x8c39,0x8c3b,0x8c5c,0x8c5d,0x8c7d,0x8ca5, 0x8d7d,0x8d7b,0x8d79,0x8dbc,0x8dc2,0x8db9,0x8dbf,0x8dc1,0x8ed8,0x8ede, 0x8edd,0x8edc,0x8ed7,0x8ee0,0x8ee1,0x9024,0x900b,0x9011,0x901c,0x900c, 0x9021,0x90ef,0x90ea,0x90f0,0x90f4,0x90f2,0x90f3,0x90d4,0x90eb,0x90ec, 0x90e9,0x9156,0x9158,0x915a,0x9153,0x9155,0x91ec,0x91f4,0x91f1,0x91f3, 0x91f8,0x91e4,0x91f9,0x91ea } }, { /* ku 38 */ { 0x91eb,0x91f7,0x91e8,0x91ee,0x957a,0x9586,0x9588,0x967c,0x966d,0x966b, 0x9671,0x966f,0x96bf,0x976a,0x9804,0x98e5,0x9997,0x509b,0x5095,0x5094, 0x509e,0x508b,0x50a3,0x5083,0x508c,0x508e,0x509d,0x5068,0x509c,0x5092, 0x5082,0x5087,0x515f,0x51d4,0x5312,0x5311,0x53a4,0x53a7,0x5591,0x55a8, 0x55a5,0x55ad,0x5577,0x5645,0x55a2,0x5593,0x5588,0x558f,0x55b5,0x5581, 0x55a3,0x5592,0x55a4,0x557d,0x558c,0x55a6,0x557f,0x5595,0x55a1,0x558e, 0x570c,0x5829,0x5837 },{ 0x5819,0x581e,0x5827,0x5823,0x5828,0x57f5,0x5848,0x5825,0x581c,0x581b, 0x5833,0x583f,0x5836,0x582e,0x5839,0x5838,0x582d,0x582c,0x583b,0x5961, 0x5aaf,0x5a94,0x5a9f,0x5a7a,0x5aa2,0x5a9e,0x5a78,0x5aa6,0x5a7c,0x5aa5, 0x5aac,0x5a95,0x5aae,0x5a37,0x5a84,0x5a8a,0x5a97,0x5a83,0x5a8b,0x5aa9, 0x5a7b,0x5a7d,0x5a8c,0x5a9c,0x5a8f,0x5a93,0x5a9d,0x5bea,0x5bcd,0x5bcb, 0x5bd4,0x5bd1,0x5bca,0x5bce,0x5c0c,0x5c30,0x5d37,0x5d43,0x5d6b,0x5d41, 0x5d4b,0x5d3f,0x5d35,0x5d51,0x5d4e,0x5d55,0x5d33,0x5d3a,0x5d52,0x5d3d, 0x5d31,0x5d59,0x5d42,0x5d39,0x5d49,0x5d38,0x5d3c,0x5d32,0x5d36,0x5d40, 0x5d45,0x5e44,0x5e41,0x5f58,0x5fa6,0x5fa5,0x5fab,0x60c9,0x60b9,0x60cc, 0x60e2,0x60ce,0x60c4,0x6114 } }, { /* ku 39 */ { 0x60f2,0x610a,0x6116,0x6105,0x60f5,0x6113,0x60f8,0x60fc,0x60fe,0x60c1, 0x6103,0x6118,0x611d,0x6110,0x60ff,0x6104,0x610b,0x624a,0x6394,0x63b1, 0x63b0,0x63ce,0x63e5,0x63e8,0x63ef,0x63c3,0x649d,0x63f3,0x63ca,0x63e0, 0x63f6,0x63d5,0x63f2,0x63f5,0x6461,0x63df,0x63be,0x63dd,0x63dc,0x63c4, 0x63d8,0x63d3,0x63c2,0x63c7,0x63cc,0x63cb,0x63c8,0x63f0,0x63d7,0x63d9, 0x6532,0x6567,0x656a,0x6564,0x655c,0x6568,0x6565,0x658c,0x659d,0x659e, 0x65ae,0x65d0,0x65d2 },{ 0x667c,0x666c,0x667b,0x6680,0x6671,0x6679,0x666a,0x6672,0x6701,0x690c, 0x68d3,0x6904,0x68dc,0x692a,0x68ec,0x68ea,0x68f1,0x690f,0x68d6,0x68f7, 0x68eb,0x68e4,0x68f6,0x6913,0x6910,0x68f3,0x68e1,0x6907,0x68cc,0x6908, 0x6970,0x68b4,0x6911,0x68ef,0x68c6,0x6914,0x68f8,0x68d0,0x68fd,0x68fc, 0x68e8,0x690b,0x690a,0x6917,0x68ce,0x68c8,0x68dd,0x68de,0x68e6,0x68f4, 0x68d1,0x6906,0x68d4,0x68e9,0x6915,0x6925,0x68c7,0x6b39,0x6b3b,0x6b3f, 0x6b3c,0x6b94,0x6b97,0x6b99,0x6b95,0x6bbd,0x6bf0,0x6bf2,0x6bf3,0x6c30, 0x6dfc,0x6e46,0x6e47,0x6e1f,0x6e49,0x6e88,0x6e3c,0x6e3d,0x6e45,0x6e62, 0x6e2b,0x6e3f,0x6e41,0x6e5d,0x6e73,0x6e1c,0x6e33,0x6e4b,0x6e40,0x6e51, 0x6e3b,0x6e03,0x6e2e,0x6e5e } }, { /* ku 3a */ { 0x6e68,0x6e5c,0x6e61,0x6e31,0x6e28,0x6e60,0x6e71,0x6e6b,0x6e39,0x6e22, 0x6e30,0x6e53,0x6e65,0x6e27,0x6e78,0x6e64,0x6e77,0x6e55,0x6e79,0x6e52, 0x6e66,0x6e35,0x6e36,0x6e5a,0x7120,0x711e,0x712f,0x70fb,0x712e,0x7131, 0x7123,0x7125,0x7122,0x7132,0x711f,0x7128,0x713a,0x711b,0x724b,0x725a, 0x7288,0x7289,0x7286,0x7285,0x728b,0x7312,0x730b,0x7330,0x7322,0x7331, 0x7333,0x7327,0x7332,0x732d,0x7326,0x7323,0x7335,0x730c,0x742e,0x742c, 0x7430,0x742b,0x7416 },{ 0x741a,0x7421,0x742d,0x7431,0x7424,0x7423,0x741d,0x7429,0x7420,0x7432, 0x74fb,0x752f,0x756f,0x756c,0x75e7,0x75da,0x75e1,0x75e6,0x75dd,0x75df, 0x75e4,0x75d7,0x7695,0x7692,0x76da,0x7746,0x7747,0x7744,0x774d,0x7745, 0x774a,0x774e,0x774b,0x774c,0x77de,0x77ec,0x7860,0x7864,0x7865,0x785c, 0x786d,0x7871,0x786a,0x786e,0x7870,0x7869,0x7868,0x785e,0x7862,0x7974, 0x7973,0x7972,0x7970,0x7a02,0x7a0a,0x7a03,0x7a0c,0x7a04,0x7a99,0x7ae6, 0x7ae4,0x7b4a,0x7b3b,0x7b44,0x7b48,0x7b4c,0x7b4e,0x7b40,0x7b58,0x7b45, 0x7ca2,0x7c9e,0x7ca8,0x7ca1,0x7d58,0x7d6f,0x7d63,0x7d53,0x7d56,0x7d67, 0x7d6a,0x7d4f,0x7d6d,0x7d5c,0x7d6b,0x7d52,0x7d54,0x7d69,0x7d51,0x7d5f, 0x7d4e,0x7f3e,0x7f3f,0x7f65 } }, { /* ku 3b */ { 0x7f66,0x7fa2,0x7fa0,0x7fa1,0x7fd7,0x8051,0x804f,0x8050,0x80fe,0x80d4, 0x8143,0x814a,0x8152,0x814f,0x8147,0x813d,0x814d,0x813a,0x81e6,0x81ee, 0x81f7,0x81f8,0x81f9,0x8204,0x823c,0x823d,0x823f,0x8275,0x833b,0x83cf, 0x83f9,0x8423,0x83c0,0x83e8,0x8412,0x83e7,0x83e4,0x83fc,0x83f6,0x8410, 0x83c6,0x83c8,0x83eb,0x83e3,0x83bf,0x8401,0x83dd,0x83e5,0x83d8,0x83ff, 0x83e1,0x83cb,0x83ce,0x83d6,0x83f5,0x83c9,0x8409,0x840f,0x83de,0x8411, 0x8406,0x83c2,0x83f3 },{ 0x83d5,0x83fa,0x83c7,0x83d1,0x83ea,0x8413,0x83c3,0x83ec,0x83ee,0x83c4, 0x83fb,0x83d7,0x83e2,0x841b,0x83db,0x83fe,0x86d8,0x86e2,0x86e6,0x86d3, 0x86e3,0x86da,0x86ea,0x86dd,0x86eb,0x86dc,0x86ec,0x86e9,0x86d7,0x86e8, 0x86d1,0x8848,0x8856,0x8855,0x88ba,0x88d7,0x88b9,0x88b8,0x88c0,0x88be, 0x88b6,0x88bc,0x88b7,0x88bd,0x88b2,0x8901,0x88c9,0x8995,0x8998,0x8997, 0x89dd,0x89da,0x89db,0x8a4e,0x8a4d,0x8a39,0x8a59,0x8a40,0x8a57,0x8a58, 0x8a44,0x8a45,0x8a52,0x8a48,0x8a51,0x8a4a,0x8a4c,0x8a4f,0x8c5f,0x8c81, 0x8c80,0x8cba,0x8cbe,0x8cb0,0x8cb9,0x8cb5,0x8d84,0x8d80,0x8d89,0x8dd8, 0x8dd3,0x8dcd,0x8dc7,0x8dd6,0x8ddc,0x8dcf,0x8dd5,0x8dd9,0x8dc8,0x8dd7, 0x8dc5,0x8eef,0x8ef7,0x8efa } }, { /* ku 3c */ { 0x8ef9,0x8ee6,0x8eee,0x8ee5,0x8ef5,0x8ee7,0x8ee8,0x8ef6,0x8eeb,0x8ef1, 0x8eec,0x8ef4,0x8ee9,0x902d,0x9034,0x902f,0x9106,0x912c,0x9104,0x90ff, 0x90fc,0x9108,0x90f9,0x90fb,0x9101,0x9100,0x9107,0x9105,0x9103,0x9161, 0x9164,0x915f,0x9162,0x9160,0x9201,0x920a,0x9225,0x9203,0x921a,0x9226, 0x920f,0x920c,0x9200,0x9212,0x91ff,0x91fd,0x9206,0x9204,0x9227,0x9202, 0x921c,0x9224,0x9219,0x9217,0x9205,0x9216,0x957b,0x958d,0x958c,0x9590, 0x9687,0x967e,0x9688 },{ 0x9689,0x9683,0x9680,0x96c2,0x96c8,0x96c3,0x96f1,0x96f0,0x976c,0x9770, 0x976e,0x9807,0x98a9,0x98eb,0x9ce6,0x9ef9,0x4e83,0x4e84,0x4eb6,0x50bd, 0x50bf,0x50c6,0x50ae,0x50c4,0x50ca,0x50b4,0x50c8,0x50c2,0x50b0,0x50c1, 0x50ba,0x50b1,0x50cb,0x50c9,0x50b6,0x50b8,0x51d7,0x527a,0x5278,0x527b, 0x527c,0x55c3,0x55db,0x55cc,0x55d0,0x55cb,0x55ca,0x55dd,0x55c0,0x55d4, 0x55c4,0x55e9,0x55bf,0x55d2,0x558d,0x55cf,0x55d5,0x55e2,0x55d6,0x55c8, 0x55f2,0x55cd,0x55d9,0x55c2,0x5714,0x5853,0x5868,0x5864,0x584f,0x584d, 0x5849,0x586f,0x5855,0x584e,0x585d,0x5859,0x5865,0x585b,0x583d,0x5863, 0x5871,0x58fc,0x5ac7,0x5ac4,0x5acb,0x5aba,0x5ab8,0x5ab1,0x5ab5,0x5ab0, 0x5abf,0x5ac8,0x5abb,0x5ac6 } }, { /* ku 3d */ { 0x5ab7,0x5ac0,0x5aca,0x5ab4,0x5ab6,0x5acd,0x5ab9,0x5a90,0x5bd6,0x5bd8, 0x5bd9,0x5c1f,0x5c33,0x5d71,0x5d63,0x5d4a,0x5d65,0x5d72,0x5d6c,0x5d5e, 0x5d68,0x5d67,0x5d62,0x5df0,0x5e4f,0x5e4e,0x5e4a,0x5e4d,0x5e4b,0x5ec5, 0x5ecc,0x5ec6,0x5ecb,0x5ec7,0x5f40,0x5faf,0x5fad,0x60f7,0x6149,0x614a, 0x612b,0x6145,0x6136,0x6132,0x612e,0x6146,0x612f,0x614f,0x6129,0x6140, 0x6220,0x9168,0x6223,0x6225,0x6224,0x63c5,0x63f1,0x63eb,0x6410,0x6412, 0x6409,0x6420,0x6424 },{ 0x6433,0x6443,0x641f,0x6415,0x6418,0x6439,0x6437,0x6422,0x6423,0x640c, 0x6426,0x6430,0x6428,0x6441,0x6435,0x642f,0x640a,0x641a,0x6440,0x6425, 0x6427,0x640b,0x63e7,0x641b,0x642e,0x6421,0x640e,0x656f,0x6592,0x65d3, 0x6686,0x668c,0x6695,0x6690,0x668b,0x668a,0x6699,0x6694,0x6678,0x6720, 0x6966,0x695f,0x6938,0x694e,0x6962,0x6971,0x693f,0x6945,0x696a,0x6939, 0x6942,0x6957,0x6959,0x697a,0x6948,0x6949,0x6935,0x696c,0x6933,0x693d, 0x6965,0x68f0,0x6978,0x6934,0x6969,0x6940,0x696f,0x6944,0x6976,0x6958, 0x6941,0x6974,0x694c,0x693b,0x694b,0x6937,0x695c,0x694f,0x6951,0x6932, 0x6952,0x692f,0x697b,0x693c,0x6b46,0x6b45,0x6b43,0x6b42,0x6b48,0x6b41, 0x6b9b,0xfa0d,0x6bfb,0x6bfc } }, { /* ku 3e */ { 0x6bf9,0x6bf7,0x6bf8,0x6e9b,0x6ed6,0x6ec8,0x6e8f,0x6ec0,0x6e9f,0x6e93, 0x6e94,0x6ea0,0x6eb1,0x6eb9,0x6ec6,0x6ed2,0x6ebd,0x6ec1,0x6e9e,0x6ec9, 0x6eb7,0x6eb0,0x6ecd,0x6ea6,0x6ecf,0x6eb2,0x6ebe,0x6ec3,0x6edc,0x6ed8, 0x6e99,0x6e92,0x6e8e,0x6e8d,0x6ea4,0x6ea1,0x6ebf,0x6eb3,0x6ed0,0x6eca, 0x6e97,0x6eae,0x6ea3,0x7147,0x7154,0x7152,0x7163,0x7160,0x7141,0x715d, 0x7162,0x7172,0x7178,0x716a,0x7161,0x7142,0x7158,0x7143,0x714b,0x7170, 0x715f,0x7150,0x7153 },{ 0x7144,0x714d,0x715a,0x724f,0x728d,0x728c,0x7291,0x7290,0x728e,0x733c, 0x7342,0x733b,0x733a,0x7340,0x734a,0x7349,0x7444,0x744a,0x744b,0x7452, 0x7451,0x7457,0x7440,0x744f,0x7450,0x744e,0x7442,0x7446,0x744d,0x7454, 0x74e1,0x74ff,0x74fe,0x74fd,0x751d,0x7579,0x7577,0x6983,0x75ef,0x760f, 0x7603,0x75f7,0x75fe,0x75fc,0x75f9,0x75f8,0x7610,0x75fb,0x75f6,0x75ed, 0x75f5,0x75fd,0x7699,0x76b5,0x76dd,0x7755,0x775f,0x7760,0x7752,0x7756, 0x775a,0x7769,0x7767,0x7754,0x7759,0x776d,0x77e0,0x7887,0x789a,0x7894, 0x788f,0x7884,0x7895,0x7885,0x7886,0x78a1,0x7883,0x7879,0x7899,0x7880, 0x7896,0x787b,0x797c,0x7982,0x797d,0x7979,0x7a11,0x7a18,0x7a19,0x7a12, 0x7a17,0x7a15,0x7a22,0x7a13 } }, { /* ku 3f */ { 0x7a1b,0x7a10,0x7aa3,0x7aa2,0x7a9e,0x7aeb,0x7b66,0x7b64,0x7b6d,0x7b74, 0x7b69,0x7b72,0x7b65,0x7b73,0x7b71,0x7b70,0x7b61,0x7b78,0x7b76,0x7b63, 0x7cb2,0x7cb4,0x7caf,0x7d88,0x7d86,0x7d80,0x7d8d,0x7d7f,0x7d85,0x7d7a, 0x7d8e,0x7d7b,0x7d83,0x7d7c,0x7d8c,0x7d94,0x7d84,0x7d7d,0x7d92,0x7f6d, 0x7f6b,0x7f67,0x7f68,0x7f6c,0x7fa6,0x7fa5,0x7fa7,0x7fdb,0x7fdc,0x8021, 0x8164,0x8160,0x8177,0x815c,0x8169,0x815b,0x8162,0x8172,0x6721,0x815e, 0x8176,0x8167,0x816f },{ 0x8144,0x8161,0x821d,0x8249,0x8244,0x8240,0x8242,0x8245,0x84f1,0x843f, 0x8456,0x8476,0x8479,0x848f,0x848d,0x8465,0x8451,0x8440,0x8486,0x8467, 0x8430,0x844d,0x847d,0x845a,0x8459,0x8474,0x8473,0x845d,0x8507,0x845e, 0x8437,0x843a,0x8434,0x847a,0x8443,0x8478,0x8432,0x8445,0x8429,0x83d9, 0x844b,0x842f,0x8442,0x842d,0x845f,0x8470,0x8439,0x844e,0x844c,0x8452, 0x846f,0x84c5,0x848e,0x843b,0x8447,0x8436,0x8433,0x8468,0x847e,0x8444, 0x842b,0x8460,0x8454,0x846e,0x8450,0x870b,0x8704,0x86f7,0x870c,0x86fa, 0x86d6,0x86f5,0x874d,0x86f8,0x870e,0x8709,0x8701,0x86f6,0x870d,0x8705, 0x88d6,0x88cb,0x88cd,0x88ce,0x88de,0x88db,0x88da,0x88cc,0x88d0,0x8985, 0x899b,0x89df,0x89e5,0x89e4 } }, { /* ku 40 */ { 0x89e1,0x89e0,0x89e2,0x89dc,0x89e6,0x8a76,0x8a86,0x8a7f,0x8a61,0x8a3f, 0x8a77,0x8a82,0x8a84,0x8a75,0x8a83,0x8a81,0x8a74,0x8a7a,0x8c3c,0x8c4b, 0x8c4a,0x8c65,0x8c64,0x8c66,0x8c86,0x8c84,0x8c85,0x8ccc,0x8d68,0x8d69, 0x8d91,0x8d8c,0x8d8e,0x8d8f,0x8d8d,0x8d93,0x8d94,0x8d90,0x8d92,0x8df0, 0x8de0,0x8dec,0x8df1,0x8dee,0x8dd0,0x8de9,0x8de3,0x8de2,0x8de7,0x8df2, 0x8deb,0x8df4,0x8f06,0x8eff,0x8f01,0x8f00,0x8f05,0x8f07,0x8f08,0x8f02, 0x8f0b,0x9052,0x903f },{ 0x9044,0x9049,0x903d,0x9110,0x910d,0x910f,0x9111,0x9116,0x9114,0x910b, 0x910e,0x916e,0x916f,0x9248,0x9252,0x9230,0x923a,0x9266,0x9233,0x9265, 0x925e,0x9283,0x922e,0x924a,0x9246,0x926d,0x926c,0x924f,0x9260,0x9267, 0x926f,0x9236,0x9261,0x9270,0x9231,0x9254,0x9263,0x9250,0x9272,0x924e, 0x9253,0x924c,0x9256,0x9232,0x959f,0x959c,0x959e,0x959b,0x9692,0x9693, 0x9691,0x9697,0x96ce,0x96fa,0x96fd,0x96f8,0x96f5,0x9773,0x9777,0x9778, 0x9772,0x980f,0x980d,0x980e,0x98ac,0x98f6,0x98f9,0x99af,0x99b2,0x99b0, 0x99b5,0x9aad,0x9aab,0x9b5b,0x9cea,0x9ced,0x9ce7,0x9e80,0x9efd,0x50e6, 0x50d4,0x50d7,0x50e8,0x50f3,0x50db,0x50ea,0x50dd,0x50e4,0x50d3,0x50ec, 0x50f0,0x50ef,0x50e3,0x50e0 } }, { /* ku 41 */ { 0x51d8,0x5280,0x5281,0x52e9,0x52eb,0x5330,0x53ac,0x5627,0x5615,0x560c, 0x5612,0x55fc,0x560f,0x561c,0x5601,0x5613,0x5602,0x55fa,0x561d,0x5604, 0x55ff,0x55f9,0x5889,0x587c,0x5890,0x5898,0x5886,0x5881,0x587f,0x5874, 0x588b,0x587a,0x5887,0x5891,0x588e,0x5876,0x5882,0x5888,0x587b,0x5894, 0x588f,0x58fe,0x596b,0x5adc,0x5aee,0x5ae5,0x5ad5,0x5aea,0x5ada,0x5aed, 0x5aeb,0x5af3,0x5ae2,0x5ae0,0x5adb,0x5aec,0x5ade,0x5add,0x5ad9,0x5ae8, 0x5adf,0x5b77,0x5be0 },{ 0x5be3,0x5c63,0x5d82,0x5d80,0x5d7d,0x5d86,0x5d7a,0x5d81,0x5d77,0x5d8a, 0x5d89,0x5d88,0x5d7e,0x5d7c,0x5d8d,0x5d79,0x5d7f,0x5e58,0x5e59,0x5e53, 0x5ed8,0x5ed1,0x5ed7,0x5ece,0x5edc,0x5ed5,0x5ed9,0x5ed2,0x5ed4,0x5f44, 0x5f43,0x5f6f,0x5fb6,0x612c,0x6128,0x6141,0x615e,0x6171,0x6173,0x6152, 0x6153,0x6172,0x616c,0x6180,0x6174,0x6154,0x617a,0x615b,0x6165,0x613b, 0x616a,0x6161,0x6156,0x6229,0x6227,0x622b,0x642b,0x644d,0x645b,0x645d, 0x6474,0x6476,0x6472,0x6473,0x647d,0x6475,0x6466,0x64a6,0x644e,0x6482, 0x645e,0x645c,0x644b,0x6453,0x6460,0x6450,0x647f,0x643f,0x646c,0x646b, 0x6459,0x6465,0x6477,0x6573,0x65a0,0x66a1,0x66a0,0x669f,0x6705,0x6704, 0x6722,0x69b1,0x69b6,0x69c9 } }, { /* ku 42 */ { 0x69a0,0x69ce,0x6996,0x69b0,0x69ac,0x69bc,0x6991,0x6999,0x698e,0x69a7, 0x698d,0x69a9,0x69be,0x69af,0x69bf,0x69c4,0x69bd,0x69a4,0x69d4,0x69b9, 0x69ca,0x699a,0x69cf,0x69b3,0x6993,0x69aa,0x69a1,0x699e,0x69d9,0x6997, 0x6990,0x69c2,0x69b5,0x69a5,0x69c6,0x6b4a,0x6b4d,0x6b4b,0x6b9e,0x6b9f, 0x6ba0,0x6bc3,0x6bc4,0x6bfe,0x6ece,0x6ef5,0x6ef1,0x6f03,0x6f25,0x6ef8, 0x6f37,0x6efb,0x6f2e,0x6f09,0x6f4e,0x6f19,0x6f1a,0x6f27,0x6f18,0x6f3b, 0x6f12,0x6eed,0x6f0a },{ 0x6f36,0x6f73,0x6ef9,0x6eee,0x6f2d,0x6f40,0x6f30,0x6f3c,0x6f35,0x6eeb, 0x6f07,0x6f0e,0x6f43,0x6f05,0x6efd,0x6ef6,0x6f39,0x6f1c,0x6efc,0x6f3a, 0x6f1f,0x6f0d,0x6f1e,0x6f08,0x6f21,0x7187,0x7190,0x7189,0x7180,0x7185, 0x7182,0x718f,0x717b,0x7186,0x7181,0x7197,0x7244,0x7253,0x7297,0x7295, 0x7293,0x7343,0x734d,0x7351,0x734c,0x7462,0x7473,0x7471,0x7475,0x7472, 0x7467,0x746e,0x7500,0x7502,0x7503,0x757d,0x7590,0x7616,0x7608,0x760c, 0x7615,0x7611,0x760a,0x7614,0x76b8,0x7781,0x777c,0x7785,0x7782,0x776e, 0x7780,0x776f,0x777e,0x7783,0x78b2,0x78aa,0x78b4,0x78ad,0x78a8,0x787e, 0x78ab,0x789e,0x78a5,0x78a0,0x78ac,0x78a2,0x78a4,0x7998,0x798a,0x798b, 0x7996,0x7995,0x7994,0x7993 } }, { /* ku 43 */ { 0x7997,0x7988,0x7992,0x7990,0x7a2b,0x7a4a,0x7a30,0x7a2f,0x7a28,0x7a26, 0x7aa8,0x7aab,0x7aac,0x7aee,0x7b88,0x7b9c,0x7b8a,0x7b91,0x7b90,0x7b96, 0x7b8d,0x7b8c,0x7b9b,0x7b8e,0x7b85,0x7b98,0x5284,0x7b99,0x7ba4,0x7b82, 0x7cbb,0x7cbf,0x7cbc,0x7cba,0x7da7,0x7db7,0x7dc2,0x7da3,0x7daa,0x7dc1, 0x7dc0,0x7dc5,0x7d9d,0x7dce,0x7dc4,0x7dc6,0x7dcb,0x7dcc,0x7daf,0x7db9, 0x7d96,0x7dbc,0x7d9f,0x7da6,0x7dae,0x7da9,0x7da1,0x7dc9,0x7f73,0x7fe2, 0x7fe3,0x7fe5,0x7fde },{ 0x8024,0x805d,0x805c,0x8189,0x8186,0x8183,0x8187,0x818d,0x818c,0x818b, 0x8215,0x8497,0x84a4,0x84a1,0x849f,0x84ba,0x84ce,0x84c2,0x84ac,0x84ae, 0x84ab,0x84b9,0x84b4,0x84c1,0x84cd,0x84aa,0x849a,0x84b1,0x84d0,0x849d, 0x84a7,0x84bb,0x84a2,0x8494,0x84c7,0x84cc,0x849b,0x84a9,0x84af,0x84a8, 0x84d6,0x8498,0x84b6,0x84cf,0x84a0,0x84d7,0x84d4,0x84d2,0x84db,0x84b0, 0x8491,0x8661,0x8733,0x8723,0x8728,0x876b,0x8740,0x872e,0x871e,0x8721, 0x8719,0x871b,0x8743,0x872c,0x8741,0x873e,0x8746,0x8720,0x8732,0x872a, 0x872d,0x873c,0x8712,0x873a,0x8731,0x8735,0x8742,0x8726,0x8727,0x8738, 0x8724,0x871a,0x8730,0x8711,0x88f7,0x88e7,0x88f1,0x88f2,0x88fa,0x88fe, 0x88ee,0x88fc,0x88f6,0x88fb } }, { /* ku 44 */ { 0x88f0,0x88ec,0x88eb,0x899d,0x89a1,0x899f,0x899e,0x89e9,0x89eb,0x89e8, 0x8aab,0x8a99,0x8a8b,0x8a92,0x8a8f,0x8a96,0x8c3d,0x8c68,0x8c69,0x8cd5, 0x8ccf,0x8cd7,0x8d96,0x8e09,0x8e02,0x8dff,0x8e0d,0x8dfd,0x8e0a,0x8e03, 0x8e07,0x8e06,0x8e05,0x8dfe,0x8e00,0x8e04,0x8f10,0x8f11,0x8f0e,0x8f0d, 0x9123,0x911c,0x9120,0x9122,0x911f,0x911d,0x911a,0x9124,0x9121,0x911b, 0x917a,0x9172,0x9179,0x9173,0x92a5,0x92a4,0x9276,0x929b,0x927a,0x92a0, 0x9294,0x92aa,0x928d },{ 0x92a6,0x929a,0x92ab,0x9279,0x9297,0x927f,0x92a3,0x92ee,0x928e,0x9282, 0x9295,0x92a2,0x927d,0x9288,0x92a1,0x928a,0x9286,0x928c,0x9299,0x92a7, 0x927e,0x9287,0x92a9,0x929d,0x928b,0x922d,0x969e,0x96a1,0x96ff,0x9758, 0x977d,0x977a,0x977e,0x9783,0x9780,0x9782,0x977b,0x9784,0x9781,0x977f, 0x97ce,0x97cd,0x9816,0x98ad,0x98ae,0x9902,0x9900,0x9907,0x999d,0x999c, 0x99c3,0x99b9,0x99bb,0x99ba,0x99c2,0x99bd,0x99c7,0x9ab1,0x9ae3,0x9ae7, 0x9b3e,0x9b3f,0x9b60,0x9b61,0x9b5f,0x9cf1,0x9cf2,0x9cf5,0x9ea7,0x50ff, 0x5103,0x5130,0x50f8,0x5106,0x5107,0x50f6,0x50fe,0x510b,0x510c,0x50fd, 0x510a,0x528b,0x528c,0x52f1,0x52ef,0x5648,0x5642,0x564c,0x5635,0x5641, 0x564a,0x5649,0x5646,0x5658 } }, { /* ku 45 */ { 0x565a,0x5640,0x5633,0x563d,0x562c,0x563e,0x5638,0x562a,0x563a,0x571a, 0x58ab,0x589d,0x58b1,0x58a0,0x58a3,0x58af,0x58ac,0x58a5,0x58a1,0x58ff, 0x5aff,0x5af4,0x5afd,0x5af7,0x5af6,0x5b03,0x5af8,0x5b02,0x5af9,0x5b01, 0x5b07,0x5b05,0x5b0f,0x5c67,0x5d99,0x5d97,0x5d9f,0x5d92,0x5da2,0x5d93, 0x5d95,0x5da0,0x5d9c,0x5da1,0x5d9a,0x5d9e,0x5e69,0x5e5d,0x5e60,0x5e5c, 0x7df3,0x5edb,0x5ede,0x5ee1,0x5f49,0x5fb2,0x618b,0x6183,0x6179,0x61b1, 0x61b0,0x61a2,0x6189 },{ 0x619b,0x6193,0x61af,0x61ad,0x619f,0x6192,0x61aa,0x61a1,0x618d,0x6166, 0x61b3,0x622d,0x646e,0x6470,0x6496,0x64a0,0x6485,0x6497,0x649c,0x648f, 0x648b,0x648a,0x648c,0x64a3,0x649f,0x6468,0x64b1,0x6498,0x6576,0x657a, 0x6579,0x657b,0x65b2,0x65b3,0x66b5,0x66b0,0x66a9,0x66b2,0x66b7,0x66aa, 0x66af,0x6a00,0x6a06,0x6a17,0x69e5,0x69f8,0x6a15,0x69f1,0x69e4,0x6a20, 0x69ff,0x69ec,0x69e2,0x6a1b,0x6a1d,0x69fe,0x6a27,0x69f2,0x69ee,0x6a14, 0x69f7,0x69e7,0x6a40,0x6a08,0x69e6,0x69fb,0x6a0d,0x69fc,0x69eb,0x6a09, 0x6a04,0x6a18,0x6a25,0x6a0f,0x69f6,0x6a26,0x6a07,0x69f4,0x6a16,0x6b51, 0x6ba5,0x6ba3,0x6ba2,0x6ba6,0x6c01,0x6c00,0x6bff,0x6c02,0x6f41,0x6f26, 0x6f7e,0x6f87,0x6fc6,0x6f92 } }, { /* ku 46 */ { 0x6f8d,0x6f89,0x6f8c,0x6f62,0x6f4f,0x6f85,0x6f5a,0x6f96,0x6f76,0x6f6c, 0x6f82,0x6f55,0x6f72,0x6f52,0x6f50,0x6f57,0x6f94,0x6f93,0x6f5d,0x6f00, 0x6f61,0x6f6b,0x6f7d,0x6f67,0x6f90,0x6f53,0x6f8b,0x6f69,0x6f7f,0x6f95, 0x6f63,0x6f77,0x6f6a,0x6f7b,0x71b2,0x71af,0x719b,0x71b0,0x71a0,0x719a, 0x71a9,0x71b5,0x719d,0x71a5,0x719e,0x71a4,0x71a1,0x71aa,0x719c,0x71a7, 0x71b3,0x7298,0x729a,0x7358,0x7352,0x735e,0x735f,0x7360,0x735d,0x735b, 0x7361,0x735a,0x7359 },{ 0x7362,0x7487,0x7489,0x748a,0x7486,0x7481,0x747d,0x7485,0x7488,0x747c, 0x7479,0x7508,0x7507,0x757e,0x7625,0x761e,0x7619,0x761d,0x761c,0x7623, 0x761a,0x7628,0x761b,0x769c,0x769d,0x769e,0x769b,0x778d,0x778f,0x7789, 0x7788,0x78cd,0x78bb,0x78cf,0x78cc,0x78d1,0x78ce,0x78d4,0x78c8,0x78c3, 0x78c4,0x78c9,0x799a,0x79a1,0x79a0,0x799c,0x79a2,0x799b,0x6b76,0x7a39, 0x7ab2,0x7ab4,0x7ab3,0x7bb7,0x7bcb,0x7bbe,0x7bac,0x7bce,0x7baf,0x7bb9, 0x7bca,0x7bb5,0x7cc5,0x7cc8,0x7ccc,0x7ccb,0x7df7,0x7ddb,0x7dea,0x7de7, 0x7dd7,0x7de1,0x7e03,0x7dfa,0x7de6,0x7df6,0x7df1,0x7df0,0x7dee,0x7ddf, 0x7f76,0x7fac,0x7fb0,0x7fad,0x7fed,0x7feb,0x7fea,0x7fec,0x7fe6,0x7fe8, 0x8064,0x8067,0x81a3,0x819f } }, { /* ku 47 */ { 0x819e,0x8195,0x81a2,0x8199,0x8197,0x8216,0x824f,0x8253,0x8252,0x8250, 0x824e,0x8251,0x8524,0x853b,0x850f,0x8500,0x8529,0x850e,0x8509,0x850d, 0x851f,0x850a,0x8527,0x851c,0x84fb,0x852b,0x84fa,0x8508,0x850c,0x84f4, 0x852a,0x84f2,0x8515,0x84f7,0x84eb,0x84f3,0x84fc,0x8512,0x84ea,0x84e9, 0x8516,0x84fe,0x8528,0x851d,0x852e,0x8502,0x84fd,0x851e,0x84f6,0x8531, 0x8526,0x84e7,0x84e8,0x84f0,0x84ef,0x84f9,0x8518,0x8520,0x8530,0x850b, 0x8519,0x852f,0x8662 },{ 0x8756,0x8763,0x8764,0x8777,0x87e1,0x8773,0x8758,0x8754,0x875b,0x8752, 0x8761,0x875a,0x8751,0x875e,0x876d,0x876a,0x8750,0x874e,0x875f,0x875d, 0x876f,0x876c,0x877a,0x876e,0x875c,0x8765,0x874f,0x877b,0x8775,0x8762, 0x8767,0x8769,0x885a,0x8905,0x890c,0x8914,0x890b,0x8917,0x8918,0x8919, 0x8906,0x8916,0x8911,0x890e,0x8909,0x89a2,0x89a4,0x89a3,0x89ed,0x89f0, 0x89ec,0x8acf,0x8ac6,0x8ab8,0x8ad3,0x8ad1,0x8ad4,0x8ad5,0x8abb,0x8ad7, 0x8abe,0x8ac0,0x8ac5,0x8ad8,0x8ac3,0x8aba,0x8abd,0x8ad9,0x8c3e,0x8c4d, 0x8c8f,0x8ce5,0x8cdf,0x8cd9,0x8ce8,0x8cda,0x8cdd,0x8ce7,0x8da0,0x8d9c, 0x8da1,0x8d9b,0x8e20,0x8e23,0x8e25,0x8e24,0x8e2e,0x8e15,0x8e1b,0x8e16, 0x8e11,0x8e19,0x8e26,0x8e27 } }, { /* ku 48 */ { 0x8e14,0x8e12,0x8e18,0x8e13,0x8e1c,0x8e17,0x8e1a,0x8f2c,0x8f24,0x8f18, 0x8f1a,0x8f20,0x8f23,0x8f16,0x8f17,0x9073,0x9070,0x906f,0x9067,0x906b, 0x912f,0x912b,0x9129,0x912a,0x9132,0x9126,0x912e,0x9185,0x9186,0x918a, 0x9181,0x9182,0x9184,0x9180,0x92d0,0x92c3,0x92c4,0x92c0,0x92d9,0x92b6, 0x92cf,0x92f1,0x92df,0x92d8,0x92e9,0x92d7,0x92dd,0x92cc,0x92ef,0x92c2, 0x92e8,0x92ca,0x92c8,0x92ce,0x92e6,0x92cd,0x92d5,0x92c9,0x92e0,0x92de, 0x92e7,0x92d1,0x92d3 },{ 0x92b5,0x92e1,0x92c6,0x92b4,0x957c,0x95ac,0x95ab,0x95ae,0x95b0,0x96a4, 0x96a2,0x96d3,0x9705,0x9708,0x9702,0x975a,0x978a,0x978e,0x9788,0x97d0, 0x97cf,0x981e,0x981d,0x9826,0x9829,0x9828,0x9820,0x981b,0x9827,0x98b2, 0x9908,0x98fa,0x9911,0x9914,0x9916,0x9917,0x9915,0x99dc,0x99cd,0x99cf, 0x99d3,0x99d4,0x99ce,0x99c9,0x99d6,0x99d8,0x99cb,0x99d7,0x99cc,0x9ab3, 0x9aec,0x9aeb,0x9af3,0x9af2,0x9af1,0x9b46,0x9b43,0x9b67,0x9b74,0x9b71, 0x9b66,0x9b76,0x9b75,0x9b70,0x9b68,0x9b64,0x9b6c,0x9cfc,0x9cfa,0x9cfd, 0x9cff,0x9cf7,0x9d07,0x9d00,0x9cf9,0x9cfb,0x9d08,0x9d05,0x9d04,0x9e83, 0x9ed3,0x9f0f,0x9f10,0x511c,0x5113,0x5117,0x511a,0x5111,0x51de,0x5334, 0x53e1,0x5670,0x5660,0x566e } }, { /* ku 49 */ { 0x5673,0x5666,0x5663,0x566d,0x5672,0x565e,0x5677,0x571c,0x571b,0x58c8, 0x58bd,0x58c9,0x58bf,0x58ba,0x58c2,0x58bc,0x58c6,0x5b17,0x5b19,0x5b1b, 0x5b21,0x5b14,0x5b13,0x5b10,0x5b16,0x5b28,0x5b1a,0x5b20,0x5b1e,0x5bef, 0x5dac,0x5db1,0x5da9,0x5da7,0x5db5,0x5db0,0x5dae,0x5daa,0x5da8,0x5db2, 0x5dad,0x5daf,0x5db4,0x5e67,0x5e68,0x5e66,0x5e6f,0x5ee9,0x5ee7,0x5ee6, 0x5ee8,0x5ee5,0x5f4b,0x5fbc,0x619d,0x61a8,0x6196,0x61c5,0x61b4,0x61c6, 0x61c1,0x61cc,0x61ba },{ 0x61bf,0x61b8,0x618c,0x64d7,0x64d6,0x64d0,0x64cf,0x64c9,0x64bd,0x6489, 0x64c3,0x64db,0x64f3,0x64d9,0x6533,0x657f,0x657c,0x65a2,0x66c8,0x66be, 0x66c0,0x66ca,0x66cb,0x66cf,0x66bd,0x66bb,0x66ba,0x66cc,0x6723,0x6a34, 0x6a66,0x6a49,0x6a67,0x6a32,0x6a68,0x6a3e,0x6a5d,0x6a6d,0x6a76,0x6a5b, 0x6a51,0x6a28,0x6a5a,0x6a3b,0x6a3f,0x6a41,0x6a6a,0x6a64,0x6a50,0x6a4f, 0x6a54,0x6a6f,0x6a69,0x6a60,0x6a3c,0x6a5e,0x6a56,0x6a55,0x6a4d,0x6a4e, 0x6a46,0x6b55,0x6b54,0x6b56,0x6ba7,0x6baa,0x6bab,0x6bc8,0x6bc7,0x6c04, 0x6c03,0x6c06,0x6fad,0x6fcb,0x6fa3,0x6fc7,0x6fbc,0x6fce,0x6fc8,0x6f5e, 0x6fc4,0x6fbd,0x6f9e,0x6fca,0x6fa8,0x7004,0x6fa5,0x6fae,0x6fba,0x6fac, 0x6faa,0x6fcf,0x6fbf,0x6fb8 } }, { /* ku 4a */ { 0x6fa2,0x6fc9,0x6fab,0x6fcd,0x6faf,0x6fb2,0x6fb0,0x71c5,0x71c2,0x71bf, 0x71b8,0x71d6,0x71c0,0x71c1,0x71cb,0x71d4,0x71ca,0x71c7,0x71cf,0x71bd, 0x71d8,0x71bc,0x71c6,0x71da,0x71db,0x729d,0x729e,0x7369,0x7366,0x7367, 0x736c,0x7365,0x736b,0x736a,0x747f,0x749a,0x74a0,0x7494,0x7492,0x7495, 0x74a1,0x750b,0x7580,0x762f,0x762d,0x7631,0x763d,0x7633,0x763c,0x7635, 0x7632,0x7630,0x76bb,0x76e6,0x779a,0x779d,0x77a1,0x779c,0x779b,0x77a2, 0x77a3,0x7795,0x7799 },{ 0x7797,0x78dd,0x78e9,0x78e5,0x78ea,0x78de,0x78e3,0x78db,0x78e1,0x78e2, 0x78ed,0x78df,0x78e0,0x79a4,0x7a44,0x7a48,0x7a47,0x7ab6,0x7ab8,0x7ab5, 0x7ab1,0x7ab7,0x7bde,0x7be3,0x7be7,0x7bdd,0x7bd5,0x7be5,0x7bda,0x7be8, 0x7bf9,0x7bd4,0x7bea,0x7be2,0x7bdc,0x7beb,0x7bd8,0x7bdf,0x7cd2,0x7cd4, 0x7cd7,0x7cd0,0x7cd1,0x7e12,0x7e21,0x7e17,0x7e0c,0x7e1f,0x7e20,0x7e13, 0x7e0e,0x7e1c,0x7e15,0x7e1a,0x7e22,0x7e0b,0x7e0f,0x7e16,0x7e0d,0x7e14, 0x7e25,0x7e24,0x7f43,0x7f7b,0x7f7c,0x7f7a,0x7fb1,0x7fef,0x802a,0x8029, 0x806c,0x81b1,0x81a6,0x81ae,0x81b9,0x81b5,0x81ab,0x81b0,0x81ac,0x81b4, 0x81b2,0x81b7,0x81a7,0x81f2,0x8255,0x8256,0x8257,0x8556,0x8545,0x856b, 0x854d,0x8553,0x8561,0x8558 } }, { /* ku 4b */ { 0x8540,0x8546,0x8564,0x8541,0x8562,0x8544,0x8551,0x8547,0x8563,0x853e, 0x855b,0x8571,0x854e,0x856e,0x8575,0x8555,0x8567,0x8560,0x858c,0x8566, 0x855d,0x8554,0x8565,0x856c,0x8663,0x8665,0x8664,0x879b,0x878f,0x8797, 0x8793,0x8792,0x8788,0x8781,0x8796,0x8798,0x8779,0x8787,0x87a3,0x8785, 0x8790,0x8791,0x879d,0x8784,0x8794,0x879c,0x879a,0x8789,0x891e,0x8926, 0x8930,0x892d,0x892e,0x8927,0x8931,0x8922,0x8929,0x8923,0x892f,0x892c, 0x891f,0x89f1,0x8ae0 },{ 0x8ae2,0x8af2,0x8af4,0x8af5,0x8add,0x8b14,0x8ae4,0x8adf,0x8af0,0x8ac8, 0x8ade,0x8ae1,0x8ae8,0x8aff,0x8aef,0x8afb,0x8c91,0x8c92,0x8c90,0x8cf5, 0x8cee,0x8cf1,0x8cf0,0x8cf3,0x8d6c,0x8d6e,0x8da5,0x8da7,0x8e33,0x8e3e, 0x8e38,0x8e40,0x8e45,0x8e36,0x8e3c,0x8e3d,0x8e41,0x8e30,0x8e3f,0x8ebd, 0x8f36,0x8f2e,0x8f35,0x8f32,0x8f39,0x8f37,0x8f34,0x9076,0x9079,0x907b, 0x9086,0x90fa,0x9133,0x9135,0x9136,0x9193,0x9190,0x9191,0x918d,0x918f, 0x9327,0x931e,0x9308,0x931f,0x9306,0x930f,0x937a,0x9338,0x933c,0x931b, 0x9323,0x9312,0x9301,0x9346,0x932d,0x930e,0x930d,0x92cb,0x931d,0x92fa, 0x9325,0x9313,0x92f9,0x92f7,0x9334,0x9302,0x9324,0x92ff,0x9329,0x9339, 0x9335,0x932a,0x9314,0x930c } }, { /* ku 4c */ { 0x930b,0x92fe,0x9309,0x9300,0x92fb,0x9316,0x95bc,0x95cd,0x95be,0x95b9, 0x95ba,0x95b6,0x95bf,0x95b5,0x95bd,0x96a9,0x96d4,0x970b,0x9712,0x9710, 0x9799,0x9797,0x9794,0x97f0,0x97f8,0x9835,0x982f,0x9832,0x9924,0x991f, 0x9927,0x9929,0x999e,0x99ee,0x99ec,0x99e5,0x99e4,0x99f0,0x99e3,0x99ea, 0x99e9,0x99e7,0x9ab9,0x9abf,0x9ab4,0x9abb,0x9af6,0x9afa,0x9af9,0x9af7, 0x9b33,0x9b80,0x9b85,0x9b87,0x9b7c,0x9b7e,0x9b7b,0x9b82,0x9b93,0x9b92, 0x9b90,0x9b7a,0x9b95 },{ 0x9b7d,0x9b88,0x9d25,0x9d17,0x9d20,0x9d1e,0x9d14,0x9d29,0x9d1d,0x9d18, 0x9d22,0x9d10,0x9d19,0x9d1f,0x9e88,0x9e86,0x9e87,0x9eae,0x9ead,0x9ed5, 0x9ed6,0x9efa,0x9f12,0x9f3d,0x5126,0x5125,0x5122,0x5124,0x5120,0x5129, 0x52f4,0x5693,0x568c,0x568d,0x5686,0x5684,0x5683,0x567e,0x5682,0x567f, 0x5681,0x58d6,0x58d4,0x58cf,0x58d2,0x5b2d,0x5b25,0x5b32,0x5b23,0x5b2c, 0x5b27,0x5b26,0x5b2f,0x5b2e,0x5b7b,0x5bf1,0x5bf2,0x5db7,0x5e6c,0x5e6a, 0x5fbe,0x5fbb,0x61c3,0x61b5,0x61bc,0x61e7,0x61e0,0x61e5,0x61e4,0x61e8, 0x61de,0x64ef,0x64e9,0x64e3,0x64eb,0x64e4,0x64e8,0x6581,0x6580,0x65b6, 0x65da,0x66d2,0x6a8d,0x6a96,0x6a81,0x6aa5,0x6a89,0x6a9f,0x6a9b,0x6aa1, 0x6a9e,0x6a87,0x6a93,0x6a8e } }, { /* ku 4d */ { 0x6a95,0x6a83,0x6aa8,0x6aa4,0x6a91,0x6a7f,0x6aa6,0x6a9a,0x6a85,0x6a8c, 0x6a92,0x6b5b,0x6bad,0x6c09,0x6fcc,0x6fa9,0x6ff4,0x6fd4,0x6fe3,0x6fdc, 0x6fed,0x6fe7,0x6fe6,0x6fde,0x6ff2,0x6fdd,0x6fe2,0x6fe8,0x71e1,0x71f1, 0x71e8,0x71f2,0x71e4,0x71f0,0x71e2,0x7373,0x736e,0x736f,0x7497,0x74b2, 0x74ab,0x7490,0x74aa,0x74ad,0x74b1,0x74a5,0x74af,0x7510,0x7511,0x7512, 0x750f,0x7584,0x7643,0x7648,0x7649,0x7647,0x76a4,0x76e9,0x77b5,0x77ab, 0x77b2,0x77b7,0x77b6 },{ 0x77b4,0x77b1,0x77a8,0x77f0,0x78f3,0x78fd,0x7902,0x78fb,0x78fc,0x78f2, 0x7905,0x78f9,0x78fe,0x7904,0x79ab,0x79a8,0x7a5c,0x7a5b,0x7a56,0x7a58, 0x7a54,0x7a5a,0x7abe,0x7ac0,0x7ac1,0x7c05,0x7c0f,0x7bf2,0x7c00,0x7bff, 0x7bfb,0x7c0e,0x7bf4,0x7c0b,0x7bf3,0x7c02,0x7c09,0x7c03,0x7c01,0x7bf8, 0x7bfd,0x7c06,0x7bf0,0x7bf1,0x7c10,0x7c0a,0x7ce8,0x7e2d,0x7e3c,0x7e42, 0x7e33,0x9848,0x7e38,0x7e2a,0x7e49,0x7e40,0x7e47,0x7e29,0x7e4c,0x7e30, 0x7e3b,0x7e36,0x7e44,0x7e3a,0x7f45,0x7f7f,0x7f7e,0x7f7d,0x7ff4,0x7ff2, 0x802c,0x81bb,0x81c4,0x81cc,0x81ca,0x81c5,0x81c7,0x81bc,0x81e9,0x825b, 0x825a,0x825c,0x8583,0x8580,0x858f,0x85a7,0x8595,0x85a0,0x858b,0x85a3, 0x857b,0x85a4,0x859a,0x859e } }, { /* ku 4e */ { 0x8577,0x857c,0x8589,0x85a1,0x857a,0x8578,0x8557,0x858e,0x8596,0x8586, 0x858d,0x8599,0x859d,0x8581,0x85a2,0x8582,0x8588,0x8585,0x8579,0x8576, 0x8598,0x8590,0x859f,0x8668,0x87be,0x87aa,0x87ad,0x87c5,0x87b0,0x87ac, 0x87b9,0x87b5,0x87bc,0x87ae,0x87c9,0x87c3,0x87c2,0x87cc,0x87b7,0x87af, 0x87c4,0x87ca,0x87b4,0x87b6,0x87bf,0x87b8,0x87bd,0x87de,0x87b2,0x8935, 0x8933,0x893c,0x893e,0x8941,0x8952,0x8937,0x8942,0x89ad,0x89af,0x89ae, 0x89f2,0x89f3,0x8b1e },{ 0x8b18,0x8b16,0x8b11,0x8b05,0x8b0b,0x8b22,0x8b0f,0x8b12,0x8b15,0x8b07, 0x8b0d,0x8b08,0x8b06,0x8b1c,0x8b13,0x8b1a,0x8c4f,0x8c70,0x8c72,0x8c71, 0x8c6f,0x8c95,0x8c94,0x8cf9,0x8d6f,0x8e4e,0x8e4d,0x8e53,0x8e50,0x8e4c, 0x8e47,0x8f43,0x8f40,0x9085,0x907e,0x9138,0x919a,0x91a2,0x919b,0x9199, 0x919f,0x91a1,0x919d,0x91a0,0x93a1,0x9383,0x93af,0x9364,0x9356,0x9347, 0x937c,0x9358,0x935c,0x9376,0x9349,0x9350,0x9351,0x9360,0x936d,0x938f, 0x934c,0x936a,0x9379,0x9357,0x9355,0x9352,0x934f,0x9371,0x9377,0x937b, 0x9361,0x935e,0x9363,0x9367,0x9380,0x934e,0x9359,0x95c7,0x95c0,0x95c9, 0x95c3,0x95c5,0x95b7,0x96ae,0x96b0,0x96ac,0x9720,0x971f,0x9718,0x971d, 0x9719,0x979a,0x97a1,0x979c } }, { /* ku 4f */ { 0x979e,0x979d,0x97d5,0x97d4,0x97f1,0x9841,0x9844,0x984a,0x9849,0x9845, 0x9843,0x9925,0x992b,0x992c,0x992a,0x9933,0x9932,0x992f,0x992d,0x9931, 0x9930,0x9998,0x99a3,0x99a1,0x9a02,0x99fa,0x99f4,0x99f7,0x99f9,0x99f8, 0x99f6,0x99fb,0x99fd,0x99fe,0x99fc,0x9a03,0x9abe,0x9afe,0x9afd,0x9b01, 0x9afc,0x9b48,0x9b9a,0x9ba8,0x9b9e,0x9b9b,0x9ba6,0x9ba1,0x9ba5,0x9ba4, 0x9b86,0x9ba2,0x9ba0,0x9baf,0x9d33,0x9d41,0x9d67,0x9d36,0x9d2e,0x9d2f, 0x9d31,0x9d38,0x9d30 },{ 0x9d45,0x9d42,0x9d43,0x9d3e,0x9d37,0x9d40,0x9d3d,0x7ff5,0x9d2d,0x9e8a, 0x9e89,0x9e8d,0x9eb0,0x9ec8,0x9eda,0x9efb,0x9eff,0x9f24,0x9f23,0x9f22, 0x9f54,0x9fa0,0x5131,0x512d,0x512e,0x5698,0x569c,0x5697,0x569a,0x569d, 0x5699,0x5970,0x5b3c,0x5c69,0x5c6a,0x5dc0,0x5e6d,0x5e6e,0x61d8,0x61df, 0x61ed,0x61ee,0x61f1,0x61ea,0x61f0,0x61eb,0x61d6,0x61e9,0x64ff,0x6504, 0x64fd,0x64f8,0x6501,0x6503,0x64fc,0x6594,0x65db,0x66da,0x66db,0x66d8, 0x6ac5,0x6ab9,0x6abd,0x6ae1,0x6ac6,0x6aba,0x6ab6,0x6ab7,0x6ac7,0x6ab4, 0x6aad,0x6b5e,0x6bc9,0x6c0b,0x7007,0x700c,0x700d,0x7001,0x7005,0x7014, 0x700e,0x6fff,0x7000,0x6ffb,0x7026,0x6ffc,0x6ff7,0x700a,0x7201,0x71ff, 0x71f9,0x7203,0x71fd,0x7376 } }, { /* ku 50 */ { 0x74b8,0x74c0,0x74b5,0x74c1,0x74be,0x74b6,0x74bb,0x74c2,0x7514,0x7513, 0x765c,0x7664,0x7659,0x7650,0x7653,0x7657,0x765a,0x76a6,0x76bd,0x76ec, 0x77c2,0x77ba,0x78ff,0x790c,0x7913,0x7914,0x7909,0x7910,0x7912,0x7911, 0x79ad,0x79ac,0x7a5f,0x7c1c,0x7c29,0x7c19,0x7c20,0x7c1f,0x7c2d,0x7c1d, 0x7c26,0x7c28,0x7c22,0x7c25,0x7c30,0x7e5c,0x7e50,0x7e56,0x7e63,0x7e58, 0x7e62,0x7e5f,0x7e51,0x7e60,0x7e57,0x7e53,0x7fb5,0x7fb3,0x7ff7,0x7ff8, 0x8075,0x81d1,0x81d2 },{ 0x81d0,0x825f,0x825e,0x85b4,0x85c6,0x85c0,0x85c3,0x85c2,0x85b3,0x85b5, 0x85bd,0x85c7,0x85c4,0x85bf,0x85cb,0x85ce,0x85c8,0x85c5,0x85b1,0x85b6, 0x85d2,0x8624,0x85b8,0x85b7,0x85be,0x8669,0x87e7,0x87e6,0x87e2,0x87db, 0x87eb,0x87ea,0x87e5,0x87df,0x87f3,0x87e4,0x87d4,0x87dc,0x87d3,0x87ed, 0x87d8,0x87e3,0x87a4,0x87d7,0x87d9,0x8801,0x87f4,0x87e8,0x87dd,0x8953, 0x894b,0x894f,0x894c,0x8946,0x8950,0x8951,0x8949,0x8b2a,0x8b27,0x8b23, 0x8b33,0x8b30,0x8b35,0x8b47,0x8b2f,0x8b3c,0x8b3e,0x8b31,0x8b25,0x8b37, 0x8b26,0x8b36,0x8b2e,0x8b24,0x8b3b,0x8b3d,0x8b3a,0x8c42,0x8c75,0x8c99, 0x8c98,0x8c97,0x8cfe,0x8d04,0x8d02,0x8d00,0x8e5c,0x8e62,0x8e60,0x8e57, 0x8e56,0x8e5e,0x8e65,0x8e67 } }, { /* ku 51 */ { 0x8e5b,0x8e5a,0x8e61,0x8e5d,0x8e69,0x8e54,0x8f46,0x8f47,0x8f48,0x8f4b, 0x9128,0x913a,0x913b,0x913e,0x91a8,0x91a5,0x91a7,0x91af,0x91aa,0x93b5, 0x938c,0x9392,0x93b7,0x939b,0x939d,0x9389,0x93a7,0x938e,0x93aa,0x939e, 0x93a6,0x9395,0x9388,0x9399,0x939f,0x938d,0x93b1,0x9391,0x93b2,0x93a4, 0x93a8,0x93b4,0x93a3,0x93a5,0x95d2,0x95d3,0x95d1,0x96b3,0x96d7,0x96da, 0x5dc2,0x96df,0x96d8,0x96dd,0x9723,0x9722,0x9725,0x97ac,0x97ae,0x97a8, 0x97ab,0x97a4,0x97aa },{ 0x97a2,0x97a5,0x97d7,0x97d9,0x97d6,0x97d8,0x97fa,0x9850,0x9851,0x9852, 0x98b8,0x9941,0x993c,0x993a,0x9a0f,0x9a0b,0x9a09,0x9a0d,0x9a04,0x9a11, 0x9a0a,0x9a05,0x9a07,0x9a06,0x9ac0,0x9adc,0x9b08,0x9b04,0x9b05,0x9b29, 0x9b35,0x9b4a,0x9b4c,0x9b4b,0x9bc7,0x9bc6,0x9bc3,0x9bbf,0x9bc1,0x9bb5, 0x9bb8,0x9bd3,0x9bb6,0x9bc4,0x9bb9,0x9bbd,0x9d5c,0x9d53,0x9d4f,0x9d4a, 0x9d5b,0x9d4b,0x9d59,0x9d56,0x9d4c,0x9d57,0x9d52,0x9d54,0x9d5f,0x9d58, 0x9d5a,0x9e8e,0x9e8c,0x9edf,0x9f01,0x9f00,0x9f16,0x9f25,0x9f2b,0x9f2a, 0x9f29,0x9f28,0x9f4c,0x9f55,0x5134,0x5135,0x5296,0x52f7,0x53b4,0x56ab, 0x56ad,0x56a6,0x56a7,0x56aa,0x56ac,0x58da,0x58dd,0x58db,0x5912,0x5b3d, 0x5b3e,0x5b3f,0x5dc3,0x5e70 } }, { /* ku 52 */ { 0x5fbf,0x61fb,0x6507,0x6510,0x650d,0x6509,0x650c,0x650e,0x6584,0x65de, 0x65dd,0x66de,0x6ae7,0x6ae0,0x6acc,0x6ad1,0x6ad9,0x6acb,0x6adf,0x6adc, 0x6ad0,0x6aeb,0x6acf,0x6acd,0x6ade,0x6b60,0x6bb0,0x6c0c,0x7019,0x7027, 0x7020,0x7016,0x702b,0x7021,0x7022,0x7023,0x7029,0x7017,0x7024,0x701c, 0x702a,0x720c,0x720a,0x7207,0x7202,0x7205,0x72a5,0x72a6,0x72a4,0x72a3, 0x72a1,0x74cb,0x74c5,0x74b7,0x74c3,0x7516,0x7660,0x77c9,0x77ca,0x77c4, 0x77f1,0x791d,0x791b },{ 0x7921,0x791c,0x7917,0x791e,0x79b0,0x7a67,0x7a68,0x7c33,0x7c3c,0x7c39, 0x7c2c,0x7c3b,0x7cec,0x7cea,0x7e76,0x7e75,0x7e78,0x7e70,0x7e77,0x7e6f, 0x7e7a,0x7e72,0x7e74,0x7e68,0x7f4b,0x7f4a,0x7f83,0x7f86,0x7fb7,0x7ffd, 0x7ffe,0x8078,0x81d7,0x81d5,0x8264,0x8261,0x8263,0x85eb,0x85f1,0x85ed, 0x85d9,0x85e1,0x85e8,0x85da,0x85d7,0x85ec,0x85f2,0x85f8,0x85d8,0x85df, 0x85e3,0x85dc,0x85d1,0x85f0,0x85e6,0x85ef,0x85de,0x85e2,0x8800,0x87fa, 0x8803,0x87f6,0x87f7,0x8809,0x880c,0x880b,0x8806,0x87fc,0x8808,0x87ff, 0x880a,0x8802,0x8962,0x895a,0x895b,0x8957,0x8961,0x895c,0x8958,0x895d, 0x8959,0x8988,0x89b7,0x89b6,0x89f6,0x8b50,0x8b48,0x8b4a,0x8b40,0x8b53, 0x8b56,0x8b54,0x8b4b,0x8b55 } }, { /* ku 53 */ { 0x8b51,0x8b42,0x8b52,0x8b57,0x8c43,0x8c77,0x8c76,0x8c9a,0x8d06,0x8d07, 0x8d09,0x8dac,0x8daa,0x8dad,0x8dab,0x8e6d,0x8e78,0x8e73,0x8e6a,0x8e6f, 0x8e7b,0x8ec2,0x8f52,0x8f51,0x8f4f,0x8f50,0x8f53,0x8fb4,0x9140,0x913f, 0x91b0,0x91ad,0x93de,0x93c7,0x93cf,0x93c2,0x93da,0x93d0,0x93f9,0x93ec, 0x93cc,0x93d9,0x93a9,0x93e6,0x93ca,0x93d4,0x93ee,0x93e3,0x93d5,0x93c4, 0x93ce,0x93c0,0x93d2,0x93e7,0x957d,0x95da,0x95db,0x96e1,0x9729,0x972b, 0x972c,0x9728,0x9726 },{ 0x97b3,0x97b7,0x97b6,0x97dd,0x97de,0x97df,0x985c,0x9859,0x985d,0x9857, 0x98bf,0x98bd,0x98bb,0x98be,0x9948,0x9947,0x9943,0x99a6,0x99a7,0x9a1a, 0x9a15,0x9a25,0x9a1d,0x9a24,0x9a1b,0x9a22,0x9a20,0x9a27,0x9a23,0x9a1e, 0x9a1c,0x9a14,0x9ac2,0x9b0b,0x9b0a,0x9b0e,0x9b0c,0x9b37,0x9bea,0x9beb, 0x9be0,0x9bde,0x9be4,0x9be6,0x9be2,0x9bf0,0x9bd4,0x9bd7,0x9bec,0x9bdc, 0x9bd9,0x9be5,0x9bd5,0x9be1,0x9bda,0x9d77,0x9d81,0x9d8a,0x9d84,0x9d88, 0x9d71,0x9d80,0x9d78,0x9d86,0x9d8b,0x9d8c,0x9d7d,0x9d6b,0x9d74,0x9d75, 0x9d70,0x9d69,0x9d85,0x9d73,0x9d7b,0x9d82,0x9d6f,0x9d79,0x9d7f,0x9d87, 0x9d68,0x9e94,0x9e91,0x9ec0,0x9efc,0x9f2d,0x9f40,0x9f41,0x9f4d,0x9f56, 0x9f57,0x9f58,0x5337,0x56b2 } }, { /* ku 54 */ { 0x56b5,0x56b3,0x58e3,0x5b45,0x5dc6,0x5dc7,0x5eee,0x5eef,0x5fc0,0x5fc1, 0x61f9,0x6517,0x6516,0x6515,0x6513,0x65df,0x66e8,0x66e3,0x66e4,0x6af3, 0x6af0,0x6aea,0x6ae8,0x6af9,0x6af1,0x6aee,0x6aef,0x703c,0x7035,0x702f, 0x7037,0x7034,0x7031,0x7042,0x7038,0x703f,0x703a,0x7039,0x7040,0x703b, 0x7033,0x7041,0x7213,0x7214,0x72a8,0x737d,0x737c,0x74ba,0x76ab,0x76aa, 0x76be,0x76ed,0x77cc,0x77ce,0x77cf,0x77cd,0x77f2,0x7925,0x7923,0x7927, 0x7928,0x7924,0x7929 },{ 0x79b2,0x7a6e,0x7a6c,0x7a6d,0x7af7,0x7c49,0x7c48,0x7c4a,0x7c47,0x7c45, 0x7cee,0x7e7b,0x7e7e,0x7e81,0x7e80,0x7fba,0x7fff,0x8079,0x81db,0x81d9, 0x820b,0x8268,0x8269,0x8622,0x85ff,0x8601,0x85fe,0x861b,0x8600,0x85f6, 0x8604,0x8609,0x8605,0x860c,0x85fd,0x8819,0x8810,0x8811,0x8817,0x8813, 0x8816,0x8963,0x8966,0x89b9,0x89f7,0x8b60,0x8b6a,0x8b5d,0x8b68,0x8b63, 0x8b65,0x8b67,0x8b6d,0x8dae,0x8e86,0x8e88,0x8e84,0x8f59,0x8f56,0x8f57, 0x8f55,0x8f58,0x8f5a,0x908d,0x9143,0x9141,0x91b7,0x91b5,0x91b2,0x91b3, 0x940b,0x9413,0x93fb,0x9420,0x940f,0x9414,0x93fe,0x9415,0x9410,0x9428, 0x9419,0x940d,0x93f5,0x9400,0x93f7,0x9407,0x940e,0x9416,0x9412,0x93fa, 0x9409,0x93f8,0x940a,0x93ff } }, { /* ku 55 */ { 0x93fc,0x940c,0x93f6,0x9411,0x9406,0x95de,0x95e0,0x95df,0x972e,0x972f, 0x97b9,0x97bb,0x97fd,0x97fe,0x9860,0x9862,0x9863,0x985f,0x98c1,0x98c2, 0x9950,0x994e,0x9959,0x994c,0x994b,0x9953,0x9a32,0x9a34,0x9a31,0x9a2c, 0x9a2a,0x9a36,0x9a29,0x9a2e,0x9a38,0x9a2d,0x9ac7,0x9aca,0x9ac6,0x9b10, 0x9b12,0x9b11,0x9c0b,0x9c08,0x9bf7,0x9c05,0x9c12,0x9bf8,0x9c40,0x9c07, 0x9c0e,0x9c06,0x9c17,0x9c14,0x9c09,0x9d9f,0x9d99,0x9da4,0x9d9d,0x9d92, 0x9d98,0x9d90,0x9d9b },{ 0x9da0,0x9d94,0x9d9c,0x9daa,0x9d97,0x9da1,0x9d9a,0x9da2,0x9da8,0x9d9e, 0x9da3,0x9dbf,0x9da9,0x9d96,0x9da6,0x9da7,0x9e99,0x9e9b,0x9e9a,0x9ee5, 0x9ee4,0x9ee7,0x9ee6,0x9f30,0x9f2e,0x9f5b,0x9f60,0x9f5e,0x9f5d,0x9f59, 0x9f91,0x513a,0x5139,0x5298,0x5297,0x56c3,0x56bd,0x56be,0x5b48,0x5b47, 0x5dcb,0x5dcf,0x5ef1,0x61fd,0x651b,0x6b02,0x6afc,0x6b03,0x6af8,0x6b00, 0x7043,0x7044,0x704a,0x7048,0x7049,0x7045,0x7046,0x721d,0x721a,0x7219, 0x737e,0x7517,0x766a,0x77d0,0x792d,0x7931,0x792f,0x7c54,0x7c53,0x7cf2, 0x7e8a,0x7e87,0x7e88,0x7e8b,0x7e86,0x7e8d,0x7f4d,0x7fbb,0x8030,0x81dd, 0x8618,0x862a,0x8626,0x861f,0x8623,0x861c,0x8619,0x8627,0x862e,0x8621, 0x8620,0x8629,0x861e,0x8625 } }, { /* ku 56 */ { 0x8829,0x881d,0x881b,0x8820,0x8824,0x881c,0x882b,0x884a,0x896d,0x8969, 0x896e,0x896b,0x89fa,0x8b79,0x8b78,0x8b45,0x8b7a,0x8b7b,0x8d10,0x8d14, 0x8daf,0x8e8e,0x8e8c,0x8f5e,0x8f5b,0x8f5d,0x9146,0x9144,0x9145,0x91b9, 0x943f,0x943b,0x9436,0x9429,0x943d,0x943c,0x9430,0x9439,0x942a,0x9437, 0x942c,0x9440,0x9431,0x95e5,0x95e4,0x95e3,0x9735,0x973a,0x97bf,0x97e1, 0x9864,0x98c9,0x98c6,0x98c0,0x9958,0x9956,0x9a39,0x9a3d,0x9a46,0x9a44, 0x9a42,0x9a41,0x9a3a },{ 0x9a3f,0x9acd,0x9b15,0x9b17,0x9b18,0x9b16,0x9b3a,0x9b52,0x9c2b,0x9c1d, 0x9c1c,0x9c2c,0x9c23,0x9c28,0x9c29,0x9c24,0x9c21,0x9db7,0x9db6,0x9dbc, 0x9dc1,0x9dc7,0x9dca,0x9dcf,0x9dbe,0x9dc5,0x9dc3,0x9dbb,0x9db5,0x9dce, 0x9db9,0x9dba,0x9dac,0x9dc8,0x9db1,0x9dad,0x9dcc,0x9db3,0x9dcd,0x9db2, 0x9e7a,0x9e9c,0x9eeb,0x9eee,0x9eed,0x9f1b,0x9f18,0x9f1a,0x9f31,0x9f4e, 0x9f65,0x9f64,0x9f92,0x4eb9,0x56c6,0x56c5,0x56cb,0x5971,0x5b4b,0x5b4c, 0x5dd5,0x5dd1,0x5ef2,0x6521,0x6520,0x6526,0x6522,0x6b0b,0x6b08,0x6b09, 0x6c0d,0x7055,0x7056,0x7057,0x7052,0x721e,0x721f,0x72a9,0x737f,0x74d8, 0x74d5,0x74d9,0x74d7,0x766d,0x76ad,0x7935,0x79b4,0x7a70,0x7a71,0x7c57, 0x7c5c,0x7c59,0x7c5b,0x7c5a } }, { /* ku 57 */ { 0x7cf4,0x7cf1,0x7e91,0x7f4f,0x7f87,0x81de,0x826b,0x8634,0x8635,0x8633, 0x862c,0x8632,0x8636,0x882c,0x8828,0x8826,0x882a,0x8825,0x8971,0x89bf, 0x89be,0x89fb,0x8b7e,0x8b84,0x8b82,0x8b86,0x8b85,0x8b7f,0x8d15,0x8e95, 0x8e94,0x8e9a,0x8e92,0x8e90,0x8e96,0x8e97,0x8f60,0x8f62,0x9147,0x944c, 0x9450,0x944a,0x944b,0x944f,0x9447,0x9445,0x9448,0x9449,0x9446,0x973f, 0x97e3,0x986a,0x9869,0x98cb,0x9954,0x995b,0x9a4e,0x9a53,0x9a54,0x9a4c, 0x9a4f,0x9a48,0x9a4a },{ 0x9a49,0x9a52,0x9a50,0x9ad0,0x9b19,0x9b2b,0x9b3b,0x9b56,0x9b55,0x9c46, 0x9c48,0x9c3f,0x9c44,0x9c39,0x9c33,0x9c41,0x9c3c,0x9c37,0x9c34,0x9c32, 0x9c3d,0x9c36,0x9ddb,0x9dd2,0x9dde,0x9dda,0x9dcb,0x9dd0,0x9ddc,0x9dd1, 0x9ddf,0x9de9,0x9dd9,0x9dd8,0x9dd6,0x9df5,0x9dd5,0x9ddd,0x9eb6,0x9ef0, 0x9f35,0x9f33,0x9f32,0x9f42,0x9f6b,0x9f95,0x9fa2,0x513d,0x5299,0x58e8, 0x58e7,0x5972,0x5b4d,0x5dd8,0x882f,0x5f4f,0x6201,0x6203,0x6204,0x6529, 0x6525,0x6596,0x66eb,0x6b11,0x6b12,0x6b0f,0x6bca,0x705b,0x705a,0x7222, 0x7382,0x7381,0x7383,0x7670,0x77d4,0x7c67,0x7c66,0x7e95,0x826c,0x863a, 0x8640,0x8639,0x863c,0x8631,0x863b,0x863e,0x8830,0x8832,0x882e,0x8833, 0x8976,0x8974,0x8973,0x89fe } }, { /* ku 58 */ { 0x8b8c,0x8b8e,0x8b8b,0x8b88,0x8c45,0x8d19,0x8e98,0x8f64,0x8f63,0x91bc, 0x9462,0x9455,0x945d,0x9457,0x945e,0x97c4,0x97c5,0x9800,0x9a56,0x9a59, 0x9b1e,0x9b1f,0x9b20,0x9c52,0x9c58,0x9c50,0x9c4a,0x9c4d,0x9c4b,0x9c55, 0x9c59,0x9c4c,0x9c4e,0x9dfb,0x9df7,0x9def,0x9de3,0x9deb,0x9df8,0x9de4, 0x9df6,0x9de1,0x9dee,0x9de6,0x9df2,0x9df0,0x9de2,0x9dec,0x9df4,0x9df3, 0x9de8,0x9ded,0x9ec2,0x9ed0,0x9ef2,0x9ef3,0x9f06,0x9f1c,0x9f38,0x9f37, 0x9f36,0x9f43,0x9f4f },{ 0x9f71,0x9f70,0x9f6e,0x9f6f,0x56d3,0x56cd,0x5b4e,0x5c6d,0x652d,0x66ed, 0x66ee,0x6b13,0x705f,0x7061,0x705d,0x7060,0x7223,0x74db,0x74e5,0x77d5, 0x7938,0x79b7,0x79b6,0x7c6a,0x7e97,0x7f89,0x826d,0x8643,0x8838,0x8837, 0x8835,0x884b,0x8b94,0x8b95,0x8e9e,0x8e9f,0x8ea0,0x8e9d,0x91be,0x91bd, 0x91c2,0x946b,0x9468,0x9469,0x96e5,0x9746,0x9743,0x9747,0x97c7,0x97e5, 0x9a5e,0x9ad5,0x9b59,0x9c63,0x9c67,0x9c66,0x9c62,0x9c5e,0x9c60,0x9e02, 0x9dfe,0x9e07,0x9e03,0x9e06,0x9e05,0x9e00,0x9e01,0x9e09,0x9dff,0x9dfd, 0x9e04,0x9ea0,0x9f1e,0x9f46,0x9f74,0x9f75,0x9f76,0x56d4,0x652e,0x65b8, 0x6b18,0x6b19,0x6b17,0x6b1a,0x7062,0x7226,0x72aa,0x77d8,0x77d9,0x7939, 0x7c69,0x7c6b,0x7cf6,0x7e9a } }, { /* ku 59 */ { 0x7e98,0x7e9b,0x7e99,0x81e0,0x81e1,0x8646,0x8647,0x8648,0x8979,0x897a, 0x897c,0x897b,0x89ff,0x8b98,0x8b99,0x8ea5,0x8ea4,0x8ea3,0x946e,0x946d, 0x946f,0x9471,0x9473,0x9749,0x9872,0x995f,0x9c68,0x9c6e,0x9c6d,0x9e0b, 0x9e0d,0x9e10,0x9e0f,0x9e12,0x9e11,0x9ea1,0x9ef5,0x9f09,0x9f47,0x9f78, 0x9f7b,0x9f7a,0x9f79,0x571e,0x7066,0x7c6f,0x883c,0x8db2,0x8ea6,0x91c3, 0x9474,0x9478,0x9476,0x9475,0x9a60,0x9c74,0x9c73,0x9c71,0x9c75,0x9e14, 0x9e13,0x9ef6,0x9f0a },{ 0x9fa4,0x7068,0x7065,0x7cf7,0x866a,0x883e,0x883d,0x883f,0x8b9e,0x8c9c, 0x8ea9,0x8ec9,0x974b,0x9873,0x9874,0x98cc,0x9961,0x99ab,0x9a64,0x9a66, 0x9a67,0x9b24,0x9e15,0x9e17,0x9f48,0x6207,0x6b1e,0x7227,0x864c,0x8ea8, 0x9482,0x9480,0x9481,0x9a69,0x9a68,0x9b2e,0x9e19,0x7229,0x864b,0x8b9f, 0x9483,0x9c79,0x9eb7,0x7675,0x9a6b,0x9c7a,0x9e1d,0x7069,0x706a,0x9ea4, 0x9f7e,0x9f49,0x9f98,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON, UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON, UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON, UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON, UBOGON,UBOGON,UBOGON,UBOGON } } }; alpine-2.10+dfsg/imap/src/charset/widths.c0000600000175000017500000102206011512502123022150 0ustar paulproteuspaulproteus/* ======================================================================== * Copyright 1988-2007 University of Washington * * Licensed under the Apache License, Version 2.0 (the "License"); * you may not use this file except in compliance with the License. * You may obtain a copy of the License at * * http://www.apache.org/licenses/LICENSE-2.0 * * * ======================================================================== */ /* * Program: Unicode width table (current as of Unicode 5.0) * * Author: Mark Crispin * Networks and Distributed Computing * Computing & Communications * University of Washington * Administration Building, AG-44 * Seattle, WA 98195 * Internet: MRC@CAC.Washington.EDU * * Date: 20 March 2006 * Last Edited: 1 March 2007 */ /* Table of 2-bit character widths, indexed by Unicode codepoint and * big-endian within bytes: * 0 zero-width * 1 single-width (half-width) * 2 double-width (full-width) * 3 ambiguous */ #define UCS4_WIDLEN 131072 static const unsigned char ucs4_widthtab[32768] = { 0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00, /* U+0000 - U+001f */ 0x55,0x55,0x55,0x55,0x55,0x55,0x55,0x55, /* U+0020 - U+003f */ 0x55,0x55,0x55,0x55,0x55,0x55,0x55,0x55, /* U+0040 - U+005f */ 0x55,0x55,0x55,0x55,0x55,0x55,0x55,0x54, /* U+0060 - U+007f */ 0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00, /* U+0080 - U+009f */ 0xf5,0xd7,0xff,0x4d,0xff,0xff,0xff,0xff, /* U+00a0 - U+00bf */ 0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff, /* U+00c0 - U+00df */ 0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff, /* U+00e0 - U+00ff */ 0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff, /* U+0100 - U+011f */ 0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff, /* U+0120 - U+013f */ 0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff, /* U+0140 - U+015f */ 0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff, /* U+0160 - U+017f */ 0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff, /* U+0180 - U+019f */ 0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff, /* U+01a0 - U+01bf */ 0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff, /* U+01c0 - U+01df */ 0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff, /* U+01e0 - U+01ff */ 0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff, /* U+0200 - U+021f */ 0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff, /* U+0220 - U+023f */ 0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff, /* U+0240 - U+025f */ 0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff, /* U+0260 - U+027f */ 0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff, /* U+0280 - U+029f */ 0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff, /* U+02a0 - U+02bf */ 0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff, /* U+02c0 - U+02df */ 0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff, /* U+02e0 - U+02ff */ 0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00, /* U+0300 - U+031f */ 0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00, /* U+0320 - U+033f */ 0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00, /* U+0340 - U+035f */ 0x00,0x00,0x00,0x00,0xff,0xff,0xff,0xff, /* U+0360 - U+037f */ 0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff, /* U+0380 - U+039f */ 0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff, /* U+03a0 - U+03bf */ 0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff, /* U+03c0 - U+03df */ 0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff, /* U+03e0 - U+03ff */ 0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff, /* U+0400 - U+041f */ 0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff, /* U+0420 - U+043f */ 0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff, /* U+0440 - U+045f */ 0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff, /* U+0460 - U+047f */ 0xfc,0x03,0x0f,0xff,0xff,0xff,0xff,0xff, /* U+0480 - U+049f */ 0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff, /* U+04a0 - U+04bf */ 0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff, /* U+04c0 - U+04df */ 0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff, /* U+04e0 - U+04ff */ 0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff, /* U+0500 - U+051f */ 0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff, /* U+0520 - U+053f */ 0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff, /* U+0540 - U+055f */ 0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff, /* U+0560 - U+057f */ 0xff,0xff,0xff,0xff,0xc0,0x00,0x00,0x00, /* U+0580 - U+059f */ 0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x0c, /* U+05a0 - U+05bf */ 0xc3,0x0c,0xff,0xff,0xff,0xff,0xff,0xff, /* U+05c0 - U+05df */ 0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff, /* U+05e0 - U+05ff */ 0x00,0xff,0xff,0xff,0x00,0x0f,0xff,0xff, /* U+0600 - U+061f */ 0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff, /* U+0620 - U+063f */ 0xff,0xff,0xfc,0x00,0x00,0x00,0x00,0x03, /* U+0640 - U+065f */ 0xff,0xff,0xff,0xff,0x3f,0xff,0xff,0xff, /* U+0660 - U+067f */ 0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff, /* U+0680 - U+069f */ 0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff, /* U+06a0 - U+06bf */ 0xff,0xff,0xff,0xff,0xff,0xf0,0x00,0x00, /* U+06c0 - U+06df */ 0x00,0x3c,0x30,0x0f,0xff,0xff,0xff,0xff, /* U+06e0 - U+06ff */ 0xff,0xff,0xff,0xfc,0xcf,0xff,0xff,0xff, /* U+0700 - U+071f */ 0xff,0xff,0xff,0xff,0x00,0x00,0x00,0x00, /* U+0720 - U+073f */ 0x00,0x00,0x03,0xff,0xff,0xff,0xff,0xff, /* U+0740 - U+075f */ 0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff, /* U+0760 - U+077f */ 0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff, /* U+0780 - U+079f */ 0xff,0xf0,0x00,0x00,0x3f,0xff,0xff,0xff, /* U+07a0 - U+07bf */ 0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff, /* U+07c0 - U+07df */ 0xff,0xff,0xfc,0x00,0x00,0xff,0xff,0xff, /* U+07e0 - U+07ff */ 0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff, /* U+0800 - U+081f */ 0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff, /* U+0820 - U+083f */ 0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff, /* U+0840 - U+085f */ 0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff, /* U+0860 - U+087f */ 0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff, /* U+0880 - U+089f */ 0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff, /* U+08a0 - U+08bf */ 0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff, /* U+08c0 - U+08df */ 0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff, /* U+08e0 - U+08ff */ 0xc3,0xff,0xff,0xff,0xff,0xff,0xff,0xff, /* U+0900 - U+091f */ 0xff,0xff,0xff,0xff,0xff,0xff,0xff,0x3f, /* U+0920 - U+093f */ 0xc0,0x00,0x3f,0xcf,0xc0,0x3f,0xff,0xff, /* U+0940 - U+095f */ 0xf0,0xff,0xff,0xff,0xff,0xff,0xff,0xff, /* U+0960 - U+097f */ 0xcf,0xff,0xff,0xff,0xff,0xff,0xff,0xff, /* U+0980 - U+099f */ 0xff,0xff,0xff,0xff,0xff,0xff,0xff,0x3f, /* U+09a0 - U+09bf */ 0xc0,0x3f,0xff,0xcf,0xff,0xff,0xff,0xff, /* U+09c0 - U+09df */ 0xf0,0xff,0xff,0xff,0xff,0xff,0xff,0xff, /* U+09e0 - U+09ff */ 0xc3,0xff,0xff,0xff,0xff,0xff,0xff,0xff, /* U+0a00 - U+0a1f */ 0xff,0xff,0xff,0xff,0xff,0xff,0xff,0x3f, /* U+0a20 - U+0a3f */ 0xc3,0xfc,0x3c,0x0f,0xff,0xff,0xff,0xff, /* U+0a40 - U+0a5f */ 0xff,0xff,0xff,0xff,0x0f,0xff,0xff,0xff, /* U+0a60 - U+0a7f */ 0xc3,0xff,0xff,0xff,0xff,0xff,0xff,0xff, /* U+0a80 - U+0a9f */ 0xff,0xff,0xff,0xff,0xff,0xff,0xff,0x3f, /* U+0aa0 - U+0abf */ 0xc0,0x0c,0x3f,0xcf,0xff,0xff,0xff,0xff, /* U+0ac0 - U+0adf */ 0xf0,0xff,0xff,0xff,0xff,0xff,0xff,0xff, /* U+0ae0 - U+0aff */ 0xcf,0xff,0xff,0xff,0xff,0xff,0xff,0xff, /* U+0b00 - U+0b1f */ 0xff,0xff,0xff,0xff,0xff,0xff,0xff,0x3c, /* U+0b20 - U+0b3f */ 0xc0,0xff,0xff,0xcf,0xff,0xf3,0xff,0xff, /* U+0b40 - U+0b5f */ 0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff, /* U+0b60 - U+0b7f */ 0xf3,0xff,0xff,0xff,0xff,0xff,0xff,0xff, /* U+0b80 - U+0b9f */ 0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff, /* U+0ba0 - U+0bbf */ 0x3f,0xff,0xff,0xcf,0xff,0xff,0xff,0xff, /* U+0bc0 - U+0bdf */ 0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff, /* U+0be0 - U+0bff */ 0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff, /* U+0c00 - U+0c1f */ 0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xf0, /* U+0c20 - U+0c3f */ 0x3f,0xf0,0x30,0x0f,0xff,0xc3,0xff,0xff, /* U+0c40 - U+0c5f */ 0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff, /* U+0c60 - U+0c7f */ 0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff, /* U+0c80 - U+0c9f */ 0xff,0xff,0xff,0xff,0xff,0xff,0xff,0x3f, /* U+0ca0 - U+0cbf */ 0xff,0xff,0xff,0x0f,0xff,0xff,0xff,0xff, /* U+0cc0 - U+0cdf */ 0xf0,0xff,0xff,0xff,0xff,0xff,0xff,0xff, /* U+0ce0 - U+0cff */ 0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff, /* U+0d00 - U+0d1f */ 0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff, /* U+0d20 - U+0d3f */ 0xc0,0xff,0xff,0xcf,0xff,0xff,0xff,0xff, /* U+0d40 - U+0d5f */ 0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff, /* U+0d60 - U+0d7f */ 0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff, /* U+0d80 - U+0d9f */ 0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff, /* U+0da0 - U+0dbf */ 0xff,0xff,0xf3,0xff,0xf0,0x33,0xff,0xff, /* U+0dc0 - U+0ddf */ 0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff, /* U+0de0 - U+0dff */ 0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff, /* U+0e00 - U+0e1f */ 0xff,0xff,0xff,0xff,0xcf,0x00,0x03,0xff, /* U+0e20 - U+0e3f */ 0xff,0xfc,0x00,0x03,0xff,0xff,0xff,0xff, /* U+0e40 - U+0e5f */ 0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff, /* U+0e60 - U+0e7f */ 0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff, /* U+0e80 - U+0e9f */ 0xff,0xff,0xff,0xff,0xcf,0x00,0x0c,0x3f, /* U+0ea0 - U+0ebf */ 0xff,0xff,0x00,0x0f,0xff,0xff,0xff,0xff, /* U+0ec0 - U+0edf */ 0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff, /* U+0ee0 - U+0eff */ 0xff,0xff,0xff,0xff,0xff,0xff,0x0f,0xff, /* U+0f00 - U+0f1f */ 0xff,0xff,0xff,0xff,0xff,0xcc,0xcf,0xff, /* U+0f20 - U+0f3f */ 0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff, /* U+0f40 - U+0f5f */ 0xff,0xff,0xff,0xff,0xc0,0x00,0x00,0x03, /* U+0f60 - U+0f7f */ 0x00,0x30,0xff,0xff,0x00,0x00,0xc0,0x00, /* U+0f80 - U+0f9f */ 0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x3f, /* U+0fa0 - U+0fbf */ 0xff,0xf3,0xff,0xff,0xff,0xff,0xff,0xff, /* U+0fc0 - U+0fdf */ 0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff, /* U+0fe0 - U+0fff */ 0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff, /* U+1000 - U+101f */ 0xff,0xff,0xff,0xc0,0x33,0xf0,0xcf,0xff, /* U+1020 - U+103f */ 0xff,0xff,0xff,0xff,0xff,0xff,0x0f,0xff, /* U+1040 - U+105f */ 0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff, /* U+1060 - U+107f */ 0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff, /* U+1080 - U+109f */ 0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff, /* U+10a0 - U+10bf */ 0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff, /* U+10c0 - U+10df */ 0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff, /* U+10e0 - U+10ff */ 0xaa,0xaa,0xaa,0xaa,0xaa,0xaa,0xaa,0xaa, /* U+1100 - U+111f */ 0xaa,0xaa,0xaa,0xaa,0xaa,0xaa,0xaa,0xaa, /* U+1120 - U+113f */ 0xaa,0xaa,0xaa,0xaa,0xaa,0xaa,0xaf,0xfe, /* U+1140 - U+115f */ 0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff, /* U+1160 - U+117f */ 0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff, /* U+1180 - U+119f */ 0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff, /* U+11a0 - U+11bf */ 0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff, /* U+11c0 - U+11df */ 0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff, /* U+11e0 - U+11ff */ 0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff, /* U+1200 - U+121f */ 0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff, /* U+1220 - U+123f */ 0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff, /* U+1240 - U+125f */ 0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff, /* U+1260 - U+127f */ 0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff, /* U+1280 - U+129f */ 0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff, /* U+12a0 - U+12bf */ 0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff, /* U+12c0 - U+12df */ 0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff, /* U+12e0 - U+12ff */ 0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff, /* U+1300 - U+131f */ 0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff, /* U+1320 - U+133f */ 0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xfc, /* U+1340 - U+135f */ 0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff, /* U+1360 - U+137f */ 0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff, /* U+1380 - U+139f */ 0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff, /* U+13a0 - U+13bf */ 0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff, /* U+13c0 - U+13df */ 0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff, /* U+13e0 - U+13ff */ 0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff, /* U+1400 - U+141f */ 0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff, /* U+1420 - U+143f */ 0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff, /* U+1440 - U+145f */ 0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff, /* U+1460 - U+147f */ 0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff, /* U+1480 - U+149f */ 0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff, /* U+14a0 - U+14bf */ 0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff, /* U+14c0 - U+14df */ 0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff, /* U+14e0 - U+14ff */ 0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff, /* U+1500 - U+151f */ 0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff, /* U+1520 - U+153f */ 0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff, /* U+1540 - U+155f */ 0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff, /* U+1560 - U+157f */ 0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff, /* U+1580 - U+159f */ 0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff, /* U+15a0 - U+15bf */ 0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff, /* U+15c0 - U+15df */ 0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff, /* U+15e0 - U+15ff */ 0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff, /* U+1600 - U+161f */ 0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff, /* U+1620 - U+163f */ 0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff, /* U+1640 - U+165f */ 0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff, /* U+1660 - U+167f */ 0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff, /* U+1680 - U+169f */ 0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff, /* U+16a0 - U+16bf */ 0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff, /* U+16c0 - U+16df */ 0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff, /* U+16e0 - U+16ff */ 0xff,0xff,0xff,0xff,0xf0,0x3f,0xff,0xff, /* U+1700 - U+171f */ 0xff,0xff,0xff,0xff,0xf0,0x3f,0xff,0xff, /* U+1720 - U+173f */ 0xff,0xff,0xff,0xff,0xf0,0xff,0xff,0xff, /* U+1740 - U+175f */ 0xff,0xff,0xff,0xff,0xf0,0xff,0xff,0xff, /* U+1760 - U+177f */ 0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff, /* U+1780 - U+179f */ 0xff,0xff,0xff,0xff,0xff,0x0c,0x00,0x0f, /* U+17a0 - U+17bf */ 0xff,0xf3,0xc0,0x00,0x00,0xff,0xff,0xcf, /* U+17c0 - U+17df */ 0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff, /* U+17e0 - U+17ff */ 0xff,0xff,0xfc,0x0f,0xff,0xff,0xff,0xff, /* U+1800 - U+181f */ 0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff, /* U+1820 - U+183f */ 0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff, /* U+1840 - U+185f */ 0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff, /* U+1860 - U+187f */ 0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff, /* U+1880 - U+189f */ 0xff,0xff,0xcf,0xff,0xff,0xff,0xff,0xff, /* U+18a0 - U+18bf */ 0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff, /* U+18c0 - U+18df */ 0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff, /* U+18e0 - U+18ff */ 0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff, /* U+1900 - U+191f */ 0x03,0xfc,0x00,0xff,0xf3,0xff,0xc0,0xff, /* U+1920 - U+193f */ 0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff, /* U+1940 - U+195f */ 0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff, /* U+1960 - U+197f */ 0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff, /* U+1980 - U+199f */ 0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff, /* U+19a0 - U+19bf */ 0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff, /* U+19c0 - U+19df */ 0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff, /* U+19e0 - U+19ff */ 0xff,0xff,0xff,0xff,0xff,0xfc,0x3f,0xff, /* U+1a00 - U+1a1f */ 0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff, /* U+1a20 - U+1a3f */ 0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff, /* U+1a40 - U+1a5f */ 0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff, /* U+1a60 - U+1a7f */ 0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff, /* U+1a80 - U+1a9f */ 0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff, /* U+1aa0 - U+1abf */ 0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff, /* U+1ac0 - U+1adf */ 0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff, /* U+1ae0 - U+1aff */ 0x00,0xff,0xff,0xff,0xff,0xff,0xff,0xff, /* U+1b00 - U+1b1f */ 0xff,0xff,0xff,0xff,0xff,0x30,0x03,0x3f, /* U+1b20 - U+1b3f */ 0xf3,0xff,0xff,0xff,0xff,0xff,0xff,0xff, /* U+1b40 - U+1b5f */ 0xff,0xff,0xfc,0x00,0x00,0xff,0xff,0xff, /* U+1b60 - U+1b7f */ 0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff, /* U+1b80 - U+1b9f */ 0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff, /* U+1ba0 - U+1bbf */ 0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff, /* U+1bc0 - U+1bdf */ 0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff, /* U+1be0 - U+1bff */ 0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff, /* U+1c00 - U+1c1f */ 0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff, /* U+1c20 - U+1c3f */ 0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff, /* U+1c40 - U+1c5f */ 0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff, /* U+1c60 - U+1c7f */ 0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff, /* U+1c80 - U+1c9f */ 0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff, /* U+1ca0 - U+1cbf */ 0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff, /* U+1cc0 - U+1cdf */ 0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff, /* U+1ce0 - U+1cff */ 0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff, /* U+1d00 - U+1d1f */ 0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff, /* U+1d20 - U+1d3f */ 0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff, /* U+1d40 - U+1d5f */ 0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff, /* U+1d60 - U+1d7f */ 0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff, /* U+1d80 - U+1d9f */ 0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff, /* U+1da0 - U+1dbf */ 0x00,0x00,0x03,0xff,0xff,0xff,0xff,0xff, /* U+1dc0 - U+1ddf */ 0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xf0, /* U+1de0 - U+1dff */ 0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff, /* U+1e00 - U+1e1f */ 0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff, /* U+1e20 - U+1e3f */ 0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff, /* U+1e40 - U+1e5f */ 0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff, /* U+1e60 - U+1e7f */ 0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff, /* U+1e80 - U+1e9f */ 0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff, /* U+1ea0 - U+1ebf */ 0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff, /* U+1ec0 - U+1edf */ 0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff, /* U+1ee0 - U+1eff */ 0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff, /* U+1f00 - U+1f1f */ 0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff, /* U+1f20 - U+1f3f */ 0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff, /* U+1f40 - U+1f5f */ 0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff, /* U+1f60 - U+1f7f */ 0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff, /* U+1f80 - U+1f9f */ 0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff, /* U+1fa0 - U+1fbf */ 0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff, /* U+1fc0 - U+1fdf */ 0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff, /* U+1fe0 - U+1fff */ 0xff,0xff,0xfc,0x00,0xff,0xff,0xff,0xff, /* U+2000 - U+201f */ 0xff,0xff,0xf0,0x03,0xff,0xff,0xff,0xff, /* U+2020 - U+203f */ 0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff, /* U+2040 - U+205f */ 0x00,0xff,0xf0,0x00,0xff,0xff,0xff,0xff, /* U+2060 - U+207f */ 0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff, /* U+2080 - U+209f */ 0xff,0xff,0xdf,0xff,0xff,0xff,0xff,0xff, /* U+20a0 - U+20bf */ 0xff,0xff,0xff,0xff,0x00,0x00,0x00,0x00, /* U+20c0 - U+20df */ 0x00,0x00,0x00,0x00,0xff,0xff,0xff,0xff, /* U+20e0 - U+20ff */ 0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff, /* U+2100 - U+211f */ 0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff, /* U+2120 - U+213f */ 0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff, /* U+2140 - U+215f */ 0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff, /* U+2160 - U+217f */ 0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff, /* U+2180 - U+219f */ 0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff, /* U+21a0 - U+21bf */ 0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff, /* U+21c0 - U+21df */ 0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff, /* U+21e0 - U+21ff */ 0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff, /* U+2200 - U+221f */ 0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff, /* U+2220 - U+223f */ 0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff, /* U+2240 - U+225f */ 0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff, /* U+2260 - U+227f */ 0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff, /* U+2280 - U+229f */ 0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff, /* U+22a0 - U+22bf */ 0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff, /* U+22c0 - U+22df */ 0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff, /* U+22e0 - U+22ff */ 0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff, /* U+2300 - U+231f */ 0xff,0xff,0xeb,0xff,0xff,0xff,0xff,0xff, /* U+2320 - U+233f */ 0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff, /* U+2340 - U+235f */ 0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff, /* U+2360 - U+237f */ 0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff, /* U+2380 - U+239f */ 0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff, /* U+23a0 - U+23bf */ 0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff, /* U+23c0 - U+23df */ 0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff, /* U+23e0 - U+23ff */ 0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff, /* U+2400 - U+241f */ 0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff, /* U+2420 - U+243f */ 0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff, /* U+2440 - U+245f */ 0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff, /* U+2460 - U+247f */ 0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff, /* U+2480 - U+249f */ 0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff, /* U+24a0 - U+24bf */ 0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff, /* U+24c0 - U+24df */ 0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff, /* U+24e0 - U+24ff */ 0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff, /* U+2500 - U+251f */ 0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff, /* U+2520 - U+253f */ 0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff, /* U+2540 - U+255f */ 0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff, /* U+2560 - U+257f */ 0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff, /* U+2580 - U+259f */ 0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff, /* U+25a0 - U+25bf */ 0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff, /* U+25c0 - U+25df */ 0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff, /* U+25e0 - U+25ff */ 0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff, /* U+2600 - U+261f */ 0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff, /* U+2620 - U+263f */ 0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff, /* U+2640 - U+265f */ 0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff, /* U+2660 - U+267f */ 0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff, /* U+2680 - U+269f */ 0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff, /* U+26a0 - U+26bf */ 0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff, /* U+26c0 - U+26df */ 0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff, /* U+26e0 - U+26ff */ 0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff, /* U+2700 - U+271f */ 0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff, /* U+2720 - U+273f */ 0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff, /* U+2740 - U+275f */ 0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff, /* U+2760 - U+277f */ 0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff, /* U+2780 - U+279f */ 0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff, /* U+27a0 - U+27bf */ 0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff, /* U+27c0 - U+27df */ 0xff,0xf5,0x55,0xff,0xff,0xff,0xff,0xff, /* U+27e0 - U+27ff */ 0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff, /* U+2800 - U+281f */ 0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff, /* U+2820 - U+283f */ 0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff, /* U+2840 - U+285f */ 0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff, /* U+2860 - U+287f */ 0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff, /* U+2880 - U+289f */ 0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff, /* U+28a0 - U+28bf */ 0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff, /* U+28c0 - U+28df */ 0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff, /* U+28e0 - U+28ff */ 0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff, /* U+2900 - U+291f */ 0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff, /* U+2920 - U+293f */ 0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff, /* U+2940 - U+295f */ 0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff, /* U+2960 - U+297f */ 0xff,0xd7,0xff,0xff,0xff,0xff,0xff,0xff, /* U+2980 - U+299f */ 0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff, /* U+29a0 - U+29bf */ 0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff, /* U+29c0 - U+29df */ 0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff, /* U+29e0 - U+29ff */ 0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff, /* U+2a00 - U+2a1f */ 0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff, /* U+2a20 - U+2a3f */ 0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff, /* U+2a40 - U+2a5f */ 0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff, /* U+2a60 - U+2a7f */ 0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff, /* U+2a80 - U+2a9f */ 0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff, /* U+2aa0 - U+2abf */ 0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff, /* U+2ac0 - U+2adf */ 0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff, /* U+2ae0 - U+2aff */ 0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff, /* U+2b00 - U+2b1f */ 0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff, /* U+2b20 - U+2b3f */ 0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff, /* U+2b40 - U+2b5f */ 0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff, /* U+2b60 - U+2b7f */ 0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff, /* U+2b80 - U+2b9f */ 0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff, /* U+2ba0 - U+2bbf */ 0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff, /* U+2bc0 - U+2bdf */ 0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff, /* U+2be0 - U+2bff */ 0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff, /* U+2c00 - U+2c1f */ 0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff, /* U+2c20 - U+2c3f */ 0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff, /* U+2c40 - U+2c5f */ 0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff, /* U+2c60 - U+2c7f */ 0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff, /* U+2c80 - U+2c9f */ 0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff, /* U+2ca0 - U+2cbf */ 0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff, /* U+2cc0 - U+2cdf */ 0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff, /* U+2ce0 - U+2cff */ 0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff, /* U+2d00 - U+2d1f */ 0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff, /* U+2d20 - U+2d3f */ 0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff, /* U+2d40 - U+2d5f */ 0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff, /* U+2d60 - U+2d7f */ 0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff, /* U+2d80 - U+2d9f */ 0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff, /* U+2da0 - U+2dbf */ 0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff, /* U+2dc0 - U+2ddf */ 0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff, /* U+2de0 - U+2dff */ 0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff, /* U+2e00 - U+2e1f */ 0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff, /* U+2e20 - U+2e3f */ 0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff, /* U+2e40 - U+2e5f */ 0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff, /* U+2e60 - U+2e7f */ 0xaa,0xaa,0xaa,0xaa,0xaa,0xaa,0xae,0xaa, /* U+2e80 - U+2e9f */ 0xaa,0xaa,0xaa,0xaa,0xaa,0xaa,0xaa,0xaa, /* U+2ea0 - U+2ebf */ 0xaa,0xaa,0xaa,0xaa,0xaa,0xaa,0xaa,0xaa, /* U+2ec0 - U+2edf */ 0xaa,0xaa,0xaa,0xaa,0xaa,0xff,0xff,0xff, /* U+2ee0 - U+2eff */ 0xaa,0xaa,0xaa,0xaa,0xaa,0xaa,0xaa,0xaa, /* U+2f00 - U+2f1f */ 0xaa,0xaa,0xaa,0xaa,0xaa,0xaa,0xaa,0xaa, /* U+2f20 - U+2f3f */ 0xaa,0xaa,0xaa,0xaa,0xaa,0xaa,0xaa,0xaa, /* U+2f40 - U+2f5f */ 0xaa,0xaa,0xaa,0xaa,0xaa,0xaa,0xaa,0xaa, /* U+2f60 - U+2f7f */ 0xaa,0xaa,0xaa,0xaa,0xaa,0xaa,0xaa,0xaa, /* U+2f80 - U+2f9f */ 0xaa,0xaa,0xaa,0xaa,0xaa,0xaa,0xaa,0xaa, /* U+2fa0 - U+2fbf */ 0xaa,0xaa,0xaa,0xaa,0xaa,0xaf,0xff,0xff, /* U+2fc0 - U+2fdf */ 0xff,0xff,0xff,0xff,0xaa,0xaa,0xaa,0xff, /* U+2fe0 - U+2fff */ 0xaa,0xaa,0xaa,0xaa,0xaa,0xaa,0xaa,0xaa, /* U+3000 - U+301f */ 0xaa,0xaa,0xa0,0x00,0xaa,0xaa,0xaa,0xab, /* U+3020 - U+303f */ 0xea,0xaa,0xaa,0xaa,0xaa,0xaa,0xaa,0xaa, /* U+3040 - U+305f */ 0xaa,0xaa,0xaa,0xaa,0xaa,0xaa,0xaa,0xaa, /* U+3060 - U+307f */ 0xaa,0xaa,0xaa,0xaa,0xaa,0xab,0xc2,0xaa, /* U+3080 - U+309f */ 0xaa,0xaa,0xaa,0xaa,0xaa,0xaa,0xaa,0xaa, /* U+30a0 - U+30bf */ 0xaa,0xaa,0xaa,0xaa,0xaa,0xaa,0xaa,0xaa, /* U+30c0 - U+30df */ 0xaa,0xaa,0xaa,0xaa,0xaa,0xaa,0xaa,0xaa, /* U+30e0 - U+30ff */ 0xff,0xea,0xaa,0xaa,0xaa,0xaa,0xaa,0xaa, /* U+3100 - U+311f */ 0xaa,0xaa,0xaa,0xbf,0xea,0xaa,0xaa,0xaa, /* U+3120 - U+313f */ 0xaa,0xaa,0xaa,0xaa,0xaa,0xaa,0xaa,0xaa, /* U+3140 - U+315f */ 0xaa,0xaa,0xaa,0xaa,0xaa,0xaa,0xaa,0xaa, /* U+3160 - U+317f */ 0xaa,0xaa,0xaa,0xab,0xaa,0xaa,0xaa,0xaa, /* U+3180 - U+319f */ 0xaa,0xaa,0xaa,0xaa,0xaa,0xaa,0xff,0xff, /* U+31a0 - U+31bf */ 0xaa,0xaa,0xaa,0xaa,0xff,0xff,0xff,0xff, /* U+31c0 - U+31df */ 0xff,0xff,0xff,0xff,0xaa,0xaa,0xaa,0xaa, /* U+31e0 - U+31ff */ 0xaa,0xaa,0xaa,0xaa,0xaa,0xaa,0xaa,0xab, /* U+3200 - U+321f */ 0xaa,0xaa,0xaa,0xaa,0xaa,0xaa,0xaa,0xaa, /* U+3220 - U+323f */ 0xaa,0xff,0xff,0xff,0xaa,0xaa,0xaa,0xaa, /* U+3240 - U+325f */ 0xaa,0xaa,0xaa,0xaa,0xaa,0xaa,0xaa,0xaa, /* U+3260 - U+327f */ 0xaa,0xaa,0xaa,0xaa,0xaa,0xaa,0xaa,0xaa, /* U+3280 - U+329f */ 0xaa,0xaa,0xaa,0xaa,0xaa,0xaa,0xaa,0xaa, /* U+32a0 - U+32bf */ 0xaa,0xaa,0xaa,0xaa,0xaa,0xaa,0xaa,0xaa, /* U+32c0 - U+32df */ 0xaa,0xaa,0xaa,0xaa,0xaa,0xaa,0xaa,0xab, /* U+32e0 - U+32ff */ 0xaa,0xaa,0xaa,0xaa,0xaa,0xaa,0xaa,0xaa, /* U+3300 - U+331f */ 0xaa,0xaa,0xaa,0xaa,0xaa,0xaa,0xaa,0xaa, /* U+3320 - U+333f */ 0xaa,0xaa,0xaa,0xaa,0xaa,0xaa,0xaa,0xaa, /* U+3340 - U+335f */ 0xaa,0xaa,0xaa,0xaa,0xaa,0xaa,0xaa,0xaa, /* U+3360 - U+337f */ 0xaa,0xaa,0xaa,0xaa,0xaa,0xaa,0xaa,0xaa, /* U+3380 - U+339f */ 0xaa,0xaa,0xaa,0xaa,0xaa,0xaa,0xaa,0xaa, /* U+33a0 - U+33bf */ 0xaa,0xaa,0xaa,0xaa,0xaa,0xaa,0xaa,0xaa, /* U+33c0 - U+33df */ 0xaa,0xaa,0xaa,0xaa,0xaa,0xaa,0xaa,0xaa, /* U+33e0 - U+33ff */ 0xaa,0xaa,0xaa,0xaa,0xaa,0xaa,0xaa,0xaa, /* U+3400 - U+341f */ 0xaa,0xaa,0xaa,0xaa,0xaa,0xaa,0xaa,0xaa, /* U+3420 - U+343f */ 0xaa,0xaa,0xaa,0xaa,0xaa,0xaa,0xaa,0xaa, /* U+3440 - U+345f */ 0xaa,0xaa,0xaa,0xaa,0xaa,0xaa,0xaa,0xaa, /* U+3460 - U+347f */ 0xaa,0xaa,0xaa,0xaa,0xaa,0xaa,0xaa,0xaa, /* U+3480 - U+349f */ 0xaa,0xaa,0xaa,0xaa,0xaa,0xaa,0xaa,0xaa, /* U+34a0 - U+34bf */ 0xaa,0xaa,0xaa,0xaa,0xaa,0xaa,0xaa,0xaa, /* U+34c0 - U+34df */ 0xaa,0xaa,0xaa,0xaa,0xaa,0xaa,0xaa,0xaa, /* U+34e0 - U+34ff */ 0xaa,0xaa,0xaa,0xaa,0xaa,0xaa,0xaa,0xaa, /* U+3500 - U+351f */ 0xaa,0xaa,0xaa,0xaa,0xaa,0xaa,0xaa,0xaa, /* U+3520 - U+353f */ 0xaa,0xaa,0xaa,0xaa,0xaa,0xaa,0xaa,0xaa, /* U+3540 - U+355f */ 0xaa,0xaa,0xaa,0xaa,0xaa,0xaa,0xaa,0xaa, /* U+3560 - U+357f */ 0xaa,0xaa,0xaa,0xaa,0xaa,0xaa,0xaa,0xaa, /* U+3580 - U+359f */ 0xaa,0xaa,0xaa,0xaa,0xaa,0xaa,0xaa,0xaa, /* U+35a0 - U+35bf */ 0xaa,0xaa,0xaa,0xaa,0xaa,0xaa,0xaa,0xaa, /* U+35c0 - U+35df */ 0xaa,0xaa,0xaa,0xaa,0xaa,0xaa,0xaa,0xaa, /* U+35e0 - U+35ff */ 0xaa,0xaa,0xaa,0xaa,0xaa,0xaa,0xaa,0xaa, /* U+3600 - U+361f */ 0xaa,0xaa,0xaa,0xaa,0xaa,0xaa,0xaa,0xaa, /* U+3620 - U+363f */ 0xaa,0xaa,0xaa,0xaa,0xaa,0xaa,0xaa,0xaa, /* U+3640 - U+365f */ 0xaa,0xaa,0xaa,0xaa,0xaa,0xaa,0xaa,0xaa, /* U+3660 - U+367f */ 0xaa,0xaa,0xaa,0xaa,0xaa,0xaa,0xaa,0xaa, /* U+3680 - U+369f */ 0xaa,0xaa,0xaa,0xaa,0xaa,0xaa,0xaa,0xaa, /* U+36a0 - U+36bf */ 0xaa,0xaa,0xaa,0xaa,0xaa,0xaa,0xaa,0xaa, /* U+36c0 - U+36df */ 0xaa,0xaa,0xaa,0xaa,0xaa,0xaa,0xaa,0xaa, /* U+36e0 - U+36ff */ 0xaa,0xaa,0xaa,0xaa,0xaa,0xaa,0xaa,0xaa, /* U+3700 - U+371f */ 0xaa,0xaa,0xaa,0xaa,0xaa,0xaa,0xaa,0xaa, /* U+3720 - U+373f */ 0xaa,0xaa,0xaa,0xaa,0xaa,0xaa,0xaa,0xaa, /* U+3740 - U+375f */ 0xaa,0xaa,0xaa,0xaa,0xaa,0xaa,0xaa,0xaa, /* U+3760 - U+377f */ 0xaa,0xaa,0xaa,0xaa,0xaa,0xaa,0xaa,0xaa, /* U+3780 - U+379f */ 0xaa,0xaa,0xaa,0xaa,0xaa,0xaa,0xaa,0xaa, /* U+37a0 - U+37bf */ 0xaa,0xaa,0xaa,0xaa,0xaa,0xaa,0xaa,0xaa, /* U+37c0 - U+37df */ 0xaa,0xaa,0xaa,0xaa,0xaa,0xaa,0xaa,0xaa, /* U+37e0 - U+37ff */ 0xaa,0xaa,0xaa,0xaa,0xaa,0xaa,0xaa,0xaa, /* U+3800 - U+381f */ 0xaa,0xaa,0xaa,0xaa,0xaa,0xaa,0xaa,0xaa, /* U+3820 - U+383f */ 0xaa,0xaa,0xaa,0xaa,0xaa,0xaa,0xaa,0xaa, /* U+3840 - U+385f */ 0xaa,0xaa,0xaa,0xaa,0xaa,0xaa,0xaa,0xaa, /* U+3860 - U+387f */ 0xaa,0xaa,0xaa,0xaa,0xaa,0xaa,0xaa,0xaa, /* U+3880 - U+389f */ 0xaa,0xaa,0xaa,0xaa,0xaa,0xaa,0xaa,0xaa, /* U+38a0 - U+38bf */ 0xaa,0xaa,0xaa,0xaa,0xaa,0xaa,0xaa,0xaa, /* U+38c0 - U+38df */ 0xaa,0xaa,0xaa,0xaa,0xaa,0xaa,0xaa,0xaa, /* U+38e0 - U+38ff */ 0xaa,0xaa,0xaa,0xaa,0xaa,0xaa,0xaa,0xaa, /* U+3900 - U+391f */ 0xaa,0xaa,0xaa,0xaa,0xaa,0xaa,0xaa,0xaa, /* U+3920 - U+393f */ 0xaa,0xaa,0xaa,0xaa,0xaa,0xaa,0xaa,0xaa, /* U+3940 - U+395f */ 0xaa,0xaa,0xaa,0xaa,0xaa,0xaa,0xaa,0xaa, /* U+3960 - U+397f */ 0xaa,0xaa,0xaa,0xaa,0xaa,0xaa,0xaa,0xaa, /* U+3980 - U+399f */ 0xaa,0xaa,0xaa,0xaa,0xaa,0xaa,0xaa,0xaa, /* U+39a0 - U+39bf */ 0xaa,0xaa,0xaa,0xaa,0xaa,0xaa,0xaa,0xaa, /* U+39c0 - U+39df */ 0xaa,0xaa,0xaa,0xaa,0xaa,0xaa,0xaa,0xaa, /* U+39e0 - U+39ff */ 0xaa,0xaa,0xaa,0xaa,0xaa,0xaa,0xaa,0xaa, /* U+3a00 - U+3a1f */ 0xaa,0xaa,0xaa,0xaa,0xaa,0xaa,0xaa,0xaa, /* U+3a20 - U+3a3f */ 0xaa,0xaa,0xaa,0xaa,0xaa,0xaa,0xaa,0xaa, /* U+3a40 - U+3a5f */ 0xaa,0xaa,0xaa,0xaa,0xaa,0xaa,0xaa,0xaa, /* U+3a60 - U+3a7f */ 0xaa,0xaa,0xaa,0xaa,0xaa,0xaa,0xaa,0xaa, /* U+3a80 - U+3a9f */ 0xaa,0xaa,0xaa,0xaa,0xaa,0xaa,0xaa,0xaa, /* U+3aa0 - U+3abf */ 0xaa,0xaa,0xaa,0xaa,0xaa,0xaa,0xaa,0xaa, /* U+3ac0 - U+3adf */ 0xaa,0xaa,0xaa,0xaa,0xaa,0xaa,0xaa,0xaa, /* U+3ae0 - U+3aff */ 0xaa,0xaa,0xaa,0xaa,0xaa,0xaa,0xaa,0xaa, /* U+3b00 - U+3b1f */ 0xaa,0xaa,0xaa,0xaa,0xaa,0xaa,0xaa,0xaa, /* U+3b20 - U+3b3f */ 0xaa,0xaa,0xaa,0xaa,0xaa,0xaa,0xaa,0xaa, /* U+3b40 - U+3b5f */ 0xaa,0xaa,0xaa,0xaa,0xaa,0xaa,0xaa,0xaa, /* U+3b60 - U+3b7f */ 0xaa,0xaa,0xaa,0xaa,0xaa,0xaa,0xaa,0xaa, /* U+3b80 - U+3b9f */ 0xaa,0xaa,0xaa,0xaa,0xaa,0xaa,0xaa,0xaa, /* U+3ba0 - U+3bbf */ 0xaa,0xaa,0xaa,0xaa,0xaa,0xaa,0xaa,0xaa, /* U+3bc0 - U+3bdf */ 0xaa,0xaa,0xaa,0xaa,0xaa,0xaa,0xaa,0xaa, /* U+3be0 - U+3bff */ 0xaa,0xaa,0xaa,0xaa,0xaa,0xaa,0xaa,0xaa, /* U+3c00 - U+3c1f */ 0xaa,0xaa,0xaa,0xaa,0xaa,0xaa,0xaa,0xaa, /* U+3c20 - U+3c3f */ 0xaa,0xaa,0xaa,0xaa,0xaa,0xaa,0xaa,0xaa, /* U+3c40 - U+3c5f */ 0xaa,0xaa,0xaa,0xaa,0xaa,0xaa,0xaa,0xaa, /* U+3c60 - U+3c7f */ 0xaa,0xaa,0xaa,0xaa,0xaa,0xaa,0xaa,0xaa, /* U+3c80 - U+3c9f */ 0xaa,0xaa,0xaa,0xaa,0xaa,0xaa,0xaa,0xaa, /* U+3ca0 - U+3cbf */ 0xaa,0xaa,0xaa,0xaa,0xaa,0xaa,0xaa,0xaa, /* U+3cc0 - U+3cdf */ 0xaa,0xaa,0xaa,0xaa,0xaa,0xaa,0xaa,0xaa, /* U+3ce0 - U+3cff */ 0xaa,0xaa,0xaa,0xaa,0xaa,0xaa,0xaa,0xaa, /* U+3d00 - U+3d1f */ 0xaa,0xaa,0xaa,0xaa,0xaa,0xaa,0xaa,0xaa, /* U+3d20 - U+3d3f */ 0xaa,0xaa,0xaa,0xaa,0xaa,0xaa,0xaa,0xaa, /* U+3d40 - U+3d5f */ 0xaa,0xaa,0xaa,0xaa,0xaa,0xaa,0xaa,0xaa, /* U+3d60 - U+3d7f */ 0xaa,0xaa,0xaa,0xaa,0xaa,0xaa,0xaa,0xaa, /* U+3d80 - U+3d9f */ 0xaa,0xaa,0xaa,0xaa,0xaa,0xaa,0xaa,0xaa, /* U+3da0 - U+3dbf */ 0xaa,0xaa,0xaa,0xaa,0xaa,0xaa,0xaa,0xaa, /* U+3dc0 - U+3ddf */ 0xaa,0xaa,0xaa,0xaa,0xaa,0xaa,0xaa,0xaa, /* U+3de0 - U+3dff */ 0xaa,0xaa,0xaa,0xaa,0xaa,0xaa,0xaa,0xaa, /* U+3e00 - U+3e1f */ 0xaa,0xaa,0xaa,0xaa,0xaa,0xaa,0xaa,0xaa, /* U+3e20 - U+3e3f */ 0xaa,0xaa,0xaa,0xaa,0xaa,0xaa,0xaa,0xaa, /* U+3e40 - U+3e5f */ 0xaa,0xaa,0xaa,0xaa,0xaa,0xaa,0xaa,0xaa, /* U+3e60 - U+3e7f */ 0xaa,0xaa,0xaa,0xaa,0xaa,0xaa,0xaa,0xaa, /* U+3e80 - U+3e9f */ 0xaa,0xaa,0xaa,0xaa,0xaa,0xaa,0xaa,0xaa, /* U+3ea0 - U+3ebf */ 0xaa,0xaa,0xaa,0xaa,0xaa,0xaa,0xaa,0xaa, /* U+3ec0 - U+3edf */ 0xaa,0xaa,0xaa,0xaa,0xaa,0xaa,0xaa,0xaa, /* U+3ee0 - U+3eff */ 0xaa,0xaa,0xaa,0xaa,0xaa,0xaa,0xaa,0xaa, /* U+3f00 - U+3f1f */ 0xaa,0xaa,0xaa,0xaa,0xaa,0xaa,0xaa,0xaa, /* U+3f20 - U+3f3f */ 0xaa,0xaa,0xaa,0xaa,0xaa,0xaa,0xaa,0xaa, /* U+3f40 - U+3f5f */ 0xaa,0xaa,0xaa,0xaa,0xaa,0xaa,0xaa,0xaa, /* U+3f60 - U+3f7f */ 0xaa,0xaa,0xaa,0xaa,0xaa,0xaa,0xaa,0xaa, /* U+3f80 - U+3f9f */ 0xaa,0xaa,0xaa,0xaa,0xaa,0xaa,0xaa,0xaa, /* U+3fa0 - U+3fbf */ 0xaa,0xaa,0xaa,0xaa,0xaa,0xaa,0xaa,0xaa, /* U+3fc0 - U+3fdf */ 0xaa,0xaa,0xaa,0xaa,0xaa,0xaa,0xaa,0xaa, /* U+3fe0 - U+3fff */ 0xaa,0xaa,0xaa,0xaa,0xaa,0xaa,0xaa,0xaa, /* U+4000 - U+401f */ 0xaa,0xaa,0xaa,0xaa,0xaa,0xaa,0xaa,0xaa, /* U+4020 - U+403f */ 0xaa,0xaa,0xaa,0xaa,0xaa,0xaa,0xaa,0xaa, /* U+4040 - U+405f */ 0xaa,0xaa,0xaa,0xaa,0xaa,0xaa,0xaa,0xaa, /* U+4060 - U+407f */ 0xaa,0xaa,0xaa,0xaa,0xaa,0xaa,0xaa,0xaa, /* U+4080 - U+409f */ 0xaa,0xaa,0xaa,0xaa,0xaa,0xaa,0xaa,0xaa, /* U+40a0 - U+40bf */ 0xaa,0xaa,0xaa,0xaa,0xaa,0xaa,0xaa,0xaa, /* U+40c0 - U+40df */ 0xaa,0xaa,0xaa,0xaa,0xaa,0xaa,0xaa,0xaa, /* U+40e0 - U+40ff */ 0xaa,0xaa,0xaa,0xaa,0xaa,0xaa,0xaa,0xaa, /* U+4100 - U+411f */ 0xaa,0xaa,0xaa,0xaa,0xaa,0xaa,0xaa,0xaa, /* U+4120 - U+413f */ 0xaa,0xaa,0xaa,0xaa,0xaa,0xaa,0xaa,0xaa, /* U+4140 - U+415f */ 0xaa,0xaa,0xaa,0xaa,0xaa,0xaa,0xaa,0xaa, /* U+4160 - U+417f */ 0xaa,0xaa,0xaa,0xaa,0xaa,0xaa,0xaa,0xaa, /* U+4180 - U+419f */ 0xaa,0xaa,0xaa,0xaa,0xaa,0xaa,0xaa,0xaa, /* U+41a0 - U+41bf */ 0xaa,0xaa,0xaa,0xaa,0xaa,0xaa,0xaa,0xaa, /* U+41c0 - U+41df */ 0xaa,0xaa,0xaa,0xaa,0xaa,0xaa,0xaa,0xaa, /* U+41e0 - U+41ff */ 0xaa,0xaa,0xaa,0xaa,0xaa,0xaa,0xaa,0xaa, /* U+4200 - U+421f */ 0xaa,0xaa,0xaa,0xaa,0xaa,0xaa,0xaa,0xaa, /* U+4220 - U+423f */ 0xaa,0xaa,0xaa,0xaa,0xaa,0xaa,0xaa,0xaa, /* U+4240 - U+425f */ 0xaa,0xaa,0xaa,0xaa,0xaa,0xaa,0xaa,0xaa, /* U+4260 - U+427f */ 0xaa,0xaa,0xaa,0xaa,0xaa,0xaa,0xaa,0xaa, /* U+4280 - U+429f */ 0xaa,0xaa,0xaa,0xaa,0xaa,0xaa,0xaa,0xaa, /* U+42a0 - U+42bf */ 0xaa,0xaa,0xaa,0xaa,0xaa,0xaa,0xaa,0xaa, /* U+42c0 - U+42df */ 0xaa,0xaa,0xaa,0xaa,0xaa,0xaa,0xaa,0xaa, /* U+42e0 - U+42ff */ 0xaa,0xaa,0xaa,0xaa,0xaa,0xaa,0xaa,0xaa, /* U+4300 - U+431f */ 0xaa,0xaa,0xaa,0xaa,0xaa,0xaa,0xaa,0xaa, /* U+4320 - U+433f */ 0xaa,0xaa,0xaa,0xaa,0xaa,0xaa,0xaa,0xaa, /* U+4340 - U+435f */ 0xaa,0xaa,0xaa,0xaa,0xaa,0xaa,0xaa,0xaa, /* U+4360 - U+437f */ 0xaa,0xaa,0xaa,0xaa,0xaa,0xaa,0xaa,0xaa, /* U+4380 - U+439f */ 0xaa,0xaa,0xaa,0xaa,0xaa,0xaa,0xaa,0xaa, /* U+43a0 - U+43bf */ 0xaa,0xaa,0xaa,0xaa,0xaa,0xaa,0xaa,0xaa, /* U+43c0 - U+43df */ 0xaa,0xaa,0xaa,0xaa,0xaa,0xaa,0xaa,0xaa, /* U+43e0 - U+43ff */ 0xaa,0xaa,0xaa,0xaa,0xaa,0xaa,0xaa,0xaa, /* U+4400 - U+441f */ 0xaa,0xaa,0xaa,0xaa,0xaa,0xaa,0xaa,0xaa, /* U+4420 - U+443f */ 0xaa,0xaa,0xaa,0xaa,0xaa,0xaa,0xaa,0xaa, /* U+4440 - U+445f */ 0xaa,0xaa,0xaa,0xaa,0xaa,0xaa,0xaa,0xaa, /* U+4460 - U+447f */ 0xaa,0xaa,0xaa,0xaa,0xaa,0xaa,0xaa,0xaa, /* U+4480 - U+449f */ 0xaa,0xaa,0xaa,0xaa,0xaa,0xaa,0xaa,0xaa, /* U+44a0 - U+44bf */ 0xaa,0xaa,0xaa,0xaa,0xaa,0xaa,0xaa,0xaa, /* U+44c0 - U+44df */ 0xaa,0xaa,0xaa,0xaa,0xaa,0xaa,0xaa,0xaa, /* U+44e0 - U+44ff */ 0xaa,0xaa,0xaa,0xaa,0xaa,0xaa,0xaa,0xaa, /* U+4500 - U+451f */ 0xaa,0xaa,0xaa,0xaa,0xaa,0xaa,0xaa,0xaa, /* U+4520 - U+453f */ 0xaa,0xaa,0xaa,0xaa,0xaa,0xaa,0xaa,0xaa, /* U+4540 - U+455f */ 0xaa,0xaa,0xaa,0xaa,0xaa,0xaa,0xaa,0xaa, /* U+4560 - U+457f */ 0xaa,0xaa,0xaa,0xaa,0xaa,0xaa,0xaa,0xaa, /* U+4580 - U+459f */ 0xaa,0xaa,0xaa,0xaa,0xaa,0xaa,0xaa,0xaa, /* U+45a0 - U+45bf */ 0xaa,0xaa,0xaa,0xaa,0xaa,0xaa,0xaa,0xaa, /* U+45c0 - U+45df */ 0xaa,0xaa,0xaa,0xaa,0xaa,0xaa,0xaa,0xaa, /* U+45e0 - U+45ff */ 0xaa,0xaa,0xaa,0xaa,0xaa,0xaa,0xaa,0xaa, /* U+4600 - U+461f */ 0xaa,0xaa,0xaa,0xaa,0xaa,0xaa,0xaa,0xaa, /* U+4620 - U+463f */ 0xaa,0xaa,0xaa,0xaa,0xaa,0xaa,0xaa,0xaa, /* U+4640 - U+465f */ 0xaa,0xaa,0xaa,0xaa,0xaa,0xaa,0xaa,0xaa, /* U+4660 - U+467f */ 0xaa,0xaa,0xaa,0xaa,0xaa,0xaa,0xaa,0xaa, /* U+4680 - U+469f */ 0xaa,0xaa,0xaa,0xaa,0xaa,0xaa,0xaa,0xaa, /* U+46a0 - U+46bf */ 0xaa,0xaa,0xaa,0xaa,0xaa,0xaa,0xaa,0xaa, /* U+46c0 - U+46df */ 0xaa,0xaa,0xaa,0xaa,0xaa,0xaa,0xaa,0xaa, /* U+46e0 - U+46ff */ 0xaa,0xaa,0xaa,0xaa,0xaa,0xaa,0xaa,0xaa, /* U+4700 - U+471f */ 0xaa,0xaa,0xaa,0xaa,0xaa,0xaa,0xaa,0xaa, /* U+4720 - U+473f */ 0xaa,0xaa,0xaa,0xaa,0xaa,0xaa,0xaa,0xaa, /* U+4740 - U+475f */ 0xaa,0xaa,0xaa,0xaa,0xaa,0xaa,0xaa,0xaa, /* U+4760 - U+477f */ 0xaa,0xaa,0xaa,0xaa,0xaa,0xaa,0xaa,0xaa, /* U+4780 - U+479f */ 0xaa,0xaa,0xaa,0xaa,0xaa,0xaa,0xaa,0xaa, /* U+47a0 - U+47bf */ 0xaa,0xaa,0xaa,0xaa,0xaa,0xaa,0xaa,0xaa, /* U+47c0 - U+47df */ 0xaa,0xaa,0xaa,0xaa,0xaa,0xaa,0xaa,0xaa, /* U+47e0 - U+47ff */ 0xaa,0xaa,0xaa,0xaa,0xaa,0xaa,0xaa,0xaa, /* U+4800 - U+481f */ 0xaa,0xaa,0xaa,0xaa,0xaa,0xaa,0xaa,0xaa, /* U+4820 - U+483f */ 0xaa,0xaa,0xaa,0xaa,0xaa,0xaa,0xaa,0xaa, /* U+4840 - U+485f */ 0xaa,0xaa,0xaa,0xaa,0xaa,0xaa,0xaa,0xaa, /* U+4860 - U+487f */ 0xaa,0xaa,0xaa,0xaa,0xaa,0xaa,0xaa,0xaa, /* U+4880 - U+489f */ 0xaa,0xaa,0xaa,0xaa,0xaa,0xaa,0xaa,0xaa, /* U+48a0 - U+48bf */ 0xaa,0xaa,0xaa,0xaa,0xaa,0xaa,0xaa,0xaa, /* U+48c0 - U+48df */ 0xaa,0xaa,0xaa,0xaa,0xaa,0xaa,0xaa,0xaa, /* U+48e0 - U+48ff */ 0xaa,0xaa,0xaa,0xaa,0xaa,0xaa,0xaa,0xaa, /* U+4900 - U+491f */ 0xaa,0xaa,0xaa,0xaa,0xaa,0xaa,0xaa,0xaa, /* U+4920 - U+493f */ 0xaa,0xaa,0xaa,0xaa,0xaa,0xaa,0xaa,0xaa, /* U+4940 - U+495f */ 0xaa,0xaa,0xaa,0xaa,0xaa,0xaa,0xaa,0xaa, /* U+4960 - U+497f */ 0xaa,0xaa,0xaa,0xaa,0xaa,0xaa,0xaa,0xaa, /* U+4980 - U+499f */ 0xaa,0xaa,0xaa,0xaa,0xaa,0xaa,0xaa,0xaa, /* U+49a0 - U+49bf */ 0xaa,0xaa,0xaa,0xaa,0xaa,0xaa,0xaa,0xaa, /* U+49c0 - U+49df */ 0xaa,0xaa,0xaa,0xaa,0xaa,0xaa,0xaa,0xaa, /* U+49e0 - U+49ff */ 0xaa,0xaa,0xaa,0xaa,0xaa,0xaa,0xaa,0xaa, /* U+4a00 - U+4a1f */ 0xaa,0xaa,0xaa,0xaa,0xaa,0xaa,0xaa,0xaa, /* U+4a20 - U+4a3f */ 0xaa,0xaa,0xaa,0xaa,0xaa,0xaa,0xaa,0xaa, /* U+4a40 - U+4a5f */ 0xaa,0xaa,0xaa,0xaa,0xaa,0xaa,0xaa,0xaa, /* U+4a60 - U+4a7f */ 0xaa,0xaa,0xaa,0xaa,0xaa,0xaa,0xaa,0xaa, /* U+4a80 - U+4a9f */ 0xaa,0xaa,0xaa,0xaa,0xaa,0xaa,0xaa,0xaa, /* U+4aa0 - U+4abf */ 0xaa,0xaa,0xaa,0xaa,0xaa,0xaa,0xaa,0xaa, /* U+4ac0 - U+4adf */ 0xaa,0xaa,0xaa,0xaa,0xaa,0xaa,0xaa,0xaa, /* U+4ae0 - U+4aff */ 0xaa,0xaa,0xaa,0xaa,0xaa,0xaa,0xaa,0xaa, /* U+4b00 - U+4b1f */ 0xaa,0xaa,0xaa,0xaa,0xaa,0xaa,0xaa,0xaa, /* U+4b20 - U+4b3f */ 0xaa,0xaa,0xaa,0xaa,0xaa,0xaa,0xaa,0xaa, /* U+4b40 - U+4b5f */ 0xaa,0xaa,0xaa,0xaa,0xaa,0xaa,0xaa,0xaa, /* U+4b60 - U+4b7f */ 0xaa,0xaa,0xaa,0xaa,0xaa,0xaa,0xaa,0xaa, /* U+4b80 - U+4b9f */ 0xaa,0xaa,0xaa,0xaa,0xaa,0xaa,0xaa,0xaa, /* U+4ba0 - U+4bbf */ 0xaa,0xaa,0xaa,0xaa,0xaa,0xaa,0xaa,0xaa, /* U+4bc0 - U+4bdf */ 0xaa,0xaa,0xaa,0xaa,0xaa,0xaa,0xaa,0xaa, /* U+4be0 - U+4bff */ 0xaa,0xaa,0xaa,0xaa,0xaa,0xaa,0xaa,0xaa, /* U+4c00 - U+4c1f */ 0xaa,0xaa,0xaa,0xaa,0xaa,0xaa,0xaa,0xaa, /* U+4c20 - U+4c3f */ 0xaa,0xaa,0xaa,0xaa,0xaa,0xaa,0xaa,0xaa, /* U+4c40 - U+4c5f */ 0xaa,0xaa,0xaa,0xaa,0xaa,0xaa,0xaa,0xaa, /* U+4c60 - U+4c7f */ 0xaa,0xaa,0xaa,0xaa,0xaa,0xaa,0xaa,0xaa, /* U+4c80 - U+4c9f */ 0xaa,0xaa,0xaa,0xaa,0xaa,0xaa,0xaa,0xaa, /* U+4ca0 - U+4cbf */ 0xaa,0xaa,0xaa,0xaa,0xaa,0xaa,0xaa,0xaa, /* U+4cc0 - U+4cdf */ 0xaa,0xaa,0xaa,0xaa,0xaa,0xaa,0xaa,0xaa, /* U+4ce0 - U+4cff */ 0xaa,0xaa,0xaa,0xaa,0xaa,0xaa,0xaa,0xaa, /* U+4d00 - U+4d1f */ 0xaa,0xaa,0xaa,0xaa,0xaa,0xaa,0xaa,0xaa, /* U+4d20 - U+4d3f */ 0xaa,0xaa,0xaa,0xaa,0xaa,0xaa,0xaa,0xaa, /* U+4d40 - U+4d5f */ 0xaa,0xaa,0xaa,0xaa,0xaa,0xaa,0xaa,0xaa, /* U+4d60 - U+4d7f */ 0xaa,0xaa,0xaa,0xaa,0xaa,0xaa,0xaa,0xaa, /* U+4d80 - U+4d9f */ 0xaa,0xaa,0xaa,0xaa,0xaa,0xaf,0xff,0xff, /* U+4da0 - U+4dbf */ 0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff, /* U+4dc0 - U+4ddf */ 0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff, /* U+4de0 - U+4dff */ 0xaa,0xaa,0xaa,0xaa,0xaa,0xaa,0xaa,0xaa, /* U+4e00 - U+4e1f */ 0xaa,0xaa,0xaa,0xaa,0xaa,0xaa,0xaa,0xaa, /* U+4e20 - U+4e3f */ 0xaa,0xaa,0xaa,0xaa,0xaa,0xaa,0xaa,0xaa, /* U+4e40 - U+4e5f */ 0xaa,0xaa,0xaa,0xaa,0xaa,0xaa,0xaa,0xaa, /* U+4e60 - U+4e7f */ 0xaa,0xaa,0xaa,0xaa,0xaa,0xaa,0xaa,0xaa, /* U+4e80 - U+4e9f */ 0xaa,0xaa,0xaa,0xaa,0xaa,0xaa,0xaa,0xaa, /* U+4ea0 - U+4ebf */ 0xaa,0xaa,0xaa,0xaa,0xaa,0xaa,0xaa,0xaa, /* U+4ec0 - U+4edf */ 0xaa,0xaa,0xaa,0xaa,0xaa,0xaa,0xaa,0xaa, /* U+4ee0 - U+4eff */ 0xaa,0xaa,0xaa,0xaa,0xaa,0xaa,0xaa,0xaa, /* U+4f00 - U+4f1f */ 0xaa,0xaa,0xaa,0xaa,0xaa,0xaa,0xaa,0xaa, /* U+4f20 - U+4f3f */ 0xaa,0xaa,0xaa,0xaa,0xaa,0xaa,0xaa,0xaa, /* U+4f40 - U+4f5f */ 0xaa,0xaa,0xaa,0xaa,0xaa,0xaa,0xaa,0xaa, /* U+4f60 - U+4f7f */ 0xaa,0xaa,0xaa,0xaa,0xaa,0xaa,0xaa,0xaa, /* U+4f80 - U+4f9f */ 0xaa,0xaa,0xaa,0xaa,0xaa,0xaa,0xaa,0xaa, /* U+4fa0 - U+4fbf */ 0xaa,0xaa,0xaa,0xaa,0xaa,0xaa,0xaa,0xaa, /* U+4fc0 - U+4fdf */ 0xaa,0xaa,0xaa,0xaa,0xaa,0xaa,0xaa,0xaa, /* U+4fe0 - U+4fff */ 0xaa,0xaa,0xaa,0xaa,0xaa,0xaa,0xaa,0xaa, /* U+5000 - U+501f */ 0xaa,0xaa,0xaa,0xaa,0xaa,0xaa,0xaa,0xaa, /* U+5020 - U+503f */ 0xaa,0xaa,0xaa,0xaa,0xaa,0xaa,0xaa,0xaa, /* U+5040 - U+505f */ 0xaa,0xaa,0xaa,0xaa,0xaa,0xaa,0xaa,0xaa, /* U+5060 - U+507f */ 0xaa,0xaa,0xaa,0xaa,0xaa,0xaa,0xaa,0xaa, /* U+5080 - U+509f */ 0xaa,0xaa,0xaa,0xaa,0xaa,0xaa,0xaa,0xaa, /* U+50a0 - U+50bf */ 0xaa,0xaa,0xaa,0xaa,0xaa,0xaa,0xaa,0xaa, /* U+50c0 - U+50df */ 0xaa,0xaa,0xaa,0xaa,0xaa,0xaa,0xaa,0xaa, /* U+50e0 - U+50ff */ 0xaa,0xaa,0xaa,0xaa,0xaa,0xaa,0xaa,0xaa, /* U+5100 - U+511f */ 0xaa,0xaa,0xaa,0xaa,0xaa,0xaa,0xaa,0xaa, /* U+5120 - U+513f */ 0xaa,0xaa,0xaa,0xaa,0xaa,0xaa,0xaa,0xaa, /* U+5140 - U+515f */ 0xaa,0xaa,0xaa,0xaa,0xaa,0xaa,0xaa,0xaa, /* U+5160 - U+517f */ 0xaa,0xaa,0xaa,0xaa,0xaa,0xaa,0xaa,0xaa, /* U+5180 - U+519f */ 0xaa,0xaa,0xaa,0xaa,0xaa,0xaa,0xaa,0xaa, /* U+51a0 - U+51bf */ 0xaa,0xaa,0xaa,0xaa,0xaa,0xaa,0xaa,0xaa, /* U+51c0 - U+51df */ 0xaa,0xaa,0xaa,0xaa,0xaa,0xaa,0xaa,0xaa, /* U+51e0 - U+51ff */ 0xaa,0xaa,0xaa,0xaa,0xaa,0xaa,0xaa,0xaa, /* U+5200 - U+521f */ 0xaa,0xaa,0xaa,0xaa,0xaa,0xaa,0xaa,0xaa, /* U+5220 - U+523f */ 0xaa,0xaa,0xaa,0xaa,0xaa,0xaa,0xaa,0xaa, /* U+5240 - U+525f */ 0xaa,0xaa,0xaa,0xaa,0xaa,0xaa,0xaa,0xaa, /* U+5260 - U+527f */ 0xaa,0xaa,0xaa,0xaa,0xaa,0xaa,0xaa,0xaa, /* U+5280 - U+529f */ 0xaa,0xaa,0xaa,0xaa,0xaa,0xaa,0xaa,0xaa, /* U+52a0 - U+52bf */ 0xaa,0xaa,0xaa,0xaa,0xaa,0xaa,0xaa,0xaa, /* U+52c0 - U+52df */ 0xaa,0xaa,0xaa,0xaa,0xaa,0xaa,0xaa,0xaa, /* U+52e0 - U+52ff */ 0xaa,0xaa,0xaa,0xaa,0xaa,0xaa,0xaa,0xaa, /* U+5300 - U+531f */ 0xaa,0xaa,0xaa,0xaa,0xaa,0xaa,0xaa,0xaa, /* U+5320 - U+533f */ 0xaa,0xaa,0xaa,0xaa,0xaa,0xaa,0xaa,0xaa, /* U+5340 - U+535f */ 0xaa,0xaa,0xaa,0xaa,0xaa,0xaa,0xaa,0xaa, /* U+5360 - U+537f */ 0xaa,0xaa,0xaa,0xaa,0xaa,0xaa,0xaa,0xaa, /* U+5380 - U+539f */ 0xaa,0xaa,0xaa,0xaa,0xaa,0xaa,0xaa,0xaa, /* U+53a0 - U+53bf */ 0xaa,0xaa,0xaa,0xaa,0xaa,0xaa,0xaa,0xaa, /* U+53c0 - U+53df */ 0xaa,0xaa,0xaa,0xaa,0xaa,0xaa,0xaa,0xaa, /* U+53e0 - U+53ff */ 0xaa,0xaa,0xaa,0xaa,0xaa,0xaa,0xaa,0xaa, /* U+5400 - U+541f */ 0xaa,0xaa,0xaa,0xaa,0xaa,0xaa,0xaa,0xaa, /* U+5420 - U+543f */ 0xaa,0xaa,0xaa,0xaa,0xaa,0xaa,0xaa,0xaa, /* U+5440 - U+545f */ 0xaa,0xaa,0xaa,0xaa,0xaa,0xaa,0xaa,0xaa, /* U+5460 - U+547f */ 0xaa,0xaa,0xaa,0xaa,0xaa,0xaa,0xaa,0xaa, /* U+5480 - U+549f */ 0xaa,0xaa,0xaa,0xaa,0xaa,0xaa,0xaa,0xaa, /* U+54a0 - U+54bf */ 0xaa,0xaa,0xaa,0xaa,0xaa,0xaa,0xaa,0xaa, /* U+54c0 - U+54df */ 0xaa,0xaa,0xaa,0xaa,0xaa,0xaa,0xaa,0xaa, /* U+54e0 - U+54ff */ 0xaa,0xaa,0xaa,0xaa,0xaa,0xaa,0xaa,0xaa, /* U+5500 - U+551f */ 0xaa,0xaa,0xaa,0xaa,0xaa,0xaa,0xaa,0xaa, /* U+5520 - U+553f */ 0xaa,0xaa,0xaa,0xaa,0xaa,0xaa,0xaa,0xaa, /* U+5540 - U+555f */ 0xaa,0xaa,0xaa,0xaa,0xaa,0xaa,0xaa,0xaa, /* U+5560 - U+557f */ 0xaa,0xaa,0xaa,0xaa,0xaa,0xaa,0xaa,0xaa, /* U+5580 - U+559f */ 0xaa,0xaa,0xaa,0xaa,0xaa,0xaa,0xaa,0xaa, /* U+55a0 - U+55bf */ 0xaa,0xaa,0xaa,0xaa,0xaa,0xaa,0xaa,0xaa, /* U+55c0 - U+55df */ 0xaa,0xaa,0xaa,0xaa,0xaa,0xaa,0xaa,0xaa, /* U+55e0 - U+55ff */ 0xaa,0xaa,0xaa,0xaa,0xaa,0xaa,0xaa,0xaa, /* U+5600 - U+561f */ 0xaa,0xaa,0xaa,0xaa,0xaa,0xaa,0xaa,0xaa, /* U+5620 - U+563f */ 0xaa,0xaa,0xaa,0xaa,0xaa,0xaa,0xaa,0xaa, /* U+5640 - U+565f */ 0xaa,0xaa,0xaa,0xaa,0xaa,0xaa,0xaa,0xaa, /* U+5660 - U+567f */ 0xaa,0xaa,0xaa,0xaa,0xaa,0xaa,0xaa,0xaa, /* U+5680 - U+569f */ 0xaa,0xaa,0xaa,0xaa,0xaa,0xaa,0xaa,0xaa, /* U+56a0 - U+56bf */ 0xaa,0xaa,0xaa,0xaa,0xaa,0xaa,0xaa,0xaa, /* U+56c0 - U+56df */ 0xaa,0xaa,0xaa,0xaa,0xaa,0xaa,0xaa,0xaa, /* U+56e0 - U+56ff */ 0xaa,0xaa,0xaa,0xaa,0xaa,0xaa,0xaa,0xaa, /* U+5700 - U+571f */ 0xaa,0xaa,0xaa,0xaa,0xaa,0xaa,0xaa,0xaa, /* U+5720 - U+573f */ 0xaa,0xaa,0xaa,0xaa,0xaa,0xaa,0xaa,0xaa, /* U+5740 - U+575f */ 0xaa,0xaa,0xaa,0xaa,0xaa,0xaa,0xaa,0xaa, /* U+5760 - U+577f */ 0xaa,0xaa,0xaa,0xaa,0xaa,0xaa,0xaa,0xaa, /* U+5780 - U+579f */ 0xaa,0xaa,0xaa,0xaa,0xaa,0xaa,0xaa,0xaa, /* U+57a0 - U+57bf */ 0xaa,0xaa,0xaa,0xaa,0xaa,0xaa,0xaa,0xaa, /* U+57c0 - U+57df */ 0xaa,0xaa,0xaa,0xaa,0xaa,0xaa,0xaa,0xaa, /* U+57e0 - U+57ff */ 0xaa,0xaa,0xaa,0xaa,0xaa,0xaa,0xaa,0xaa, /* U+5800 - U+581f */ 0xaa,0xaa,0xaa,0xaa,0xaa,0xaa,0xaa,0xaa, /* U+5820 - U+583f */ 0xaa,0xaa,0xaa,0xaa,0xaa,0xaa,0xaa,0xaa, /* U+5840 - U+585f */ 0xaa,0xaa,0xaa,0xaa,0xaa,0xaa,0xaa,0xaa, /* U+5860 - U+587f */ 0xaa,0xaa,0xaa,0xaa,0xaa,0xaa,0xaa,0xaa, /* U+5880 - U+589f */ 0xaa,0xaa,0xaa,0xaa,0xaa,0xaa,0xaa,0xaa, /* U+58a0 - U+58bf */ 0xaa,0xaa,0xaa,0xaa,0xaa,0xaa,0xaa,0xaa, /* U+58c0 - U+58df */ 0xaa,0xaa,0xaa,0xaa,0xaa,0xaa,0xaa,0xaa, /* U+58e0 - U+58ff */ 0xaa,0xaa,0xaa,0xaa,0xaa,0xaa,0xaa,0xaa, /* U+5900 - U+591f */ 0xaa,0xaa,0xaa,0xaa,0xaa,0xaa,0xaa,0xaa, /* U+5920 - U+593f */ 0xaa,0xaa,0xaa,0xaa,0xaa,0xaa,0xaa,0xaa, /* U+5940 - U+595f */ 0xaa,0xaa,0xaa,0xaa,0xaa,0xaa,0xaa,0xaa, /* U+5960 - U+597f */ 0xaa,0xaa,0xaa,0xaa,0xaa,0xaa,0xaa,0xaa, /* U+5980 - U+599f */ 0xaa,0xaa,0xaa,0xaa,0xaa,0xaa,0xaa,0xaa, /* U+59a0 - U+59bf */ 0xaa,0xaa,0xaa,0xaa,0xaa,0xaa,0xaa,0xaa, /* U+59c0 - U+59df */ 0xaa,0xaa,0xaa,0xaa,0xaa,0xaa,0xaa,0xaa, /* U+59e0 - U+59ff */ 0xaa,0xaa,0xaa,0xaa,0xaa,0xaa,0xaa,0xaa, /* U+5a00 - U+5a1f */ 0xaa,0xaa,0xaa,0xaa,0xaa,0xaa,0xaa,0xaa, /* U+5a20 - U+5a3f */ 0xaa,0xaa,0xaa,0xaa,0xaa,0xaa,0xaa,0xaa, /* U+5a40 - U+5a5f */ 0xaa,0xaa,0xaa,0xaa,0xaa,0xaa,0xaa,0xaa, /* U+5a60 - U+5a7f */ 0xaa,0xaa,0xaa,0xaa,0xaa,0xaa,0xaa,0xaa, /* U+5a80 - U+5a9f */ 0xaa,0xaa,0xaa,0xaa,0xaa,0xaa,0xaa,0xaa, /* U+5aa0 - U+5abf */ 0xaa,0xaa,0xaa,0xaa,0xaa,0xaa,0xaa,0xaa, /* U+5ac0 - U+5adf */ 0xaa,0xaa,0xaa,0xaa,0xaa,0xaa,0xaa,0xaa, /* U+5ae0 - U+5aff */ 0xaa,0xaa,0xaa,0xaa,0xaa,0xaa,0xaa,0xaa, /* U+5b00 - U+5b1f */ 0xaa,0xaa,0xaa,0xaa,0xaa,0xaa,0xaa,0xaa, /* U+5b20 - U+5b3f */ 0xaa,0xaa,0xaa,0xaa,0xaa,0xaa,0xaa,0xaa, /* U+5b40 - U+5b5f */ 0xaa,0xaa,0xaa,0xaa,0xaa,0xaa,0xaa,0xaa, /* U+5b60 - U+5b7f */ 0xaa,0xaa,0xaa,0xaa,0xaa,0xaa,0xaa,0xaa, /* U+5b80 - U+5b9f */ 0xaa,0xaa,0xaa,0xaa,0xaa,0xaa,0xaa,0xaa, /* U+5ba0 - U+5bbf */ 0xaa,0xaa,0xaa,0xaa,0xaa,0xaa,0xaa,0xaa, /* U+5bc0 - U+5bdf */ 0xaa,0xaa,0xaa,0xaa,0xaa,0xaa,0xaa,0xaa, /* U+5be0 - U+5bff */ 0xaa,0xaa,0xaa,0xaa,0xaa,0xaa,0xaa,0xaa, /* U+5c00 - U+5c1f */ 0xaa,0xaa,0xaa,0xaa,0xaa,0xaa,0xaa,0xaa, /* U+5c20 - U+5c3f */ 0xaa,0xaa,0xaa,0xaa,0xaa,0xaa,0xaa,0xaa, /* U+5c40 - U+5c5f */ 0xaa,0xaa,0xaa,0xaa,0xaa,0xaa,0xaa,0xaa, /* U+5c60 - U+5c7f */ 0xaa,0xaa,0xaa,0xaa,0xaa,0xaa,0xaa,0xaa, /* U+5c80 - U+5c9f */ 0xaa,0xaa,0xaa,0xaa,0xaa,0xaa,0xaa,0xaa, /* U+5ca0 - U+5cbf */ 0xaa,0xaa,0xaa,0xaa,0xaa,0xaa,0xaa,0xaa, /* U+5cc0 - U+5cdf */ 0xaa,0xaa,0xaa,0xaa,0xaa,0xaa,0xaa,0xaa, /* U+5ce0 - U+5cff */ 0xaa,0xaa,0xaa,0xaa,0xaa,0xaa,0xaa,0xaa, /* U+5d00 - U+5d1f */ 0xaa,0xaa,0xaa,0xaa,0xaa,0xaa,0xaa,0xaa, /* U+5d20 - U+5d3f */ 0xaa,0xaa,0xaa,0xaa,0xaa,0xaa,0xaa,0xaa, /* U+5d40 - U+5d5f */ 0xaa,0xaa,0xaa,0xaa,0xaa,0xaa,0xaa,0xaa, /* U+5d60 - U+5d7f */ 0xaa,0xaa,0xaa,0xaa,0xaa,0xaa,0xaa,0xaa, /* U+5d80 - U+5d9f */ 0xaa,0xaa,0xaa,0xaa,0xaa,0xaa,0xaa,0xaa, /* U+5da0 - U+5dbf */ 0xaa,0xaa,0xaa,0xaa,0xaa,0xaa,0xaa,0xaa, /* U+5dc0 - U+5ddf */ 0xaa,0xaa,0xaa,0xaa,0xaa,0xaa,0xaa,0xaa, /* U+5de0 - U+5dff */ 0xaa,0xaa,0xaa,0xaa,0xaa,0xaa,0xaa,0xaa, /* U+5e00 - U+5e1f */ 0xaa,0xaa,0xaa,0xaa,0xaa,0xaa,0xaa,0xaa, /* U+5e20 - U+5e3f */ 0xaa,0xaa,0xaa,0xaa,0xaa,0xaa,0xaa,0xaa, /* U+5e40 - U+5e5f */ 0xaa,0xaa,0xaa,0xaa,0xaa,0xaa,0xaa,0xaa, /* U+5e60 - U+5e7f */ 0xaa,0xaa,0xaa,0xaa,0xaa,0xaa,0xaa,0xaa, /* U+5e80 - U+5e9f */ 0xaa,0xaa,0xaa,0xaa,0xaa,0xaa,0xaa,0xaa, /* U+5ea0 - U+5ebf */ 0xaa,0xaa,0xaa,0xaa,0xaa,0xaa,0xaa,0xaa, /* U+5ec0 - U+5edf */ 0xaa,0xaa,0xaa,0xaa,0xaa,0xaa,0xaa,0xaa, /* U+5ee0 - U+5eff */ 0xaa,0xaa,0xaa,0xaa,0xaa,0xaa,0xaa,0xaa, /* U+5f00 - U+5f1f */ 0xaa,0xaa,0xaa,0xaa,0xaa,0xaa,0xaa,0xaa, /* U+5f20 - U+5f3f */ 0xaa,0xaa,0xaa,0xaa,0xaa,0xaa,0xaa,0xaa, /* U+5f40 - U+5f5f */ 0xaa,0xaa,0xaa,0xaa,0xaa,0xaa,0xaa,0xaa, /* U+5f60 - U+5f7f */ 0xaa,0xaa,0xaa,0xaa,0xaa,0xaa,0xaa,0xaa, /* U+5f80 - U+5f9f */ 0xaa,0xaa,0xaa,0xaa,0xaa,0xaa,0xaa,0xaa, /* U+5fa0 - U+5fbf */ 0xaa,0xaa,0xaa,0xaa,0xaa,0xaa,0xaa,0xaa, /* U+5fc0 - U+5fdf */ 0xaa,0xaa,0xaa,0xaa,0xaa,0xaa,0xaa,0xaa, /* U+5fe0 - U+5fff */ 0xaa,0xaa,0xaa,0xaa,0xaa,0xaa,0xaa,0xaa, /* U+6000 - U+601f */ 0xaa,0xaa,0xaa,0xaa,0xaa,0xaa,0xaa,0xaa, /* U+6020 - U+603f */ 0xaa,0xaa,0xaa,0xaa,0xaa,0xaa,0xaa,0xaa, /* U+6040 - U+605f */ 0xaa,0xaa,0xaa,0xaa,0xaa,0xaa,0xaa,0xaa, /* U+6060 - U+607f */ 0xaa,0xaa,0xaa,0xaa,0xaa,0xaa,0xaa,0xaa, /* U+6080 - U+609f */ 0xaa,0xaa,0xaa,0xaa,0xaa,0xaa,0xaa,0xaa, /* U+60a0 - U+60bf */ 0xaa,0xaa,0xaa,0xaa,0xaa,0xaa,0xaa,0xaa, /* U+60c0 - U+60df */ 0xaa,0xaa,0xaa,0xaa,0xaa,0xaa,0xaa,0xaa, /* U+60e0 - U+60ff */ 0xaa,0xaa,0xaa,0xaa,0xaa,0xaa,0xaa,0xaa, /* U+6100 - U+611f */ 0xaa,0xaa,0xaa,0xaa,0xaa,0xaa,0xaa,0xaa, /* U+6120 - U+613f */ 0xaa,0xaa,0xaa,0xaa,0xaa,0xaa,0xaa,0xaa, /* U+6140 - U+615f */ 0xaa,0xaa,0xaa,0xaa,0xaa,0xaa,0xaa,0xaa, /* U+6160 - U+617f */ 0xaa,0xaa,0xaa,0xaa,0xaa,0xaa,0xaa,0xaa, /* U+6180 - U+619f */ 0xaa,0xaa,0xaa,0xaa,0xaa,0xaa,0xaa,0xaa, /* U+61a0 - U+61bf */ 0xaa,0xaa,0xaa,0xaa,0xaa,0xaa,0xaa,0xaa, /* U+61c0 - U+61df */ 0xaa,0xaa,0xaa,0xaa,0xaa,0xaa,0xaa,0xaa, /* U+61e0 - U+61ff */ 0xaa,0xaa,0xaa,0xaa,0xaa,0xaa,0xaa,0xaa, /* U+6200 - U+621f */ 0xaa,0xaa,0xaa,0xaa,0xaa,0xaa,0xaa,0xaa, /* U+6220 - U+623f */ 0xaa,0xaa,0xaa,0xaa,0xaa,0xaa,0xaa,0xaa, /* U+6240 - U+625f */ 0xaa,0xaa,0xaa,0xaa,0xaa,0xaa,0xaa,0xaa, /* U+6260 - U+627f */ 0xaa,0xaa,0xaa,0xaa,0xaa,0xaa,0xaa,0xaa, /* U+6280 - U+629f */ 0xaa,0xaa,0xaa,0xaa,0xaa,0xaa,0xaa,0xaa, /* U+62a0 - U+62bf */ 0xaa,0xaa,0xaa,0xaa,0xaa,0xaa,0xaa,0xaa, /* U+62c0 - U+62df */ 0xaa,0xaa,0xaa,0xaa,0xaa,0xaa,0xaa,0xaa, /* U+62e0 - U+62ff */ 0xaa,0xaa,0xaa,0xaa,0xaa,0xaa,0xaa,0xaa, /* U+6300 - U+631f */ 0xaa,0xaa,0xaa,0xaa,0xaa,0xaa,0xaa,0xaa, /* U+6320 - U+633f */ 0xaa,0xaa,0xaa,0xaa,0xaa,0xaa,0xaa,0xaa, /* U+6340 - U+635f */ 0xaa,0xaa,0xaa,0xaa,0xaa,0xaa,0xaa,0xaa, /* U+6360 - U+637f */ 0xaa,0xaa,0xaa,0xaa,0xaa,0xaa,0xaa,0xaa, /* U+6380 - U+639f */ 0xaa,0xaa,0xaa,0xaa,0xaa,0xaa,0xaa,0xaa, /* U+63a0 - U+63bf */ 0xaa,0xaa,0xaa,0xaa,0xaa,0xaa,0xaa,0xaa, /* U+63c0 - U+63df */ 0xaa,0xaa,0xaa,0xaa,0xaa,0xaa,0xaa,0xaa, /* U+63e0 - U+63ff */ 0xaa,0xaa,0xaa,0xaa,0xaa,0xaa,0xaa,0xaa, /* U+6400 - U+641f */ 0xaa,0xaa,0xaa,0xaa,0xaa,0xaa,0xaa,0xaa, /* U+6420 - U+643f */ 0xaa,0xaa,0xaa,0xaa,0xaa,0xaa,0xaa,0xaa, /* U+6440 - U+645f */ 0xaa,0xaa,0xaa,0xaa,0xaa,0xaa,0xaa,0xaa, /* U+6460 - U+647f */ 0xaa,0xaa,0xaa,0xaa,0xaa,0xaa,0xaa,0xaa, /* U+6480 - U+649f */ 0xaa,0xaa,0xaa,0xaa,0xaa,0xaa,0xaa,0xaa, /* U+64a0 - U+64bf */ 0xaa,0xaa,0xaa,0xaa,0xaa,0xaa,0xaa,0xaa, /* U+64c0 - U+64df */ 0xaa,0xaa,0xaa,0xaa,0xaa,0xaa,0xaa,0xaa, /* U+64e0 - U+64ff */ 0xaa,0xaa,0xaa,0xaa,0xaa,0xaa,0xaa,0xaa, /* U+6500 - U+651f */ 0xaa,0xaa,0xaa,0xaa,0xaa,0xaa,0xaa,0xaa, /* U+6520 - U+653f */ 0xaa,0xaa,0xaa,0xaa,0xaa,0xaa,0xaa,0xaa, /* U+6540 - U+655f */ 0xaa,0xaa,0xaa,0xaa,0xaa,0xaa,0xaa,0xaa, /* U+6560 - U+657f */ 0xaa,0xaa,0xaa,0xaa,0xaa,0xaa,0xaa,0xaa, /* U+6580 - U+659f */ 0xaa,0xaa,0xaa,0xaa,0xaa,0xaa,0xaa,0xaa, /* U+65a0 - U+65bf */ 0xaa,0xaa,0xaa,0xaa,0xaa,0xaa,0xaa,0xaa, /* U+65c0 - U+65df */ 0xaa,0xaa,0xaa,0xaa,0xaa,0xaa,0xaa,0xaa, /* U+65e0 - U+65ff */ 0xaa,0xaa,0xaa,0xaa,0xaa,0xaa,0xaa,0xaa, /* U+6600 - U+661f */ 0xaa,0xaa,0xaa,0xaa,0xaa,0xaa,0xaa,0xaa, /* U+6620 - U+663f */ 0xaa,0xaa,0xaa,0xaa,0xaa,0xaa,0xaa,0xaa, /* U+6640 - U+665f */ 0xaa,0xaa,0xaa,0xaa,0xaa,0xaa,0xaa,0xaa, /* U+6660 - U+667f */ 0xaa,0xaa,0xaa,0xaa,0xaa,0xaa,0xaa,0xaa, /* U+6680 - U+669f */ 0xaa,0xaa,0xaa,0xaa,0xaa,0xaa,0xaa,0xaa, /* U+66a0 - U+66bf */ 0xaa,0xaa,0xaa,0xaa,0xaa,0xaa,0xaa,0xaa, /* U+66c0 - U+66df */ 0xaa,0xaa,0xaa,0xaa,0xaa,0xaa,0xaa,0xaa, /* U+66e0 - U+66ff */ 0xaa,0xaa,0xaa,0xaa,0xaa,0xaa,0xaa,0xaa, /* U+6700 - U+671f */ 0xaa,0xaa,0xaa,0xaa,0xaa,0xaa,0xaa,0xaa, /* U+6720 - U+673f */ 0xaa,0xaa,0xaa,0xaa,0xaa,0xaa,0xaa,0xaa, /* U+6740 - U+675f */ 0xaa,0xaa,0xaa,0xaa,0xaa,0xaa,0xaa,0xaa, /* U+6760 - U+677f */ 0xaa,0xaa,0xaa,0xaa,0xaa,0xaa,0xaa,0xaa, /* U+6780 - U+679f */ 0xaa,0xaa,0xaa,0xaa,0xaa,0xaa,0xaa,0xaa, /* U+67a0 - U+67bf */ 0xaa,0xaa,0xaa,0xaa,0xaa,0xaa,0xaa,0xaa, /* U+67c0 - U+67df */ 0xaa,0xaa,0xaa,0xaa,0xaa,0xaa,0xaa,0xaa, /* U+67e0 - U+67ff */ 0xaa,0xaa,0xaa,0xaa,0xaa,0xaa,0xaa,0xaa, /* U+6800 - U+681f */ 0xaa,0xaa,0xaa,0xaa,0xaa,0xaa,0xaa,0xaa, /* U+6820 - U+683f */ 0xaa,0xaa,0xaa,0xaa,0xaa,0xaa,0xaa,0xaa, /* U+6840 - U+685f */ 0xaa,0xaa,0xaa,0xaa,0xaa,0xaa,0xaa,0xaa, /* U+6860 - U+687f */ 0xaa,0xaa,0xaa,0xaa,0xaa,0xaa,0xaa,0xaa, /* U+6880 - U+689f */ 0xaa,0xaa,0xaa,0xaa,0xaa,0xaa,0xaa,0xaa, /* U+68a0 - U+68bf */ 0xaa,0xaa,0xaa,0xaa,0xaa,0xaa,0xaa,0xaa, /* U+68c0 - U+68df */ 0xaa,0xaa,0xaa,0xaa,0xaa,0xaa,0xaa,0xaa, /* U+68e0 - U+68ff */ 0xaa,0xaa,0xaa,0xaa,0xaa,0xaa,0xaa,0xaa, /* U+6900 - U+691f */ 0xaa,0xaa,0xaa,0xaa,0xaa,0xaa,0xaa,0xaa, /* U+6920 - U+693f */ 0xaa,0xaa,0xaa,0xaa,0xaa,0xaa,0xaa,0xaa, /* U+6940 - U+695f */ 0xaa,0xaa,0xaa,0xaa,0xaa,0xaa,0xaa,0xaa, /* U+6960 - U+697f */ 0xaa,0xaa,0xaa,0xaa,0xaa,0xaa,0xaa,0xaa, /* U+6980 - U+699f */ 0xaa,0xaa,0xaa,0xaa,0xaa,0xaa,0xaa,0xaa, /* U+69a0 - U+69bf */ 0xaa,0xaa,0xaa,0xaa,0xaa,0xaa,0xaa,0xaa, /* U+69c0 - U+69df */ 0xaa,0xaa,0xaa,0xaa,0xaa,0xaa,0xaa,0xaa, /* U+69e0 - U+69ff */ 0xaa,0xaa,0xaa,0xaa,0xaa,0xaa,0xaa,0xaa, /* U+6a00 - U+6a1f */ 0xaa,0xaa,0xaa,0xaa,0xaa,0xaa,0xaa,0xaa, /* U+6a20 - U+6a3f */ 0xaa,0xaa,0xaa,0xaa,0xaa,0xaa,0xaa,0xaa, /* U+6a40 - U+6a5f */ 0xaa,0xaa,0xaa,0xaa,0xaa,0xaa,0xaa,0xaa, /* U+6a60 - U+6a7f */ 0xaa,0xaa,0xaa,0xaa,0xaa,0xaa,0xaa,0xaa, /* U+6a80 - U+6a9f */ 0xaa,0xaa,0xaa,0xaa,0xaa,0xaa,0xaa,0xaa, /* U+6aa0 - U+6abf */ 0xaa,0xaa,0xaa,0xaa,0xaa,0xaa,0xaa,0xaa, /* U+6ac0 - U+6adf */ 0xaa,0xaa,0xaa,0xaa,0xaa,0xaa,0xaa,0xaa, /* U+6ae0 - U+6aff */ 0xaa,0xaa,0xaa,0xaa,0xaa,0xaa,0xaa,0xaa, /* U+6b00 - U+6b1f */ 0xaa,0xaa,0xaa,0xaa,0xaa,0xaa,0xaa,0xaa, /* U+6b20 - U+6b3f */ 0xaa,0xaa,0xaa,0xaa,0xaa,0xaa,0xaa,0xaa, /* U+6b40 - U+6b5f */ 0xaa,0xaa,0xaa,0xaa,0xaa,0xaa,0xaa,0xaa, /* U+6b60 - U+6b7f */ 0xaa,0xaa,0xaa,0xaa,0xaa,0xaa,0xaa,0xaa, /* U+6b80 - U+6b9f */ 0xaa,0xaa,0xaa,0xaa,0xaa,0xaa,0xaa,0xaa, /* U+6ba0 - U+6bbf */ 0xaa,0xaa,0xaa,0xaa,0xaa,0xaa,0xaa,0xaa, /* U+6bc0 - U+6bdf */ 0xaa,0xaa,0xaa,0xaa,0xaa,0xaa,0xaa,0xaa, /* U+6be0 - U+6bff */ 0xaa,0xaa,0xaa,0xaa,0xaa,0xaa,0xaa,0xaa, /* U+6c00 - U+6c1f */ 0xaa,0xaa,0xaa,0xaa,0xaa,0xaa,0xaa,0xaa, /* U+6c20 - U+6c3f */ 0xaa,0xaa,0xaa,0xaa,0xaa,0xaa,0xaa,0xaa, /* U+6c40 - U+6c5f */ 0xaa,0xaa,0xaa,0xaa,0xaa,0xaa,0xaa,0xaa, /* U+6c60 - U+6c7f */ 0xaa,0xaa,0xaa,0xaa,0xaa,0xaa,0xaa,0xaa, /* U+6c80 - U+6c9f */ 0xaa,0xaa,0xaa,0xaa,0xaa,0xaa,0xaa,0xaa, /* U+6ca0 - U+6cbf */ 0xaa,0xaa,0xaa,0xaa,0xaa,0xaa,0xaa,0xaa, /* U+6cc0 - U+6cdf */ 0xaa,0xaa,0xaa,0xaa,0xaa,0xaa,0xaa,0xaa, /* U+6ce0 - U+6cff */ 0xaa,0xaa,0xaa,0xaa,0xaa,0xaa,0xaa,0xaa, /* U+6d00 - U+6d1f */ 0xaa,0xaa,0xaa,0xaa,0xaa,0xaa,0xaa,0xaa, /* U+6d20 - U+6d3f */ 0xaa,0xaa,0xaa,0xaa,0xaa,0xaa,0xaa,0xaa, /* U+6d40 - U+6d5f */ 0xaa,0xaa,0xaa,0xaa,0xaa,0xaa,0xaa,0xaa, /* U+6d60 - U+6d7f */ 0xaa,0xaa,0xaa,0xaa,0xaa,0xaa,0xaa,0xaa, /* U+6d80 - U+6d9f */ 0xaa,0xaa,0xaa,0xaa,0xaa,0xaa,0xaa,0xaa, /* U+6da0 - U+6dbf */ 0xaa,0xaa,0xaa,0xaa,0xaa,0xaa,0xaa,0xaa, /* U+6dc0 - U+6ddf */ 0xaa,0xaa,0xaa,0xaa,0xaa,0xaa,0xaa,0xaa, /* U+6de0 - U+6dff */ 0xaa,0xaa,0xaa,0xaa,0xaa,0xaa,0xaa,0xaa, /* U+6e00 - U+6e1f */ 0xaa,0xaa,0xaa,0xaa,0xaa,0xaa,0xaa,0xaa, /* U+6e20 - U+6e3f */ 0xaa,0xaa,0xaa,0xaa,0xaa,0xaa,0xaa,0xaa, /* U+6e40 - U+6e5f */ 0xaa,0xaa,0xaa,0xaa,0xaa,0xaa,0xaa,0xaa, /* U+6e60 - U+6e7f */ 0xaa,0xaa,0xaa,0xaa,0xaa,0xaa,0xaa,0xaa, /* U+6e80 - U+6e9f */ 0xaa,0xaa,0xaa,0xaa,0xaa,0xaa,0xaa,0xaa, /* U+6ea0 - U+6ebf */ 0xaa,0xaa,0xaa,0xaa,0xaa,0xaa,0xaa,0xaa, /* U+6ec0 - U+6edf */ 0xaa,0xaa,0xaa,0xaa,0xaa,0xaa,0xaa,0xaa, /* U+6ee0 - U+6eff */ 0xaa,0xaa,0xaa,0xaa,0xaa,0xaa,0xaa,0xaa, /* U+6f00 - U+6f1f */ 0xaa,0xaa,0xaa,0xaa,0xaa,0xaa,0xaa,0xaa, /* U+6f20 - U+6f3f */ 0xaa,0xaa,0xaa,0xaa,0xaa,0xaa,0xaa,0xaa, /* U+6f40 - U+6f5f */ 0xaa,0xaa,0xaa,0xaa,0xaa,0xaa,0xaa,0xaa, /* U+6f60 - U+6f7f */ 0xaa,0xaa,0xaa,0xaa,0xaa,0xaa,0xaa,0xaa, /* U+6f80 - U+6f9f */ 0xaa,0xaa,0xaa,0xaa,0xaa,0xaa,0xaa,0xaa, /* U+6fa0 - U+6fbf */ 0xaa,0xaa,0xaa,0xaa,0xaa,0xaa,0xaa,0xaa, /* U+6fc0 - U+6fdf */ 0xaa,0xaa,0xaa,0xaa,0xaa,0xaa,0xaa,0xaa, /* U+6fe0 - U+6fff */ 0xaa,0xaa,0xaa,0xaa,0xaa,0xaa,0xaa,0xaa, /* U+7000 - U+701f */ 0xaa,0xaa,0xaa,0xaa,0xaa,0xaa,0xaa,0xaa, /* U+7020 - U+703f */ 0xaa,0xaa,0xaa,0xaa,0xaa,0xaa,0xaa,0xaa, /* U+7040 - U+705f */ 0xaa,0xaa,0xaa,0xaa,0xaa,0xaa,0xaa,0xaa, /* U+7060 - U+707f */ 0xaa,0xaa,0xaa,0xaa,0xaa,0xaa,0xaa,0xaa, /* U+7080 - U+709f */ 0xaa,0xaa,0xaa,0xaa,0xaa,0xaa,0xaa,0xaa, /* U+70a0 - U+70bf */ 0xaa,0xaa,0xaa,0xaa,0xaa,0xaa,0xaa,0xaa, /* U+70c0 - U+70df */ 0xaa,0xaa,0xaa,0xaa,0xaa,0xaa,0xaa,0xaa, /* U+70e0 - U+70ff */ 0xaa,0xaa,0xaa,0xaa,0xaa,0xaa,0xaa,0xaa, /* U+7100 - U+711f */ 0xaa,0xaa,0xaa,0xaa,0xaa,0xaa,0xaa,0xaa, /* U+7120 - U+713f */ 0xaa,0xaa,0xaa,0xaa,0xaa,0xaa,0xaa,0xaa, /* U+7140 - U+715f */ 0xaa,0xaa,0xaa,0xaa,0xaa,0xaa,0xaa,0xaa, /* U+7160 - U+717f */ 0xaa,0xaa,0xaa,0xaa,0xaa,0xaa,0xaa,0xaa, /* U+7180 - U+719f */ 0xaa,0xaa,0xaa,0xaa,0xaa,0xaa,0xaa,0xaa, /* U+71a0 - U+71bf */ 0xaa,0xaa,0xaa,0xaa,0xaa,0xaa,0xaa,0xaa, /* U+71c0 - U+71df */ 0xaa,0xaa,0xaa,0xaa,0xaa,0xaa,0xaa,0xaa, /* U+71e0 - U+71ff */ 0xaa,0xaa,0xaa,0xaa,0xaa,0xaa,0xaa,0xaa, /* U+7200 - U+721f */ 0xaa,0xaa,0xaa,0xaa,0xaa,0xaa,0xaa,0xaa, /* U+7220 - U+723f */ 0xaa,0xaa,0xaa,0xaa,0xaa,0xaa,0xaa,0xaa, /* U+7240 - U+725f */ 0xaa,0xaa,0xaa,0xaa,0xaa,0xaa,0xaa,0xaa, /* U+7260 - U+727f */ 0xaa,0xaa,0xaa,0xaa,0xaa,0xaa,0xaa,0xaa, /* U+7280 - U+729f */ 0xaa,0xaa,0xaa,0xaa,0xaa,0xaa,0xaa,0xaa, /* U+72a0 - U+72bf */ 0xaa,0xaa,0xaa,0xaa,0xaa,0xaa,0xaa,0xaa, /* U+72c0 - U+72df */ 0xaa,0xaa,0xaa,0xaa,0xaa,0xaa,0xaa,0xaa, /* U+72e0 - U+72ff */ 0xaa,0xaa,0xaa,0xaa,0xaa,0xaa,0xaa,0xaa, /* U+7300 - U+731f */ 0xaa,0xaa,0xaa,0xaa,0xaa,0xaa,0xaa,0xaa, /* U+7320 - U+733f */ 0xaa,0xaa,0xaa,0xaa,0xaa,0xaa,0xaa,0xaa, /* U+7340 - U+735f */ 0xaa,0xaa,0xaa,0xaa,0xaa,0xaa,0xaa,0xaa, /* U+7360 - U+737f */ 0xaa,0xaa,0xaa,0xaa,0xaa,0xaa,0xaa,0xaa, /* U+7380 - U+739f */ 0xaa,0xaa,0xaa,0xaa,0xaa,0xaa,0xaa,0xaa, /* U+73a0 - U+73bf */ 0xaa,0xaa,0xaa,0xaa,0xaa,0xaa,0xaa,0xaa, /* U+73c0 - U+73df */ 0xaa,0xaa,0xaa,0xaa,0xaa,0xaa,0xaa,0xaa, /* U+73e0 - U+73ff */ 0xaa,0xaa,0xaa,0xaa,0xaa,0xaa,0xaa,0xaa, /* U+7400 - U+741f */ 0xaa,0xaa,0xaa,0xaa,0xaa,0xaa,0xaa,0xaa, /* U+7420 - U+743f */ 0xaa,0xaa,0xaa,0xaa,0xaa,0xaa,0xaa,0xaa, /* U+7440 - U+745f */ 0xaa,0xaa,0xaa,0xaa,0xaa,0xaa,0xaa,0xaa, /* U+7460 - U+747f */ 0xaa,0xaa,0xaa,0xaa,0xaa,0xaa,0xaa,0xaa, /* U+7480 - U+749f */ 0xaa,0xaa,0xaa,0xaa,0xaa,0xaa,0xaa,0xaa, /* U+74a0 - U+74bf */ 0xaa,0xaa,0xaa,0xaa,0xaa,0xaa,0xaa,0xaa, /* U+74c0 - U+74df */ 0xaa,0xaa,0xaa,0xaa,0xaa,0xaa,0xaa,0xaa, /* U+74e0 - U+74ff */ 0xaa,0xaa,0xaa,0xaa,0xaa,0xaa,0xaa,0xaa, /* U+7500 - U+751f */ 0xaa,0xaa,0xaa,0xaa,0xaa,0xaa,0xaa,0xaa, /* U+7520 - U+753f */ 0xaa,0xaa,0xaa,0xaa,0xaa,0xaa,0xaa,0xaa, /* U+7540 - U+755f */ 0xaa,0xaa,0xaa,0xaa,0xaa,0xaa,0xaa,0xaa, /* U+7560 - U+757f */ 0xaa,0xaa,0xaa,0xaa,0xaa,0xaa,0xaa,0xaa, /* U+7580 - U+759f */ 0xaa,0xaa,0xaa,0xaa,0xaa,0xaa,0xaa,0xaa, /* U+75a0 - U+75bf */ 0xaa,0xaa,0xaa,0xaa,0xaa,0xaa,0xaa,0xaa, /* U+75c0 - U+75df */ 0xaa,0xaa,0xaa,0xaa,0xaa,0xaa,0xaa,0xaa, /* U+75e0 - U+75ff */ 0xaa,0xaa,0xaa,0xaa,0xaa,0xaa,0xaa,0xaa, /* U+7600 - U+761f */ 0xaa,0xaa,0xaa,0xaa,0xaa,0xaa,0xaa,0xaa, /* U+7620 - U+763f */ 0xaa,0xaa,0xaa,0xaa,0xaa,0xaa,0xaa,0xaa, /* U+7640 - U+765f */ 0xaa,0xaa,0xaa,0xaa,0xaa,0xaa,0xaa,0xaa, /* U+7660 - U+767f */ 0xaa,0xaa,0xaa,0xaa,0xaa,0xaa,0xaa,0xaa, /* U+7680 - U+769f */ 0xaa,0xaa,0xaa,0xaa,0xaa,0xaa,0xaa,0xaa, /* U+76a0 - U+76bf */ 0xaa,0xaa,0xaa,0xaa,0xaa,0xaa,0xaa,0xaa, /* U+76c0 - U+76df */ 0xaa,0xaa,0xaa,0xaa,0xaa,0xaa,0xaa,0xaa, /* U+76e0 - U+76ff */ 0xaa,0xaa,0xaa,0xaa,0xaa,0xaa,0xaa,0xaa, /* U+7700 - U+771f */ 0xaa,0xaa,0xaa,0xaa,0xaa,0xaa,0xaa,0xaa, /* U+7720 - U+773f */ 0xaa,0xaa,0xaa,0xaa,0xaa,0xaa,0xaa,0xaa, /* U+7740 - U+775f */ 0xaa,0xaa,0xaa,0xaa,0xaa,0xaa,0xaa,0xaa, /* U+7760 - U+777f */ 0xaa,0xaa,0xaa,0xaa,0xaa,0xaa,0xaa,0xaa, /* U+7780 - U+779f */ 0xaa,0xaa,0xaa,0xaa,0xaa,0xaa,0xaa,0xaa, /* U+77a0 - U+77bf */ 0xaa,0xaa,0xaa,0xaa,0xaa,0xaa,0xaa,0xaa, /* U+77c0 - U+77df */ 0xaa,0xaa,0xaa,0xaa,0xaa,0xaa,0xaa,0xaa, /* U+77e0 - U+77ff */ 0xaa,0xaa,0xaa,0xaa,0xaa,0xaa,0xaa,0xaa, /* U+7800 - U+781f */ 0xaa,0xaa,0xaa,0xaa,0xaa,0xaa,0xaa,0xaa, /* U+7820 - U+783f */ 0xaa,0xaa,0xaa,0xaa,0xaa,0xaa,0xaa,0xaa, /* U+7840 - U+785f */ 0xaa,0xaa,0xaa,0xaa,0xaa,0xaa,0xaa,0xaa, /* U+7860 - U+787f */ 0xaa,0xaa,0xaa,0xaa,0xaa,0xaa,0xaa,0xaa, /* U+7880 - U+789f */ 0xaa,0xaa,0xaa,0xaa,0xaa,0xaa,0xaa,0xaa, /* U+78a0 - U+78bf */ 0xaa,0xaa,0xaa,0xaa,0xaa,0xaa,0xaa,0xaa, /* U+78c0 - U+78df */ 0xaa,0xaa,0xaa,0xaa,0xaa,0xaa,0xaa,0xaa, /* U+78e0 - U+78ff */ 0xaa,0xaa,0xaa,0xaa,0xaa,0xaa,0xaa,0xaa, /* U+7900 - U+791f */ 0xaa,0xaa,0xaa,0xaa,0xaa,0xaa,0xaa,0xaa, /* U+7920 - U+793f */ 0xaa,0xaa,0xaa,0xaa,0xaa,0xaa,0xaa,0xaa, /* U+7940 - U+795f */ 0xaa,0xaa,0xaa,0xaa,0xaa,0xaa,0xaa,0xaa, /* U+7960 - U+797f */ 0xaa,0xaa,0xaa,0xaa,0xaa,0xaa,0xaa,0xaa, /* U+7980 - U+799f */ 0xaa,0xaa,0xaa,0xaa,0xaa,0xaa,0xaa,0xaa, /* U+79a0 - U+79bf */ 0xaa,0xaa,0xaa,0xaa,0xaa,0xaa,0xaa,0xaa, /* U+79c0 - U+79df */ 0xaa,0xaa,0xaa,0xaa,0xaa,0xaa,0xaa,0xaa, /* U+79e0 - U+79ff */ 0xaa,0xaa,0xaa,0xaa,0xaa,0xaa,0xaa,0xaa, /* U+7a00 - U+7a1f */ 0xaa,0xaa,0xaa,0xaa,0xaa,0xaa,0xaa,0xaa, /* U+7a20 - U+7a3f */ 0xaa,0xaa,0xaa,0xaa,0xaa,0xaa,0xaa,0xaa, /* U+7a40 - U+7a5f */ 0xaa,0xaa,0xaa,0xaa,0xaa,0xaa,0xaa,0xaa, /* U+7a60 - U+7a7f */ 0xaa,0xaa,0xaa,0xaa,0xaa,0xaa,0xaa,0xaa, /* U+7a80 - U+7a9f */ 0xaa,0xaa,0xaa,0xaa,0xaa,0xaa,0xaa,0xaa, /* U+7aa0 - U+7abf */ 0xaa,0xaa,0xaa,0xaa,0xaa,0xaa,0xaa,0xaa, /* U+7ac0 - U+7adf */ 0xaa,0xaa,0xaa,0xaa,0xaa,0xaa,0xaa,0xaa, /* U+7ae0 - U+7aff */ 0xaa,0xaa,0xaa,0xaa,0xaa,0xaa,0xaa,0xaa, /* U+7b00 - U+7b1f */ 0xaa,0xaa,0xaa,0xaa,0xaa,0xaa,0xaa,0xaa, /* U+7b20 - U+7b3f */ 0xaa,0xaa,0xaa,0xaa,0xaa,0xaa,0xaa,0xaa, /* U+7b40 - U+7b5f */ 0xaa,0xaa,0xaa,0xaa,0xaa,0xaa,0xaa,0xaa, /* U+7b60 - U+7b7f */ 0xaa,0xaa,0xaa,0xaa,0xaa,0xaa,0xaa,0xaa, /* U+7b80 - U+7b9f */ 0xaa,0xaa,0xaa,0xaa,0xaa,0xaa,0xaa,0xaa, /* U+7ba0 - U+7bbf */ 0xaa,0xaa,0xaa,0xaa,0xaa,0xaa,0xaa,0xaa, /* U+7bc0 - U+7bdf */ 0xaa,0xaa,0xaa,0xaa,0xaa,0xaa,0xaa,0xaa, /* U+7be0 - U+7bff */ 0xaa,0xaa,0xaa,0xaa,0xaa,0xaa,0xaa,0xaa, /* U+7c00 - U+7c1f */ 0xaa,0xaa,0xaa,0xaa,0xaa,0xaa,0xaa,0xaa, /* U+7c20 - U+7c3f */ 0xaa,0xaa,0xaa,0xaa,0xaa,0xaa,0xaa,0xaa, /* U+7c40 - U+7c5f */ 0xaa,0xaa,0xaa,0xaa,0xaa,0xaa,0xaa,0xaa, /* U+7c60 - U+7c7f */ 0xaa,0xaa,0xaa,0xaa,0xaa,0xaa,0xaa,0xaa, /* U+7c80 - U+7c9f */ 0xaa,0xaa,0xaa,0xaa,0xaa,0xaa,0xaa,0xaa, /* U+7ca0 - U+7cbf */ 0xaa,0xaa,0xaa,0xaa,0xaa,0xaa,0xaa,0xaa, /* U+7cc0 - U+7cdf */ 0xaa,0xaa,0xaa,0xaa,0xaa,0xaa,0xaa,0xaa, /* U+7ce0 - U+7cff */ 0xaa,0xaa,0xaa,0xaa,0xaa,0xaa,0xaa,0xaa, /* U+7d00 - U+7d1f */ 0xaa,0xaa,0xaa,0xaa,0xaa,0xaa,0xaa,0xaa, /* U+7d20 - U+7d3f */ 0xaa,0xaa,0xaa,0xaa,0xaa,0xaa,0xaa,0xaa, /* U+7d40 - U+7d5f */ 0xaa,0xaa,0xaa,0xaa,0xaa,0xaa,0xaa,0xaa, /* U+7d60 - U+7d7f */ 0xaa,0xaa,0xaa,0xaa,0xaa,0xaa,0xaa,0xaa, /* U+7d80 - U+7d9f */ 0xaa,0xaa,0xaa,0xaa,0xaa,0xaa,0xaa,0xaa, /* U+7da0 - U+7dbf */ 0xaa,0xaa,0xaa,0xaa,0xaa,0xaa,0xaa,0xaa, /* U+7dc0 - U+7ddf */ 0xaa,0xaa,0xaa,0xaa,0xaa,0xaa,0xaa,0xaa, /* U+7de0 - U+7dff */ 0xaa,0xaa,0xaa,0xaa,0xaa,0xaa,0xaa,0xaa, /* U+7e00 - U+7e1f */ 0xaa,0xaa,0xaa,0xaa,0xaa,0xaa,0xaa,0xaa, /* U+7e20 - U+7e3f */ 0xaa,0xaa,0xaa,0xaa,0xaa,0xaa,0xaa,0xaa, /* U+7e40 - U+7e5f */ 0xaa,0xaa,0xaa,0xaa,0xaa,0xaa,0xaa,0xaa, /* U+7e60 - U+7e7f */ 0xaa,0xaa,0xaa,0xaa,0xaa,0xaa,0xaa,0xaa, /* U+7e80 - U+7e9f */ 0xaa,0xaa,0xaa,0xaa,0xaa,0xaa,0xaa,0xaa, /* U+7ea0 - U+7ebf */ 0xaa,0xaa,0xaa,0xaa,0xaa,0xaa,0xaa,0xaa, /* U+7ec0 - U+7edf */ 0xaa,0xaa,0xaa,0xaa,0xaa,0xaa,0xaa,0xaa, /* U+7ee0 - U+7eff */ 0xaa,0xaa,0xaa,0xaa,0xaa,0xaa,0xaa,0xaa, /* U+7f00 - U+7f1f */ 0xaa,0xaa,0xaa,0xaa,0xaa,0xaa,0xaa,0xaa, /* U+7f20 - U+7f3f */ 0xaa,0xaa,0xaa,0xaa,0xaa,0xaa,0xaa,0xaa, /* U+7f40 - U+7f5f */ 0xaa,0xaa,0xaa,0xaa,0xaa,0xaa,0xaa,0xaa, /* U+7f60 - U+7f7f */ 0xaa,0xaa,0xaa,0xaa,0xaa,0xaa,0xaa,0xaa, /* U+7f80 - U+7f9f */ 0xaa,0xaa,0xaa,0xaa,0xaa,0xaa,0xaa,0xaa, /* U+7fa0 - U+7fbf */ 0xaa,0xaa,0xaa,0xaa,0xaa,0xaa,0xaa,0xaa, /* U+7fc0 - U+7fdf */ 0xaa,0xaa,0xaa,0xaa,0xaa,0xaa,0xaa,0xaa, /* U+7fe0 - U+7fff */ 0xaa,0xaa,0xaa,0xaa,0xaa,0xaa,0xaa,0xaa, /* U+8000 - U+801f */ 0xaa,0xaa,0xaa,0xaa,0xaa,0xaa,0xaa,0xaa, /* U+8020 - U+803f */ 0xaa,0xaa,0xaa,0xaa,0xaa,0xaa,0xaa,0xaa, /* U+8040 - U+805f */ 0xaa,0xaa,0xaa,0xaa,0xaa,0xaa,0xaa,0xaa, /* U+8060 - U+807f */ 0xaa,0xaa,0xaa,0xaa,0xaa,0xaa,0xaa,0xaa, /* U+8080 - U+809f */ 0xaa,0xaa,0xaa,0xaa,0xaa,0xaa,0xaa,0xaa, /* U+80a0 - U+80bf */ 0xaa,0xaa,0xaa,0xaa,0xaa,0xaa,0xaa,0xaa, /* U+80c0 - U+80df */ 0xaa,0xaa,0xaa,0xaa,0xaa,0xaa,0xaa,0xaa, /* U+80e0 - U+80ff */ 0xaa,0xaa,0xaa,0xaa,0xaa,0xaa,0xaa,0xaa, /* U+8100 - U+811f */ 0xaa,0xaa,0xaa,0xaa,0xaa,0xaa,0xaa,0xaa, /* U+8120 - U+813f */ 0xaa,0xaa,0xaa,0xaa,0xaa,0xaa,0xaa,0xaa, /* U+8140 - U+815f */ 0xaa,0xaa,0xaa,0xaa,0xaa,0xaa,0xaa,0xaa, /* U+8160 - U+817f */ 0xaa,0xaa,0xaa,0xaa,0xaa,0xaa,0xaa,0xaa, /* U+8180 - U+819f */ 0xaa,0xaa,0xaa,0xaa,0xaa,0xaa,0xaa,0xaa, /* U+81a0 - U+81bf */ 0xaa,0xaa,0xaa,0xaa,0xaa,0xaa,0xaa,0xaa, /* U+81c0 - U+81df */ 0xaa,0xaa,0xaa,0xaa,0xaa,0xaa,0xaa,0xaa, /* U+81e0 - U+81ff */ 0xaa,0xaa,0xaa,0xaa,0xaa,0xaa,0xaa,0xaa, /* U+8200 - U+821f */ 0xaa,0xaa,0xaa,0xaa,0xaa,0xaa,0xaa,0xaa, /* U+8220 - U+823f */ 0xaa,0xaa,0xaa,0xaa,0xaa,0xaa,0xaa,0xaa, /* U+8240 - U+825f */ 0xaa,0xaa,0xaa,0xaa,0xaa,0xaa,0xaa,0xaa, /* U+8260 - U+827f */ 0xaa,0xaa,0xaa,0xaa,0xaa,0xaa,0xaa,0xaa, /* U+8280 - U+829f */ 0xaa,0xaa,0xaa,0xaa,0xaa,0xaa,0xaa,0xaa, /* U+82a0 - U+82bf */ 0xaa,0xaa,0xaa,0xaa,0xaa,0xaa,0xaa,0xaa, /* U+82c0 - U+82df */ 0xaa,0xaa,0xaa,0xaa,0xaa,0xaa,0xaa,0xaa, /* U+82e0 - U+82ff */ 0xaa,0xaa,0xaa,0xaa,0xaa,0xaa,0xaa,0xaa, /* U+8300 - U+831f */ 0xaa,0xaa,0xaa,0xaa,0xaa,0xaa,0xaa,0xaa, /* U+8320 - U+833f */ 0xaa,0xaa,0xaa,0xaa,0xaa,0xaa,0xaa,0xaa, /* U+8340 - U+835f */ 0xaa,0xaa,0xaa,0xaa,0xaa,0xaa,0xaa,0xaa, /* U+8360 - U+837f */ 0xaa,0xaa,0xaa,0xaa,0xaa,0xaa,0xaa,0xaa, /* U+8380 - U+839f */ 0xaa,0xaa,0xaa,0xaa,0xaa,0xaa,0xaa,0xaa, /* U+83a0 - U+83bf */ 0xaa,0xaa,0xaa,0xaa,0xaa,0xaa,0xaa,0xaa, /* U+83c0 - U+83df */ 0xaa,0xaa,0xaa,0xaa,0xaa,0xaa,0xaa,0xaa, /* U+83e0 - U+83ff */ 0xaa,0xaa,0xaa,0xaa,0xaa,0xaa,0xaa,0xaa, /* U+8400 - U+841f */ 0xaa,0xaa,0xaa,0xaa,0xaa,0xaa,0xaa,0xaa, /* U+8420 - U+843f */ 0xaa,0xaa,0xaa,0xaa,0xaa,0xaa,0xaa,0xaa, /* U+8440 - U+845f */ 0xaa,0xaa,0xaa,0xaa,0xaa,0xaa,0xaa,0xaa, /* U+8460 - U+847f */ 0xaa,0xaa,0xaa,0xaa,0xaa,0xaa,0xaa,0xaa, /* U+8480 - U+849f */ 0xaa,0xaa,0xaa,0xaa,0xaa,0xaa,0xaa,0xaa, /* U+84a0 - U+84bf */ 0xaa,0xaa,0xaa,0xaa,0xaa,0xaa,0xaa,0xaa, /* U+84c0 - U+84df */ 0xaa,0xaa,0xaa,0xaa,0xaa,0xaa,0xaa,0xaa, /* U+84e0 - U+84ff */ 0xaa,0xaa,0xaa,0xaa,0xaa,0xaa,0xaa,0xaa, /* U+8500 - U+851f */ 0xaa,0xaa,0xaa,0xaa,0xaa,0xaa,0xaa,0xaa, /* U+8520 - U+853f */ 0xaa,0xaa,0xaa,0xaa,0xaa,0xaa,0xaa,0xaa, /* U+8540 - U+855f */ 0xaa,0xaa,0xaa,0xaa,0xaa,0xaa,0xaa,0xaa, /* U+8560 - U+857f */ 0xaa,0xaa,0xaa,0xaa,0xaa,0xaa,0xaa,0xaa, /* U+8580 - U+859f */ 0xaa,0xaa,0xaa,0xaa,0xaa,0xaa,0xaa,0xaa, /* U+85a0 - U+85bf */ 0xaa,0xaa,0xaa,0xaa,0xaa,0xaa,0xaa,0xaa, /* U+85c0 - U+85df */ 0xaa,0xaa,0xaa,0xaa,0xaa,0xaa,0xaa,0xaa, /* U+85e0 - U+85ff */ 0xaa,0xaa,0xaa,0xaa,0xaa,0xaa,0xaa,0xaa, /* U+8600 - U+861f */ 0xaa,0xaa,0xaa,0xaa,0xaa,0xaa,0xaa,0xaa, /* U+8620 - U+863f */ 0xaa,0xaa,0xaa,0xaa,0xaa,0xaa,0xaa,0xaa, /* U+8640 - U+865f */ 0xaa,0xaa,0xaa,0xaa,0xaa,0xaa,0xaa,0xaa, /* U+8660 - U+867f */ 0xaa,0xaa,0xaa,0xaa,0xaa,0xaa,0xaa,0xaa, /* U+8680 - U+869f */ 0xaa,0xaa,0xaa,0xaa,0xaa,0xaa,0xaa,0xaa, /* U+86a0 - U+86bf */ 0xaa,0xaa,0xaa,0xaa,0xaa,0xaa,0xaa,0xaa, /* U+86c0 - U+86df */ 0xaa,0xaa,0xaa,0xaa,0xaa,0xaa,0xaa,0xaa, /* U+86e0 - U+86ff */ 0xaa,0xaa,0xaa,0xaa,0xaa,0xaa,0xaa,0xaa, /* U+8700 - U+871f */ 0xaa,0xaa,0xaa,0xaa,0xaa,0xaa,0xaa,0xaa, /* U+8720 - U+873f */ 0xaa,0xaa,0xaa,0xaa,0xaa,0xaa,0xaa,0xaa, /* U+8740 - U+875f */ 0xaa,0xaa,0xaa,0xaa,0xaa,0xaa,0xaa,0xaa, /* U+8760 - U+877f */ 0xaa,0xaa,0xaa,0xaa,0xaa,0xaa,0xaa,0xaa, /* U+8780 - U+879f */ 0xaa,0xaa,0xaa,0xaa,0xaa,0xaa,0xaa,0xaa, /* U+87a0 - U+87bf */ 0xaa,0xaa,0xaa,0xaa,0xaa,0xaa,0xaa,0xaa, /* U+87c0 - U+87df */ 0xaa,0xaa,0xaa,0xaa,0xaa,0xaa,0xaa,0xaa, /* U+87e0 - U+87ff */ 0xaa,0xaa,0xaa,0xaa,0xaa,0xaa,0xaa,0xaa, /* U+8800 - U+881f */ 0xaa,0xaa,0xaa,0xaa,0xaa,0xaa,0xaa,0xaa, /* U+8820 - U+883f */ 0xaa,0xaa,0xaa,0xaa,0xaa,0xaa,0xaa,0xaa, /* U+8840 - U+885f */ 0xaa,0xaa,0xaa,0xaa,0xaa,0xaa,0xaa,0xaa, /* U+8860 - U+887f */ 0xaa,0xaa,0xaa,0xaa,0xaa,0xaa,0xaa,0xaa, /* U+8880 - U+889f */ 0xaa,0xaa,0xaa,0xaa,0xaa,0xaa,0xaa,0xaa, /* U+88a0 - U+88bf */ 0xaa,0xaa,0xaa,0xaa,0xaa,0xaa,0xaa,0xaa, /* U+88c0 - U+88df */ 0xaa,0xaa,0xaa,0xaa,0xaa,0xaa,0xaa,0xaa, /* U+88e0 - U+88ff */ 0xaa,0xaa,0xaa,0xaa,0xaa,0xaa,0xaa,0xaa, /* U+8900 - U+891f */ 0xaa,0xaa,0xaa,0xaa,0xaa,0xaa,0xaa,0xaa, /* U+8920 - U+893f */ 0xaa,0xaa,0xaa,0xaa,0xaa,0xaa,0xaa,0xaa, /* U+8940 - U+895f */ 0xaa,0xaa,0xaa,0xaa,0xaa,0xaa,0xaa,0xaa, /* U+8960 - U+897f */ 0xaa,0xaa,0xaa,0xaa,0xaa,0xaa,0xaa,0xaa, /* U+8980 - U+899f */ 0xaa,0xaa,0xaa,0xaa,0xaa,0xaa,0xaa,0xaa, /* U+89a0 - U+89bf */ 0xaa,0xaa,0xaa,0xaa,0xaa,0xaa,0xaa,0xaa, /* U+89c0 - U+89df */ 0xaa,0xaa,0xaa,0xaa,0xaa,0xaa,0xaa,0xaa, /* U+89e0 - U+89ff */ 0xaa,0xaa,0xaa,0xaa,0xaa,0xaa,0xaa,0xaa, /* U+8a00 - U+8a1f */ 0xaa,0xaa,0xaa,0xaa,0xaa,0xaa,0xaa,0xaa, /* U+8a20 - U+8a3f */ 0xaa,0xaa,0xaa,0xaa,0xaa,0xaa,0xaa,0xaa, /* U+8a40 - U+8a5f */ 0xaa,0xaa,0xaa,0xaa,0xaa,0xaa,0xaa,0xaa, /* U+8a60 - U+8a7f */ 0xaa,0xaa,0xaa,0xaa,0xaa,0xaa,0xaa,0xaa, /* U+8a80 - U+8a9f */ 0xaa,0xaa,0xaa,0xaa,0xaa,0xaa,0xaa,0xaa, /* U+8aa0 - U+8abf */ 0xaa,0xaa,0xaa,0xaa,0xaa,0xaa,0xaa,0xaa, /* U+8ac0 - U+8adf */ 0xaa,0xaa,0xaa,0xaa,0xaa,0xaa,0xaa,0xaa, /* U+8ae0 - U+8aff */ 0xaa,0xaa,0xaa,0xaa,0xaa,0xaa,0xaa,0xaa, /* U+8b00 - U+8b1f */ 0xaa,0xaa,0xaa,0xaa,0xaa,0xaa,0xaa,0xaa, /* U+8b20 - U+8b3f */ 0xaa,0xaa,0xaa,0xaa,0xaa,0xaa,0xaa,0xaa, /* U+8b40 - U+8b5f */ 0xaa,0xaa,0xaa,0xaa,0xaa,0xaa,0xaa,0xaa, /* U+8b60 - U+8b7f */ 0xaa,0xaa,0xaa,0xaa,0xaa,0xaa,0xaa,0xaa, /* U+8b80 - U+8b9f */ 0xaa,0xaa,0xaa,0xaa,0xaa,0xaa,0xaa,0xaa, /* U+8ba0 - U+8bbf */ 0xaa,0xaa,0xaa,0xaa,0xaa,0xaa,0xaa,0xaa, /* U+8bc0 - U+8bdf */ 0xaa,0xaa,0xaa,0xaa,0xaa,0xaa,0xaa,0xaa, /* U+8be0 - U+8bff */ 0xaa,0xaa,0xaa,0xaa,0xaa,0xaa,0xaa,0xaa, /* U+8c00 - U+8c1f */ 0xaa,0xaa,0xaa,0xaa,0xaa,0xaa,0xaa,0xaa, /* U+8c20 - U+8c3f */ 0xaa,0xaa,0xaa,0xaa,0xaa,0xaa,0xaa,0xaa, /* U+8c40 - U+8c5f */ 0xaa,0xaa,0xaa,0xaa,0xaa,0xaa,0xaa,0xaa, /* U+8c60 - U+8c7f */ 0xaa,0xaa,0xaa,0xaa,0xaa,0xaa,0xaa,0xaa, /* U+8c80 - U+8c9f */ 0xaa,0xaa,0xaa,0xaa,0xaa,0xaa,0xaa,0xaa, /* U+8ca0 - U+8cbf */ 0xaa,0xaa,0xaa,0xaa,0xaa,0xaa,0xaa,0xaa, /* U+8cc0 - U+8cdf */ 0xaa,0xaa,0xaa,0xaa,0xaa,0xaa,0xaa,0xaa, /* U+8ce0 - U+8cff */ 0xaa,0xaa,0xaa,0xaa,0xaa,0xaa,0xaa,0xaa, /* U+8d00 - U+8d1f */ 0xaa,0xaa,0xaa,0xaa,0xaa,0xaa,0xaa,0xaa, /* U+8d20 - U+8d3f */ 0xaa,0xaa,0xaa,0xaa,0xaa,0xaa,0xaa,0xaa, /* U+8d40 - U+8d5f */ 0xaa,0xaa,0xaa,0xaa,0xaa,0xaa,0xaa,0xaa, /* U+8d60 - U+8d7f */ 0xaa,0xaa,0xaa,0xaa,0xaa,0xaa,0xaa,0xaa, /* U+8d80 - U+8d9f */ 0xaa,0xaa,0xaa,0xaa,0xaa,0xaa,0xaa,0xaa, /* U+8da0 - U+8dbf */ 0xaa,0xaa,0xaa,0xaa,0xaa,0xaa,0xaa,0xaa, /* U+8dc0 - U+8ddf */ 0xaa,0xaa,0xaa,0xaa,0xaa,0xaa,0xaa,0xaa, /* U+8de0 - U+8dff */ 0xaa,0xaa,0xaa,0xaa,0xaa,0xaa,0xaa,0xaa, /* U+8e00 - U+8e1f */ 0xaa,0xaa,0xaa,0xaa,0xaa,0xaa,0xaa,0xaa, /* U+8e20 - U+8e3f */ 0xaa,0xaa,0xaa,0xaa,0xaa,0xaa,0xaa,0xaa, /* U+8e40 - U+8e5f */ 0xaa,0xaa,0xaa,0xaa,0xaa,0xaa,0xaa,0xaa, /* U+8e60 - U+8e7f */ 0xaa,0xaa,0xaa,0xaa,0xaa,0xaa,0xaa,0xaa, /* U+8e80 - U+8e9f */ 0xaa,0xaa,0xaa,0xaa,0xaa,0xaa,0xaa,0xaa, /* U+8ea0 - U+8ebf */ 0xaa,0xaa,0xaa,0xaa,0xaa,0xaa,0xaa,0xaa, /* U+8ec0 - U+8edf */ 0xaa,0xaa,0xaa,0xaa,0xaa,0xaa,0xaa,0xaa, /* U+8ee0 - U+8eff */ 0xaa,0xaa,0xaa,0xaa,0xaa,0xaa,0xaa,0xaa, /* U+8f00 - U+8f1f */ 0xaa,0xaa,0xaa,0xaa,0xaa,0xaa,0xaa,0xaa, /* U+8f20 - U+8f3f */ 0xaa,0xaa,0xaa,0xaa,0xaa,0xaa,0xaa,0xaa, /* U+8f40 - U+8f5f */ 0xaa,0xaa,0xaa,0xaa,0xaa,0xaa,0xaa,0xaa, /* U+8f60 - U+8f7f */ 0xaa,0xaa,0xaa,0xaa,0xaa,0xaa,0xaa,0xaa, /* U+8f80 - U+8f9f */ 0xaa,0xaa,0xaa,0xaa,0xaa,0xaa,0xaa,0xaa, /* U+8fa0 - U+8fbf */ 0xaa,0xaa,0xaa,0xaa,0xaa,0xaa,0xaa,0xaa, /* U+8fc0 - U+8fdf */ 0xaa,0xaa,0xaa,0xaa,0xaa,0xaa,0xaa,0xaa, /* U+8fe0 - U+8fff */ 0xaa,0xaa,0xaa,0xaa,0xaa,0xaa,0xaa,0xaa, /* U+9000 - U+901f */ 0xaa,0xaa,0xaa,0xaa,0xaa,0xaa,0xaa,0xaa, /* U+9020 - U+903f */ 0xaa,0xaa,0xaa,0xaa,0xaa,0xaa,0xaa,0xaa, /* U+9040 - U+905f */ 0xaa,0xaa,0xaa,0xaa,0xaa,0xaa,0xaa,0xaa, /* U+9060 - U+907f */ 0xaa,0xaa,0xaa,0xaa,0xaa,0xaa,0xaa,0xaa, /* U+9080 - U+909f */ 0xaa,0xaa,0xaa,0xaa,0xaa,0xaa,0xaa,0xaa, /* U+90a0 - U+90bf */ 0xaa,0xaa,0xaa,0xaa,0xaa,0xaa,0xaa,0xaa, /* U+90c0 - U+90df */ 0xaa,0xaa,0xaa,0xaa,0xaa,0xaa,0xaa,0xaa, /* U+90e0 - U+90ff */ 0xaa,0xaa,0xaa,0xaa,0xaa,0xaa,0xaa,0xaa, /* U+9100 - U+911f */ 0xaa,0xaa,0xaa,0xaa,0xaa,0xaa,0xaa,0xaa, /* U+9120 - U+913f */ 0xaa,0xaa,0xaa,0xaa,0xaa,0xaa,0xaa,0xaa, /* U+9140 - U+915f */ 0xaa,0xaa,0xaa,0xaa,0xaa,0xaa,0xaa,0xaa, /* U+9160 - U+917f */ 0xaa,0xaa,0xaa,0xaa,0xaa,0xaa,0xaa,0xaa, /* U+9180 - U+919f */ 0xaa,0xaa,0xaa,0xaa,0xaa,0xaa,0xaa,0xaa, /* U+91a0 - U+91bf */ 0xaa,0xaa,0xaa,0xaa,0xaa,0xaa,0xaa,0xaa, /* U+91c0 - U+91df */ 0xaa,0xaa,0xaa,0xaa,0xaa,0xaa,0xaa,0xaa, /* U+91e0 - U+91ff */ 0xaa,0xaa,0xaa,0xaa,0xaa,0xaa,0xaa,0xaa, /* U+9200 - U+921f */ 0xaa,0xaa,0xaa,0xaa,0xaa,0xaa,0xaa,0xaa, /* U+9220 - U+923f */ 0xaa,0xaa,0xaa,0xaa,0xaa,0xaa,0xaa,0xaa, /* U+9240 - U+925f */ 0xaa,0xaa,0xaa,0xaa,0xaa,0xaa,0xaa,0xaa, /* U+9260 - U+927f */ 0xaa,0xaa,0xaa,0xaa,0xaa,0xaa,0xaa,0xaa, /* U+9280 - U+929f */ 0xaa,0xaa,0xaa,0xaa,0xaa,0xaa,0xaa,0xaa, /* U+92a0 - U+92bf */ 0xaa,0xaa,0xaa,0xaa,0xaa,0xaa,0xaa,0xaa, /* U+92c0 - U+92df */ 0xaa,0xaa,0xaa,0xaa,0xaa,0xaa,0xaa,0xaa, /* U+92e0 - U+92ff */ 0xaa,0xaa,0xaa,0xaa,0xaa,0xaa,0xaa,0xaa, /* U+9300 - U+931f */ 0xaa,0xaa,0xaa,0xaa,0xaa,0xaa,0xaa,0xaa, /* U+9320 - U+933f */ 0xaa,0xaa,0xaa,0xaa,0xaa,0xaa,0xaa,0xaa, /* U+9340 - U+935f */ 0xaa,0xaa,0xaa,0xaa,0xaa,0xaa,0xaa,0xaa, /* U+9360 - U+937f */ 0xaa,0xaa,0xaa,0xaa,0xaa,0xaa,0xaa,0xaa, /* U+9380 - U+939f */ 0xaa,0xaa,0xaa,0xaa,0xaa,0xaa,0xaa,0xaa, /* U+93a0 - U+93bf */ 0xaa,0xaa,0xaa,0xaa,0xaa,0xaa,0xaa,0xaa, /* U+93c0 - U+93df */ 0xaa,0xaa,0xaa,0xaa,0xaa,0xaa,0xaa,0xaa, /* U+93e0 - U+93ff */ 0xaa,0xaa,0xaa,0xaa,0xaa,0xaa,0xaa,0xaa, /* U+9400 - U+941f */ 0xaa,0xaa,0xaa,0xaa,0xaa,0xaa,0xaa,0xaa, /* U+9420 - U+943f */ 0xaa,0xaa,0xaa,0xaa,0xaa,0xaa,0xaa,0xaa, /* U+9440 - U+945f */ 0xaa,0xaa,0xaa,0xaa,0xaa,0xaa,0xaa,0xaa, /* U+9460 - U+947f */ 0xaa,0xaa,0xaa,0xaa,0xaa,0xaa,0xaa,0xaa, /* U+9480 - U+949f */ 0xaa,0xaa,0xaa,0xaa,0xaa,0xaa,0xaa,0xaa, /* U+94a0 - U+94bf */ 0xaa,0xaa,0xaa,0xaa,0xaa,0xaa,0xaa,0xaa, /* U+94c0 - U+94df */ 0xaa,0xaa,0xaa,0xaa,0xaa,0xaa,0xaa,0xaa, /* U+94e0 - U+94ff */ 0xaa,0xaa,0xaa,0xaa,0xaa,0xaa,0xaa,0xaa, /* U+9500 - U+951f */ 0xaa,0xaa,0xaa,0xaa,0xaa,0xaa,0xaa,0xaa, /* U+9520 - U+953f */ 0xaa,0xaa,0xaa,0xaa,0xaa,0xaa,0xaa,0xaa, /* U+9540 - U+955f */ 0xaa,0xaa,0xaa,0xaa,0xaa,0xaa,0xaa,0xaa, /* U+9560 - U+957f */ 0xaa,0xaa,0xaa,0xaa,0xaa,0xaa,0xaa,0xaa, /* U+9580 - U+959f */ 0xaa,0xaa,0xaa,0xaa,0xaa,0xaa,0xaa,0xaa, /* U+95a0 - U+95bf */ 0xaa,0xaa,0xaa,0xaa,0xaa,0xaa,0xaa,0xaa, /* U+95c0 - U+95df */ 0xaa,0xaa,0xaa,0xaa,0xaa,0xaa,0xaa,0xaa, /* U+95e0 - U+95ff */ 0xaa,0xaa,0xaa,0xaa,0xaa,0xaa,0xaa,0xaa, /* U+9600 - U+961f */ 0xaa,0xaa,0xaa,0xaa,0xaa,0xaa,0xaa,0xaa, /* U+9620 - U+963f */ 0xaa,0xaa,0xaa,0xaa,0xaa,0xaa,0xaa,0xaa, /* U+9640 - U+965f */ 0xaa,0xaa,0xaa,0xaa,0xaa,0xaa,0xaa,0xaa, /* U+9660 - U+967f */ 0xaa,0xaa,0xaa,0xaa,0xaa,0xaa,0xaa,0xaa, /* U+9680 - U+969f */ 0xaa,0xaa,0xaa,0xaa,0xaa,0xaa,0xaa,0xaa, /* U+96a0 - U+96bf */ 0xaa,0xaa,0xaa,0xaa,0xaa,0xaa,0xaa,0xaa, /* U+96c0 - U+96df */ 0xaa,0xaa,0xaa,0xaa,0xaa,0xaa,0xaa,0xaa, /* U+96e0 - U+96ff */ 0xaa,0xaa,0xaa,0xaa,0xaa,0xaa,0xaa,0xaa, /* U+9700 - U+971f */ 0xaa,0xaa,0xaa,0xaa,0xaa,0xaa,0xaa,0xaa, /* U+9720 - U+973f */ 0xaa,0xaa,0xaa,0xaa,0xaa,0xaa,0xaa,0xaa, /* U+9740 - U+975f */ 0xaa,0xaa,0xaa,0xaa,0xaa,0xaa,0xaa,0xaa, /* U+9760 - U+977f */ 0xaa,0xaa,0xaa,0xaa,0xaa,0xaa,0xaa,0xaa, /* U+9780 - U+979f */ 0xaa,0xaa,0xaa,0xaa,0xaa,0xaa,0xaa,0xaa, /* U+97a0 - U+97bf */ 0xaa,0xaa,0xaa,0xaa,0xaa,0xaa,0xaa,0xaa, /* U+97c0 - U+97df */ 0xaa,0xaa,0xaa,0xaa,0xaa,0xaa,0xaa,0xaa, /* U+97e0 - U+97ff */ 0xaa,0xaa,0xaa,0xaa,0xaa,0xaa,0xaa,0xaa, /* U+9800 - U+981f */ 0xaa,0xaa,0xaa,0xaa,0xaa,0xaa,0xaa,0xaa, /* U+9820 - U+983f */ 0xaa,0xaa,0xaa,0xaa,0xaa,0xaa,0xaa,0xaa, /* U+9840 - U+985f */ 0xaa,0xaa,0xaa,0xaa,0xaa,0xaa,0xaa,0xaa, /* U+9860 - U+987f */ 0xaa,0xaa,0xaa,0xaa,0xaa,0xaa,0xaa,0xaa, /* U+9880 - U+989f */ 0xaa,0xaa,0xaa,0xaa,0xaa,0xaa,0xaa,0xaa, /* U+98a0 - U+98bf */ 0xaa,0xaa,0xaa,0xaa,0xaa,0xaa,0xaa,0xaa, /* U+98c0 - U+98df */ 0xaa,0xaa,0xaa,0xaa,0xaa,0xaa,0xaa,0xaa, /* U+98e0 - U+98ff */ 0xaa,0xaa,0xaa,0xaa,0xaa,0xaa,0xaa,0xaa, /* U+9900 - U+991f */ 0xaa,0xaa,0xaa,0xaa,0xaa,0xaa,0xaa,0xaa, /* U+9920 - U+993f */ 0xaa,0xaa,0xaa,0xaa,0xaa,0xaa,0xaa,0xaa, /* U+9940 - U+995f */ 0xaa,0xaa,0xaa,0xaa,0xaa,0xaa,0xaa,0xaa, /* U+9960 - U+997f */ 0xaa,0xaa,0xaa,0xaa,0xaa,0xaa,0xaa,0xaa, /* U+9980 - U+999f */ 0xaa,0xaa,0xaa,0xaa,0xaa,0xaa,0xaa,0xaa, /* U+99a0 - U+99bf */ 0xaa,0xaa,0xaa,0xaa,0xaa,0xaa,0xaa,0xaa, /* U+99c0 - U+99df */ 0xaa,0xaa,0xaa,0xaa,0xaa,0xaa,0xaa,0xaa, /* U+99e0 - U+99ff */ 0xaa,0xaa,0xaa,0xaa,0xaa,0xaa,0xaa,0xaa, /* U+9a00 - U+9a1f */ 0xaa,0xaa,0xaa,0xaa,0xaa,0xaa,0xaa,0xaa, /* U+9a20 - U+9a3f */ 0xaa,0xaa,0xaa,0xaa,0xaa,0xaa,0xaa,0xaa, /* U+9a40 - U+9a5f */ 0xaa,0xaa,0xaa,0xaa,0xaa,0xaa,0xaa,0xaa, /* U+9a60 - U+9a7f */ 0xaa,0xaa,0xaa,0xaa,0xaa,0xaa,0xaa,0xaa, /* U+9a80 - U+9a9f */ 0xaa,0xaa,0xaa,0xaa,0xaa,0xaa,0xaa,0xaa, /* U+9aa0 - U+9abf */ 0xaa,0xaa,0xaa,0xaa,0xaa,0xaa,0xaa,0xaa, /* U+9ac0 - U+9adf */ 0xaa,0xaa,0xaa,0xaa,0xaa,0xaa,0xaa,0xaa, /* U+9ae0 - U+9aff */ 0xaa,0xaa,0xaa,0xaa,0xaa,0xaa,0xaa,0xaa, /* U+9b00 - U+9b1f */ 0xaa,0xaa,0xaa,0xaa,0xaa,0xaa,0xaa,0xaa, /* U+9b20 - U+9b3f */ 0xaa,0xaa,0xaa,0xaa,0xaa,0xaa,0xaa,0xaa, /* U+9b40 - U+9b5f */ 0xaa,0xaa,0xaa,0xaa,0xaa,0xaa,0xaa,0xaa, /* U+9b60 - U+9b7f */ 0xaa,0xaa,0xaa,0xaa,0xaa,0xaa,0xaa,0xaa, /* U+9b80 - U+9b9f */ 0xaa,0xaa,0xaa,0xaa,0xaa,0xaa,0xaa,0xaa, /* U+9ba0 - U+9bbf */ 0xaa,0xaa,0xaa,0xaa,0xaa,0xaa,0xaa,0xaa, /* U+9bc0 - U+9bdf */ 0xaa,0xaa,0xaa,0xaa,0xaa,0xaa,0xaa,0xaa, /* U+9be0 - U+9bff */ 0xaa,0xaa,0xaa,0xaa,0xaa,0xaa,0xaa,0xaa, /* U+9c00 - U+9c1f */ 0xaa,0xaa,0xaa,0xaa,0xaa,0xaa,0xaa,0xaa, /* U+9c20 - U+9c3f */ 0xaa,0xaa,0xaa,0xaa,0xaa,0xaa,0xaa,0xaa, /* U+9c40 - U+9c5f */ 0xaa,0xaa,0xaa,0xaa,0xaa,0xaa,0xaa,0xaa, /* U+9c60 - U+9c7f */ 0xaa,0xaa,0xaa,0xaa,0xaa,0xaa,0xaa,0xaa, /* U+9c80 - U+9c9f */ 0xaa,0xaa,0xaa,0xaa,0xaa,0xaa,0xaa,0xaa, /* U+9ca0 - U+9cbf */ 0xaa,0xaa,0xaa,0xaa,0xaa,0xaa,0xaa,0xaa, /* U+9cc0 - U+9cdf */ 0xaa,0xaa,0xaa,0xaa,0xaa,0xaa,0xaa,0xaa, /* U+9ce0 - U+9cff */ 0xaa,0xaa,0xaa,0xaa,0xaa,0xaa,0xaa,0xaa, /* U+9d00 - U+9d1f */ 0xaa,0xaa,0xaa,0xaa,0xaa,0xaa,0xaa,0xaa, /* U+9d20 - U+9d3f */ 0xaa,0xaa,0xaa,0xaa,0xaa,0xaa,0xaa,0xaa, /* U+9d40 - U+9d5f */ 0xaa,0xaa,0xaa,0xaa,0xaa,0xaa,0xaa,0xaa, /* U+9d60 - U+9d7f */ 0xaa,0xaa,0xaa,0xaa,0xaa,0xaa,0xaa,0xaa, /* U+9d80 - U+9d9f */ 0xaa,0xaa,0xaa,0xaa,0xaa,0xaa,0xaa,0xaa, /* U+9da0 - U+9dbf */ 0xaa,0xaa,0xaa,0xaa,0xaa,0xaa,0xaa,0xaa, /* U+9dc0 - U+9ddf */ 0xaa,0xaa,0xaa,0xaa,0xaa,0xaa,0xaa,0xaa, /* U+9de0 - U+9dff */ 0xaa,0xaa,0xaa,0xaa,0xaa,0xaa,0xaa,0xaa, /* U+9e00 - U+9e1f */ 0xaa,0xaa,0xaa,0xaa,0xaa,0xaa,0xaa,0xaa, /* U+9e20 - U+9e3f */ 0xaa,0xaa,0xaa,0xaa,0xaa,0xaa,0xaa,0xaa, /* U+9e40 - U+9e5f */ 0xaa,0xaa,0xaa,0xaa,0xaa,0xaa,0xaa,0xaa, /* U+9e60 - U+9e7f */ 0xaa,0xaa,0xaa,0xaa,0xaa,0xaa,0xaa,0xaa, /* U+9e80 - U+9e9f */ 0xaa,0xaa,0xaa,0xaa,0xaa,0xaa,0xaa,0xaa, /* U+9ea0 - U+9ebf */ 0xaa,0xaa,0xaa,0xaa,0xaa,0xaa,0xaa,0xaa, /* U+9ec0 - U+9edf */ 0xaa,0xaa,0xaa,0xaa,0xaa,0xaa,0xaa,0xaa, /* U+9ee0 - U+9eff */ 0xaa,0xaa,0xaa,0xaa,0xaa,0xaa,0xaa,0xaa, /* U+9f00 - U+9f1f */ 0xaa,0xaa,0xaa,0xaa,0xaa,0xaa,0xaa,0xaa, /* U+9f20 - U+9f3f */ 0xaa,0xaa,0xaa,0xaa,0xaa,0xaa,0xaa,0xaa, /* U+9f40 - U+9f5f */ 0xaa,0xaa,0xaa,0xaa,0xaa,0xaa,0xaa,0xaa, /* U+9f60 - U+9f7f */ 0xaa,0xaa,0xaa,0xaa,0xaa,0xaa,0xaa,0xaa, /* U+9f80 - U+9f9f */ 0xaa,0xaa,0xaa,0xaa,0xaa,0xaa,0xaa,0xff, /* U+9fa0 - U+9fbf */ 0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff, /* U+9fc0 - U+9fdf */ 0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff, /* U+9fe0 - U+9fff */ 0xaa,0xaa,0xaa,0xaa,0xaa,0xaa,0xaa,0xaa, /* U+a000 - U+a01f */ 0xaa,0xaa,0xaa,0xaa,0xaa,0xaa,0xaa,0xaa, /* U+a020 - U+a03f */ 0xaa,0xaa,0xaa,0xaa,0xaa,0xaa,0xaa,0xaa, /* U+a040 - U+a05f */ 0xaa,0xaa,0xaa,0xaa,0xaa,0xaa,0xaa,0xaa, /* U+a060 - U+a07f */ 0xaa,0xaa,0xaa,0xaa,0xaa,0xaa,0xaa,0xaa, /* U+a080 - U+a09f */ 0xaa,0xaa,0xaa,0xaa,0xaa,0xaa,0xaa,0xaa, /* U+a0a0 - U+a0bf */ 0xaa,0xaa,0xaa,0xaa,0xaa,0xaa,0xaa,0xaa, /* U+a0c0 - U+a0df */ 0xaa,0xaa,0xaa,0xaa,0xaa,0xaa,0xaa,0xaa, /* U+a0e0 - U+a0ff */ 0xaa,0xaa,0xaa,0xaa,0xaa,0xaa,0xaa,0xaa, /* U+a100 - U+a11f */ 0xaa,0xaa,0xaa,0xaa,0xaa,0xaa,0xaa,0xaa, /* U+a120 - U+a13f */ 0xaa,0xaa,0xaa,0xaa,0xaa,0xaa,0xaa,0xaa, /* U+a140 - U+a15f */ 0xaa,0xaa,0xaa,0xaa,0xaa,0xaa,0xaa,0xaa, /* U+a160 - U+a17f */ 0xaa,0xaa,0xaa,0xaa,0xaa,0xaa,0xaa,0xaa, /* U+a180 - U+a19f */ 0xaa,0xaa,0xaa,0xaa,0xaa,0xaa,0xaa,0xaa, /* U+a1a0 - U+a1bf */ 0xaa,0xaa,0xaa,0xaa,0xaa,0xaa,0xaa,0xaa, /* U+a1c0 - U+a1df */ 0xaa,0xaa,0xaa,0xaa,0xaa,0xaa,0xaa,0xaa, /* U+a1e0 - U+a1ff */ 0xaa,0xaa,0xaa,0xaa,0xaa,0xaa,0xaa,0xaa, /* U+a200 - U+a21f */ 0xaa,0xaa,0xaa,0xaa,0xaa,0xaa,0xaa,0xaa, /* U+a220 - U+a23f */ 0xaa,0xaa,0xaa,0xaa,0xaa,0xaa,0xaa,0xaa, /* U+a240 - U+a25f */ 0xaa,0xaa,0xaa,0xaa,0xaa,0xaa,0xaa,0xaa, /* U+a260 - U+a27f */ 0xaa,0xaa,0xaa,0xaa,0xaa,0xaa,0xaa,0xaa, /* U+a280 - U+a29f */ 0xaa,0xaa,0xaa,0xaa,0xaa,0xaa,0xaa,0xaa, /* U+a2a0 - U+a2bf */ 0xaa,0xaa,0xaa,0xaa,0xaa,0xaa,0xaa,0xaa, /* U+a2c0 - U+a2df */ 0xaa,0xaa,0xaa,0xaa,0xaa,0xaa,0xaa,0xaa, /* U+a2e0 - U+a2ff */ 0xaa,0xaa,0xaa,0xaa,0xaa,0xaa,0xaa,0xaa, /* U+a300 - U+a31f */ 0xaa,0xaa,0xaa,0xaa,0xaa,0xaa,0xaa,0xaa, /* U+a320 - U+a33f */ 0xaa,0xaa,0xaa,0xaa,0xaa,0xaa,0xaa,0xaa, /* U+a340 - U+a35f */ 0xaa,0xaa,0xaa,0xaa,0xaa,0xaa,0xaa,0xaa, /* U+a360 - U+a37f */ 0xaa,0xaa,0xaa,0xaa,0xaa,0xaa,0xaa,0xaa, /* U+a380 - U+a39f */ 0xaa,0xaa,0xaa,0xaa,0xaa,0xaa,0xaa,0xaa, /* U+a3a0 - U+a3bf */ 0xaa,0xaa,0xaa,0xaa,0xaa,0xaa,0xaa,0xaa, /* U+a3c0 - U+a3df */ 0xaa,0xaa,0xaa,0xaa,0xaa,0xaa,0xaa,0xaa, /* U+a3e0 - U+a3ff */ 0xaa,0xaa,0xaa,0xaa,0xaa,0xaa,0xaa,0xaa, /* U+a400 - U+a41f */ 0xaa,0xaa,0xaa,0xaa,0xaa,0xaa,0xaa,0xaa, /* U+a420 - U+a43f */ 0xaa,0xaa,0xaa,0xaa,0xaa,0xaa,0xaa,0xaa, /* U+a440 - U+a45f */ 0xaa,0xaa,0xaa,0xaa,0xaa,0xaa,0xaa,0xaa, /* U+a460 - U+a47f */ 0xaa,0xaa,0xaa,0xbf,0xaa,0xaa,0xaa,0xaa, /* U+a480 - U+a49f */ 0xaa,0xaa,0xaa,0xaa,0xaa,0xaa,0xaa,0xaa, /* U+a4a0 - U+a4bf */ 0xaa,0xab,0xff,0xff,0xff,0xff,0xff,0xff, /* U+a4c0 - U+a4df */ 0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff, /* U+a4e0 - U+a4ff */ 0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff, /* U+a500 - U+a51f */ 0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff, /* U+a520 - U+a53f */ 0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff, /* U+a540 - U+a55f */ 0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff, /* U+a560 - U+a57f */ 0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff, /* U+a580 - U+a59f */ 0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff, /* U+a5a0 - U+a5bf */ 0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff, /* U+a5c0 - U+a5df */ 0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff, /* U+a5e0 - U+a5ff */ 0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff, /* U+a600 - U+a61f */ 0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff, /* U+a620 - U+a63f */ 0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff, /* U+a640 - U+a65f */ 0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff, /* U+a660 - U+a67f */ 0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff, /* U+a680 - U+a69f */ 0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff, /* U+a6a0 - U+a6bf */ 0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff, /* U+a6c0 - U+a6df */ 0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff, /* U+a6e0 - U+a6ff */ 0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff, /* U+a700 - U+a71f */ 0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff, /* U+a720 - U+a73f */ 0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff, /* U+a740 - U+a75f */ 0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff, /* U+a760 - U+a77f */ 0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff, /* U+a780 - U+a79f */ 0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff, /* U+a7a0 - U+a7bf */ 0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff, /* U+a7c0 - U+a7df */ 0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff, /* U+a7e0 - U+a7ff */ 0xf3,0xf3,0xfc,0xff,0xff,0xff,0xff,0xff, /* U+a800 - U+a81f */ 0xff,0xc3,0xff,0xff,0xff,0xff,0xff,0xff, /* U+a820 - U+a83f */ 0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff, /* U+a840 - U+a85f */ 0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff, /* U+a860 - U+a87f */ 0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff, /* U+a880 - U+a89f */ 0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff, /* U+a8a0 - U+a8bf */ 0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff, /* U+a8c0 - U+a8df */ 0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff, /* U+a8e0 - U+a8ff */ 0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff, /* U+a900 - U+a91f */ 0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff, /* U+a920 - U+a93f */ 0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff, /* U+a940 - U+a95f */ 0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff, /* U+a960 - U+a97f */ 0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff, /* U+a980 - U+a99f */ 0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff, /* U+a9a0 - U+a9bf */ 0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff, /* U+a9c0 - U+a9df */ 0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff, /* U+a9e0 - U+a9ff */ 0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff, /* U+aa00 - U+aa1f */ 0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff, /* U+aa20 - U+aa3f */ 0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff, /* U+aa40 - U+aa5f */ 0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff, /* U+aa60 - U+aa7f */ 0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff, /* U+aa80 - U+aa9f */ 0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff, /* U+aaa0 - U+aabf */ 0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff, /* U+aac0 - U+aadf */ 0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff, /* U+aae0 - U+aaff */ 0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff, /* U+ab00 - U+ab1f */ 0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff, /* U+ab20 - U+ab3f */ 0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff, /* U+ab40 - U+ab5f */ 0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff, /* U+ab60 - U+ab7f */ 0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff, /* U+ab80 - U+ab9f */ 0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff, /* U+aba0 - U+abbf */ 0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff, /* U+abc0 - U+abdf */ 0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff, /* U+abe0 - U+abff */ 0xaa,0xaa,0xaa,0xaa,0xaa,0xaa,0xaa,0xaa, /* U+ac00 - U+ac1f */ 0xaa,0xaa,0xaa,0xaa,0xaa,0xaa,0xaa,0xaa, /* U+ac20 - U+ac3f */ 0xaa,0xaa,0xaa,0xaa,0xaa,0xaa,0xaa,0xaa, /* U+ac40 - U+ac5f */ 0xaa,0xaa,0xaa,0xaa,0xaa,0xaa,0xaa,0xaa, /* U+ac60 - U+ac7f */ 0xaa,0xaa,0xaa,0xaa,0xaa,0xaa,0xaa,0xaa, /* U+ac80 - U+ac9f */ 0xaa,0xaa,0xaa,0xaa,0xaa,0xaa,0xaa,0xaa, /* U+aca0 - U+acbf */ 0xaa,0xaa,0xaa,0xaa,0xaa,0xaa,0xaa,0xaa, /* U+acc0 - U+acdf */ 0xaa,0xaa,0xaa,0xaa,0xaa,0xaa,0xaa,0xaa, /* U+ace0 - U+acff */ 0xaa,0xaa,0xaa,0xaa,0xaa,0xaa,0xaa,0xaa, /* U+ad00 - U+ad1f */ 0xaa,0xaa,0xaa,0xaa,0xaa,0xaa,0xaa,0xaa, /* U+ad20 - U+ad3f */ 0xaa,0xaa,0xaa,0xaa,0xaa,0xaa,0xaa,0xaa, /* U+ad40 - U+ad5f */ 0xaa,0xaa,0xaa,0xaa,0xaa,0xaa,0xaa,0xaa, /* U+ad60 - U+ad7f */ 0xaa,0xaa,0xaa,0xaa,0xaa,0xaa,0xaa,0xaa, /* U+ad80 - U+ad9f */ 0xaa,0xaa,0xaa,0xaa,0xaa,0xaa,0xaa,0xaa, /* U+ada0 - U+adbf */ 0xaa,0xaa,0xaa,0xaa,0xaa,0xaa,0xaa,0xaa, /* U+adc0 - U+addf */ 0xaa,0xaa,0xaa,0xaa,0xaa,0xaa,0xaa,0xaa, /* U+ade0 - U+adff */ 0xaa,0xaa,0xaa,0xaa,0xaa,0xaa,0xaa,0xaa, /* U+ae00 - U+ae1f */ 0xaa,0xaa,0xaa,0xaa,0xaa,0xaa,0xaa,0xaa, /* U+ae20 - U+ae3f */ 0xaa,0xaa,0xaa,0xaa,0xaa,0xaa,0xaa,0xaa, /* U+ae40 - U+ae5f */ 0xaa,0xaa,0xaa,0xaa,0xaa,0xaa,0xaa,0xaa, /* U+ae60 - U+ae7f */ 0xaa,0xaa,0xaa,0xaa,0xaa,0xaa,0xaa,0xaa, /* U+ae80 - U+ae9f */ 0xaa,0xaa,0xaa,0xaa,0xaa,0xaa,0xaa,0xaa, /* U+aea0 - U+aebf */ 0xaa,0xaa,0xaa,0xaa,0xaa,0xaa,0xaa,0xaa, /* U+aec0 - U+aedf */ 0xaa,0xaa,0xaa,0xaa,0xaa,0xaa,0xaa,0xaa, /* U+aee0 - U+aeff */ 0xaa,0xaa,0xaa,0xaa,0xaa,0xaa,0xaa,0xaa, /* U+af00 - U+af1f */ 0xaa,0xaa,0xaa,0xaa,0xaa,0xaa,0xaa,0xaa, /* U+af20 - U+af3f */ 0xaa,0xaa,0xaa,0xaa,0xaa,0xaa,0xaa,0xaa, /* U+af40 - U+af5f */ 0xaa,0xaa,0xaa,0xaa,0xaa,0xaa,0xaa,0xaa, /* U+af60 - U+af7f */ 0xaa,0xaa,0xaa,0xaa,0xaa,0xaa,0xaa,0xaa, /* U+af80 - U+af9f */ 0xaa,0xaa,0xaa,0xaa,0xaa,0xaa,0xaa,0xaa, /* U+afa0 - U+afbf */ 0xaa,0xaa,0xaa,0xaa,0xaa,0xaa,0xaa,0xaa, /* U+afc0 - U+afdf */ 0xaa,0xaa,0xaa,0xaa,0xaa,0xaa,0xaa,0xaa, /* U+afe0 - U+afff */ 0xaa,0xaa,0xaa,0xaa,0xaa,0xaa,0xaa,0xaa, /* U+b000 - U+b01f */ 0xaa,0xaa,0xaa,0xaa,0xaa,0xaa,0xaa,0xaa, /* U+b020 - U+b03f */ 0xaa,0xaa,0xaa,0xaa,0xaa,0xaa,0xaa,0xaa, /* U+b040 - U+b05f */ 0xaa,0xaa,0xaa,0xaa,0xaa,0xaa,0xaa,0xaa, /* U+b060 - U+b07f */ 0xaa,0xaa,0xaa,0xaa,0xaa,0xaa,0xaa,0xaa, /* U+b080 - U+b09f */ 0xaa,0xaa,0xaa,0xaa,0xaa,0xaa,0xaa,0xaa, /* U+b0a0 - U+b0bf */ 0xaa,0xaa,0xaa,0xaa,0xaa,0xaa,0xaa,0xaa, /* U+b0c0 - U+b0df */ 0xaa,0xaa,0xaa,0xaa,0xaa,0xaa,0xaa,0xaa, /* U+b0e0 - U+b0ff */ 0xaa,0xaa,0xaa,0xaa,0xaa,0xaa,0xaa,0xaa, /* U+b100 - U+b11f */ 0xaa,0xaa,0xaa,0xaa,0xaa,0xaa,0xaa,0xaa, /* U+b120 - U+b13f */ 0xaa,0xaa,0xaa,0xaa,0xaa,0xaa,0xaa,0xaa, /* U+b140 - U+b15f */ 0xaa,0xaa,0xaa,0xaa,0xaa,0xaa,0xaa,0xaa, /* U+b160 - U+b17f */ 0xaa,0xaa,0xaa,0xaa,0xaa,0xaa,0xaa,0xaa, /* U+b180 - U+b19f */ 0xaa,0xaa,0xaa,0xaa,0xaa,0xaa,0xaa,0xaa, /* U+b1a0 - U+b1bf */ 0xaa,0xaa,0xaa,0xaa,0xaa,0xaa,0xaa,0xaa, /* U+b1c0 - U+b1df */ 0xaa,0xaa,0xaa,0xaa,0xaa,0xaa,0xaa,0xaa, /* U+b1e0 - U+b1ff */ 0xaa,0xaa,0xaa,0xaa,0xaa,0xaa,0xaa,0xaa, /* U+b200 - U+b21f */ 0xaa,0xaa,0xaa,0xaa,0xaa,0xaa,0xaa,0xaa, /* U+b220 - U+b23f */ 0xaa,0xaa,0xaa,0xaa,0xaa,0xaa,0xaa,0xaa, /* U+b240 - U+b25f */ 0xaa,0xaa,0xaa,0xaa,0xaa,0xaa,0xaa,0xaa, /* U+b260 - U+b27f */ 0xaa,0xaa,0xaa,0xaa,0xaa,0xaa,0xaa,0xaa, /* U+b280 - U+b29f */ 0xaa,0xaa,0xaa,0xaa,0xaa,0xaa,0xaa,0xaa, /* U+b2a0 - U+b2bf */ 0xaa,0xaa,0xaa,0xaa,0xaa,0xaa,0xaa,0xaa, /* U+b2c0 - U+b2df */ 0xaa,0xaa,0xaa,0xaa,0xaa,0xaa,0xaa,0xaa, /* U+b2e0 - U+b2ff */ 0xaa,0xaa,0xaa,0xaa,0xaa,0xaa,0xaa,0xaa, /* U+b300 - U+b31f */ 0xaa,0xaa,0xaa,0xaa,0xaa,0xaa,0xaa,0xaa, /* U+b320 - U+b33f */ 0xaa,0xaa,0xaa,0xaa,0xaa,0xaa,0xaa,0xaa, /* U+b340 - U+b35f */ 0xaa,0xaa,0xaa,0xaa,0xaa,0xaa,0xaa,0xaa, /* U+b360 - U+b37f */ 0xaa,0xaa,0xaa,0xaa,0xaa,0xaa,0xaa,0xaa, /* U+b380 - U+b39f */ 0xaa,0xaa,0xaa,0xaa,0xaa,0xaa,0xaa,0xaa, /* U+b3a0 - U+b3bf */ 0xaa,0xaa,0xaa,0xaa,0xaa,0xaa,0xaa,0xaa, /* U+b3c0 - U+b3df */ 0xaa,0xaa,0xaa,0xaa,0xaa,0xaa,0xaa,0xaa, /* U+b3e0 - U+b3ff */ 0xaa,0xaa,0xaa,0xaa,0xaa,0xaa,0xaa,0xaa, /* U+b400 - U+b41f */ 0xaa,0xaa,0xaa,0xaa,0xaa,0xaa,0xaa,0xaa, /* U+b420 - U+b43f */ 0xaa,0xaa,0xaa,0xaa,0xaa,0xaa,0xaa,0xaa, /* U+b440 - U+b45f */ 0xaa,0xaa,0xaa,0xaa,0xaa,0xaa,0xaa,0xaa, /* U+b460 - U+b47f */ 0xaa,0xaa,0xaa,0xaa,0xaa,0xaa,0xaa,0xaa, /* U+b480 - U+b49f */ 0xaa,0xaa,0xaa,0xaa,0xaa,0xaa,0xaa,0xaa, /* U+b4a0 - U+b4bf */ 0xaa,0xaa,0xaa,0xaa,0xaa,0xaa,0xaa,0xaa, /* U+b4c0 - U+b4df */ 0xaa,0xaa,0xaa,0xaa,0xaa,0xaa,0xaa,0xaa, /* U+b4e0 - U+b4ff */ 0xaa,0xaa,0xaa,0xaa,0xaa,0xaa,0xaa,0xaa, /* U+b500 - U+b51f */ 0xaa,0xaa,0xaa,0xaa,0xaa,0xaa,0xaa,0xaa, /* U+b520 - U+b53f */ 0xaa,0xaa,0xaa,0xaa,0xaa,0xaa,0xaa,0xaa, /* U+b540 - U+b55f */ 0xaa,0xaa,0xaa,0xaa,0xaa,0xaa,0xaa,0xaa, /* U+b560 - U+b57f */ 0xaa,0xaa,0xaa,0xaa,0xaa,0xaa,0xaa,0xaa, /* U+b580 - U+b59f */ 0xaa,0xaa,0xaa,0xaa,0xaa,0xaa,0xaa,0xaa, /* U+b5a0 - U+b5bf */ 0xaa,0xaa,0xaa,0xaa,0xaa,0xaa,0xaa,0xaa, /* U+b5c0 - U+b5df */ 0xaa,0xaa,0xaa,0xaa,0xaa,0xaa,0xaa,0xaa, /* U+b5e0 - U+b5ff */ 0xaa,0xaa,0xaa,0xaa,0xaa,0xaa,0xaa,0xaa, /* U+b600 - U+b61f */ 0xaa,0xaa,0xaa,0xaa,0xaa,0xaa,0xaa,0xaa, /* U+b620 - U+b63f */ 0xaa,0xaa,0xaa,0xaa,0xaa,0xaa,0xaa,0xaa, /* U+b640 - U+b65f */ 0xaa,0xaa,0xaa,0xaa,0xaa,0xaa,0xaa,0xaa, /* U+b660 - U+b67f */ 0xaa,0xaa,0xaa,0xaa,0xaa,0xaa,0xaa,0xaa, /* U+b680 - U+b69f */ 0xaa,0xaa,0xaa,0xaa,0xaa,0xaa,0xaa,0xaa, /* U+b6a0 - U+b6bf */ 0xaa,0xaa,0xaa,0xaa,0xaa,0xaa,0xaa,0xaa, /* U+b6c0 - U+b6df */ 0xaa,0xaa,0xaa,0xaa,0xaa,0xaa,0xaa,0xaa, /* U+b6e0 - U+b6ff */ 0xaa,0xaa,0xaa,0xaa,0xaa,0xaa,0xaa,0xaa, /* U+b700 - U+b71f */ 0xaa,0xaa,0xaa,0xaa,0xaa,0xaa,0xaa,0xaa, /* U+b720 - U+b73f */ 0xaa,0xaa,0xaa,0xaa,0xaa,0xaa,0xaa,0xaa, /* U+b740 - U+b75f */ 0xaa,0xaa,0xaa,0xaa,0xaa,0xaa,0xaa,0xaa, /* U+b760 - U+b77f */ 0xaa,0xaa,0xaa,0xaa,0xaa,0xaa,0xaa,0xaa, /* U+b780 - U+b79f */ 0xaa,0xaa,0xaa,0xaa,0xaa,0xaa,0xaa,0xaa, /* U+b7a0 - U+b7bf */ 0xaa,0xaa,0xaa,0xaa,0xaa,0xaa,0xaa,0xaa, /* U+b7c0 - U+b7df */ 0xaa,0xaa,0xaa,0xaa,0xaa,0xaa,0xaa,0xaa, /* U+b7e0 - U+b7ff */ 0xaa,0xaa,0xaa,0xaa,0xaa,0xaa,0xaa,0xaa, /* U+b800 - U+b81f */ 0xaa,0xaa,0xaa,0xaa,0xaa,0xaa,0xaa,0xaa, /* U+b820 - U+b83f */ 0xaa,0xaa,0xaa,0xaa,0xaa,0xaa,0xaa,0xaa, /* U+b840 - U+b85f */ 0xaa,0xaa,0xaa,0xaa,0xaa,0xaa,0xaa,0xaa, /* U+b860 - U+b87f */ 0xaa,0xaa,0xaa,0xaa,0xaa,0xaa,0xaa,0xaa, /* U+b880 - U+b89f */ 0xaa,0xaa,0xaa,0xaa,0xaa,0xaa,0xaa,0xaa, /* U+b8a0 - U+b8bf */ 0xaa,0xaa,0xaa,0xaa,0xaa,0xaa,0xaa,0xaa, /* U+b8c0 - U+b8df */ 0xaa,0xaa,0xaa,0xaa,0xaa,0xaa,0xaa,0xaa, /* U+b8e0 - U+b8ff */ 0xaa,0xaa,0xaa,0xaa,0xaa,0xaa,0xaa,0xaa, /* U+b900 - U+b91f */ 0xaa,0xaa,0xaa,0xaa,0xaa,0xaa,0xaa,0xaa, /* U+b920 - U+b93f */ 0xaa,0xaa,0xaa,0xaa,0xaa,0xaa,0xaa,0xaa, /* U+b940 - U+b95f */ 0xaa,0xaa,0xaa,0xaa,0xaa,0xaa,0xaa,0xaa, /* U+b960 - U+b97f */ 0xaa,0xaa,0xaa,0xaa,0xaa,0xaa,0xaa,0xaa, /* U+b980 - U+b99f */ 0xaa,0xaa,0xaa,0xaa,0xaa,0xaa,0xaa,0xaa, /* U+b9a0 - U+b9bf */ 0xaa,0xaa,0xaa,0xaa,0xaa,0xaa,0xaa,0xaa, /* U+b9c0 - U+b9df */ 0xaa,0xaa,0xaa,0xaa,0xaa,0xaa,0xaa,0xaa, /* U+b9e0 - U+b9ff */ 0xaa,0xaa,0xaa,0xaa,0xaa,0xaa,0xaa,0xaa, /* U+ba00 - U+ba1f */ 0xaa,0xaa,0xaa,0xaa,0xaa,0xaa,0xaa,0xaa, /* U+ba20 - U+ba3f */ 0xaa,0xaa,0xaa,0xaa,0xaa,0xaa,0xaa,0xaa, /* U+ba40 - U+ba5f */ 0xaa,0xaa,0xaa,0xaa,0xaa,0xaa,0xaa,0xaa, /* U+ba60 - U+ba7f */ 0xaa,0xaa,0xaa,0xaa,0xaa,0xaa,0xaa,0xaa, /* U+ba80 - U+ba9f */ 0xaa,0xaa,0xaa,0xaa,0xaa,0xaa,0xaa,0xaa, /* U+baa0 - U+babf */ 0xaa,0xaa,0xaa,0xaa,0xaa,0xaa,0xaa,0xaa, /* U+bac0 - U+badf */ 0xaa,0xaa,0xaa,0xaa,0xaa,0xaa,0xaa,0xaa, /* U+bae0 - U+baff */ 0xaa,0xaa,0xaa,0xaa,0xaa,0xaa,0xaa,0xaa, /* U+bb00 - U+bb1f */ 0xaa,0xaa,0xaa,0xaa,0xaa,0xaa,0xaa,0xaa, /* U+bb20 - U+bb3f */ 0xaa,0xaa,0xaa,0xaa,0xaa,0xaa,0xaa,0xaa, /* U+bb40 - U+bb5f */ 0xaa,0xaa,0xaa,0xaa,0xaa,0xaa,0xaa,0xaa, /* U+bb60 - U+bb7f */ 0xaa,0xaa,0xaa,0xaa,0xaa,0xaa,0xaa,0xaa, /* U+bb80 - U+bb9f */ 0xaa,0xaa,0xaa,0xaa,0xaa,0xaa,0xaa,0xaa, /* U+bba0 - U+bbbf */ 0xaa,0xaa,0xaa,0xaa,0xaa,0xaa,0xaa,0xaa, /* U+bbc0 - U+bbdf */ 0xaa,0xaa,0xaa,0xaa,0xaa,0xaa,0xaa,0xaa, /* U+bbe0 - U+bbff */ 0xaa,0xaa,0xaa,0xaa,0xaa,0xaa,0xaa,0xaa, /* U+bc00 - U+bc1f */ 0xaa,0xaa,0xaa,0xaa,0xaa,0xaa,0xaa,0xaa, /* U+bc20 - U+bc3f */ 0xaa,0xaa,0xaa,0xaa,0xaa,0xaa,0xaa,0xaa, /* U+bc40 - U+bc5f */ 0xaa,0xaa,0xaa,0xaa,0xaa,0xaa,0xaa,0xaa, /* U+bc60 - U+bc7f */ 0xaa,0xaa,0xaa,0xaa,0xaa,0xaa,0xaa,0xaa, /* U+bc80 - U+bc9f */ 0xaa,0xaa,0xaa,0xaa,0xaa,0xaa,0xaa,0xaa, /* U+bca0 - U+bcbf */ 0xaa,0xaa,0xaa,0xaa,0xaa,0xaa,0xaa,0xaa, /* U+bcc0 - U+bcdf */ 0xaa,0xaa,0xaa,0xaa,0xaa,0xaa,0xaa,0xaa, /* U+bce0 - U+bcff */ 0xaa,0xaa,0xaa,0xaa,0xaa,0xaa,0xaa,0xaa, /* U+bd00 - U+bd1f */ 0xaa,0xaa,0xaa,0xaa,0xaa,0xaa,0xaa,0xaa, /* U+bd20 - U+bd3f */ 0xaa,0xaa,0xaa,0xaa,0xaa,0xaa,0xaa,0xaa, /* U+bd40 - U+bd5f */ 0xaa,0xaa,0xaa,0xaa,0xaa,0xaa,0xaa,0xaa, /* U+bd60 - U+bd7f */ 0xaa,0xaa,0xaa,0xaa,0xaa,0xaa,0xaa,0xaa, /* U+bd80 - U+bd9f */ 0xaa,0xaa,0xaa,0xaa,0xaa,0xaa,0xaa,0xaa, /* U+bda0 - U+bdbf */ 0xaa,0xaa,0xaa,0xaa,0xaa,0xaa,0xaa,0xaa, /* U+bdc0 - U+bddf */ 0xaa,0xaa,0xaa,0xaa,0xaa,0xaa,0xaa,0xaa, /* U+bde0 - U+bdff */ 0xaa,0xaa,0xaa,0xaa,0xaa,0xaa,0xaa,0xaa, /* U+be00 - U+be1f */ 0xaa,0xaa,0xaa,0xaa,0xaa,0xaa,0xaa,0xaa, /* U+be20 - U+be3f */ 0xaa,0xaa,0xaa,0xaa,0xaa,0xaa,0xaa,0xaa, /* U+be40 - U+be5f */ 0xaa,0xaa,0xaa,0xaa,0xaa,0xaa,0xaa,0xaa, /* U+be60 - U+be7f */ 0xaa,0xaa,0xaa,0xaa,0xaa,0xaa,0xaa,0xaa, /* U+be80 - U+be9f */ 0xaa,0xaa,0xaa,0xaa,0xaa,0xaa,0xaa,0xaa, /* U+bea0 - U+bebf */ 0xaa,0xaa,0xaa,0xaa,0xaa,0xaa,0xaa,0xaa, /* U+bec0 - U+bedf */ 0xaa,0xaa,0xaa,0xaa,0xaa,0xaa,0xaa,0xaa, /* U+bee0 - U+beff */ 0xaa,0xaa,0xaa,0xaa,0xaa,0xaa,0xaa,0xaa, /* U+bf00 - U+bf1f */ 0xaa,0xaa,0xaa,0xaa,0xaa,0xaa,0xaa,0xaa, /* U+bf20 - U+bf3f */ 0xaa,0xaa,0xaa,0xaa,0xaa,0xaa,0xaa,0xaa, /* U+bf40 - U+bf5f */ 0xaa,0xaa,0xaa,0xaa,0xaa,0xaa,0xaa,0xaa, /* U+bf60 - U+bf7f */ 0xaa,0xaa,0xaa,0xaa,0xaa,0xaa,0xaa,0xaa, /* U+bf80 - U+bf9f */ 0xaa,0xaa,0xaa,0xaa,0xaa,0xaa,0xaa,0xaa, /* U+bfa0 - U+bfbf */ 0xaa,0xaa,0xaa,0xaa,0xaa,0xaa,0xaa,0xaa, /* U+bfc0 - U+bfdf */ 0xaa,0xaa,0xaa,0xaa,0xaa,0xaa,0xaa,0xaa, /* U+bfe0 - U+bfff */ 0xaa,0xaa,0xaa,0xaa,0xaa,0xaa,0xaa,0xaa, /* U+c000 - U+c01f */ 0xaa,0xaa,0xaa,0xaa,0xaa,0xaa,0xaa,0xaa, /* U+c020 - U+c03f */ 0xaa,0xaa,0xaa,0xaa,0xaa,0xaa,0xaa,0xaa, /* U+c040 - U+c05f */ 0xaa,0xaa,0xaa,0xaa,0xaa,0xaa,0xaa,0xaa, /* U+c060 - U+c07f */ 0xaa,0xaa,0xaa,0xaa,0xaa,0xaa,0xaa,0xaa, /* U+c080 - U+c09f */ 0xaa,0xaa,0xaa,0xaa,0xaa,0xaa,0xaa,0xaa, /* U+c0a0 - U+c0bf */ 0xaa,0xaa,0xaa,0xaa,0xaa,0xaa,0xaa,0xaa, /* U+c0c0 - U+c0df */ 0xaa,0xaa,0xaa,0xaa,0xaa,0xaa,0xaa,0xaa, /* U+c0e0 - U+c0ff */ 0xaa,0xaa,0xaa,0xaa,0xaa,0xaa,0xaa,0xaa, /* U+c100 - U+c11f */ 0xaa,0xaa,0xaa,0xaa,0xaa,0xaa,0xaa,0xaa, /* U+c120 - U+c13f */ 0xaa,0xaa,0xaa,0xaa,0xaa,0xaa,0xaa,0xaa, /* U+c140 - U+c15f */ 0xaa,0xaa,0xaa,0xaa,0xaa,0xaa,0xaa,0xaa, /* U+c160 - U+c17f */ 0xaa,0xaa,0xaa,0xaa,0xaa,0xaa,0xaa,0xaa, /* U+c180 - U+c19f */ 0xaa,0xaa,0xaa,0xaa,0xaa,0xaa,0xaa,0xaa, /* U+c1a0 - U+c1bf */ 0xaa,0xaa,0xaa,0xaa,0xaa,0xaa,0xaa,0xaa, /* U+c1c0 - U+c1df */ 0xaa,0xaa,0xaa,0xaa,0xaa,0xaa,0xaa,0xaa, /* U+c1e0 - U+c1ff */ 0xaa,0xaa,0xaa,0xaa,0xaa,0xaa,0xaa,0xaa, /* U+c200 - U+c21f */ 0xaa,0xaa,0xaa,0xaa,0xaa,0xaa,0xaa,0xaa, /* U+c220 - U+c23f */ 0xaa,0xaa,0xaa,0xaa,0xaa,0xaa,0xaa,0xaa, /* U+c240 - U+c25f */ 0xaa,0xaa,0xaa,0xaa,0xaa,0xaa,0xaa,0xaa, /* U+c260 - U+c27f */ 0xaa,0xaa,0xaa,0xaa,0xaa,0xaa,0xaa,0xaa, /* U+c280 - U+c29f */ 0xaa,0xaa,0xaa,0xaa,0xaa,0xaa,0xaa,0xaa, /* U+c2a0 - U+c2bf */ 0xaa,0xaa,0xaa,0xaa,0xaa,0xaa,0xaa,0xaa, /* U+c2c0 - U+c2df */ 0xaa,0xaa,0xaa,0xaa,0xaa,0xaa,0xaa,0xaa, /* U+c2e0 - U+c2ff */ 0xaa,0xaa,0xaa,0xaa,0xaa,0xaa,0xaa,0xaa, /* U+c300 - U+c31f */ 0xaa,0xaa,0xaa,0xaa,0xaa,0xaa,0xaa,0xaa, /* U+c320 - U+c33f */ 0xaa,0xaa,0xaa,0xaa,0xaa,0xaa,0xaa,0xaa, /* U+c340 - U+c35f */ 0xaa,0xaa,0xaa,0xaa,0xaa,0xaa,0xaa,0xaa, /* U+c360 - U+c37f */ 0xaa,0xaa,0xaa,0xaa,0xaa,0xaa,0xaa,0xaa, /* U+c380 - U+c39f */ 0xaa,0xaa,0xaa,0xaa,0xaa,0xaa,0xaa,0xaa, /* U+c3a0 - U+c3bf */ 0xaa,0xaa,0xaa,0xaa,0xaa,0xaa,0xaa,0xaa, /* U+c3c0 - U+c3df */ 0xaa,0xaa,0xaa,0xaa,0xaa,0xaa,0xaa,0xaa, /* U+c3e0 - U+c3ff */ 0xaa,0xaa,0xaa,0xaa,0xaa,0xaa,0xaa,0xaa, /* U+c400 - U+c41f */ 0xaa,0xaa,0xaa,0xaa,0xaa,0xaa,0xaa,0xaa, /* U+c420 - U+c43f */ 0xaa,0xaa,0xaa,0xaa,0xaa,0xaa,0xaa,0xaa, /* U+c440 - U+c45f */ 0xaa,0xaa,0xaa,0xaa,0xaa,0xaa,0xaa,0xaa, /* U+c460 - U+c47f */ 0xaa,0xaa,0xaa,0xaa,0xaa,0xaa,0xaa,0xaa, /* U+c480 - U+c49f */ 0xaa,0xaa,0xaa,0xaa,0xaa,0xaa,0xaa,0xaa, /* U+c4a0 - U+c4bf */ 0xaa,0xaa,0xaa,0xaa,0xaa,0xaa,0xaa,0xaa, /* U+c4c0 - U+c4df */ 0xaa,0xaa,0xaa,0xaa,0xaa,0xaa,0xaa,0xaa, /* U+c4e0 - U+c4ff */ 0xaa,0xaa,0xaa,0xaa,0xaa,0xaa,0xaa,0xaa, /* U+c500 - U+c51f */ 0xaa,0xaa,0xaa,0xaa,0xaa,0xaa,0xaa,0xaa, /* U+c520 - U+c53f */ 0xaa,0xaa,0xaa,0xaa,0xaa,0xaa,0xaa,0xaa, /* U+c540 - U+c55f */ 0xaa,0xaa,0xaa,0xaa,0xaa,0xaa,0xaa,0xaa, /* U+c560 - U+c57f */ 0xaa,0xaa,0xaa,0xaa,0xaa,0xaa,0xaa,0xaa, /* U+c580 - U+c59f */ 0xaa,0xaa,0xaa,0xaa,0xaa,0xaa,0xaa,0xaa, /* U+c5a0 - U+c5bf */ 0xaa,0xaa,0xaa,0xaa,0xaa,0xaa,0xaa,0xaa, /* U+c5c0 - U+c5df */ 0xaa,0xaa,0xaa,0xaa,0xaa,0xaa,0xaa,0xaa, /* U+c5e0 - U+c5ff */ 0xaa,0xaa,0xaa,0xaa,0xaa,0xaa,0xaa,0xaa, /* U+c600 - U+c61f */ 0xaa,0xaa,0xaa,0xaa,0xaa,0xaa,0xaa,0xaa, /* U+c620 - U+c63f */ 0xaa,0xaa,0xaa,0xaa,0xaa,0xaa,0xaa,0xaa, /* U+c640 - U+c65f */ 0xaa,0xaa,0xaa,0xaa,0xaa,0xaa,0xaa,0xaa, /* U+c660 - U+c67f */ 0xaa,0xaa,0xaa,0xaa,0xaa,0xaa,0xaa,0xaa, /* U+c680 - U+c69f */ 0xaa,0xaa,0xaa,0xaa,0xaa,0xaa,0xaa,0xaa, /* U+c6a0 - U+c6bf */ 0xaa,0xaa,0xaa,0xaa,0xaa,0xaa,0xaa,0xaa, /* U+c6c0 - U+c6df */ 0xaa,0xaa,0xaa,0xaa,0xaa,0xaa,0xaa,0xaa, /* U+c6e0 - U+c6ff */ 0xaa,0xaa,0xaa,0xaa,0xaa,0xaa,0xaa,0xaa, /* U+c700 - U+c71f */ 0xaa,0xaa,0xaa,0xaa,0xaa,0xaa,0xaa,0xaa, /* U+c720 - U+c73f */ 0xaa,0xaa,0xaa,0xaa,0xaa,0xaa,0xaa,0xaa, /* U+c740 - U+c75f */ 0xaa,0xaa,0xaa,0xaa,0xaa,0xaa,0xaa,0xaa, /* U+c760 - U+c77f */ 0xaa,0xaa,0xaa,0xaa,0xaa,0xaa,0xaa,0xaa, /* U+c780 - U+c79f */ 0xaa,0xaa,0xaa,0xaa,0xaa,0xaa,0xaa,0xaa, /* U+c7a0 - U+c7bf */ 0xaa,0xaa,0xaa,0xaa,0xaa,0xaa,0xaa,0xaa, /* U+c7c0 - U+c7df */ 0xaa,0xaa,0xaa,0xaa,0xaa,0xaa,0xaa,0xaa, /* U+c7e0 - U+c7ff */ 0xaa,0xaa,0xaa,0xaa,0xaa,0xaa,0xaa,0xaa, /* U+c800 - U+c81f */ 0xaa,0xaa,0xaa,0xaa,0xaa,0xaa,0xaa,0xaa, /* U+c820 - U+c83f */ 0xaa,0xaa,0xaa,0xaa,0xaa,0xaa,0xaa,0xaa, /* U+c840 - U+c85f */ 0xaa,0xaa,0xaa,0xaa,0xaa,0xaa,0xaa,0xaa, /* U+c860 - U+c87f */ 0xaa,0xaa,0xaa,0xaa,0xaa,0xaa,0xaa,0xaa, /* U+c880 - U+c89f */ 0xaa,0xaa,0xaa,0xaa,0xaa,0xaa,0xaa,0xaa, /* U+c8a0 - U+c8bf */ 0xaa,0xaa,0xaa,0xaa,0xaa,0xaa,0xaa,0xaa, /* U+c8c0 - U+c8df */ 0xaa,0xaa,0xaa,0xaa,0xaa,0xaa,0xaa,0xaa, /* U+c8e0 - U+c8ff */ 0xaa,0xaa,0xaa,0xaa,0xaa,0xaa,0xaa,0xaa, /* U+c900 - U+c91f */ 0xaa,0xaa,0xaa,0xaa,0xaa,0xaa,0xaa,0xaa, /* U+c920 - U+c93f */ 0xaa,0xaa,0xaa,0xaa,0xaa,0xaa,0xaa,0xaa, /* U+c940 - U+c95f */ 0xaa,0xaa,0xaa,0xaa,0xaa,0xaa,0xaa,0xaa, /* U+c960 - U+c97f */ 0xaa,0xaa,0xaa,0xaa,0xaa,0xaa,0xaa,0xaa, /* U+c980 - U+c99f */ 0xaa,0xaa,0xaa,0xaa,0xaa,0xaa,0xaa,0xaa, /* U+c9a0 - U+c9bf */ 0xaa,0xaa,0xaa,0xaa,0xaa,0xaa,0xaa,0xaa, /* U+c9c0 - U+c9df */ 0xaa,0xaa,0xaa,0xaa,0xaa,0xaa,0xaa,0xaa, /* U+c9e0 - U+c9ff */ 0xaa,0xaa,0xaa,0xaa,0xaa,0xaa,0xaa,0xaa, /* U+ca00 - U+ca1f */ 0xaa,0xaa,0xaa,0xaa,0xaa,0xaa,0xaa,0xaa, /* U+ca20 - U+ca3f */ 0xaa,0xaa,0xaa,0xaa,0xaa,0xaa,0xaa,0xaa, /* U+ca40 - U+ca5f */ 0xaa,0xaa,0xaa,0xaa,0xaa,0xaa,0xaa,0xaa, /* U+ca60 - U+ca7f */ 0xaa,0xaa,0xaa,0xaa,0xaa,0xaa,0xaa,0xaa, /* U+ca80 - U+ca9f */ 0xaa,0xaa,0xaa,0xaa,0xaa,0xaa,0xaa,0xaa, /* U+caa0 - U+cabf */ 0xaa,0xaa,0xaa,0xaa,0xaa,0xaa,0xaa,0xaa, /* U+cac0 - U+cadf */ 0xaa,0xaa,0xaa,0xaa,0xaa,0xaa,0xaa,0xaa, /* U+cae0 - U+caff */ 0xaa,0xaa,0xaa,0xaa,0xaa,0xaa,0xaa,0xaa, /* U+cb00 - U+cb1f */ 0xaa,0xaa,0xaa,0xaa,0xaa,0xaa,0xaa,0xaa, /* U+cb20 - U+cb3f */ 0xaa,0xaa,0xaa,0xaa,0xaa,0xaa,0xaa,0xaa, /* U+cb40 - U+cb5f */ 0xaa,0xaa,0xaa,0xaa,0xaa,0xaa,0xaa,0xaa, /* U+cb60 - U+cb7f */ 0xaa,0xaa,0xaa,0xaa,0xaa,0xaa,0xaa,0xaa, /* U+cb80 - U+cb9f */ 0xaa,0xaa,0xaa,0xaa,0xaa,0xaa,0xaa,0xaa, /* U+cba0 - U+cbbf */ 0xaa,0xaa,0xaa,0xaa,0xaa,0xaa,0xaa,0xaa, /* U+cbc0 - U+cbdf */ 0xaa,0xaa,0xaa,0xaa,0xaa,0xaa,0xaa,0xaa, /* U+cbe0 - U+cbff */ 0xaa,0xaa,0xaa,0xaa,0xaa,0xaa,0xaa,0xaa, /* U+cc00 - U+cc1f */ 0xaa,0xaa,0xaa,0xaa,0xaa,0xaa,0xaa,0xaa, /* U+cc20 - U+cc3f */ 0xaa,0xaa,0xaa,0xaa,0xaa,0xaa,0xaa,0xaa, /* U+cc40 - U+cc5f */ 0xaa,0xaa,0xaa,0xaa,0xaa,0xaa,0xaa,0xaa, /* U+cc60 - U+cc7f */ 0xaa,0xaa,0xaa,0xaa,0xaa,0xaa,0xaa,0xaa, /* U+cc80 - U+cc9f */ 0xaa,0xaa,0xaa,0xaa,0xaa,0xaa,0xaa,0xaa, /* U+cca0 - U+ccbf */ 0xaa,0xaa,0xaa,0xaa,0xaa,0xaa,0xaa,0xaa, /* U+ccc0 - U+ccdf */ 0xaa,0xaa,0xaa,0xaa,0xaa,0xaa,0xaa,0xaa, /* U+cce0 - U+ccff */ 0xaa,0xaa,0xaa,0xaa,0xaa,0xaa,0xaa,0xaa, /* U+cd00 - U+cd1f */ 0xaa,0xaa,0xaa,0xaa,0xaa,0xaa,0xaa,0xaa, /* U+cd20 - U+cd3f */ 0xaa,0xaa,0xaa,0xaa,0xaa,0xaa,0xaa,0xaa, /* U+cd40 - U+cd5f */ 0xaa,0xaa,0xaa,0xaa,0xaa,0xaa,0xaa,0xaa, /* U+cd60 - U+cd7f */ 0xaa,0xaa,0xaa,0xaa,0xaa,0xaa,0xaa,0xaa, /* U+cd80 - U+cd9f */ 0xaa,0xaa,0xaa,0xaa,0xaa,0xaa,0xaa,0xaa, /* U+cda0 - U+cdbf */ 0xaa,0xaa,0xaa,0xaa,0xaa,0xaa,0xaa,0xaa, /* U+cdc0 - U+cddf */ 0xaa,0xaa,0xaa,0xaa,0xaa,0xaa,0xaa,0xaa, /* U+cde0 - U+cdff */ 0xaa,0xaa,0xaa,0xaa,0xaa,0xaa,0xaa,0xaa, /* U+ce00 - U+ce1f */ 0xaa,0xaa,0xaa,0xaa,0xaa,0xaa,0xaa,0xaa, /* U+ce20 - U+ce3f */ 0xaa,0xaa,0xaa,0xaa,0xaa,0xaa,0xaa,0xaa, /* U+ce40 - U+ce5f */ 0xaa,0xaa,0xaa,0xaa,0xaa,0xaa,0xaa,0xaa, /* U+ce60 - U+ce7f */ 0xaa,0xaa,0xaa,0xaa,0xaa,0xaa,0xaa,0xaa, /* U+ce80 - U+ce9f */ 0xaa,0xaa,0xaa,0xaa,0xaa,0xaa,0xaa,0xaa, /* U+cea0 - U+cebf */ 0xaa,0xaa,0xaa,0xaa,0xaa,0xaa,0xaa,0xaa, /* U+cec0 - U+cedf */ 0xaa,0xaa,0xaa,0xaa,0xaa,0xaa,0xaa,0xaa, /* U+cee0 - U+ceff */ 0xaa,0xaa,0xaa,0xaa,0xaa,0xaa,0xaa,0xaa, /* U+cf00 - U+cf1f */ 0xaa,0xaa,0xaa,0xaa,0xaa,0xaa,0xaa,0xaa, /* U+cf20 - U+cf3f */ 0xaa,0xaa,0xaa,0xaa,0xaa,0xaa,0xaa,0xaa, /* U+cf40 - U+cf5f */ 0xaa,0xaa,0xaa,0xaa,0xaa,0xaa,0xaa,0xaa, /* U+cf60 - U+cf7f */ 0xaa,0xaa,0xaa,0xaa,0xaa,0xaa,0xaa,0xaa, /* U+cf80 - U+cf9f */ 0xaa,0xaa,0xaa,0xaa,0xaa,0xaa,0xaa,0xaa, /* U+cfa0 - U+cfbf */ 0xaa,0xaa,0xaa,0xaa,0xaa,0xaa,0xaa,0xaa, /* U+cfc0 - U+cfdf */ 0xaa,0xaa,0xaa,0xaa,0xaa,0xaa,0xaa,0xaa, /* U+cfe0 - U+cfff */ 0xaa,0xaa,0xaa,0xaa,0xaa,0xaa,0xaa,0xaa, /* U+d000 - U+d01f */ 0xaa,0xaa,0xaa,0xaa,0xaa,0xaa,0xaa,0xaa, /* U+d020 - U+d03f */ 0xaa,0xaa,0xaa,0xaa,0xaa,0xaa,0xaa,0xaa, /* U+d040 - U+d05f */ 0xaa,0xaa,0xaa,0xaa,0xaa,0xaa,0xaa,0xaa, /* U+d060 - U+d07f */ 0xaa,0xaa,0xaa,0xaa,0xaa,0xaa,0xaa,0xaa, /* U+d080 - U+d09f */ 0xaa,0xaa,0xaa,0xaa,0xaa,0xaa,0xaa,0xaa, /* U+d0a0 - U+d0bf */ 0xaa,0xaa,0xaa,0xaa,0xaa,0xaa,0xaa,0xaa, /* U+d0c0 - U+d0df */ 0xaa,0xaa,0xaa,0xaa,0xaa,0xaa,0xaa,0xaa, /* U+d0e0 - U+d0ff */ 0xaa,0xaa,0xaa,0xaa,0xaa,0xaa,0xaa,0xaa, /* U+d100 - U+d11f */ 0xaa,0xaa,0xaa,0xaa,0xaa,0xaa,0xaa,0xaa, /* U+d120 - U+d13f */ 0xaa,0xaa,0xaa,0xaa,0xaa,0xaa,0xaa,0xaa, /* U+d140 - U+d15f */ 0xaa,0xaa,0xaa,0xaa,0xaa,0xaa,0xaa,0xaa, /* U+d160 - U+d17f */ 0xaa,0xaa,0xaa,0xaa,0xaa,0xaa,0xaa,0xaa, /* U+d180 - U+d19f */ 0xaa,0xaa,0xaa,0xaa,0xaa,0xaa,0xaa,0xaa, /* U+d1a0 - U+d1bf */ 0xaa,0xaa,0xaa,0xaa,0xaa,0xaa,0xaa,0xaa, /* U+d1c0 - U+d1df */ 0xaa,0xaa,0xaa,0xaa,0xaa,0xaa,0xaa,0xaa, /* U+d1e0 - U+d1ff */ 0xaa,0xaa,0xaa,0xaa,0xaa,0xaa,0xaa,0xaa, /* U+d200 - U+d21f */ 0xaa,0xaa,0xaa,0xaa,0xaa,0xaa,0xaa,0xaa, /* U+d220 - U+d23f */ 0xaa,0xaa,0xaa,0xaa,0xaa,0xaa,0xaa,0xaa, /* U+d240 - U+d25f */ 0xaa,0xaa,0xaa,0xaa,0xaa,0xaa,0xaa,0xaa, /* U+d260 - U+d27f */ 0xaa,0xaa,0xaa,0xaa,0xaa,0xaa,0xaa,0xaa, /* U+d280 - U+d29f */ 0xaa,0xaa,0xaa,0xaa,0xaa,0xaa,0xaa,0xaa, /* U+d2a0 - U+d2bf */ 0xaa,0xaa,0xaa,0xaa,0xaa,0xaa,0xaa,0xaa, /* U+d2c0 - U+d2df */ 0xaa,0xaa,0xaa,0xaa,0xaa,0xaa,0xaa,0xaa, /* U+d2e0 - U+d2ff */ 0xaa,0xaa,0xaa,0xaa,0xaa,0xaa,0xaa,0xaa, /* U+d300 - U+d31f */ 0xaa,0xaa,0xaa,0xaa,0xaa,0xaa,0xaa,0xaa, /* U+d320 - U+d33f */ 0xaa,0xaa,0xaa,0xaa,0xaa,0xaa,0xaa,0xaa, /* U+d340 - U+d35f */ 0xaa,0xaa,0xaa,0xaa,0xaa,0xaa,0xaa,0xaa, /* U+d360 - U+d37f */ 0xaa,0xaa,0xaa,0xaa,0xaa,0xaa,0xaa,0xaa, /* U+d380 - U+d39f */ 0xaa,0xaa,0xaa,0xaa,0xaa,0xaa,0xaa,0xaa, /* U+d3a0 - U+d3bf */ 0xaa,0xaa,0xaa,0xaa,0xaa,0xaa,0xaa,0xaa, /* U+d3c0 - U+d3df */ 0xaa,0xaa,0xaa,0xaa,0xaa,0xaa,0xaa,0xaa, /* U+d3e0 - U+d3ff */ 0xaa,0xaa,0xaa,0xaa,0xaa,0xaa,0xaa,0xaa, /* U+d400 - U+d41f */ 0xaa,0xaa,0xaa,0xaa,0xaa,0xaa,0xaa,0xaa, /* U+d420 - U+d43f */ 0xaa,0xaa,0xaa,0xaa,0xaa,0xaa,0xaa,0xaa, /* U+d440 - U+d45f */ 0xaa,0xaa,0xaa,0xaa,0xaa,0xaa,0xaa,0xaa, /* U+d460 - U+d47f */ 0xaa,0xaa,0xaa,0xaa,0xaa,0xaa,0xaa,0xaa, /* U+d480 - U+d49f */ 0xaa,0xaa,0xaa,0xaa,0xaa,0xaa,0xaa,0xaa, /* U+d4a0 - U+d4bf */ 0xaa,0xaa,0xaa,0xaa,0xaa,0xaa,0xaa,0xaa, /* U+d4c0 - U+d4df */ 0xaa,0xaa,0xaa,0xaa,0xaa,0xaa,0xaa,0xaa, /* U+d4e0 - U+d4ff */ 0xaa,0xaa,0xaa,0xaa,0xaa,0xaa,0xaa,0xaa, /* U+d500 - U+d51f */ 0xaa,0xaa,0xaa,0xaa,0xaa,0xaa,0xaa,0xaa, /* U+d520 - U+d53f */ 0xaa,0xaa,0xaa,0xaa,0xaa,0xaa,0xaa,0xaa, /* U+d540 - U+d55f */ 0xaa,0xaa,0xaa,0xaa,0xaa,0xaa,0xaa,0xaa, /* U+d560 - U+d57f */ 0xaa,0xaa,0xaa,0xaa,0xaa,0xaa,0xaa,0xaa, /* U+d580 - U+d59f */ 0xaa,0xaa,0xaa,0xaa,0xaa,0xaa,0xaa,0xaa, /* U+d5a0 - U+d5bf */ 0xaa,0xaa,0xaa,0xaa,0xaa,0xaa,0xaa,0xaa, /* U+d5c0 - U+d5df */ 0xaa,0xaa,0xaa,0xaa,0xaa,0xaa,0xaa,0xaa, /* U+d5e0 - U+d5ff */ 0xaa,0xaa,0xaa,0xaa,0xaa,0xaa,0xaa,0xaa, /* U+d600 - U+d61f */ 0xaa,0xaa,0xaa,0xaa,0xaa,0xaa,0xaa,0xaa, /* U+d620 - U+d63f */ 0xaa,0xaa,0xaa,0xaa,0xaa,0xaa,0xaa,0xaa, /* U+d640 - U+d65f */ 0xaa,0xaa,0xaa,0xaa,0xaa,0xaa,0xaa,0xaa, /* U+d660 - U+d67f */ 0xaa,0xaa,0xaa,0xaa,0xaa,0xaa,0xaa,0xaa, /* U+d680 - U+d69f */ 0xaa,0xaa,0xaa,0xaa,0xaa,0xaa,0xaa,0xaa, /* U+d6a0 - U+d6bf */ 0xaa,0xaa,0xaa,0xaa,0xaa,0xaa,0xaa,0xaa, /* U+d6c0 - U+d6df */ 0xaa,0xaa,0xaa,0xaa,0xaa,0xaa,0xaa,0xaa, /* U+d6e0 - U+d6ff */ 0xaa,0xaa,0xaa,0xaa,0xaa,0xaa,0xaa,0xaa, /* U+d700 - U+d71f */ 0xaa,0xaa,0xaa,0xaa,0xaa,0xaa,0xaa,0xaa, /* U+d720 - U+d73f */ 0xaa,0xaa,0xaa,0xaa,0xaa,0xaa,0xaa,0xaa, /* U+d740 - U+d75f */ 0xaa,0xaa,0xaa,0xaa,0xaa,0xaa,0xaa,0xaa, /* U+d760 - U+d77f */ 0xaa,0xaa,0xaa,0xaa,0xaa,0xaa,0xaa,0xaa, /* U+d780 - U+d79f */ 0xaa,0xff,0xff,0xff,0xff,0xff,0xff,0xff, /* U+d7a0 - U+d7bf */ 0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff, /* U+d7c0 - U+d7df */ 0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff, /* U+d7e0 - U+d7ff */ 0x3f,0xff,0xff,0xff,0xff,0xff,0xff,0xff, /* U+d800 - U+d81f */ 0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff, /* U+d820 - U+d83f */ 0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff, /* U+d840 - U+d85f */ 0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff, /* U+d860 - U+d87f */ 0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff, /* U+d880 - U+d89f */ 0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff, /* U+d8a0 - U+d8bf */ 0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff, /* U+d8c0 - U+d8df */ 0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff, /* U+d8e0 - U+d8ff */ 0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff, /* U+d900 - U+d91f */ 0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff, /* U+d920 - U+d93f */ 0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff, /* U+d940 - U+d95f */ 0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff, /* U+d960 - U+d97f */ 0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff, /* U+d980 - U+d99f */ 0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff, /* U+d9a0 - U+d9bf */ 0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff, /* U+d9c0 - U+d9df */ 0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff, /* U+d9e0 - U+d9ff */ 0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff, /* U+da00 - U+da1f */ 0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff, /* U+da20 - U+da3f */ 0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff, /* U+da40 - U+da5f */ 0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff, /* U+da60 - U+da7f */ 0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff, /* U+da80 - U+da9f */ 0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff, /* U+daa0 - U+dabf */ 0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff, /* U+dac0 - U+dadf */ 0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff, /* U+dae0 - U+daff */ 0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff, /* U+db00 - U+db1f */ 0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff, /* U+db20 - U+db3f */ 0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff, /* U+db40 - U+db5f */ 0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xfc, /* U+db60 - U+db7f */ 0x3f,0xff,0xff,0xff,0xff,0xff,0xff,0xff, /* U+db80 - U+db9f */ 0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff, /* U+dba0 - U+dbbf */ 0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff, /* U+dbc0 - U+dbdf */ 0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xfc, /* U+dbe0 - U+dbff */ 0x3f,0xff,0xff,0xff,0xff,0xff,0xff,0xff, /* U+dc00 - U+dc1f */ 0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff, /* U+dc20 - U+dc3f */ 0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff, /* U+dc40 - U+dc5f */ 0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff, /* U+dc60 - U+dc7f */ 0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff, /* U+dc80 - U+dc9f */ 0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff, /* U+dca0 - U+dcbf */ 0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff, /* U+dcc0 - U+dcdf */ 0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff, /* U+dce0 - U+dcff */ 0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff, /* U+dd00 - U+dd1f */ 0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff, /* U+dd20 - U+dd3f */ 0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff, /* U+dd40 - U+dd5f */ 0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff, /* U+dd60 - U+dd7f */ 0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff, /* U+dd80 - U+dd9f */ 0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff, /* U+dda0 - U+ddbf */ 0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff, /* U+ddc0 - U+dddf */ 0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff, /* U+dde0 - U+ddff */ 0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff, /* U+de00 - U+de1f */ 0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff, /* U+de20 - U+de3f */ 0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff, /* U+de40 - U+de5f */ 0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff, /* U+de60 - U+de7f */ 0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff, /* U+de80 - U+de9f */ 0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff, /* U+dea0 - U+debf */ 0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff, /* U+dec0 - U+dedf */ 0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff, /* U+dee0 - U+deff */ 0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff, /* U+df00 - U+df1f */ 0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff, /* U+df20 - U+df3f */ 0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff, /* U+df40 - U+df5f */ 0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff, /* U+df60 - U+df7f */ 0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff, /* U+df80 - U+df9f */ 0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff, /* U+dfa0 - U+dfbf */ 0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff, /* U+dfc0 - U+dfdf */ 0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xfc, /* U+dfe0 - U+dfff */ 0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff, /* U+e000 - U+e01f */ 0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff, /* U+e020 - U+e03f */ 0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff, /* U+e040 - U+e05f */ 0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff, /* U+e060 - U+e07f */ 0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff, /* U+e080 - U+e09f */ 0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff, /* U+e0a0 - U+e0bf */ 0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff, /* U+e0c0 - U+e0df */ 0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff, /* U+e0e0 - U+e0ff */ 0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff, /* U+e100 - U+e11f */ 0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff, /* U+e120 - U+e13f */ 0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff, /* U+e140 - U+e15f */ 0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff, /* U+e160 - U+e17f */ 0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff, /* U+e180 - U+e19f */ 0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff, /* U+e1a0 - U+e1bf */ 0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff, /* U+e1c0 - U+e1df */ 0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff, /* U+e1e0 - U+e1ff */ 0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff, /* U+e200 - U+e21f */ 0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff, /* U+e220 - U+e23f */ 0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff, /* U+e240 - U+e25f */ 0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff, /* U+e260 - U+e27f */ 0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff, /* U+e280 - U+e29f */ 0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff, /* U+e2a0 - U+e2bf */ 0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff, /* U+e2c0 - U+e2df */ 0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff, /* U+e2e0 - U+e2ff */ 0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff, /* U+e300 - U+e31f */ 0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff, /* U+e320 - U+e33f */ 0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff, /* U+e340 - U+e35f */ 0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff, /* U+e360 - U+e37f */ 0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff, /* U+e380 - U+e39f */ 0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff, /* U+e3a0 - U+e3bf */ 0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff, /* U+e3c0 - U+e3df */ 0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff, /* U+e3e0 - U+e3ff */ 0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff, /* U+e400 - U+e41f */ 0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff, /* U+e420 - U+e43f */ 0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff, /* U+e440 - U+e45f */ 0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff, /* U+e460 - U+e47f */ 0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff, /* U+e480 - U+e49f */ 0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff, /* U+e4a0 - U+e4bf */ 0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff, /* U+e4c0 - U+e4df */ 0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff, /* U+e4e0 - U+e4ff */ 0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff, /* U+e500 - U+e51f */ 0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff, /* U+e520 - U+e53f */ 0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff, /* U+e540 - U+e55f */ 0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff, /* U+e560 - U+e57f */ 0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff, /* U+e580 - U+e59f */ 0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff, /* U+e5a0 - U+e5bf */ 0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff, /* U+e5c0 - U+e5df */ 0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff, /* U+e5e0 - U+e5ff */ 0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff, /* U+e600 - U+e61f */ 0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff, /* U+e620 - U+e63f */ 0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff, /* U+e640 - U+e65f */ 0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff, /* U+e660 - U+e67f */ 0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff, /* U+e680 - U+e69f */ 0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff, /* U+e6a0 - U+e6bf */ 0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff, /* U+e6c0 - U+e6df */ 0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff, /* U+e6e0 - U+e6ff */ 0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff, /* U+e700 - U+e71f */ 0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff, /* U+e720 - U+e73f */ 0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff, /* U+e740 - U+e75f */ 0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff, /* U+e760 - U+e77f */ 0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff, /* U+e780 - U+e79f */ 0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff, /* U+e7a0 - U+e7bf */ 0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff, /* U+e7c0 - U+e7df */ 0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff, /* U+e7e0 - U+e7ff */ 0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff, /* U+e800 - U+e81f */ 0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff, /* U+e820 - U+e83f */ 0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff, /* U+e840 - U+e85f */ 0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff, /* U+e860 - U+e87f */ 0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff, /* U+e880 - U+e89f */ 0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff, /* U+e8a0 - U+e8bf */ 0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff, /* U+e8c0 - U+e8df */ 0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff, /* U+e8e0 - U+e8ff */ 0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff, /* U+e900 - U+e91f */ 0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff, /* U+e920 - U+e93f */ 0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff, /* U+e940 - U+e95f */ 0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff, /* U+e960 - U+e97f */ 0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff, /* U+e980 - U+e99f */ 0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff, /* U+e9a0 - U+e9bf */ 0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff, /* U+e9c0 - U+e9df */ 0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff, /* U+e9e0 - U+e9ff */ 0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff, /* U+ea00 - U+ea1f */ 0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff, /* U+ea20 - U+ea3f */ 0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff, /* U+ea40 - U+ea5f */ 0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff, /* U+ea60 - U+ea7f */ 0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff, /* U+ea80 - U+ea9f */ 0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff, /* U+eaa0 - U+eabf */ 0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff, /* U+eac0 - U+eadf */ 0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff, /* U+eae0 - U+eaff */ 0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff, /* U+eb00 - U+eb1f */ 0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff, /* U+eb20 - U+eb3f */ 0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff, /* U+eb40 - U+eb5f */ 0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff, /* U+eb60 - U+eb7f */ 0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff, /* U+eb80 - U+eb9f */ 0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff, /* U+eba0 - U+ebbf */ 0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff, /* U+ebc0 - U+ebdf */ 0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff, /* U+ebe0 - U+ebff */ 0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff, /* U+ec00 - U+ec1f */ 0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff, /* U+ec20 - U+ec3f */ 0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff, /* U+ec40 - U+ec5f */ 0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff, /* U+ec60 - U+ec7f */ 0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff, /* U+ec80 - U+ec9f */ 0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff, /* U+eca0 - U+ecbf */ 0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff, /* U+ecc0 - U+ecdf */ 0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff, /* U+ece0 - U+ecff */ 0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff, /* U+ed00 - U+ed1f */ 0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff, /* U+ed20 - U+ed3f */ 0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff, /* U+ed40 - U+ed5f */ 0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff, /* U+ed60 - U+ed7f */ 0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff, /* U+ed80 - U+ed9f */ 0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff, /* U+eda0 - U+edbf */ 0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff, /* U+edc0 - U+eddf */ 0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff, /* U+ede0 - U+edff */ 0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff, /* U+ee00 - U+ee1f */ 0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff, /* U+ee20 - U+ee3f */ 0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff, /* U+ee40 - U+ee5f */ 0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff, /* U+ee60 - U+ee7f */ 0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff, /* U+ee80 - U+ee9f */ 0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff, /* U+eea0 - U+eebf */ 0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff, /* U+eec0 - U+eedf */ 0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff, /* U+eee0 - U+eeff */ 0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff, /* U+ef00 - U+ef1f */ 0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff, /* U+ef20 - U+ef3f */ 0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff, /* U+ef40 - U+ef5f */ 0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff, /* U+ef60 - U+ef7f */ 0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff, /* U+ef80 - U+ef9f */ 0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff, /* U+efa0 - U+efbf */ 0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff, /* U+efc0 - U+efdf */ 0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff, /* U+efe0 - U+efff */ 0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff, /* U+f000 - U+f01f */ 0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff, /* U+f020 - U+f03f */ 0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff, /* U+f040 - U+f05f */ 0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff, /* U+f060 - U+f07f */ 0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff, /* U+f080 - U+f09f */ 0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff, /* U+f0a0 - U+f0bf */ 0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff, /* U+f0c0 - U+f0df */ 0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff, /* U+f0e0 - U+f0ff */ 0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff, /* U+f100 - U+f11f */ 0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff, /* U+f120 - U+f13f */ 0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff, /* U+f140 - U+f15f */ 0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff, /* U+f160 - U+f17f */ 0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff, /* U+f180 - U+f19f */ 0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff, /* U+f1a0 - U+f1bf */ 0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff, /* U+f1c0 - U+f1df */ 0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff, /* U+f1e0 - U+f1ff */ 0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff, /* U+f200 - U+f21f */ 0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff, /* U+f220 - U+f23f */ 0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff, /* U+f240 - U+f25f */ 0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff, /* U+f260 - U+f27f */ 0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff, /* U+f280 - U+f29f */ 0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff, /* U+f2a0 - U+f2bf */ 0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff, /* U+f2c0 - U+f2df */ 0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff, /* U+f2e0 - U+f2ff */ 0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff, /* U+f300 - U+f31f */ 0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff, /* U+f320 - U+f33f */ 0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff, /* U+f340 - U+f35f */ 0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff, /* U+f360 - U+f37f */ 0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff, /* U+f380 - U+f39f */ 0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff, /* U+f3a0 - U+f3bf */ 0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff, /* U+f3c0 - U+f3df */ 0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff, /* U+f3e0 - U+f3ff */ 0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff, /* U+f400 - U+f41f */ 0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff, /* U+f420 - U+f43f */ 0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff, /* U+f440 - U+f45f */ 0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff, /* U+f460 - U+f47f */ 0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff, /* U+f480 - U+f49f */ 0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff, /* U+f4a0 - U+f4bf */ 0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff, /* U+f4c0 - U+f4df */ 0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff, /* U+f4e0 - U+f4ff */ 0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff, /* U+f500 - U+f51f */ 0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff, /* U+f520 - U+f53f */ 0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff, /* U+f540 - U+f55f */ 0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff, /* U+f560 - U+f57f */ 0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff, /* U+f580 - U+f59f */ 0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff, /* U+f5a0 - U+f5bf */ 0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff, /* U+f5c0 - U+f5df */ 0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff, /* U+f5e0 - U+f5ff */ 0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff, /* U+f600 - U+f61f */ 0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff, /* U+f620 - U+f63f */ 0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff, /* U+f640 - U+f65f */ 0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff, /* U+f660 - U+f67f */ 0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff, /* U+f680 - U+f69f */ 0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff, /* U+f6a0 - U+f6bf */ 0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff, /* U+f6c0 - U+f6df */ 0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff, /* U+f6e0 - U+f6ff */ 0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff, /* U+f700 - U+f71f */ 0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff, /* U+f720 - U+f73f */ 0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff, /* U+f740 - U+f75f */ 0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff, /* U+f760 - U+f77f */ 0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff, /* U+f780 - U+f79f */ 0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff, /* U+f7a0 - U+f7bf */ 0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff, /* U+f7c0 - U+f7df */ 0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff, /* U+f7e0 - U+f7ff */ 0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff, /* U+f800 - U+f81f */ 0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff, /* U+f820 - U+f83f */ 0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff, /* U+f840 - U+f85f */ 0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff, /* U+f860 - U+f87f */ 0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff, /* U+f880 - U+f89f */ 0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff, /* U+f8a0 - U+f8bf */ 0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff, /* U+f8c0 - U+f8df */ 0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff, /* U+f8e0 - U+f8ff */ 0xaa,0xaa,0xaa,0xaa,0xaa,0xaa,0xaa,0xaa, /* U+f900 - U+f91f */ 0xaa,0xaa,0xaa,0xaa,0xaa,0xaa,0xaa,0xaa, /* U+f920 - U+f93f */ 0xaa,0xaa,0xaa,0xaa,0xaa,0xaa,0xaa,0xaa, /* U+f940 - U+f95f */ 0xaa,0xaa,0xaa,0xaa,0xaa,0xaa,0xaa,0xaa, /* U+f960 - U+f97f */ 0xaa,0xaa,0xaa,0xaa,0xaa,0xaa,0xaa,0xaa, /* U+f980 - U+f99f */ 0xaa,0xaa,0xaa,0xaa,0xaa,0xaa,0xaa,0xaa, /* U+f9a0 - U+f9bf */ 0xaa,0xaa,0xaa,0xaa,0xaa,0xaa,0xaa,0xaa, /* U+f9c0 - U+f9df */ 0xaa,0xaa,0xaa,0xaa,0xaa,0xaa,0xaa,0xaa, /* U+f9e0 - U+f9ff */ 0xaa,0xaa,0xaa,0xaa,0xaa,0xaa,0xaa,0xaa, /* U+fa00 - U+fa1f */ 0xaa,0xaa,0xaa,0xaf,0xaa,0xaa,0xaa,0xaa, /* U+fa20 - U+fa3f */ 0xaa,0xaa,0xaa,0xaa,0xaa,0xaa,0xaa,0xaa, /* U+fa40 - U+fa5f */ 0xaa,0xaa,0xab,0xff,0xaa,0xaa,0xaa,0xaa, /* U+fa60 - U+fa7f */ 0xaa,0xaa,0xaa,0xaa,0xaa,0xaa,0xaa,0xaa, /* U+fa80 - U+fa9f */ 0xaa,0xaa,0xaa,0xaa,0xaa,0xaa,0xaa,0xaa, /* U+faa0 - U+fabf */ 0xaa,0xaa,0xaa,0xaa,0xaa,0xaa,0xaf,0xff, /* U+fac0 - U+fadf */ 0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff, /* U+fae0 - U+faff */ 0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xf3, /* U+fb00 - U+fb1f */ 0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff, /* U+fb20 - U+fb3f */ 0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff, /* U+fb40 - U+fb5f */ 0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff, /* U+fb60 - U+fb7f */ 0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff, /* U+fb80 - U+fb9f */ 0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff, /* U+fba0 - U+fbbf */ 0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff, /* U+fbc0 - U+fbdf */ 0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff, /* U+fbe0 - U+fbff */ 0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff, /* U+fc00 - U+fc1f */ 0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff, /* U+fc20 - U+fc3f */ 0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff, /* U+fc40 - U+fc5f */ 0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff, /* U+fc60 - U+fc7f */ 0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff, /* U+fc80 - U+fc9f */ 0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff, /* U+fca0 - U+fcbf */ 0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff, /* U+fcc0 - U+fcdf */ 0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff, /* U+fce0 - U+fcff */ 0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff, /* U+fd00 - U+fd1f */ 0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff, /* U+fd20 - U+fd3f */ 0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff, /* U+fd40 - U+fd5f */ 0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff, /* U+fd60 - U+fd7f */ 0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff, /* U+fd80 - U+fd9f */ 0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff, /* U+fda0 - U+fdbf */ 0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff, /* U+fdc0 - U+fddf */ 0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff, /* U+fde0 - U+fdff */ 0x00,0x00,0x00,0x00,0xaa,0xaa,0xaf,0xff, /* U+fe00 - U+fe1f */ 0x00,0xff,0xff,0xff,0xaa,0xaa,0xaa,0xaa, /* U+fe20 - U+fe3f */ 0xaa,0xaa,0xaa,0xaa,0xab,0xaa,0xaa,0xaa, /* U+fe40 - U+fe5f */ 0xaa,0xab,0xaa,0xff,0xff,0xff,0xff,0xff, /* U+fe60 - U+fe7f */ 0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff, /* U+fe80 - U+fe9f */ 0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff, /* U+fea0 - U+febf */ 0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff, /* U+fec0 - U+fedf */ 0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xfc, /* U+fee0 - U+feff */ 0xea,0xaa,0xaa,0xaa,0xaa,0xaa,0xaa,0xaa, /* U+ff00 - U+ff1f */ 0xaa,0xaa,0xaa,0xaa,0xaa,0xaa,0xaa,0xaa, /* U+ff20 - U+ff3f */ 0xaa,0xaa,0xaa,0xaa,0xaa,0xaa,0xaa,0xaa, /* U+ff40 - U+ff5f */ 0x95,0x55,0x55,0x55,0x55,0x55,0x55,0x55, /* U+ff60 - U+ff7f */ 0x55,0x55,0x55,0x55,0x55,0x55,0x55,0x55, /* U+ff80 - U+ff9f */ 0x55,0x55,0x55,0x55,0x55,0x55,0x55,0x57, /* U+ffa0 - U+ffbf */ 0xf5,0x55,0xf5,0x55,0xf5,0x55,0xf5,0x7f, /* U+ffc0 - U+ffdf */ 0xaa,0xab,0x55,0x57,0xff,0xff,0xc0,0xff, /* U+ffe0 - U+ffff */ 0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff, /* U+10000 - U+1001f */ 0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff, /* U+10020 - U+1003f */ 0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff, /* U+10040 - U+1005f */ 0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff, /* U+10060 - U+1007f */ 0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff, /* U+10080 - U+1009f */ 0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff, /* U+100a0 - U+100bf */ 0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff, /* U+100c0 - U+100df */ 0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff, /* U+100e0 - U+100ff */ 0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff, /* U+10100 - U+1011f */ 0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff, /* U+10120 - U+1013f */ 0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff, /* U+10140 - U+1015f */ 0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff, /* U+10160 - U+1017f */ 0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff, /* U+10180 - U+1019f */ 0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff, /* U+101a0 - U+101bf */ 0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff, /* U+101c0 - U+101df */ 0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff, /* U+101e0 - U+101ff */ 0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff, /* U+10200 - U+1021f */ 0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff, /* U+10220 - U+1023f */ 0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff, /* U+10240 - U+1025f */ 0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff, /* U+10260 - U+1027f */ 0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff, /* U+10280 - U+1029f */ 0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff, /* U+102a0 - U+102bf */ 0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff, /* U+102c0 - U+102df */ 0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff, /* U+102e0 - U+102ff */ 0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff, /* U+10300 - U+1031f */ 0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff, /* U+10320 - U+1033f */ 0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff, /* U+10340 - U+1035f */ 0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff, /* U+10360 - U+1037f */ 0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff, /* U+10380 - U+1039f */ 0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff, /* U+103a0 - U+103bf */ 0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff, /* U+103c0 - U+103df */ 0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff, /* U+103e0 - U+103ff */ 0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff, /* U+10400 - U+1041f */ 0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff, /* U+10420 - U+1043f */ 0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff, /* U+10440 - U+1045f */ 0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff, /* U+10460 - U+1047f */ 0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff, /* U+10480 - U+1049f */ 0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff, /* U+104a0 - U+104bf */ 0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff, /* U+104c0 - U+104df */ 0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff, /* U+104e0 - U+104ff */ 0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff, /* U+10500 - U+1051f */ 0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff, /* U+10520 - U+1053f */ 0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff, /* U+10540 - U+1055f */ 0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff, /* U+10560 - U+1057f */ 0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff, /* U+10580 - U+1059f */ 0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff, /* U+105a0 - U+105bf */ 0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff, /* U+105c0 - U+105df */ 0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff, /* U+105e0 - U+105ff */ 0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff, /* U+10600 - U+1061f */ 0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff, /* U+10620 - U+1063f */ 0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff, /* U+10640 - U+1065f */ 0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff, /* U+10660 - U+1067f */ 0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff, /* U+10680 - U+1069f */ 0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff, /* U+106a0 - U+106bf */ 0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff, /* U+106c0 - U+106df */ 0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff, /* U+106e0 - U+106ff */ 0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff, /* U+10700 - U+1071f */ 0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff, /* U+10720 - U+1073f */ 0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff, /* U+10740 - U+1075f */ 0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff, /* U+10760 - U+1077f */ 0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff, /* U+10780 - U+1079f */ 0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff, /* U+107a0 - U+107bf */ 0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff, /* U+107c0 - U+107df */ 0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff, /* U+107e0 - U+107ff */ 0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff, /* U+10800 - U+1081f */ 0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff, /* U+10820 - U+1083f */ 0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff, /* U+10840 - U+1085f */ 0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff, /* U+10860 - U+1087f */ 0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff, /* U+10880 - U+1089f */ 0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff, /* U+108a0 - U+108bf */ 0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff, /* U+108c0 - U+108df */ 0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff, /* U+108e0 - U+108ff */ 0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff, /* U+10900 - U+1091f */ 0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff, /* U+10920 - U+1093f */ 0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff, /* U+10940 - U+1095f */ 0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff, /* U+10960 - U+1097f */ 0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff, /* U+10980 - U+1099f */ 0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff, /* U+109a0 - U+109bf */ 0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff, /* U+109c0 - U+109df */ 0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff, /* U+109e0 - U+109ff */ 0xc0,0xc3,0xff,0x00,0xff,0xff,0xff,0xff, /* U+10a00 - U+10a1f */ 0xff,0xff,0xff,0xff,0xff,0xff,0x03,0xfc, /* U+10a20 - U+10a3f */ 0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff, /* U+10a40 - U+10a5f */ 0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff, /* U+10a60 - U+10a7f */ 0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff, /* U+10a80 - U+10a9f */ 0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff, /* U+10aa0 - U+10abf */ 0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff, /* U+10ac0 - U+10adf */ 0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff, /* U+10ae0 - U+10aff */ 0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff, /* U+10b00 - U+10b1f */ 0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff, /* U+10b20 - U+10b3f */ 0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff, /* U+10b40 - U+10b5f */ 0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff, /* U+10b60 - U+10b7f */ 0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff, /* U+10b80 - U+10b9f */ 0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff, /* U+10ba0 - U+10bbf */ 0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff, /* U+10bc0 - U+10bdf */ 0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff, /* U+10be0 - U+10bff */ 0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff, /* U+10c00 - U+10c1f */ 0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff, /* U+10c20 - U+10c3f */ 0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff, /* U+10c40 - U+10c5f */ 0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff, /* U+10c60 - U+10c7f */ 0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff, /* U+10c80 - U+10c9f */ 0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff, /* U+10ca0 - U+10cbf */ 0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff, /* U+10cc0 - U+10cdf */ 0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff, /* U+10ce0 - U+10cff */ 0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff, /* U+10d00 - U+10d1f */ 0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff, /* U+10d20 - U+10d3f */ 0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff, /* U+10d40 - U+10d5f */ 0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff, /* U+10d60 - U+10d7f */ 0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff, /* U+10d80 - U+10d9f */ 0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff, /* U+10da0 - U+10dbf */ 0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff, /* U+10dc0 - U+10ddf */ 0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff, /* U+10de0 - U+10dff */ 0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff, /* U+10e00 - U+10e1f */ 0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff, /* U+10e20 - U+10e3f */ 0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff, /* U+10e40 - U+10e5f */ 0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff, /* U+10e60 - U+10e7f */ 0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff, /* U+10e80 - U+10e9f */ 0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff, /* U+10ea0 - U+10ebf */ 0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff, /* U+10ec0 - U+10edf */ 0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff, /* U+10ee0 - U+10eff */ 0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff, /* U+10f00 - U+10f1f */ 0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff, /* U+10f20 - U+10f3f */ 0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff, /* U+10f40 - U+10f5f */ 0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff, /* U+10f60 - U+10f7f */ 0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff, /* U+10f80 - U+10f9f */ 0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff, /* U+10fa0 - U+10fbf */ 0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff, /* U+10fc0 - U+10fdf */ 0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff, /* U+10fe0 - U+10fff */ 0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff, /* U+11000 - U+1101f */ 0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff, /* U+11020 - U+1103f */ 0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff, /* U+11040 - U+1105f */ 0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff, /* U+11060 - U+1107f */ 0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff, /* U+11080 - U+1109f */ 0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff, /* U+110a0 - U+110bf */ 0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff, /* U+110c0 - U+110df */ 0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff, /* U+110e0 - U+110ff */ 0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff, /* U+11100 - U+1111f */ 0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff, /* U+11120 - U+1113f */ 0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff, /* U+11140 - U+1115f */ 0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff, /* U+11160 - U+1117f */ 0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff, /* U+11180 - U+1119f */ 0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff, /* U+111a0 - U+111bf */ 0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff, /* U+111c0 - U+111df */ 0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff, /* U+111e0 - U+111ff */ 0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff, /* U+11200 - U+1121f */ 0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff, /* U+11220 - U+1123f */ 0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff, /* U+11240 - U+1125f */ 0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff, /* U+11260 - U+1127f */ 0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff, /* U+11280 - U+1129f */ 0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff, /* U+112a0 - U+112bf */ 0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff, /* U+112c0 - U+112df */ 0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff, /* U+112e0 - U+112ff */ 0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff, /* U+11300 - U+1131f */ 0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff, /* U+11320 - U+1133f */ 0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff, /* U+11340 - U+1135f */ 0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff, /* U+11360 - U+1137f */ 0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff, /* U+11380 - U+1139f */ 0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff, /* U+113a0 - U+113bf */ 0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff, /* U+113c0 - U+113df */ 0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff, /* U+113e0 - U+113ff */ 0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff, /* U+11400 - U+1141f */ 0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff, /* U+11420 - U+1143f */ 0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff, /* U+11440 - U+1145f */ 0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff, /* U+11460 - U+1147f */ 0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff, /* U+11480 - U+1149f */ 0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff, /* U+114a0 - U+114bf */ 0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff, /* U+114c0 - U+114df */ 0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff, /* U+114e0 - U+114ff */ 0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff, /* U+11500 - U+1151f */ 0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff, /* U+11520 - U+1153f */ 0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff, /* U+11540 - U+1155f */ 0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff, /* U+11560 - U+1157f */ 0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff, /* U+11580 - U+1159f */ 0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff, /* U+115a0 - U+115bf */ 0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff, /* U+115c0 - U+115df */ 0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff, /* U+115e0 - U+115ff */ 0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff, /* U+11600 - U+1161f */ 0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff, /* U+11620 - U+1163f */ 0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff, /* U+11640 - U+1165f */ 0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff, /* U+11660 - U+1167f */ 0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff, /* U+11680 - U+1169f */ 0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff, /* U+116a0 - U+116bf */ 0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff, /* U+116c0 - U+116df */ 0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff, /* U+116e0 - U+116ff */ 0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff, /* U+11700 - U+1171f */ 0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff, /* U+11720 - U+1173f */ 0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff, /* U+11740 - U+1175f */ 0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff, /* U+11760 - U+1177f */ 0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff, /* U+11780 - U+1179f */ 0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff, /* U+117a0 - U+117bf */ 0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff, /* U+117c0 - U+117df */ 0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff, /* U+117e0 - U+117ff */ 0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff, /* U+11800 - U+1181f */ 0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff, /* U+11820 - U+1183f */ 0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff, /* U+11840 - U+1185f */ 0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff, /* U+11860 - U+1187f */ 0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff, /* U+11880 - U+1189f */ 0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff, /* U+118a0 - U+118bf */ 0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff, /* U+118c0 - U+118df */ 0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff, /* U+118e0 - U+118ff */ 0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff, /* U+11900 - U+1191f */ 0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff, /* U+11920 - U+1193f */ 0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff, /* U+11940 - U+1195f */ 0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff, /* U+11960 - U+1197f */ 0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff, /* U+11980 - U+1199f */ 0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff, /* U+119a0 - U+119bf */ 0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff, /* U+119c0 - U+119df */ 0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff, /* U+119e0 - U+119ff */ 0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff, /* U+11a00 - U+11a1f */ 0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff, /* U+11a20 - U+11a3f */ 0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff, /* U+11a40 - U+11a5f */ 0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff, /* U+11a60 - U+11a7f */ 0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff, /* U+11a80 - U+11a9f */ 0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff, /* U+11aa0 - U+11abf */ 0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff, /* U+11ac0 - U+11adf */ 0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff, /* U+11ae0 - U+11aff */ 0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff, /* U+11b00 - U+11b1f */ 0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff, /* U+11b20 - U+11b3f */ 0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff, /* U+11b40 - U+11b5f */ 0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff, /* U+11b60 - U+11b7f */ 0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff, /* U+11b80 - U+11b9f */ 0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff, /* U+11ba0 - U+11bbf */ 0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff, /* U+11bc0 - U+11bdf */ 0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff, /* U+11be0 - U+11bff */ 0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff, /* U+11c00 - U+11c1f */ 0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff, /* U+11c20 - U+11c3f */ 0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff, /* U+11c40 - U+11c5f */ 0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff, /* U+11c60 - U+11c7f */ 0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff, /* U+11c80 - U+11c9f */ 0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff, /* U+11ca0 - U+11cbf */ 0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff, /* U+11cc0 - U+11cdf */ 0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff, /* U+11ce0 - U+11cff */ 0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff, /* U+11d00 - U+11d1f */ 0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff, /* U+11d20 - U+11d3f */ 0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff, /* U+11d40 - U+11d5f */ 0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff, /* U+11d60 - U+11d7f */ 0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff, /* U+11d80 - U+11d9f */ 0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff, /* U+11da0 - U+11dbf */ 0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff, /* U+11dc0 - U+11ddf */ 0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff, /* U+11de0 - U+11dff */ 0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff, /* U+11e00 - U+11e1f */ 0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff, /* U+11e20 - U+11e3f */ 0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff, /* U+11e40 - U+11e5f */ 0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff, /* U+11e60 - U+11e7f */ 0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff, /* U+11e80 - U+11e9f */ 0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff, /* U+11ea0 - U+11ebf */ 0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff, /* U+11ec0 - U+11edf */ 0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff, /* U+11ee0 - U+11eff */ 0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff, /* U+11f00 - U+11f1f */ 0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff, /* U+11f20 - U+11f3f */ 0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff, /* U+11f40 - U+11f5f */ 0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff, /* U+11f60 - U+11f7f */ 0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff, /* U+11f80 - U+11f9f */ 0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff, /* U+11fa0 - U+11fbf */ 0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff, /* U+11fc0 - U+11fdf */ 0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff, /* U+11fe0 - U+11fff */ 0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff, /* U+12000 - U+1201f */ 0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff, /* U+12020 - U+1203f */ 0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff, /* U+12040 - U+1205f */ 0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff, /* U+12060 - U+1207f */ 0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff, /* U+12080 - U+1209f */ 0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff, /* U+120a0 - U+120bf */ 0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff, /* U+120c0 - U+120df */ 0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff, /* U+120e0 - U+120ff */ 0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff, /* U+12100 - U+1211f */ 0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff, /* U+12120 - U+1213f */ 0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff, /* U+12140 - U+1215f */ 0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff, /* U+12160 - U+1217f */ 0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff, /* U+12180 - U+1219f */ 0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff, /* U+121a0 - U+121bf */ 0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff, /* U+121c0 - U+121df */ 0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff, /* U+121e0 - U+121ff */ 0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff, /* U+12200 - U+1221f */ 0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff, /* U+12220 - U+1223f */ 0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff, /* U+12240 - U+1225f */ 0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff, /* U+12260 - U+1227f */ 0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff, /* U+12280 - U+1229f */ 0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff, /* U+122a0 - U+122bf */ 0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff, /* U+122c0 - U+122df */ 0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff, /* U+122e0 - U+122ff */ 0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff, /* U+12300 - U+1231f */ 0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff, /* U+12320 - U+1233f */ 0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff, /* U+12340 - U+1235f */ 0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff, /* U+12360 - U+1237f */ 0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff, /* U+12380 - U+1239f */ 0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff, /* U+123a0 - U+123bf */ 0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff, /* U+123c0 - U+123df */ 0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff, /* U+123e0 - U+123ff */ 0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff, /* U+12400 - U+1241f */ 0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff, /* U+12420 - U+1243f */ 0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff, /* U+12440 - U+1245f */ 0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff, /* U+12460 - U+1247f */ 0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff, /* U+12480 - U+1249f */ 0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff, /* U+124a0 - U+124bf */ 0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff, /* U+124c0 - U+124df */ 0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff, /* U+124e0 - U+124ff */ 0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff, /* U+12500 - U+1251f */ 0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff, /* U+12520 - U+1253f */ 0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff, /* U+12540 - U+1255f */ 0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff, /* U+12560 - U+1257f */ 0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff, /* U+12580 - U+1259f */ 0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff, /* U+125a0 - U+125bf */ 0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff, /* U+125c0 - U+125df */ 0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff, /* U+125e0 - U+125ff */ 0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff, /* U+12600 - U+1261f */ 0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff, /* U+12620 - U+1263f */ 0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff, /* U+12640 - U+1265f */ 0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff, /* U+12660 - U+1267f */ 0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff, /* U+12680 - U+1269f */ 0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff, /* U+126a0 - U+126bf */ 0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff, /* U+126c0 - U+126df */ 0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff, /* U+126e0 - U+126ff */ 0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff, /* U+12700 - U+1271f */ 0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff, /* U+12720 - U+1273f */ 0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff, /* U+12740 - U+1275f */ 0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff, /* U+12760 - U+1277f */ 0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff, /* U+12780 - U+1279f */ 0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff, /* U+127a0 - U+127bf */ 0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff, /* U+127c0 - U+127df */ 0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff, /* U+127e0 - U+127ff */ 0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff, /* U+12800 - U+1281f */ 0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff, /* U+12820 - U+1283f */ 0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff, /* U+12840 - U+1285f */ 0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff, /* U+12860 - U+1287f */ 0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff, /* U+12880 - U+1289f */ 0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff, /* U+128a0 - U+128bf */ 0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff, /* U+128c0 - U+128df */ 0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff, /* U+128e0 - U+128ff */ 0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff, /* U+12900 - U+1291f */ 0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff, /* U+12920 - U+1293f */ 0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff, /* U+12940 - U+1295f */ 0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff, /* U+12960 - U+1297f */ 0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff, /* U+12980 - U+1299f */ 0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff, /* U+129a0 - U+129bf */ 0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff, /* U+129c0 - U+129df */ 0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff, /* U+129e0 - U+129ff */ 0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff, /* U+12a00 - U+12a1f */ 0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff, /* U+12a20 - U+12a3f */ 0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff, /* U+12a40 - U+12a5f */ 0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff, /* U+12a60 - U+12a7f */ 0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff, /* U+12a80 - U+12a9f */ 0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff, /* U+12aa0 - U+12abf */ 0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff, /* U+12ac0 - U+12adf */ 0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff, /* U+12ae0 - U+12aff */ 0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff, /* U+12b00 - U+12b1f */ 0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff, /* U+12b20 - U+12b3f */ 0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff, /* U+12b40 - U+12b5f */ 0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff, /* U+12b60 - U+12b7f */ 0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff, /* U+12b80 - U+12b9f */ 0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff, /* U+12ba0 - U+12bbf */ 0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff, /* U+12bc0 - U+12bdf */ 0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff, /* U+12be0 - U+12bff */ 0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff, /* U+12c00 - U+12c1f */ 0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff, /* U+12c20 - U+12c3f */ 0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff, /* U+12c40 - U+12c5f */ 0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff, /* U+12c60 - U+12c7f */ 0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff, /* U+12c80 - U+12c9f */ 0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff, /* U+12ca0 - U+12cbf */ 0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff, /* U+12cc0 - U+12cdf */ 0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff, /* U+12ce0 - U+12cff */ 0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff, /* U+12d00 - U+12d1f */ 0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff, /* U+12d20 - U+12d3f */ 0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff, /* U+12d40 - U+12d5f */ 0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff, /* U+12d60 - U+12d7f */ 0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff, /* U+12d80 - U+12d9f */ 0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff, /* U+12da0 - U+12dbf */ 0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff, /* U+12dc0 - U+12ddf */ 0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff, /* U+12de0 - U+12dff */ 0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff, /* U+12e00 - U+12e1f */ 0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff, /* U+12e20 - U+12e3f */ 0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff, /* U+12e40 - U+12e5f */ 0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff, /* U+12e60 - U+12e7f */ 0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff, /* U+12e80 - U+12e9f */ 0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff, /* U+12ea0 - U+12ebf */ 0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff, /* U+12ec0 - U+12edf */ 0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff, /* U+12ee0 - U+12eff */ 0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff, /* U+12f00 - U+12f1f */ 0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff, /* U+12f20 - U+12f3f */ 0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff, /* U+12f40 - U+12f5f */ 0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff, /* U+12f60 - U+12f7f */ 0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff, /* U+12f80 - U+12f9f */ 0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff, /* U+12fa0 - U+12fbf */ 0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff, /* U+12fc0 - U+12fdf */ 0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff, /* U+12fe0 - U+12fff */ 0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff, /* U+13000 - U+1301f */ 0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff, /* U+13020 - U+1303f */ 0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff, /* U+13040 - U+1305f */ 0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff, /* U+13060 - U+1307f */ 0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff, /* U+13080 - U+1309f */ 0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff, /* U+130a0 - U+130bf */ 0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff, /* U+130c0 - U+130df */ 0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff, /* U+130e0 - U+130ff */ 0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff, /* U+13100 - U+1311f */ 0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff, /* U+13120 - U+1313f */ 0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff, /* U+13140 - U+1315f */ 0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff, /* U+13160 - U+1317f */ 0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff, /* U+13180 - U+1319f */ 0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff, /* U+131a0 - U+131bf */ 0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff, /* U+131c0 - U+131df */ 0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff, /* U+131e0 - U+131ff */ 0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff, /* U+13200 - U+1321f */ 0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff, /* U+13220 - U+1323f */ 0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff, /* U+13240 - U+1325f */ 0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff, /* U+13260 - U+1327f */ 0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff, /* U+13280 - U+1329f */ 0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff, /* U+132a0 - U+132bf */ 0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff, /* U+132c0 - U+132df */ 0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff, /* U+132e0 - U+132ff */ 0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff, /* U+13300 - U+1331f */ 0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff, /* U+13320 - U+1333f */ 0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff, /* U+13340 - U+1335f */ 0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff, /* U+13360 - U+1337f */ 0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff, /* U+13380 - U+1339f */ 0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff, /* U+133a0 - U+133bf */ 0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff, /* U+133c0 - U+133df */ 0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff, /* U+133e0 - U+133ff */ 0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff, /* U+13400 - U+1341f */ 0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff, /* U+13420 - U+1343f */ 0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff, /* U+13440 - U+1345f */ 0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff, /* U+13460 - U+1347f */ 0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff, /* U+13480 - U+1349f */ 0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff, /* U+134a0 - U+134bf */ 0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff, /* U+134c0 - U+134df */ 0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff, /* U+134e0 - U+134ff */ 0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff, /* U+13500 - U+1351f */ 0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff, /* U+13520 - U+1353f */ 0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff, /* U+13540 - U+1355f */ 0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff, /* U+13560 - U+1357f */ 0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff, /* U+13580 - U+1359f */ 0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff, /* U+135a0 - U+135bf */ 0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff, /* U+135c0 - U+135df */ 0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff, /* U+135e0 - U+135ff */ 0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff, /* U+13600 - U+1361f */ 0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff, /* U+13620 - U+1363f */ 0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff, /* U+13640 - U+1365f */ 0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff, /* U+13660 - U+1367f */ 0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff, /* U+13680 - U+1369f */ 0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff, /* U+136a0 - U+136bf */ 0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff, /* U+136c0 - U+136df */ 0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff, /* U+136e0 - U+136ff */ 0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff, /* U+13700 - U+1371f */ 0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff, /* U+13720 - U+1373f */ 0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff, /* U+13740 - U+1375f */ 0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff, /* U+13760 - U+1377f */ 0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff, /* U+13780 - U+1379f */ 0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff, /* U+137a0 - U+137bf */ 0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff, /* U+137c0 - U+137df */ 0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff, /* U+137e0 - U+137ff */ 0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff, /* U+13800 - U+1381f */ 0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff, /* U+13820 - U+1383f */ 0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff, /* U+13840 - U+1385f */ 0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff, /* U+13860 - U+1387f */ 0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff, /* U+13880 - U+1389f */ 0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff, /* U+138a0 - U+138bf */ 0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff, /* U+138c0 - U+138df */ 0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff, /* U+138e0 - U+138ff */ 0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff, /* U+13900 - U+1391f */ 0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff, /* U+13920 - U+1393f */ 0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff, /* U+13940 - U+1395f */ 0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff, /* U+13960 - U+1397f */ 0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff, /* U+13980 - U+1399f */ 0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff, /* U+139a0 - U+139bf */ 0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff, /* U+139c0 - U+139df */ 0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff, /* U+139e0 - U+139ff */ 0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff, /* U+13a00 - U+13a1f */ 0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff, /* U+13a20 - U+13a3f */ 0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff, /* U+13a40 - U+13a5f */ 0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff, /* U+13a60 - U+13a7f */ 0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff, /* U+13a80 - U+13a9f */ 0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff, /* U+13aa0 - U+13abf */ 0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff, /* U+13ac0 - U+13adf */ 0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff, /* U+13ae0 - U+13aff */ 0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff, /* U+13b00 - U+13b1f */ 0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff, /* U+13b20 - U+13b3f */ 0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff, /* U+13b40 - U+13b5f */ 0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff, /* U+13b60 - U+13b7f */ 0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff, /* U+13b80 - U+13b9f */ 0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff, /* U+13ba0 - U+13bbf */ 0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff, /* U+13bc0 - U+13bdf */ 0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff, /* U+13be0 - U+13bff */ 0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff, /* U+13c00 - U+13c1f */ 0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff, /* U+13c20 - U+13c3f */ 0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff, /* U+13c40 - U+13c5f */ 0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff, /* U+13c60 - U+13c7f */ 0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff, /* U+13c80 - U+13c9f */ 0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff, /* U+13ca0 - U+13cbf */ 0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff, /* U+13cc0 - U+13cdf */ 0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff, /* U+13ce0 - U+13cff */ 0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff, /* U+13d00 - U+13d1f */ 0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff, /* U+13d20 - U+13d3f */ 0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff, /* U+13d40 - U+13d5f */ 0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff, /* U+13d60 - U+13d7f */ 0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff, /* U+13d80 - U+13d9f */ 0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff, /* U+13da0 - U+13dbf */ 0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff, /* U+13dc0 - U+13ddf */ 0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff, /* U+13de0 - U+13dff */ 0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff, /* U+13e00 - U+13e1f */ 0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff, /* U+13e20 - U+13e3f */ 0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff, /* U+13e40 - U+13e5f */ 0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff, /* U+13e60 - U+13e7f */ 0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff, /* U+13e80 - U+13e9f */ 0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff, /* U+13ea0 - U+13ebf */ 0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff, /* U+13ec0 - U+13edf */ 0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff, /* U+13ee0 - U+13eff */ 0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff, /* U+13f00 - U+13f1f */ 0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff, /* U+13f20 - U+13f3f */ 0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff, /* U+13f40 - U+13f5f */ 0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff, /* U+13f60 - U+13f7f */ 0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff, /* U+13f80 - U+13f9f */ 0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff, /* U+13fa0 - U+13fbf */ 0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff, /* U+13fc0 - U+13fdf */ 0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff, /* U+13fe0 - U+13fff */ 0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff, /* U+14000 - U+1401f */ 0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff, /* U+14020 - U+1403f */ 0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff, /* U+14040 - U+1405f */ 0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff, /* U+14060 - U+1407f */ 0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff, /* U+14080 - U+1409f */ 0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff, /* U+140a0 - U+140bf */ 0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff, /* U+140c0 - U+140df */ 0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff, /* U+140e0 - U+140ff */ 0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff, /* U+14100 - U+1411f */ 0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff, /* U+14120 - U+1413f */ 0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff, /* U+14140 - U+1415f */ 0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff, /* U+14160 - U+1417f */ 0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff, /* U+14180 - U+1419f */ 0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff, /* U+141a0 - U+141bf */ 0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff, /* U+141c0 - U+141df */ 0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff, /* U+141e0 - U+141ff */ 0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff, /* U+14200 - U+1421f */ 0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff, /* U+14220 - U+1423f */ 0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff, /* U+14240 - U+1425f */ 0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff, /* U+14260 - U+1427f */ 0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff, /* U+14280 - U+1429f */ 0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff, /* U+142a0 - U+142bf */ 0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff, /* U+142c0 - U+142df */ 0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff, /* U+142e0 - U+142ff */ 0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff, /* U+14300 - U+1431f */ 0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff, /* U+14320 - U+1433f */ 0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff, /* U+14340 - U+1435f */ 0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff, /* U+14360 - U+1437f */ 0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff, /* U+14380 - U+1439f */ 0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff, /* U+143a0 - U+143bf */ 0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff, /* U+143c0 - U+143df */ 0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff, /* U+143e0 - U+143ff */ 0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff, /* U+14400 - U+1441f */ 0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff, /* U+14420 - U+1443f */ 0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff, /* U+14440 - U+1445f */ 0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff, /* U+14460 - U+1447f */ 0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff, /* U+14480 - U+1449f */ 0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff, /* U+144a0 - U+144bf */ 0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff, /* U+144c0 - U+144df */ 0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff, /* U+144e0 - U+144ff */ 0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff, /* U+14500 - U+1451f */ 0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff, /* U+14520 - U+1453f */ 0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff, /* U+14540 - U+1455f */ 0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff, /* U+14560 - U+1457f */ 0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff, /* U+14580 - U+1459f */ 0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff, /* U+145a0 - U+145bf */ 0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff, /* U+145c0 - U+145df */ 0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff, /* U+145e0 - U+145ff */ 0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff, /* U+14600 - U+1461f */ 0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff, /* U+14620 - U+1463f */ 0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff, /* U+14640 - U+1465f */ 0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff, /* U+14660 - U+1467f */ 0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff, /* U+14680 - U+1469f */ 0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff, /* U+146a0 - U+146bf */ 0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff, /* U+146c0 - U+146df */ 0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff, /* U+146e0 - U+146ff */ 0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff, /* U+14700 - U+1471f */ 0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff, /* U+14720 - U+1473f */ 0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff, /* U+14740 - U+1475f */ 0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff, /* U+14760 - U+1477f */ 0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff, /* U+14780 - U+1479f */ 0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff, /* U+147a0 - U+147bf */ 0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff, /* U+147c0 - U+147df */ 0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff, /* U+147e0 - U+147ff */ 0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff, /* U+14800 - U+1481f */ 0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff, /* U+14820 - U+1483f */ 0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff, /* U+14840 - U+1485f */ 0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff, /* U+14860 - U+1487f */ 0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff, /* U+14880 - U+1489f */ 0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff, /* U+148a0 - U+148bf */ 0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff, /* U+148c0 - U+148df */ 0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff, /* U+148e0 - U+148ff */ 0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff, /* U+14900 - U+1491f */ 0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff, /* U+14920 - U+1493f */ 0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff, /* U+14940 - U+1495f */ 0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff, /* U+14960 - U+1497f */ 0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff, /* U+14980 - U+1499f */ 0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff, /* U+149a0 - U+149bf */ 0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff, /* U+149c0 - U+149df */ 0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff, /* U+149e0 - U+149ff */ 0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff, /* U+14a00 - U+14a1f */ 0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff, /* U+14a20 - U+14a3f */ 0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff, /* U+14a40 - U+14a5f */ 0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff, /* U+14a60 - U+14a7f */ 0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff, /* U+14a80 - U+14a9f */ 0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff, /* U+14aa0 - U+14abf */ 0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff, /* U+14ac0 - U+14adf */ 0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff, /* U+14ae0 - U+14aff */ 0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff, /* U+14b00 - U+14b1f */ 0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff, /* U+14b20 - U+14b3f */ 0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff, /* U+14b40 - U+14b5f */ 0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff, /* U+14b60 - U+14b7f */ 0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff, /* U+14b80 - U+14b9f */ 0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff, /* U+14ba0 - U+14bbf */ 0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff, /* U+14bc0 - U+14bdf */ 0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff, /* U+14be0 - U+14bff */ 0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff, /* U+14c00 - U+14c1f */ 0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff, /* U+14c20 - U+14c3f */ 0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff, /* U+14c40 - U+14c5f */ 0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff, /* U+14c60 - U+14c7f */ 0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff, /* U+14c80 - U+14c9f */ 0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff, /* U+14ca0 - U+14cbf */ 0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff, /* U+14cc0 - U+14cdf */ 0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff, /* U+14ce0 - U+14cff */ 0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff, /* U+14d00 - U+14d1f */ 0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff, /* U+14d20 - U+14d3f */ 0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff, /* U+14d40 - U+14d5f */ 0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff, /* U+14d60 - U+14d7f */ 0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff, /* U+14d80 - U+14d9f */ 0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff, /* U+14da0 - U+14dbf */ 0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff, /* U+14dc0 - U+14ddf */ 0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff, /* U+14de0 - U+14dff */ 0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff, /* U+14e00 - U+14e1f */ 0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff, /* U+14e20 - U+14e3f */ 0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff, /* U+14e40 - U+14e5f */ 0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff, /* U+14e60 - U+14e7f */ 0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff, /* U+14e80 - U+14e9f */ 0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff, /* U+14ea0 - U+14ebf */ 0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff, /* U+14ec0 - U+14edf */ 0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff, /* U+14ee0 - U+14eff */ 0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff, /* U+14f00 - U+14f1f */ 0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff, /* U+14f20 - U+14f3f */ 0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff, /* U+14f40 - U+14f5f */ 0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff, /* U+14f60 - U+14f7f */ 0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff, /* U+14f80 - U+14f9f */ 0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff, /* U+14fa0 - U+14fbf */ 0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff, /* U+14fc0 - U+14fdf */ 0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff, /* U+14fe0 - U+14fff */ 0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff, /* U+15000 - U+1501f */ 0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff, /* U+15020 - U+1503f */ 0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff, /* U+15040 - U+1505f */ 0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff, /* U+15060 - U+1507f */ 0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff, /* U+15080 - U+1509f */ 0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff, /* U+150a0 - U+150bf */ 0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff, /* U+150c0 - U+150df */ 0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff, /* U+150e0 - U+150ff */ 0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff, /* U+15100 - U+1511f */ 0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff, /* U+15120 - U+1513f */ 0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff, /* U+15140 - U+1515f */ 0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff, /* U+15160 - U+1517f */ 0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff, /* U+15180 - U+1519f */ 0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff, /* U+151a0 - U+151bf */ 0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff, /* U+151c0 - U+151df */ 0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff, /* U+151e0 - U+151ff */ 0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff, /* U+15200 - U+1521f */ 0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff, /* U+15220 - U+1523f */ 0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff, /* U+15240 - U+1525f */ 0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff, /* U+15260 - U+1527f */ 0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff, /* U+15280 - U+1529f */ 0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff, /* U+152a0 - U+152bf */ 0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff, /* U+152c0 - U+152df */ 0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff, /* U+152e0 - U+152ff */ 0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff, /* U+15300 - U+1531f */ 0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff, /* U+15320 - U+1533f */ 0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff, /* U+15340 - U+1535f */ 0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff, /* U+15360 - U+1537f */ 0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff, /* U+15380 - U+1539f */ 0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff, /* U+153a0 - U+153bf */ 0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff, /* U+153c0 - U+153df */ 0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff, /* U+153e0 - U+153ff */ 0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff, /* U+15400 - U+1541f */ 0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff, /* U+15420 - U+1543f */ 0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff, /* U+15440 - U+1545f */ 0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff, /* U+15460 - U+1547f */ 0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff, /* U+15480 - U+1549f */ 0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff, /* U+154a0 - U+154bf */ 0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff, /* U+154c0 - U+154df */ 0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff, /* U+154e0 - U+154ff */ 0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff, /* U+15500 - U+1551f */ 0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff, /* U+15520 - U+1553f */ 0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff, /* U+15540 - U+1555f */ 0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff, /* U+15560 - U+1557f */ 0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff, /* U+15580 - U+1559f */ 0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff, /* U+155a0 - U+155bf */ 0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff, /* U+155c0 - U+155df */ 0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff, /* U+155e0 - U+155ff */ 0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff, /* U+15600 - U+1561f */ 0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff, /* U+15620 - U+1563f */ 0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff, /* U+15640 - U+1565f */ 0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff, /* U+15660 - U+1567f */ 0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff, /* U+15680 - U+1569f */ 0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff, /* U+156a0 - U+156bf */ 0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff, /* U+156c0 - U+156df */ 0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff, /* U+156e0 - U+156ff */ 0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff, /* U+15700 - U+1571f */ 0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff, /* U+15720 - U+1573f */ 0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff, /* U+15740 - U+1575f */ 0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff, /* U+15760 - U+1577f */ 0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff, /* U+15780 - U+1579f */ 0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff, /* U+157a0 - U+157bf */ 0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff, /* U+157c0 - U+157df */ 0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff, /* U+157e0 - U+157ff */ 0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff, /* U+15800 - U+1581f */ 0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff, /* U+15820 - U+1583f */ 0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff, /* U+15840 - U+1585f */ 0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff, /* U+15860 - U+1587f */ 0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff, /* U+15880 - U+1589f */ 0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff, /* U+158a0 - U+158bf */ 0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff, /* U+158c0 - U+158df */ 0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff, /* U+158e0 - U+158ff */ 0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff, /* U+15900 - U+1591f */ 0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff, /* U+15920 - U+1593f */ 0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff, /* U+15940 - U+1595f */ 0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff, /* U+15960 - U+1597f */ 0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff, /* U+15980 - U+1599f */ 0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff, /* U+159a0 - U+159bf */ 0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff, /* U+159c0 - U+159df */ 0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff, /* U+159e0 - U+159ff */ 0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff, /* U+15a00 - U+15a1f */ 0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff, /* U+15a20 - U+15a3f */ 0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff, /* U+15a40 - U+15a5f */ 0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff, /* U+15a60 - U+15a7f */ 0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff, /* U+15a80 - U+15a9f */ 0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff, /* U+15aa0 - U+15abf */ 0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff, /* U+15ac0 - U+15adf */ 0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff, /* U+15ae0 - U+15aff */ 0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff, /* U+15b00 - U+15b1f */ 0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff, /* U+15b20 - U+15b3f */ 0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff, /* U+15b40 - U+15b5f */ 0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff, /* U+15b60 - U+15b7f */ 0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff, /* U+15b80 - U+15b9f */ 0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff, /* U+15ba0 - U+15bbf */ 0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff, /* U+15bc0 - U+15bdf */ 0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff, /* U+15be0 - U+15bff */ 0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff, /* U+15c00 - U+15c1f */ 0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff, /* U+15c20 - U+15c3f */ 0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff, /* U+15c40 - U+15c5f */ 0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff, /* U+15c60 - U+15c7f */ 0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff, /* U+15c80 - U+15c9f */ 0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff, /* U+15ca0 - U+15cbf */ 0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff, /* U+15cc0 - U+15cdf */ 0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff, /* U+15ce0 - U+15cff */ 0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff, /* U+15d00 - U+15d1f */ 0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff, /* U+15d20 - U+15d3f */ 0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff, /* U+15d40 - U+15d5f */ 0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff, /* U+15d60 - U+15d7f */ 0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff, /* U+15d80 - U+15d9f */ 0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff, /* U+15da0 - U+15dbf */ 0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff, /* U+15dc0 - U+15ddf */ 0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff, /* U+15de0 - U+15dff */ 0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff, /* U+15e00 - U+15e1f */ 0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff, /* U+15e20 - U+15e3f */ 0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff, /* U+15e40 - U+15e5f */ 0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff, /* U+15e60 - U+15e7f */ 0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff, /* U+15e80 - U+15e9f */ 0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff, /* U+15ea0 - U+15ebf */ 0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff, /* U+15ec0 - U+15edf */ 0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff, /* U+15ee0 - U+15eff */ 0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff, /* U+15f00 - U+15f1f */ 0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff, /* U+15f20 - U+15f3f */ 0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff, /* U+15f40 - U+15f5f */ 0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff, /* U+15f60 - U+15f7f */ 0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff, /* U+15f80 - U+15f9f */ 0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff, /* U+15fa0 - U+15fbf */ 0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff, /* U+15fc0 - U+15fdf */ 0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff, /* U+15fe0 - U+15fff */ 0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff, /* U+16000 - U+1601f */ 0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff, /* U+16020 - U+1603f */ 0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff, /* U+16040 - U+1605f */ 0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff, /* U+16060 - U+1607f */ 0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff, /* U+16080 - U+1609f */ 0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff, /* U+160a0 - U+160bf */ 0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff, /* U+160c0 - U+160df */ 0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff, /* U+160e0 - U+160ff */ 0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff, /* U+16100 - U+1611f */ 0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff, /* U+16120 - U+1613f */ 0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff, /* U+16140 - U+1615f */ 0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff, /* U+16160 - U+1617f */ 0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff, /* U+16180 - U+1619f */ 0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff, /* U+161a0 - U+161bf */ 0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff, /* U+161c0 - U+161df */ 0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff, /* U+161e0 - U+161ff */ 0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff, /* U+16200 - U+1621f */ 0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff, /* U+16220 - U+1623f */ 0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff, /* U+16240 - U+1625f */ 0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff, /* U+16260 - U+1627f */ 0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff, /* U+16280 - U+1629f */ 0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff, /* U+162a0 - U+162bf */ 0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff, /* U+162c0 - U+162df */ 0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff, /* U+162e0 - U+162ff */ 0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff, /* U+16300 - U+1631f */ 0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff, /* U+16320 - U+1633f */ 0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff, /* U+16340 - U+1635f */ 0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff, /* U+16360 - U+1637f */ 0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff, /* U+16380 - U+1639f */ 0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff, /* U+163a0 - U+163bf */ 0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff, /* U+163c0 - U+163df */ 0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff, /* U+163e0 - U+163ff */ 0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff, /* U+16400 - U+1641f */ 0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff, /* U+16420 - U+1643f */ 0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff, /* U+16440 - U+1645f */ 0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff, /* U+16460 - U+1647f */ 0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff, /* U+16480 - U+1649f */ 0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff, /* U+164a0 - U+164bf */ 0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff, /* U+164c0 - U+164df */ 0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff, /* U+164e0 - U+164ff */ 0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff, /* U+16500 - U+1651f */ 0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff, /* U+16520 - U+1653f */ 0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff, /* U+16540 - U+1655f */ 0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff, /* U+16560 - U+1657f */ 0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff, /* U+16580 - U+1659f */ 0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff, /* U+165a0 - U+165bf */ 0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff, /* U+165c0 - U+165df */ 0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff, /* U+165e0 - U+165ff */ 0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff, /* U+16600 - U+1661f */ 0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff, /* U+16620 - U+1663f */ 0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff, /* U+16640 - U+1665f */ 0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff, /* U+16660 - U+1667f */ 0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff, /* U+16680 - U+1669f */ 0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff, /* U+166a0 - U+166bf */ 0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff, /* U+166c0 - U+166df */ 0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff, /* U+166e0 - U+166ff */ 0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff, /* U+16700 - U+1671f */ 0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff, /* U+16720 - U+1673f */ 0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff, /* U+16740 - U+1675f */ 0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff, /* U+16760 - U+1677f */ 0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff, /* U+16780 - U+1679f */ 0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff, /* U+167a0 - U+167bf */ 0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff, /* U+167c0 - U+167df */ 0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff, /* U+167e0 - U+167ff */ 0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff, /* U+16800 - U+1681f */ 0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff, /* U+16820 - U+1683f */ 0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff, /* U+16840 - U+1685f */ 0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff, /* U+16860 - U+1687f */ 0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff, /* U+16880 - U+1689f */ 0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff, /* U+168a0 - U+168bf */ 0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff, /* U+168c0 - U+168df */ 0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff, /* U+168e0 - U+168ff */ 0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff, /* U+16900 - U+1691f */ 0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff, /* U+16920 - U+1693f */ 0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff, /* U+16940 - U+1695f */ 0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff, /* U+16960 - U+1697f */ 0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff, /* U+16980 - U+1699f */ 0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff, /* U+169a0 - U+169bf */ 0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff, /* U+169c0 - U+169df */ 0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff, /* U+169e0 - U+169ff */ 0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff, /* U+16a00 - U+16a1f */ 0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff, /* U+16a20 - U+16a3f */ 0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff, /* U+16a40 - U+16a5f */ 0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff, /* U+16a60 - U+16a7f */ 0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff, /* U+16a80 - U+16a9f */ 0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff, /* U+16aa0 - U+16abf */ 0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff, /* U+16ac0 - U+16adf */ 0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff, /* U+16ae0 - U+16aff */ 0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff, /* U+16b00 - U+16b1f */ 0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff, /* U+16b20 - U+16b3f */ 0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff, /* U+16b40 - U+16b5f */ 0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff, /* U+16b60 - U+16b7f */ 0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff, /* U+16b80 - U+16b9f */ 0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff, /* U+16ba0 - U+16bbf */ 0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff, /* U+16bc0 - U+16bdf */ 0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff, /* U+16be0 - U+16bff */ 0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff, /* U+16c00 - U+16c1f */ 0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff, /* U+16c20 - U+16c3f */ 0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff, /* U+16c40 - U+16c5f */ 0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff, /* U+16c60 - U+16c7f */ 0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff, /* U+16c80 - U+16c9f */ 0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff, /* U+16ca0 - U+16cbf */ 0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff, /* U+16cc0 - U+16cdf */ 0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff, /* U+16ce0 - U+16cff */ 0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff, /* U+16d00 - U+16d1f */ 0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff, /* U+16d20 - U+16d3f */ 0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff, /* U+16d40 - U+16d5f */ 0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff, /* U+16d60 - U+16d7f */ 0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff, /* U+16d80 - U+16d9f */ 0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff, /* U+16da0 - U+16dbf */ 0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff, /* U+16dc0 - U+16ddf */ 0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff, /* U+16de0 - U+16dff */ 0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff, /* U+16e00 - U+16e1f */ 0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff, /* U+16e20 - U+16e3f */ 0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff, /* U+16e40 - U+16e5f */ 0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff, /* U+16e60 - U+16e7f */ 0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff, /* U+16e80 - U+16e9f */ 0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff, /* U+16ea0 - U+16ebf */ 0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff, /* U+16ec0 - U+16edf */ 0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff, /* U+16ee0 - U+16eff */ 0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff, /* U+16f00 - U+16f1f */ 0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff, /* U+16f20 - U+16f3f */ 0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff, /* U+16f40 - U+16f5f */ 0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff, /* U+16f60 - U+16f7f */ 0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff, /* U+16f80 - U+16f9f */ 0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff, /* U+16fa0 - U+16fbf */ 0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff, /* U+16fc0 - U+16fdf */ 0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff, /* U+16fe0 - U+16fff */ 0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff, /* U+17000 - U+1701f */ 0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff, /* U+17020 - U+1703f */ 0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff, /* U+17040 - U+1705f */ 0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff, /* U+17060 - U+1707f */ 0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff, /* U+17080 - U+1709f */ 0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff, /* U+170a0 - U+170bf */ 0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff, /* U+170c0 - U+170df */ 0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff, /* U+170e0 - U+170ff */ 0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff, /* U+17100 - U+1711f */ 0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff, /* U+17120 - U+1713f */ 0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff, /* U+17140 - U+1715f */ 0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff, /* U+17160 - U+1717f */ 0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff, /* U+17180 - U+1719f */ 0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff, /* U+171a0 - U+171bf */ 0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff, /* U+171c0 - U+171df */ 0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff, /* U+171e0 - U+171ff */ 0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff, /* U+17200 - U+1721f */ 0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff, /* U+17220 - U+1723f */ 0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff, /* U+17240 - U+1725f */ 0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff, /* U+17260 - U+1727f */ 0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff, /* U+17280 - U+1729f */ 0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff, /* U+172a0 - U+172bf */ 0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff, /* U+172c0 - U+172df */ 0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff, /* U+172e0 - U+172ff */ 0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff, /* U+17300 - U+1731f */ 0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff, /* U+17320 - U+1733f */ 0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff, /* U+17340 - U+1735f */ 0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff, /* U+17360 - U+1737f */ 0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff, /* U+17380 - U+1739f */ 0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff, /* U+173a0 - U+173bf */ 0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff, /* U+173c0 - U+173df */ 0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff, /* U+173e0 - U+173ff */ 0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff, /* U+17400 - U+1741f */ 0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff, /* U+17420 - U+1743f */ 0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff, /* U+17440 - U+1745f */ 0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff, /* U+17460 - U+1747f */ 0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff, /* U+17480 - U+1749f */ 0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff, /* U+174a0 - U+174bf */ 0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff, /* U+174c0 - U+174df */ 0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff, /* U+174e0 - U+174ff */ 0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff, /* U+17500 - U+1751f */ 0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff, /* U+17520 - U+1753f */ 0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff, /* U+17540 - U+1755f */ 0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff, /* U+17560 - U+1757f */ 0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff, /* U+17580 - U+1759f */ 0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff, /* U+175a0 - U+175bf */ 0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff, /* U+175c0 - U+175df */ 0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff, /* U+175e0 - U+175ff */ 0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff, /* U+17600 - U+1761f */ 0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff, /* U+17620 - U+1763f */ 0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff, /* U+17640 - U+1765f */ 0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff, /* U+17660 - U+1767f */ 0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff, /* U+17680 - U+1769f */ 0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff, /* U+176a0 - U+176bf */ 0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff, /* U+176c0 - U+176df */ 0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff, /* U+176e0 - U+176ff */ 0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff, /* U+17700 - U+1771f */ 0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff, /* U+17720 - U+1773f */ 0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff, /* U+17740 - U+1775f */ 0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff, /* U+17760 - U+1777f */ 0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff, /* U+17780 - U+1779f */ 0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff, /* U+177a0 - U+177bf */ 0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff, /* U+177c0 - U+177df */ 0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff, /* U+177e0 - U+177ff */ 0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff, /* U+17800 - U+1781f */ 0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff, /* U+17820 - U+1783f */ 0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff, /* U+17840 - U+1785f */ 0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff, /* U+17860 - U+1787f */ 0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff, /* U+17880 - U+1789f */ 0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff, /* U+178a0 - U+178bf */ 0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff, /* U+178c0 - U+178df */ 0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff, /* U+178e0 - U+178ff */ 0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff, /* U+17900 - U+1791f */ 0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff, /* U+17920 - U+1793f */ 0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff, /* U+17940 - U+1795f */ 0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff, /* U+17960 - U+1797f */ 0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff, /* U+17980 - U+1799f */ 0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff, /* U+179a0 - U+179bf */ 0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff, /* U+179c0 - U+179df */ 0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff, /* U+179e0 - U+179ff */ 0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff, /* U+17a00 - U+17a1f */ 0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff, /* U+17a20 - U+17a3f */ 0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff, /* U+17a40 - U+17a5f */ 0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff, /* U+17a60 - U+17a7f */ 0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff, /* U+17a80 - U+17a9f */ 0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff, /* U+17aa0 - U+17abf */ 0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff, /* U+17ac0 - U+17adf */ 0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff, /* U+17ae0 - U+17aff */ 0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff, /* U+17b00 - U+17b1f */ 0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff, /* U+17b20 - U+17b3f */ 0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff, /* U+17b40 - U+17b5f */ 0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff, /* U+17b60 - U+17b7f */ 0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff, /* U+17b80 - U+17b9f */ 0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff, /* U+17ba0 - U+17bbf */ 0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff, /* U+17bc0 - U+17bdf */ 0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff, /* U+17be0 - U+17bff */ 0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff, /* U+17c00 - U+17c1f */ 0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff, /* U+17c20 - U+17c3f */ 0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff, /* U+17c40 - U+17c5f */ 0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff, /* U+17c60 - U+17c7f */ 0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff, /* U+17c80 - U+17c9f */ 0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff, /* U+17ca0 - U+17cbf */ 0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff, /* U+17cc0 - U+17cdf */ 0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff, /* U+17ce0 - U+17cff */ 0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff, /* U+17d00 - U+17d1f */ 0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff, /* U+17d20 - U+17d3f */ 0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff, /* U+17d40 - U+17d5f */ 0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff, /* U+17d60 - U+17d7f */ 0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff, /* U+17d80 - U+17d9f */ 0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff, /* U+17da0 - U+17dbf */ 0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff, /* U+17dc0 - U+17ddf */ 0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff, /* U+17de0 - U+17dff */ 0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff, /* U+17e00 - U+17e1f */ 0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff, /* U+17e20 - U+17e3f */ 0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff, /* U+17e40 - U+17e5f */ 0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff, /* U+17e60 - U+17e7f */ 0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff, /* U+17e80 - U+17e9f */ 0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff, /* U+17ea0 - U+17ebf */ 0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff, /* U+17ec0 - U+17edf */ 0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff, /* U+17ee0 - U+17eff */ 0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff, /* U+17f00 - U+17f1f */ 0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff, /* U+17f20 - U+17f3f */ 0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff, /* U+17f40 - U+17f5f */ 0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff, /* U+17f60 - U+17f7f */ 0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff, /* U+17f80 - U+17f9f */ 0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff, /* U+17fa0 - U+17fbf */ 0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff, /* U+17fc0 - U+17fdf */ 0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff, /* U+17fe0 - U+17fff */ 0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff, /* U+18000 - U+1801f */ 0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff, /* U+18020 - U+1803f */ 0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff, /* U+18040 - U+1805f */ 0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff, /* U+18060 - U+1807f */ 0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff, /* U+18080 - U+1809f */ 0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff, /* U+180a0 - U+180bf */ 0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff, /* U+180c0 - U+180df */ 0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff, /* U+180e0 - U+180ff */ 0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff, /* U+18100 - U+1811f */ 0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff, /* U+18120 - U+1813f */ 0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff, /* U+18140 - U+1815f */ 0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff, /* U+18160 - U+1817f */ 0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff, /* U+18180 - U+1819f */ 0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff, /* U+181a0 - U+181bf */ 0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff, /* U+181c0 - U+181df */ 0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff, /* U+181e0 - U+181ff */ 0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff, /* U+18200 - U+1821f */ 0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff, /* U+18220 - U+1823f */ 0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff, /* U+18240 - U+1825f */ 0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff, /* U+18260 - U+1827f */ 0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff, /* U+18280 - U+1829f */ 0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff, /* U+182a0 - U+182bf */ 0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff, /* U+182c0 - U+182df */ 0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff, /* U+182e0 - U+182ff */ 0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff, /* U+18300 - U+1831f */ 0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff, /* U+18320 - U+1833f */ 0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff, /* U+18340 - U+1835f */ 0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff, /* U+18360 - U+1837f */ 0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff, /* U+18380 - U+1839f */ 0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff, /* U+183a0 - U+183bf */ 0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff, /* U+183c0 - U+183df */ 0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff, /* U+183e0 - U+183ff */ 0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff, /* U+18400 - U+1841f */ 0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff, /* U+18420 - U+1843f */ 0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff, /* U+18440 - U+1845f */ 0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff, /* U+18460 - U+1847f */ 0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff, /* U+18480 - U+1849f */ 0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff, /* U+184a0 - U+184bf */ 0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff, /* U+184c0 - U+184df */ 0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff, /* U+184e0 - U+184ff */ 0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff, /* U+18500 - U+1851f */ 0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff, /* U+18520 - U+1853f */ 0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff, /* U+18540 - U+1855f */ 0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff, /* U+18560 - U+1857f */ 0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff, /* U+18580 - U+1859f */ 0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff, /* U+185a0 - U+185bf */ 0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff, /* U+185c0 - U+185df */ 0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff, /* U+185e0 - U+185ff */ 0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff, /* U+18600 - U+1861f */ 0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff, /* U+18620 - U+1863f */ 0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff, /* U+18640 - U+1865f */ 0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff, /* U+18660 - U+1867f */ 0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff, /* U+18680 - U+1869f */ 0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff, /* U+186a0 - U+186bf */ 0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff, /* U+186c0 - U+186df */ 0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff, /* U+186e0 - U+186ff */ 0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff, /* U+18700 - U+1871f */ 0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff, /* U+18720 - U+1873f */ 0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff, /* U+18740 - U+1875f */ 0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff, /* U+18760 - U+1877f */ 0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff, /* U+18780 - U+1879f */ 0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff, /* U+187a0 - U+187bf */ 0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff, /* U+187c0 - U+187df */ 0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff, /* U+187e0 - U+187ff */ 0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff, /* U+18800 - U+1881f */ 0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff, /* U+18820 - U+1883f */ 0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff, /* U+18840 - U+1885f */ 0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff, /* U+18860 - U+1887f */ 0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff, /* U+18880 - U+1889f */ 0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff, /* U+188a0 - U+188bf */ 0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff, /* U+188c0 - U+188df */ 0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff, /* U+188e0 - U+188ff */ 0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff, /* U+18900 - U+1891f */ 0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff, /* U+18920 - U+1893f */ 0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff, /* U+18940 - U+1895f */ 0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff, /* U+18960 - U+1897f */ 0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff, /* U+18980 - U+1899f */ 0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff, /* U+189a0 - U+189bf */ 0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff, /* U+189c0 - U+189df */ 0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff, /* U+189e0 - U+189ff */ 0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff, /* U+18a00 - U+18a1f */ 0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff, /* U+18a20 - U+18a3f */ 0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff, /* U+18a40 - U+18a5f */ 0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff, /* U+18a60 - U+18a7f */ 0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff, /* U+18a80 - U+18a9f */ 0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff, /* U+18aa0 - U+18abf */ 0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff, /* U+18ac0 - U+18adf */ 0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff, /* U+18ae0 - U+18aff */ 0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff, /* U+18b00 - U+18b1f */ 0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff, /* U+18b20 - U+18b3f */ 0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff, /* U+18b40 - U+18b5f */ 0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff, /* U+18b60 - U+18b7f */ 0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff, /* U+18b80 - U+18b9f */ 0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff, /* U+18ba0 - U+18bbf */ 0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff, /* U+18bc0 - U+18bdf */ 0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff, /* U+18be0 - U+18bff */ 0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff, /* U+18c00 - U+18c1f */ 0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff, /* U+18c20 - U+18c3f */ 0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff, /* U+18c40 - U+18c5f */ 0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff, /* U+18c60 - U+18c7f */ 0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff, /* U+18c80 - U+18c9f */ 0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff, /* U+18ca0 - U+18cbf */ 0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff, /* U+18cc0 - U+18cdf */ 0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff, /* U+18ce0 - U+18cff */ 0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff, /* U+18d00 - U+18d1f */ 0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff, /* U+18d20 - U+18d3f */ 0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff, /* U+18d40 - U+18d5f */ 0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff, /* U+18d60 - U+18d7f */ 0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff, /* U+18d80 - U+18d9f */ 0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff, /* U+18da0 - U+18dbf */ 0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff, /* U+18dc0 - U+18ddf */ 0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff, /* U+18de0 - U+18dff */ 0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff, /* U+18e00 - U+18e1f */ 0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff, /* U+18e20 - U+18e3f */ 0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff, /* U+18e40 - U+18e5f */ 0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff, /* U+18e60 - U+18e7f */ 0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff, /* U+18e80 - U+18e9f */ 0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff, /* U+18ea0 - U+18ebf */ 0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff, /* U+18ec0 - U+18edf */ 0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff, /* U+18ee0 - U+18eff */ 0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff, /* U+18f00 - U+18f1f */ 0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff, /* U+18f20 - U+18f3f */ 0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff, /* U+18f40 - U+18f5f */ 0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff, /* U+18f60 - U+18f7f */ 0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff, /* U+18f80 - U+18f9f */ 0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff, /* U+18fa0 - U+18fbf */ 0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff, /* U+18fc0 - U+18fdf */ 0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff, /* U+18fe0 - U+18fff */ 0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff, /* U+19000 - U+1901f */ 0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff, /* U+19020 - U+1903f */ 0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff, /* U+19040 - U+1905f */ 0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff, /* U+19060 - U+1907f */ 0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff, /* U+19080 - U+1909f */ 0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff, /* U+190a0 - U+190bf */ 0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff, /* U+190c0 - U+190df */ 0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff, /* U+190e0 - U+190ff */ 0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff, /* U+19100 - U+1911f */ 0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff, /* U+19120 - U+1913f */ 0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff, /* U+19140 - U+1915f */ 0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff, /* U+19160 - U+1917f */ 0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff, /* U+19180 - U+1919f */ 0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff, /* U+191a0 - U+191bf */ 0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff, /* U+191c0 - U+191df */ 0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff, /* U+191e0 - U+191ff */ 0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff, /* U+19200 - U+1921f */ 0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff, /* U+19220 - U+1923f */ 0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff, /* U+19240 - U+1925f */ 0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff, /* U+19260 - U+1927f */ 0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff, /* U+19280 - U+1929f */ 0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff, /* U+192a0 - U+192bf */ 0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff, /* U+192c0 - U+192df */ 0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff, /* U+192e0 - U+192ff */ 0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff, /* U+19300 - U+1931f */ 0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff, /* U+19320 - U+1933f */ 0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff, /* U+19340 - U+1935f */ 0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff, /* U+19360 - U+1937f */ 0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff, /* U+19380 - U+1939f */ 0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff, /* U+193a0 - U+193bf */ 0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff, /* U+193c0 - U+193df */ 0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff, /* U+193e0 - U+193ff */ 0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff, /* U+19400 - U+1941f */ 0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff, /* U+19420 - U+1943f */ 0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff, /* U+19440 - U+1945f */ 0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff, /* U+19460 - U+1947f */ 0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff, /* U+19480 - U+1949f */ 0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff, /* U+194a0 - U+194bf */ 0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff, /* U+194c0 - U+194df */ 0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff, /* U+194e0 - U+194ff */ 0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff, /* U+19500 - U+1951f */ 0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff, /* U+19520 - U+1953f */ 0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff, /* U+19540 - U+1955f */ 0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff, /* U+19560 - U+1957f */ 0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff, /* U+19580 - U+1959f */ 0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff, /* U+195a0 - U+195bf */ 0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff, /* U+195c0 - U+195df */ 0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff, /* U+195e0 - U+195ff */ 0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff, /* U+19600 - U+1961f */ 0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff, /* U+19620 - U+1963f */ 0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff, /* U+19640 - U+1965f */ 0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff, /* U+19660 - U+1967f */ 0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff, /* U+19680 - U+1969f */ 0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff, /* U+196a0 - U+196bf */ 0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff, /* U+196c0 - U+196df */ 0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff, /* U+196e0 - U+196ff */ 0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff, /* U+19700 - U+1971f */ 0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff, /* U+19720 - U+1973f */ 0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff, /* U+19740 - U+1975f */ 0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff, /* U+19760 - U+1977f */ 0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff, /* U+19780 - U+1979f */ 0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff, /* U+197a0 - U+197bf */ 0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff, /* U+197c0 - U+197df */ 0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff, /* U+197e0 - U+197ff */ 0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff, /* U+19800 - U+1981f */ 0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff, /* U+19820 - U+1983f */ 0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff, /* U+19840 - U+1985f */ 0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff, /* U+19860 - U+1987f */ 0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff, /* U+19880 - U+1989f */ 0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff, /* U+198a0 - U+198bf */ 0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff, /* U+198c0 - U+198df */ 0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff, /* U+198e0 - U+198ff */ 0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff, /* U+19900 - U+1991f */ 0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff, /* U+19920 - U+1993f */ 0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff, /* U+19940 - U+1995f */ 0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff, /* U+19960 - U+1997f */ 0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff, /* U+19980 - U+1999f */ 0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff, /* U+199a0 - U+199bf */ 0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff, /* U+199c0 - U+199df */ 0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff, /* U+199e0 - U+199ff */ 0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff, /* U+19a00 - U+19a1f */ 0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff, /* U+19a20 - U+19a3f */ 0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff, /* U+19a40 - U+19a5f */ 0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff, /* U+19a60 - U+19a7f */ 0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff, /* U+19a80 - U+19a9f */ 0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff, /* U+19aa0 - U+19abf */ 0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff, /* U+19ac0 - U+19adf */ 0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff, /* U+19ae0 - U+19aff */ 0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff, /* U+19b00 - U+19b1f */ 0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff, /* U+19b20 - U+19b3f */ 0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff, /* U+19b40 - U+19b5f */ 0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff, /* U+19b60 - U+19b7f */ 0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff, /* U+19b80 - U+19b9f */ 0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff, /* U+19ba0 - U+19bbf */ 0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff, /* U+19bc0 - U+19bdf */ 0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff, /* U+19be0 - U+19bff */ 0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff, /* U+19c00 - U+19c1f */ 0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff, /* U+19c20 - U+19c3f */ 0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff, /* U+19c40 - U+19c5f */ 0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff, /* U+19c60 - U+19c7f */ 0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff, /* U+19c80 - U+19c9f */ 0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff, /* U+19ca0 - U+19cbf */ 0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff, /* U+19cc0 - U+19cdf */ 0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff, /* U+19ce0 - U+19cff */ 0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff, /* U+19d00 - U+19d1f */ 0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff, /* U+19d20 - U+19d3f */ 0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff, /* U+19d40 - U+19d5f */ 0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff, /* U+19d60 - U+19d7f */ 0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff, /* U+19d80 - U+19d9f */ 0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff, /* U+19da0 - U+19dbf */ 0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff, /* U+19dc0 - U+19ddf */ 0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff, /* U+19de0 - U+19dff */ 0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff, /* U+19e00 - U+19e1f */ 0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff, /* U+19e20 - U+19e3f */ 0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff, /* U+19e40 - U+19e5f */ 0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff, /* U+19e60 - U+19e7f */ 0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff, /* U+19e80 - U+19e9f */ 0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff, /* U+19ea0 - U+19ebf */ 0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff, /* U+19ec0 - U+19edf */ 0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff, /* U+19ee0 - U+19eff */ 0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff, /* U+19f00 - U+19f1f */ 0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff, /* U+19f20 - U+19f3f */ 0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff, /* U+19f40 - U+19f5f */ 0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff, /* U+19f60 - U+19f7f */ 0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff, /* U+19f80 - U+19f9f */ 0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff, /* U+19fa0 - U+19fbf */ 0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff, /* U+19fc0 - U+19fdf */ 0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff, /* U+19fe0 - U+19fff */ 0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff, /* U+1a000 - U+1a01f */ 0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff, /* U+1a020 - U+1a03f */ 0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff, /* U+1a040 - U+1a05f */ 0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff, /* U+1a060 - U+1a07f */ 0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff, /* U+1a080 - U+1a09f */ 0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff, /* U+1a0a0 - U+1a0bf */ 0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff, /* U+1a0c0 - U+1a0df */ 0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff, /* U+1a0e0 - U+1a0ff */ 0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff, /* U+1a100 - U+1a11f */ 0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff, /* U+1a120 - U+1a13f */ 0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff, /* U+1a140 - U+1a15f */ 0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff, /* U+1a160 - U+1a17f */ 0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff, /* U+1a180 - U+1a19f */ 0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff, /* U+1a1a0 - U+1a1bf */ 0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff, /* U+1a1c0 - U+1a1df */ 0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff, /* U+1a1e0 - U+1a1ff */ 0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff, /* U+1a200 - U+1a21f */ 0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff, /* U+1a220 - U+1a23f */ 0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff, /* U+1a240 - U+1a25f */ 0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff, /* U+1a260 - U+1a27f */ 0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff, /* U+1a280 - U+1a29f */ 0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff, /* U+1a2a0 - U+1a2bf */ 0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff, /* U+1a2c0 - U+1a2df */ 0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff, /* U+1a2e0 - U+1a2ff */ 0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff, /* U+1a300 - U+1a31f */ 0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff, /* U+1a320 - U+1a33f */ 0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff, /* U+1a340 - U+1a35f */ 0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff, /* U+1a360 - U+1a37f */ 0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff, /* U+1a380 - U+1a39f */ 0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff, /* U+1a3a0 - U+1a3bf */ 0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff, /* U+1a3c0 - U+1a3df */ 0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff, /* U+1a3e0 - U+1a3ff */ 0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff, /* U+1a400 - U+1a41f */ 0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff, /* U+1a420 - U+1a43f */ 0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff, /* U+1a440 - U+1a45f */ 0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff, /* U+1a460 - U+1a47f */ 0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff, /* U+1a480 - U+1a49f */ 0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff, /* U+1a4a0 - U+1a4bf */ 0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff, /* U+1a4c0 - U+1a4df */ 0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff, /* U+1a4e0 - U+1a4ff */ 0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff, /* U+1a500 - U+1a51f */ 0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff, /* U+1a520 - U+1a53f */ 0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff, /* U+1a540 - U+1a55f */ 0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff, /* U+1a560 - U+1a57f */ 0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff, /* U+1a580 - U+1a59f */ 0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff, /* U+1a5a0 - U+1a5bf */ 0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff, /* U+1a5c0 - U+1a5df */ 0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff, /* U+1a5e0 - U+1a5ff */ 0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff, /* U+1a600 - U+1a61f */ 0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff, /* U+1a620 - U+1a63f */ 0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff, /* U+1a640 - U+1a65f */ 0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff, /* U+1a660 - U+1a67f */ 0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff, /* U+1a680 - U+1a69f */ 0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff, /* U+1a6a0 - U+1a6bf */ 0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff, /* U+1a6c0 - U+1a6df */ 0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff, /* U+1a6e0 - U+1a6ff */ 0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff, /* U+1a700 - U+1a71f */ 0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff, /* U+1a720 - U+1a73f */ 0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff, /* U+1a740 - U+1a75f */ 0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff, /* U+1a760 - U+1a77f */ 0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff, /* U+1a780 - U+1a79f */ 0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff, /* U+1a7a0 - U+1a7bf */ 0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff, /* U+1a7c0 - U+1a7df */ 0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff, /* U+1a7e0 - U+1a7ff */ 0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff, /* U+1a800 - U+1a81f */ 0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff, /* U+1a820 - U+1a83f */ 0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff, /* U+1a840 - U+1a85f */ 0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff, /* U+1a860 - U+1a87f */ 0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff, /* U+1a880 - U+1a89f */ 0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff, /* U+1a8a0 - U+1a8bf */ 0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff, /* U+1a8c0 - U+1a8df */ 0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff, /* U+1a8e0 - U+1a8ff */ 0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff, /* U+1a900 - U+1a91f */ 0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff, /* U+1a920 - U+1a93f */ 0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff, /* U+1a940 - U+1a95f */ 0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff, /* U+1a960 - U+1a97f */ 0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff, /* U+1a980 - U+1a99f */ 0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff, /* U+1a9a0 - U+1a9bf */ 0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff, /* U+1a9c0 - U+1a9df */ 0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff, /* U+1a9e0 - U+1a9ff */ 0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff, /* U+1aa00 - U+1aa1f */ 0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff, /* U+1aa20 - U+1aa3f */ 0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff, /* U+1aa40 - U+1aa5f */ 0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff, /* U+1aa60 - U+1aa7f */ 0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff, /* U+1aa80 - U+1aa9f */ 0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff, /* U+1aaa0 - U+1aabf */ 0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff, /* U+1aac0 - U+1aadf */ 0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff, /* U+1aae0 - U+1aaff */ 0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff, /* U+1ab00 - U+1ab1f */ 0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff, /* U+1ab20 - U+1ab3f */ 0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff, /* U+1ab40 - U+1ab5f */ 0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff, /* U+1ab60 - U+1ab7f */ 0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff, /* U+1ab80 - U+1ab9f */ 0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff, /* U+1aba0 - U+1abbf */ 0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff, /* U+1abc0 - U+1abdf */ 0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff, /* U+1abe0 - U+1abff */ 0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff, /* U+1ac00 - U+1ac1f */ 0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff, /* U+1ac20 - U+1ac3f */ 0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff, /* U+1ac40 - U+1ac5f */ 0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff, /* U+1ac60 - U+1ac7f */ 0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff, /* U+1ac80 - U+1ac9f */ 0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff, /* U+1aca0 - U+1acbf */ 0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff, /* U+1acc0 - U+1acdf */ 0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff, /* U+1ace0 - U+1acff */ 0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff, /* U+1ad00 - U+1ad1f */ 0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff, /* U+1ad20 - U+1ad3f */ 0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff, /* U+1ad40 - U+1ad5f */ 0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff, /* U+1ad60 - U+1ad7f */ 0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff, /* U+1ad80 - U+1ad9f */ 0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff, /* U+1ada0 - U+1adbf */ 0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff, /* U+1adc0 - U+1addf */ 0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff, /* U+1ade0 - U+1adff */ 0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff, /* U+1ae00 - U+1ae1f */ 0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff, /* U+1ae20 - U+1ae3f */ 0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff, /* U+1ae40 - U+1ae5f */ 0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff, /* U+1ae60 - U+1ae7f */ 0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff, /* U+1ae80 - U+1ae9f */ 0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff, /* U+1aea0 - U+1aebf */ 0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff, /* U+1aec0 - U+1aedf */ 0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff, /* U+1aee0 - U+1aeff */ 0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff, /* U+1af00 - U+1af1f */ 0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff, /* U+1af20 - U+1af3f */ 0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff, /* U+1af40 - U+1af5f */ 0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff, /* U+1af60 - U+1af7f */ 0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff, /* U+1af80 - U+1af9f */ 0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff, /* U+1afa0 - U+1afbf */ 0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff, /* U+1afc0 - U+1afdf */ 0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff, /* U+1afe0 - U+1afff */ 0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff, /* U+1b000 - U+1b01f */ 0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff, /* U+1b020 - U+1b03f */ 0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff, /* U+1b040 - U+1b05f */ 0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff, /* U+1b060 - U+1b07f */ 0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff, /* U+1b080 - U+1b09f */ 0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff, /* U+1b0a0 - U+1b0bf */ 0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff, /* U+1b0c0 - U+1b0df */ 0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff, /* U+1b0e0 - U+1b0ff */ 0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff, /* U+1b100 - U+1b11f */ 0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff, /* U+1b120 - U+1b13f */ 0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff, /* U+1b140 - U+1b15f */ 0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff, /* U+1b160 - U+1b17f */ 0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff, /* U+1b180 - U+1b19f */ 0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff, /* U+1b1a0 - U+1b1bf */ 0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff, /* U+1b1c0 - U+1b1df */ 0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff, /* U+1b1e0 - U+1b1ff */ 0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff, /* U+1b200 - U+1b21f */ 0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff, /* U+1b220 - U+1b23f */ 0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff, /* U+1b240 - U+1b25f */ 0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff, /* U+1b260 - U+1b27f */ 0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff, /* U+1b280 - U+1b29f */ 0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff, /* U+1b2a0 - U+1b2bf */ 0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff, /* U+1b2c0 - U+1b2df */ 0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff, /* U+1b2e0 - U+1b2ff */ 0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff, /* U+1b300 - U+1b31f */ 0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff, /* U+1b320 - U+1b33f */ 0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff, /* U+1b340 - U+1b35f */ 0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff, /* U+1b360 - U+1b37f */ 0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff, /* U+1b380 - U+1b39f */ 0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff, /* U+1b3a0 - U+1b3bf */ 0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff, /* U+1b3c0 - U+1b3df */ 0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff, /* U+1b3e0 - U+1b3ff */ 0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff, /* U+1b400 - U+1b41f */ 0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff, /* U+1b420 - U+1b43f */ 0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff, /* U+1b440 - U+1b45f */ 0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff, /* U+1b460 - U+1b47f */ 0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff, /* U+1b480 - U+1b49f */ 0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff, /* U+1b4a0 - U+1b4bf */ 0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff, /* U+1b4c0 - U+1b4df */ 0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff, /* U+1b4e0 - U+1b4ff */ 0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff, /* U+1b500 - U+1b51f */ 0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff, /* U+1b520 - U+1b53f */ 0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff, /* U+1b540 - U+1b55f */ 0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff, /* U+1b560 - U+1b57f */ 0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff, /* U+1b580 - U+1b59f */ 0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff, /* U+1b5a0 - U+1b5bf */ 0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff, /* U+1b5c0 - U+1b5df */ 0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff, /* U+1b5e0 - U+1b5ff */ 0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff, /* U+1b600 - U+1b61f */ 0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff, /* U+1b620 - U+1b63f */ 0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff, /* U+1b640 - U+1b65f */ 0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff, /* U+1b660 - U+1b67f */ 0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff, /* U+1b680 - U+1b69f */ 0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff, /* U+1b6a0 - U+1b6bf */ 0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff, /* U+1b6c0 - U+1b6df */ 0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff, /* U+1b6e0 - U+1b6ff */ 0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff, /* U+1b700 - U+1b71f */ 0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff, /* U+1b720 - U+1b73f */ 0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff, /* U+1b740 - U+1b75f */ 0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff, /* U+1b760 - U+1b77f */ 0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff, /* U+1b780 - U+1b79f */ 0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff, /* U+1b7a0 - U+1b7bf */ 0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff, /* U+1b7c0 - U+1b7df */ 0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff, /* U+1b7e0 - U+1b7ff */ 0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff, /* U+1b800 - U+1b81f */ 0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff, /* U+1b820 - U+1b83f */ 0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff, /* U+1b840 - U+1b85f */ 0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff, /* U+1b860 - U+1b87f */ 0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff, /* U+1b880 - U+1b89f */ 0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff, /* U+1b8a0 - U+1b8bf */ 0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff, /* U+1b8c0 - U+1b8df */ 0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff, /* U+1b8e0 - U+1b8ff */ 0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff, /* U+1b900 - U+1b91f */ 0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff, /* U+1b920 - U+1b93f */ 0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff, /* U+1b940 - U+1b95f */ 0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff, /* U+1b960 - U+1b97f */ 0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff, /* U+1b980 - U+1b99f */ 0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff, /* U+1b9a0 - U+1b9bf */ 0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff, /* U+1b9c0 - U+1b9df */ 0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff, /* U+1b9e0 - U+1b9ff */ 0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff, /* U+1ba00 - U+1ba1f */ 0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff, /* U+1ba20 - U+1ba3f */ 0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff, /* U+1ba40 - U+1ba5f */ 0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff, /* U+1ba60 - U+1ba7f */ 0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff, /* U+1ba80 - U+1ba9f */ 0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff, /* U+1baa0 - U+1babf */ 0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff, /* U+1bac0 - U+1badf */ 0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff, /* U+1bae0 - U+1baff */ 0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff, /* U+1bb00 - U+1bb1f */ 0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff, /* U+1bb20 - U+1bb3f */ 0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff, /* U+1bb40 - U+1bb5f */ 0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff, /* U+1bb60 - U+1bb7f */ 0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff, /* U+1bb80 - U+1bb9f */ 0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff, /* U+1bba0 - U+1bbbf */ 0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff, /* U+1bbc0 - U+1bbdf */ 0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff, /* U+1bbe0 - U+1bbff */ 0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff, /* U+1bc00 - U+1bc1f */ 0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff, /* U+1bc20 - U+1bc3f */ 0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff, /* U+1bc40 - U+1bc5f */ 0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff, /* U+1bc60 - U+1bc7f */ 0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff, /* U+1bc80 - U+1bc9f */ 0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff, /* U+1bca0 - U+1bcbf */ 0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff, /* U+1bcc0 - U+1bcdf */ 0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff, /* U+1bce0 - U+1bcff */ 0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff, /* U+1bd00 - U+1bd1f */ 0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff, /* U+1bd20 - U+1bd3f */ 0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff, /* U+1bd40 - U+1bd5f */ 0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff, /* U+1bd60 - U+1bd7f */ 0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff, /* U+1bd80 - U+1bd9f */ 0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff, /* U+1bda0 - U+1bdbf */ 0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff, /* U+1bdc0 - U+1bddf */ 0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff, /* U+1bde0 - U+1bdff */ 0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff, /* U+1be00 - U+1be1f */ 0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff, /* U+1be20 - U+1be3f */ 0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff, /* U+1be40 - U+1be5f */ 0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff, /* U+1be60 - U+1be7f */ 0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff, /* U+1be80 - U+1be9f */ 0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff, /* U+1bea0 - U+1bebf */ 0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff, /* U+1bec0 - U+1bedf */ 0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff, /* U+1bee0 - U+1beff */ 0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff, /* U+1bf00 - U+1bf1f */ 0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff, /* U+1bf20 - U+1bf3f */ 0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff, /* U+1bf40 - U+1bf5f */ 0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff, /* U+1bf60 - U+1bf7f */ 0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff, /* U+1bf80 - U+1bf9f */ 0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff, /* U+1bfa0 - U+1bfbf */ 0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff, /* U+1bfc0 - U+1bfdf */ 0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff, /* U+1bfe0 - U+1bfff */ 0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff, /* U+1c000 - U+1c01f */ 0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff, /* U+1c020 - U+1c03f */ 0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff, /* U+1c040 - U+1c05f */ 0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff, /* U+1c060 - U+1c07f */ 0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff, /* U+1c080 - U+1c09f */ 0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff, /* U+1c0a0 - U+1c0bf */ 0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff, /* U+1c0c0 - U+1c0df */ 0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff, /* U+1c0e0 - U+1c0ff */ 0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff, /* U+1c100 - U+1c11f */ 0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff, /* U+1c120 - U+1c13f */ 0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff, /* U+1c140 - U+1c15f */ 0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff, /* U+1c160 - U+1c17f */ 0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff, /* U+1c180 - U+1c19f */ 0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff, /* U+1c1a0 - U+1c1bf */ 0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff, /* U+1c1c0 - U+1c1df */ 0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff, /* U+1c1e0 - U+1c1ff */ 0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff, /* U+1c200 - U+1c21f */ 0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff, /* U+1c220 - U+1c23f */ 0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff, /* U+1c240 - U+1c25f */ 0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff, /* U+1c260 - U+1c27f */ 0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff, /* U+1c280 - U+1c29f */ 0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff, /* U+1c2a0 - U+1c2bf */ 0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff, /* U+1c2c0 - U+1c2df */ 0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff, /* U+1c2e0 - U+1c2ff */ 0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff, /* U+1c300 - U+1c31f */ 0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff, /* U+1c320 - U+1c33f */ 0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff, /* U+1c340 - U+1c35f */ 0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff, /* U+1c360 - U+1c37f */ 0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff, /* U+1c380 - U+1c39f */ 0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff, /* U+1c3a0 - U+1c3bf */ 0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff, /* U+1c3c0 - U+1c3df */ 0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff, /* U+1c3e0 - U+1c3ff */ 0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff, /* U+1c400 - U+1c41f */ 0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff, /* U+1c420 - U+1c43f */ 0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff, /* U+1c440 - U+1c45f */ 0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff, /* U+1c460 - U+1c47f */ 0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff, /* U+1c480 - U+1c49f */ 0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff, /* U+1c4a0 - U+1c4bf */ 0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff, /* U+1c4c0 - U+1c4df */ 0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff, /* U+1c4e0 - U+1c4ff */ 0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff, /* U+1c500 - U+1c51f */ 0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff, /* U+1c520 - U+1c53f */ 0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff, /* U+1c540 - U+1c55f */ 0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff, /* U+1c560 - U+1c57f */ 0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff, /* U+1c580 - U+1c59f */ 0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff, /* U+1c5a0 - U+1c5bf */ 0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff, /* U+1c5c0 - U+1c5df */ 0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff, /* U+1c5e0 - U+1c5ff */ 0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff, /* U+1c600 - U+1c61f */ 0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff, /* U+1c620 - U+1c63f */ 0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff, /* U+1c640 - U+1c65f */ 0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff, /* U+1c660 - U+1c67f */ 0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff, /* U+1c680 - U+1c69f */ 0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff, /* U+1c6a0 - U+1c6bf */ 0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff, /* U+1c6c0 - U+1c6df */ 0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff, /* U+1c6e0 - U+1c6ff */ 0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff, /* U+1c700 - U+1c71f */ 0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff, /* U+1c720 - U+1c73f */ 0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff, /* U+1c740 - U+1c75f */ 0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff, /* U+1c760 - U+1c77f */ 0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff, /* U+1c780 - U+1c79f */ 0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff, /* U+1c7a0 - U+1c7bf */ 0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff, /* U+1c7c0 - U+1c7df */ 0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff, /* U+1c7e0 - U+1c7ff */ 0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff, /* U+1c800 - U+1c81f */ 0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff, /* U+1c820 - U+1c83f */ 0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff, /* U+1c840 - U+1c85f */ 0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff, /* U+1c860 - U+1c87f */ 0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff, /* U+1c880 - U+1c89f */ 0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff, /* U+1c8a0 - U+1c8bf */ 0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff, /* U+1c8c0 - U+1c8df */ 0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff, /* U+1c8e0 - U+1c8ff */ 0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff, /* U+1c900 - U+1c91f */ 0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff, /* U+1c920 - U+1c93f */ 0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff, /* U+1c940 - U+1c95f */ 0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff, /* U+1c960 - U+1c97f */ 0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff, /* U+1c980 - U+1c99f */ 0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff, /* U+1c9a0 - U+1c9bf */ 0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff, /* U+1c9c0 - U+1c9df */ 0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff, /* U+1c9e0 - U+1c9ff */ 0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff, /* U+1ca00 - U+1ca1f */ 0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff, /* U+1ca20 - U+1ca3f */ 0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff, /* U+1ca40 - U+1ca5f */ 0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff, /* U+1ca60 - U+1ca7f */ 0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff, /* U+1ca80 - U+1ca9f */ 0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff, /* U+1caa0 - U+1cabf */ 0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff, /* U+1cac0 - U+1cadf */ 0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff, /* U+1cae0 - U+1caff */ 0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff, /* U+1cb00 - U+1cb1f */ 0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff, /* U+1cb20 - U+1cb3f */ 0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff, /* U+1cb40 - U+1cb5f */ 0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff, /* U+1cb60 - U+1cb7f */ 0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff, /* U+1cb80 - U+1cb9f */ 0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff, /* U+1cba0 - U+1cbbf */ 0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff, /* U+1cbc0 - U+1cbdf */ 0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff, /* U+1cbe0 - U+1cbff */ 0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff, /* U+1cc00 - U+1cc1f */ 0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff, /* U+1cc20 - U+1cc3f */ 0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff, /* U+1cc40 - U+1cc5f */ 0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff, /* U+1cc60 - U+1cc7f */ 0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff, /* U+1cc80 - U+1cc9f */ 0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff, /* U+1cca0 - U+1ccbf */ 0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff, /* U+1ccc0 - U+1ccdf */ 0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff, /* U+1cce0 - U+1ccff */ 0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff, /* U+1cd00 - U+1cd1f */ 0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff, /* U+1cd20 - U+1cd3f */ 0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff, /* U+1cd40 - U+1cd5f */ 0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff, /* U+1cd60 - U+1cd7f */ 0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff, /* U+1cd80 - U+1cd9f */ 0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff, /* U+1cda0 - U+1cdbf */ 0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff, /* U+1cdc0 - U+1cddf */ 0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff, /* U+1cde0 - U+1cdff */ 0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff, /* U+1ce00 - U+1ce1f */ 0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff, /* U+1ce20 - U+1ce3f */ 0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff, /* U+1ce40 - U+1ce5f */ 0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff, /* U+1ce60 - U+1ce7f */ 0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff, /* U+1ce80 - U+1ce9f */ 0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff, /* U+1cea0 - U+1cebf */ 0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff, /* U+1cec0 - U+1cedf */ 0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff, /* U+1cee0 - U+1ceff */ 0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff, /* U+1cf00 - U+1cf1f */ 0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff, /* U+1cf20 - U+1cf3f */ 0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff, /* U+1cf40 - U+1cf5f */ 0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff, /* U+1cf60 - U+1cf7f */ 0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff, /* U+1cf80 - U+1cf9f */ 0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff, /* U+1cfa0 - U+1cfbf */ 0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff, /* U+1cfc0 - U+1cfdf */ 0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff, /* U+1cfe0 - U+1cfff */ 0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff, /* U+1d000 - U+1d01f */ 0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff, /* U+1d020 - U+1d03f */ 0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff, /* U+1d040 - U+1d05f */ 0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff, /* U+1d060 - U+1d07f */ 0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff, /* U+1d080 - U+1d09f */ 0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff, /* U+1d0a0 - U+1d0bf */ 0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff, /* U+1d0c0 - U+1d0df */ 0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff, /* U+1d0e0 - U+1d0ff */ 0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff, /* U+1d100 - U+1d11f */ 0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff, /* U+1d120 - U+1d13f */ 0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff, /* U+1d140 - U+1d15f */ 0xff,0xfc,0x0f,0xff,0xfc,0x00,0x00,0x00, /* U+1d160 - U+1d17f */ 0x03,0xc0,0x00,0xff,0xff,0xff,0xff,0xff, /* U+1d180 - U+1d19f */ 0xff,0xff,0xf0,0x0f,0xff,0xff,0xff,0xff, /* U+1d1a0 - U+1d1bf */ 0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff, /* U+1d1c0 - U+1d1df */ 0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff, /* U+1d1e0 - U+1d1ff */ 0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff, /* U+1d200 - U+1d21f */ 0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff, /* U+1d220 - U+1d23f */ 0xf0,0x3f,0xff,0xff,0xff,0xff,0xff,0xff, /* U+1d240 - U+1d25f */ 0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff, /* U+1d260 - U+1d27f */ 0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff, /* U+1d280 - U+1d29f */ 0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff, /* U+1d2a0 - U+1d2bf */ 0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff, /* U+1d2c0 - U+1d2df */ 0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff, /* U+1d2e0 - U+1d2ff */ 0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff, /* U+1d300 - U+1d31f */ 0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff, /* U+1d320 - U+1d33f */ 0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff, /* U+1d340 - U+1d35f */ 0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff, /* U+1d360 - U+1d37f */ 0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff, /* U+1d380 - U+1d39f */ 0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff, /* U+1d3a0 - U+1d3bf */ 0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff, /* U+1d3c0 - U+1d3df */ 0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff, /* U+1d3e0 - U+1d3ff */ 0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff, /* U+1d400 - U+1d41f */ 0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff, /* U+1d420 - U+1d43f */ 0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff, /* U+1d440 - U+1d45f */ 0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff, /* U+1d460 - U+1d47f */ 0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff, /* U+1d480 - U+1d49f */ 0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff, /* U+1d4a0 - U+1d4bf */ 0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff, /* U+1d4c0 - U+1d4df */ 0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff, /* U+1d4e0 - U+1d4ff */ 0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff, /* U+1d500 - U+1d51f */ 0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff, /* U+1d520 - U+1d53f */ 0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff, /* U+1d540 - U+1d55f */ 0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff, /* U+1d560 - U+1d57f */ 0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff, /* U+1d580 - U+1d59f */ 0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff, /* U+1d5a0 - U+1d5bf */ 0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff, /* U+1d5c0 - U+1d5df */ 0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff, /* U+1d5e0 - U+1d5ff */ 0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff, /* U+1d600 - U+1d61f */ 0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff, /* U+1d620 - U+1d63f */ 0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff, /* U+1d640 - U+1d65f */ 0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff, /* U+1d660 - U+1d67f */ 0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff, /* U+1d680 - U+1d69f */ 0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff, /* U+1d6a0 - U+1d6bf */ 0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff, /* U+1d6c0 - U+1d6df */ 0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff, /* U+1d6e0 - U+1d6ff */ 0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff, /* U+1d700 - U+1d71f */ 0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff, /* U+1d720 - U+1d73f */ 0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff, /* U+1d740 - U+1d75f */ 0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff, /* U+1d760 - U+1d77f */ 0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff, /* U+1d780 - U+1d79f */ 0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff, /* U+1d7a0 - U+1d7bf */ 0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff, /* U+1d7c0 - U+1d7df */ 0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff, /* U+1d7e0 - U+1d7ff */ 0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff, /* U+1d800 - U+1d81f */ 0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff, /* U+1d820 - U+1d83f */ 0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff, /* U+1d840 - U+1d85f */ 0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff, /* U+1d860 - U+1d87f */ 0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff, /* U+1d880 - U+1d89f */ 0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff, /* U+1d8a0 - U+1d8bf */ 0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff, /* U+1d8c0 - U+1d8df */ 0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff, /* U+1d8e0 - U+1d8ff */ 0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff, /* U+1d900 - U+1d91f */ 0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff, /* U+1d920 - U+1d93f */ 0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff, /* U+1d940 - U+1d95f */ 0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff, /* U+1d960 - U+1d97f */ 0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff, /* U+1d980 - U+1d99f */ 0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff, /* U+1d9a0 - U+1d9bf */ 0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff, /* U+1d9c0 - U+1d9df */ 0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff, /* U+1d9e0 - U+1d9ff */ 0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff, /* U+1da00 - U+1da1f */ 0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff, /* U+1da20 - U+1da3f */ 0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff, /* U+1da40 - U+1da5f */ 0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff, /* U+1da60 - U+1da7f */ 0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff, /* U+1da80 - U+1da9f */ 0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff, /* U+1daa0 - U+1dabf */ 0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff, /* U+1dac0 - U+1dadf */ 0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff, /* U+1dae0 - U+1daff */ 0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff, /* U+1db00 - U+1db1f */ 0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff, /* U+1db20 - U+1db3f */ 0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff, /* U+1db40 - U+1db5f */ 0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff, /* U+1db60 - U+1db7f */ 0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff, /* U+1db80 - U+1db9f */ 0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff, /* U+1dba0 - U+1dbbf */ 0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff, /* U+1dbc0 - U+1dbdf */ 0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff, /* U+1dbe0 - U+1dbff */ 0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff, /* U+1dc00 - U+1dc1f */ 0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff, /* U+1dc20 - U+1dc3f */ 0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff, /* U+1dc40 - U+1dc5f */ 0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff, /* U+1dc60 - U+1dc7f */ 0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff, /* U+1dc80 - U+1dc9f */ 0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff, /* U+1dca0 - U+1dcbf */ 0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff, /* U+1dcc0 - U+1dcdf */ 0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff, /* U+1dce0 - U+1dcff */ 0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff, /* U+1dd00 - U+1dd1f */ 0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff, /* U+1dd20 - U+1dd3f */ 0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff, /* U+1dd40 - U+1dd5f */ 0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff, /* U+1dd60 - U+1dd7f */ 0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff, /* U+1dd80 - U+1dd9f */ 0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff, /* U+1dda0 - U+1ddbf */ 0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff, /* U+1ddc0 - U+1dddf */ 0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff, /* U+1dde0 - U+1ddff */ 0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff, /* U+1de00 - U+1de1f */ 0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff, /* U+1de20 - U+1de3f */ 0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff, /* U+1de40 - U+1de5f */ 0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff, /* U+1de60 - U+1de7f */ 0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff, /* U+1de80 - U+1de9f */ 0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff, /* U+1dea0 - U+1debf */ 0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff, /* U+1dec0 - U+1dedf */ 0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff, /* U+1dee0 - U+1deff */ 0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff, /* U+1df00 - U+1df1f */ 0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff, /* U+1df20 - U+1df3f */ 0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff, /* U+1df40 - U+1df5f */ 0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff, /* U+1df60 - U+1df7f */ 0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff, /* U+1df80 - U+1df9f */ 0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff, /* U+1dfa0 - U+1dfbf */ 0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff, /* U+1dfc0 - U+1dfdf */ 0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff, /* U+1dfe0 - U+1dfff */ 0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff, /* U+1e000 - U+1e01f */ 0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff, /* U+1e020 - U+1e03f */ 0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff, /* U+1e040 - U+1e05f */ 0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff, /* U+1e060 - U+1e07f */ 0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff, /* U+1e080 - U+1e09f */ 0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff, /* U+1e0a0 - U+1e0bf */ 0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff, /* U+1e0c0 - U+1e0df */ 0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff, /* U+1e0e0 - U+1e0ff */ 0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff, /* U+1e100 - U+1e11f */ 0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff, /* U+1e120 - U+1e13f */ 0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff, /* U+1e140 - U+1e15f */ 0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff, /* U+1e160 - U+1e17f */ 0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff, /* U+1e180 - U+1e19f */ 0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff, /* U+1e1a0 - U+1e1bf */ 0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff, /* U+1e1c0 - U+1e1df */ 0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff, /* U+1e1e0 - U+1e1ff */ 0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff, /* U+1e200 - U+1e21f */ 0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff, /* U+1e220 - U+1e23f */ 0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff, /* U+1e240 - U+1e25f */ 0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff, /* U+1e260 - U+1e27f */ 0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff, /* U+1e280 - U+1e29f */ 0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff, /* U+1e2a0 - U+1e2bf */ 0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff, /* U+1e2c0 - U+1e2df */ 0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff, /* U+1e2e0 - U+1e2ff */ 0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff, /* U+1e300 - U+1e31f */ 0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff, /* U+1e320 - U+1e33f */ 0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff, /* U+1e340 - U+1e35f */ 0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff, /* U+1e360 - U+1e37f */ 0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff, /* U+1e380 - U+1e39f */ 0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff, /* U+1e3a0 - U+1e3bf */ 0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff, /* U+1e3c0 - U+1e3df */ 0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff, /* U+1e3e0 - U+1e3ff */ 0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff, /* U+1e400 - U+1e41f */ 0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff, /* U+1e420 - U+1e43f */ 0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff, /* U+1e440 - U+1e45f */ 0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff, /* U+1e460 - U+1e47f */ 0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff, /* U+1e480 - U+1e49f */ 0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff, /* U+1e4a0 - U+1e4bf */ 0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff, /* U+1e4c0 - U+1e4df */ 0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff, /* U+1e4e0 - U+1e4ff */ 0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff, /* U+1e500 - U+1e51f */ 0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff, /* U+1e520 - U+1e53f */ 0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff, /* U+1e540 - U+1e55f */ 0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff, /* U+1e560 - U+1e57f */ 0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff, /* U+1e580 - U+1e59f */ 0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff, /* U+1e5a0 - U+1e5bf */ 0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff, /* U+1e5c0 - U+1e5df */ 0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff, /* U+1e5e0 - U+1e5ff */ 0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff, /* U+1e600 - U+1e61f */ 0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff, /* U+1e620 - U+1e63f */ 0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff, /* U+1e640 - U+1e65f */ 0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff, /* U+1e660 - U+1e67f */ 0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff, /* U+1e680 - U+1e69f */ 0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff, /* U+1e6a0 - U+1e6bf */ 0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff, /* U+1e6c0 - U+1e6df */ 0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff, /* U+1e6e0 - U+1e6ff */ 0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff, /* U+1e700 - U+1e71f */ 0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff, /* U+1e720 - U+1e73f */ 0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff, /* U+1e740 - U+1e75f */ 0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff, /* U+1e760 - U+1e77f */ 0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff, /* U+1e780 - U+1e79f */ 0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff, /* U+1e7a0 - U+1e7bf */ 0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff, /* U+1e7c0 - U+1e7df */ 0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff, /* U+1e7e0 - U+1e7ff */ 0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff, /* U+1e800 - U+1e81f */ 0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff, /* U+1e820 - U+1e83f */ 0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff, /* U+1e840 - U+1e85f */ 0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff, /* U+1e860 - U+1e87f */ 0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff, /* U+1e880 - U+1e89f */ 0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff, /* U+1e8a0 - U+1e8bf */ 0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff, /* U+1e8c0 - U+1e8df */ 0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff, /* U+1e8e0 - U+1e8ff */ 0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff, /* U+1e900 - U+1e91f */ 0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff, /* U+1e920 - U+1e93f */ 0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff, /* U+1e940 - U+1e95f */ 0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff, /* U+1e960 - U+1e97f */ 0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff, /* U+1e980 - U+1e99f */ 0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff, /* U+1e9a0 - U+1e9bf */ 0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff, /* U+1e9c0 - U+1e9df */ 0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff, /* U+1e9e0 - U+1e9ff */ 0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff, /* U+1ea00 - U+1ea1f */ 0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff, /* U+1ea20 - U+1ea3f */ 0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff, /* U+1ea40 - U+1ea5f */ 0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff, /* U+1ea60 - U+1ea7f */ 0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff, /* U+1ea80 - U+1ea9f */ 0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff, /* U+1eaa0 - U+1eabf */ 0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff, /* U+1eac0 - U+1eadf */ 0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff, /* U+1eae0 - U+1eaff */ 0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff, /* U+1eb00 - U+1eb1f */ 0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff, /* U+1eb20 - U+1eb3f */ 0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff, /* U+1eb40 - U+1eb5f */ 0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff, /* U+1eb60 - U+1eb7f */ 0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff, /* U+1eb80 - U+1eb9f */ 0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff, /* U+1eba0 - U+1ebbf */ 0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff, /* U+1ebc0 - U+1ebdf */ 0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff, /* U+1ebe0 - U+1ebff */ 0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff, /* U+1ec00 - U+1ec1f */ 0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff, /* U+1ec20 - U+1ec3f */ 0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff, /* U+1ec40 - U+1ec5f */ 0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff, /* U+1ec60 - U+1ec7f */ 0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff, /* U+1ec80 - U+1ec9f */ 0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff, /* U+1eca0 - U+1ecbf */ 0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff, /* U+1ecc0 - U+1ecdf */ 0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff, /* U+1ece0 - U+1ecff */ 0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff, /* U+1ed00 - U+1ed1f */ 0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff, /* U+1ed20 - U+1ed3f */ 0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff, /* U+1ed40 - U+1ed5f */ 0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff, /* U+1ed60 - U+1ed7f */ 0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff, /* U+1ed80 - U+1ed9f */ 0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff, /* U+1eda0 - U+1edbf */ 0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff, /* U+1edc0 - U+1eddf */ 0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff, /* U+1ede0 - U+1edff */ 0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff, /* U+1ee00 - U+1ee1f */ 0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff, /* U+1ee20 - U+1ee3f */ 0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff, /* U+1ee40 - U+1ee5f */ 0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff, /* U+1ee60 - U+1ee7f */ 0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff, /* U+1ee80 - U+1ee9f */ 0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff, /* U+1eea0 - U+1eebf */ 0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff, /* U+1eec0 - U+1eedf */ 0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff, /* U+1eee0 - U+1eeff */ 0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff, /* U+1ef00 - U+1ef1f */ 0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff, /* U+1ef20 - U+1ef3f */ 0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff, /* U+1ef40 - U+1ef5f */ 0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff, /* U+1ef60 - U+1ef7f */ 0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff, /* U+1ef80 - U+1ef9f */ 0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff, /* U+1efa0 - U+1efbf */ 0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff, /* U+1efc0 - U+1efdf */ 0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff, /* U+1efe0 - U+1efff */ 0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff, /* U+1f000 - U+1f01f */ 0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff, /* U+1f020 - U+1f03f */ 0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff, /* U+1f040 - U+1f05f */ 0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff, /* U+1f060 - U+1f07f */ 0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff, /* U+1f080 - U+1f09f */ 0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff, /* U+1f0a0 - U+1f0bf */ 0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff, /* U+1f0c0 - U+1f0df */ 0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff, /* U+1f0e0 - U+1f0ff */ 0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff, /* U+1f100 - U+1f11f */ 0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff, /* U+1f120 - U+1f13f */ 0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff, /* U+1f140 - U+1f15f */ 0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff, /* U+1f160 - U+1f17f */ 0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff, /* U+1f180 - U+1f19f */ 0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff, /* U+1f1a0 - U+1f1bf */ 0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff, /* U+1f1c0 - U+1f1df */ 0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff, /* U+1f1e0 - U+1f1ff */ 0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff, /* U+1f200 - U+1f21f */ 0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff, /* U+1f220 - U+1f23f */ 0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff, /* U+1f240 - U+1f25f */ 0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff, /* U+1f260 - U+1f27f */ 0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff, /* U+1f280 - U+1f29f */ 0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff, /* U+1f2a0 - U+1f2bf */ 0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff, /* U+1f2c0 - U+1f2df */ 0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff, /* U+1f2e0 - U+1f2ff */ 0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff, /* U+1f300 - U+1f31f */ 0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff, /* U+1f320 - U+1f33f */ 0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff, /* U+1f340 - U+1f35f */ 0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff, /* U+1f360 - U+1f37f */ 0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff, /* U+1f380 - U+1f39f */ 0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff, /* U+1f3a0 - U+1f3bf */ 0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff, /* U+1f3c0 - U+1f3df */ 0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff, /* U+1f3e0 - U+1f3ff */ 0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff, /* U+1f400 - U+1f41f */ 0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff, /* U+1f420 - U+1f43f */ 0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff, /* U+1f440 - U+1f45f */ 0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff, /* U+1f460 - U+1f47f */ 0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff, /* U+1f480 - U+1f49f */ 0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff, /* U+1f4a0 - U+1f4bf */ 0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff, /* U+1f4c0 - U+1f4df */ 0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff, /* U+1f4e0 - U+1f4ff */ 0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff, /* U+1f500 - U+1f51f */ 0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff, /* U+1f520 - U+1f53f */ 0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff, /* U+1f540 - U+1f55f */ 0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff, /* U+1f560 - U+1f57f */ 0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff, /* U+1f580 - U+1f59f */ 0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff, /* U+1f5a0 - U+1f5bf */ 0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff, /* U+1f5c0 - U+1f5df */ 0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff, /* U+1f5e0 - U+1f5ff */ 0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff, /* U+1f600 - U+1f61f */ 0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff, /* U+1f620 - U+1f63f */ 0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff, /* U+1f640 - U+1f65f */ 0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff, /* U+1f660 - U+1f67f */ 0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff, /* U+1f680 - U+1f69f */ 0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff, /* U+1f6a0 - U+1f6bf */ 0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff, /* U+1f6c0 - U+1f6df */ 0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff, /* U+1f6e0 - U+1f6ff */ 0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff, /* U+1f700 - U+1f71f */ 0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff, /* U+1f720 - U+1f73f */ 0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff, /* U+1f740 - U+1f75f */ 0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff, /* U+1f760 - U+1f77f */ 0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff, /* U+1f780 - U+1f79f */ 0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff, /* U+1f7a0 - U+1f7bf */ 0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff, /* U+1f7c0 - U+1f7df */ 0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff, /* U+1f7e0 - U+1f7ff */ 0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff, /* U+1f800 - U+1f81f */ 0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff, /* U+1f820 - U+1f83f */ 0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff, /* U+1f840 - U+1f85f */ 0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff, /* U+1f860 - U+1f87f */ 0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff, /* U+1f880 - U+1f89f */ 0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff, /* U+1f8a0 - U+1f8bf */ 0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff, /* U+1f8c0 - U+1f8df */ 0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff, /* U+1f8e0 - U+1f8ff */ 0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff, /* U+1f900 - U+1f91f */ 0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff, /* U+1f920 - U+1f93f */ 0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff, /* U+1f940 - U+1f95f */ 0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff, /* U+1f960 - U+1f97f */ 0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff, /* U+1f980 - U+1f99f */ 0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff, /* U+1f9a0 - U+1f9bf */ 0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff, /* U+1f9c0 - U+1f9df */ 0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff, /* U+1f9e0 - U+1f9ff */ 0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff, /* U+1fa00 - U+1fa1f */ 0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff, /* U+1fa20 - U+1fa3f */ 0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff, /* U+1fa40 - U+1fa5f */ 0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff, /* U+1fa60 - U+1fa7f */ 0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff, /* U+1fa80 - U+1fa9f */ 0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff, /* U+1faa0 - U+1fabf */ 0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff, /* U+1fac0 - U+1fadf */ 0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff, /* U+1fae0 - U+1faff */ 0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff, /* U+1fb00 - U+1fb1f */ 0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff, /* U+1fb20 - U+1fb3f */ 0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff, /* U+1fb40 - U+1fb5f */ 0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff, /* U+1fb60 - U+1fb7f */ 0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff, /* U+1fb80 - U+1fb9f */ 0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff, /* U+1fba0 - U+1fbbf */ 0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff, /* U+1fbc0 - U+1fbdf */ 0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff, /* U+1fbe0 - U+1fbff */ 0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff, /* U+1fc00 - U+1fc1f */ 0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff, /* U+1fc20 - U+1fc3f */ 0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff, /* U+1fc40 - U+1fc5f */ 0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff, /* U+1fc60 - U+1fc7f */ 0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff, /* U+1fc80 - U+1fc9f */ 0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff, /* U+1fca0 - U+1fcbf */ 0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff, /* U+1fcc0 - U+1fcdf */ 0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff, /* U+1fce0 - U+1fcff */ 0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff, /* U+1fd00 - U+1fd1f */ 0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff, /* U+1fd20 - U+1fd3f */ 0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff, /* U+1fd40 - U+1fd5f */ 0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff, /* U+1fd60 - U+1fd7f */ 0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff, /* U+1fd80 - U+1fd9f */ 0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff, /* U+1fda0 - U+1fdbf */ 0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff, /* U+1fdc0 - U+1fddf */ 0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff, /* U+1fde0 - U+1fdff */ 0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff, /* U+1fe00 - U+1fe1f */ 0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff, /* U+1fe20 - U+1fe3f */ 0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff, /* U+1fe40 - U+1fe5f */ 0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff, /* U+1fe60 - U+1fe7f */ 0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff, /* U+1fe80 - U+1fe9f */ 0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff, /* U+1fea0 - U+1febf */ 0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff, /* U+1fec0 - U+1fedf */ 0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff, /* U+1fee0 - U+1feff */ 0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff, /* U+1ff00 - U+1ff1f */ 0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff, /* U+1ff20 - U+1ff3f */ 0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff, /* U+1ff40 - U+1ff5f */ 0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff, /* U+1ff60 - U+1ff7f */ 0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff, /* U+1ff80 - U+1ff9f */ 0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff, /* U+1ffa0 - U+1ffbf */ 0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff, /* U+1ffc0 - U+1ffdf */ 0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff /* U+1ffe0 - U+1ffff */ }; alpine-2.10+dfsg/imap/src/charset/koi8_r.c0000600000175000017500000000341611512502123022044 0ustar paulproteuspaulproteus/* ======================================================================== * Copyright 1988-2006 University of Washington * * Licensed under the Apache License, Version 2.0 (the "License"); * you may not use this file except in compliance with the License. * You may obtain a copy of the License at * * http://www.apache.org/licenses/LICENSE-2.0 * * * ======================================================================== */ /* * Program: KOI8-R conversion table * * Author: Mark Crispin * Networks and Distributed Computing * Computing & Communications * University of Washington * Administration Building, AG-44 * Seattle, WA 98195 * Internet: MRC@CAC.Washington.EDU * * Date: 3 July 1997 * Last Edited: 30 August 2006 */ /* KOI8-R is a de-facto standard of Russia */ static const unsigned short koi8rtab[128] = { 0x2500,0x2502,0x250c,0x2510,0x2514,0x2518,0x251c,0x2524, 0x252c,0x2534,0x253c,0x2580,0x2584,0x2588,0x258c,0x2590, 0x2591,0x2592,0x2593,0x2320,0x25a0,0x2219,0x221a,0x2248, 0x2264,0x2265,0x00a0,0x2321,0x00b0,0x00b2,0x00b7,0x00f7, 0x2550,0x2551,0x2552,0x0451,0x2553,0x2554,0x2555,0x2556, 0x2557,0x2558,0x2559,0x255a,0x255b,0x255c,0x255d,0x255e, 0x255f,0x2560,0x2561,0x0401,0x2562,0x2563,0x2564,0x2565, 0x2566,0x2567,0x2568,0x2569,0x256a,0x256b,0x256c,0x00a9, 0x044e,0x0430,0x0431,0x0446,0x0434,0x0435,0x0444,0x0433, 0x0445,0x0438,0x0439,0x043a,0x043b,0x043c,0x043d,0x043e, 0x043f,0x044f,0x0440,0x0441,0x0442,0x0443,0x0436,0x0432, 0x044c,0x044b,0x0437,0x0448,0x044d,0x0449,0x0447,0x044a, 0x042e,0x0410,0x0411,0x0426,0x0414,0x0415,0x0424,0x0413, 0x0425,0x0418,0x0419,0x041a,0x041b,0x041c,0x041d,0x041e, 0x041f,0x042f,0x0420,0x0421,0x0422,0x0423,0x0416,0x0412, 0x042c,0x042b,0x0417,0x0428,0x042d,0x0429,0x0427,0x042a }; alpine-2.10+dfsg/imap/src/charset/gb_12345.c0000600000175000017500000020147411512502123022003 0ustar paulproteuspaulproteus/* ======================================================================== * Copyright 1988-2006 University of Washington * * Licensed under the Apache License, Version 2.0 (the "License"); * you may not use this file except in compliance with the License. * You may obtain a copy of the License at * * http://www.apache.org/licenses/LICENSE-2.0 * * * ======================================================================== */ /* * Program: GB 12345 conversion table * * Author: Mark Crispin * Networks and Distributed Computing * Computing & Communications * University of Washington * Administration Building, AG-44 * Seattle, WA 98195 * Internet: MRC@CAC.Washington.EDU * * Date: 15 May 1998 * Last Edited: 30 August 2006 */ /* GB 12345 is the national standard of the People's Republic of China * (mainland China) for traditional Chinese characters. */ #define BASE_GB12345_KU 0xa1 #define BASE_GB12345_TEN 0xa1 #define MAX_GB12345_KU 89 #define MAX_GB12345_TEN 94 #define GB12345TOUNICODE(c,c1,ku,ten) \ ((((ku = (c & 0x7f) - BASE_GB12345_KU) < MAX_GB12345_KU) && \ ((ten = (c1 & 0x7f) - BASE_GB12345_TEN) < MAX_GB12345_TEN)) ? \ gb12345tab[ku][ten] : UBOGON) static const unsigned short gb12345tab[MAX_GB12345_KU][MAX_GB12345_TEN] = { { /* ku 01 */ 0x3000,0x3001,0x3002,0x30fb,0x02c9,0x02c7,0x00a8,0x3003,0x3005,0x2015, 0xff5e,0x2225,0x2026,0x2018,0x2019,0x201c,0x201d,0x3014,0x3015,0x3008, 0x3009,0x300a,0x300b,0x300c,0x300d,0x300e,0x300f,0x3016,0x3017,0x3010, 0x3011,0x00b1,0x00d7,0x00f7,0x2236,0x2227,0x2228,0x2211,0x220f,0x222a, 0x2229,0x2208,0x2237,0x221a,0x22a5,0x2225,0x2220,0x2312,0x2299,0x222b, 0x222e,0x2261,0x224c,0x2248,0x223d,0x221d,0x2260,0x226e,0x226f,0x2264, 0x2265,0x221e,0x2235,0x2234,0x2642,0x2640,0x00b0,0x2032,0x2033,0x2103, 0xff04,0x00a4,0xffe0,0xffe1,0x2030,0x00a7,0x2116,0x2606,0x2605,0x25cb, 0x25cf,0x25ce,0x25c7,0x25c6,0x25a1,0x25a0,0x25b3,0x25b2,0x203b,0x2192, 0x2190,0x2191,0x2193,0x3013 }, { /* ku 02 */ UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON, UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,0x2488,0x2489,0x248a,0x248b, 0x248c,0x248d,0x248e,0x248f,0x2490,0x2491,0x2492,0x2493,0x2494,0x2495, 0x2496,0x2497,0x2498,0x2499,0x249a,0x249b,0x2474,0x2475,0x2476,0x2477, 0x2478,0x2479,0x247a,0x247b,0x247c,0x247d,0x247e,0x247f,0x2480,0x2481, 0x2482,0x2483,0x2484,0x2485,0x2486,0x2487,0x2460,0x2461,0x2462,0x2463, 0x2464,0x2465,0x2466,0x2467,0x2468,0x2469,UBOGON,UBOGON,0x3220,0x3221, 0x3222,0x3223,0x3224,0x3225,0x3226,0x3227,0x3228,0x3229,UBOGON,UBOGON, 0x2160,0x2161,0x2162,0x2163,0x2164,0x2165,0x2166,0x2167,0x2168,0x2169, 0x216a,0x216b,UBOGON,UBOGON }, { /* ku 03 */ 0xff01,0xff02,0xff03,0xffe5,0xff05,0xff06,0xff07,0xff08,0xff09,0xff0a, 0xff0b,0xff0c,0xff0d,0xff0e,0xff0f,0xff10,0xff11,0xff12,0xff13,0xff14, 0xff15,0xff16,0xff17,0xff18,0xff19,0xff1a,0xff1b,0xff1c,0xff1d,0xff1e, 0xff1f,0xff20,0xff21,0xff22,0xff23,0xff24,0xff25,0xff26,0xff27,0xff28, 0xff29,0xff2a,0xff2b,0xff2c,0xff2d,0xff2e,0xff2f,0xff30,0xff31,0xff32, 0xff33,0xff34,0xff35,0xff36,0xff37,0xff38,0xff39,0xff3a,0xff3b,0xff3c, 0xff3d,0xff3e,0xff3f,0xff40,0xff41,0xff42,0xff43,0xff44,0xff45,0xff46, 0xff47,0xff48,0xff49,0xff4a,0xff4b,0xff4c,0xff4d,0xff4e,0xff4f,0xff50, 0xff51,0xff52,0xff53,0xff54,0xff55,0xff56,0xff57,0xff58,0xff59,0xff5a, 0xff5b,0xff5c,0xff5d,0xffe3 }, { /* ku 04 */ 0x3041,0x3042,0x3043,0x3044,0x3045,0x3046,0x3047,0x3048,0x3049,0x304a, 0x304b,0x304c,0x304d,0x304e,0x304f,0x3050,0x3051,0x3052,0x3053,0x3054, 0x3055,0x3056,0x3057,0x3058,0x3059,0x305a,0x305b,0x305c,0x305d,0x305e, 0x305f,0x3060,0x3061,0x3062,0x3063,0x3064,0x3065,0x3066,0x3067,0x3068, 0x3069,0x306a,0x306b,0x306c,0x306d,0x306e,0x306f,0x3070,0x3071,0x3072, 0x3073,0x3074,0x3075,0x3076,0x3077,0x3078,0x3079,0x307a,0x307b,0x307c, 0x307d,0x307e,0x307f,0x3080,0x3081,0x3082,0x3083,0x3084,0x3085,0x3086, 0x3087,0x3088,0x3089,0x308a,0x308b,0x308c,0x308d,0x308e,0x308f,0x3090, 0x3091,0x3092,0x3093,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON, UBOGON,UBOGON,UBOGON,UBOGON }, { /* ku 05 */ 0x30a1,0x30a2,0x30a3,0x30a4,0x30a5,0x30a6,0x30a7,0x30a8,0x30a9,0x30aa, 0x30ab,0x30ac,0x30ad,0x30ae,0x30af,0x30b0,0x30b1,0x30b2,0x30b3,0x30b4, 0x30b5,0x30b6,0x30b7,0x30b8,0x30b9,0x30ba,0x30bb,0x30bc,0x30bd,0x30be, 0x30bf,0x30c0,0x30c1,0x30c2,0x30c3,0x30c4,0x30c5,0x30c6,0x30c7,0x30c8, 0x30c9,0x30ca,0x30cb,0x30cc,0x30cd,0x30ce,0x30cf,0x30d0,0x30d1,0x30d2, 0x30d3,0x30d4,0x30d5,0x30d6,0x30d7,0x30d8,0x30d9,0x30da,0x30db,0x30dc, 0x30dd,0x30de,0x30df,0x30e0,0x30e1,0x30e2,0x30e3,0x30e4,0x30e5,0x30e6, 0x30e7,0x30e8,0x30e9,0x30ea,0x30eb,0x30ec,0x30ed,0x30ee,0x30ef,0x30f0, 0x30f1,0x30f2,0x30f3,0x30f4,0x30f5,0x30f6,UBOGON,UBOGON,UBOGON,UBOGON, UBOGON,UBOGON,UBOGON,UBOGON }, { /* ku 06 */ 0x0391,0x0392,0x0393,0x0394,0x0395,0x0396,0x0397,0x0398,0x0399,0x039a, 0x039b,0x039c,0x039d,0x039e,0x039f,0x03a0,0x03a1,0x03a3,0x03a4,0x03a5, 0x03a6,0x03a7,0x03a8,0x03a9,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON, UBOGON,UBOGON,0x03b1,0x03b2,0x03b3,0x03b4,0x03b5,0x03b6,0x03b7,0x03b8, 0x03b9,0x03ba,0x03bb,0x03bc,0x03bd,0x03be,0x03bf,0x03c0,0x03c1,0x03c3, 0x03c4,0x03c5,0x03c6,0x03c7,0x03c8,0x03c9,UBOGON,UBOGON,UBOGON,UBOGON, UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON, UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON, UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON, UBOGON,UBOGON,UBOGON,UBOGON }, { /* ku 07 */ 0x0410,0x0411,0x0412,0x0413,0x0414,0x0415,0x0401,0x0416,0x0417,0x0418, 0x0419,0x041a,0x041b,0x041c,0x041d,0x041e,0x041f,0x0420,0x0421,0x0422, 0x0423,0x0424,0x0425,0x0426,0x0427,0x0428,0x0429,0x042a,0x042b,0x042c, 0x042d,0x042e,0x042f,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON, UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,0x0430,0x0431, 0x0432,0x0433,0x0434,0x0435,0x0451,0x0436,0x0437,0x0438,0x0439,0x043a, 0x043b,0x043c,0x043d,0x043e,0x043f,0x0440,0x0441,0x0442,0x0443,0x0444, 0x0445,0x0446,0x0447,0x0448,0x0449,0x044a,0x044b,0x044c,0x044d,0x044e, 0x044f,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON, UBOGON,UBOGON,UBOGON,UBOGON }, { /* ku 08 */ 0x0101,0x00e1,0x01ce,0x00e0,0x0113,0x00e9,0x011b,0x00e8,0x012b,0x00ed, 0x01d0,0x00ec,0x014d,0x00f3,0x01d2,0x00f2,0x016b,0x00fa,0x01d4,0x00f9, 0x01d6,0x01d8,0x01da,0x01dc,0x00fc,0x00ea,UBOGON,UBOGON,UBOGON,UBOGON, UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,0x3105,0x3106,0x3107,0x3108, 0x3109,0x310a,0x310b,0x310c,0x310d,0x310e,0x310f,0x3110,0x3111,0x3112, 0x3113,0x3114,0x3115,0x3116,0x3117,0x3118,0x3119,0x311a,0x311b,0x311c, 0x311d,0x311e,0x311f,0x3120,0x3121,0x3122,0x3123,0x3124,0x3125,0x3126, 0x3127,0x3128,0x3129,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON, UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON, UBOGON,UBOGON,UBOGON,UBOGON }, { /* ku 09 */ UBOGON,UBOGON,UBOGON,0x2500,0x2501,0x2502,0x2503,0x2504,0x2505,0x2506, 0x2507,0x2508,0x2509,0x250a,0x250b,0x250c,0x250d,0x250e,0x250f,0x2510, 0x2511,0x2512,0x2513,0x2514,0x2515,0x2516,0x2517,0x2518,0x2519,0x251a, 0x251b,0x251c,0x251d,0x251e,0x251f,0x2520,0x2521,0x2522,0x2523,0x2524, 0x2525,0x2526,0x2527,0x2528,0x2529,0x252a,0x252b,0x252c,0x252d,0x252e, 0x252f,0x2530,0x2531,0x2532,0x2533,0x2534,0x2535,0x2536,0x2537,0x2538, 0x2539,0x253a,0x253b,0x253c,0x253d,0x253e,0x253f,0x2540,0x2541,0x2542, 0x2543,0x2544,0x2545,0x2546,0x2547,0x2548,0x2549,0x254a,0x254b,UBOGON, UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON, UBOGON,UBOGON,UBOGON,UBOGON }, { /* ku 0a */ UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON, UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON, UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON, UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON, UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON, UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON, UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON, UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON, UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON, UBOGON,UBOGON,UBOGON,UBOGON }, { /* ku 0b */ UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON, UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON, UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON, UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON, UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON, UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON, UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON, UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON, UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON, UBOGON,UBOGON,UBOGON,UBOGON }, { /* ku 0c */ UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON, UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON, UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON, UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON, UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON, UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON, UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON, UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON, UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON, UBOGON,UBOGON,UBOGON,UBOGON }, { /* ku 0d */ UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON, UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON, UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON, UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON, UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON, UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON, UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON, UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON, UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON, UBOGON,UBOGON,UBOGON,UBOGON }, { /* ku 0e */ UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON, UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON, UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON, UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON, UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON, UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON, UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON, UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON, UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON, UBOGON,UBOGON,UBOGON,UBOGON }, { /* ku 0f */ UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON, UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON, UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON, UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON, UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON, UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON, UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON, UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON, UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON, UBOGON,UBOGON,UBOGON,UBOGON }, { /* ku 10 */ 0x554a,0x963f,0x57c3,0x6328,0x54ce,0x5509,0x54c0,0x769a,0x764c,0x85f9, 0x77ee,0x827e,0x7919,0x611b,0x9698,0x978d,0x6c28,0x5b89,0x4ffa,0x6309, 0x6697,0x5cb8,0x80fa,0x6848,0x9aaf,0x6602,0x76ce,0x51f9,0x6556,0x71ac, 0x7ff1,0x8956,0x50b2,0x5965,0x61ca,0x6fb3,0x82ad,0x634c,0x6252,0x53ed, 0x5427,0x7b06,0x516b,0x75a4,0x5df4,0x62d4,0x8dcb,0x9776,0x628a,0x8019, 0x58e9,0x9738,0x7f77,0x7238,0x767d,0x67cf,0x767e,0x64fa,0x4f70,0x6557, 0x62dc,0x7a17,0x6591,0x73ed,0x642c,0x6273,0x822c,0x9812,0x677f,0x7248, 0x626e,0x62cc,0x4f34,0x74e3,0x534a,0x8fa6,0x7d46,0x90a6,0x5e6b,0x6886, 0x699c,0x8180,0x7d81,0x68d2,0x78c5,0x868c,0x938a,0x508d,0x8b17,0x82de, 0x80de,0x5305,0x8912,0x5265 }, { /* ku 11 */ 0x8584,0x96f9,0x4fdd,0x5821,0x98fd,0x5bf6,0x62b1,0x5831,0x66b4,0x8c79, 0x9b91,0x7206,0x676f,0x7891,0x60b2,0x5351,0x5317,0x8f29,0x80cc,0x8c9d, 0x92c7,0x500d,0x72fd,0x5099,0x618a,0x7119,0x88ab,0x5954,0x82ef,0x672c, 0x7b28,0x5d29,0x7db3,0x752d,0x6cf5,0x8e66,0x8ff8,0x903c,0x9f3b,0x6bd4, 0x9119,0x7b46,0x5f7c,0x78a7,0x84d6,0x853d,0x7562,0x6583,0x6bd6,0x5e63, 0x5e87,0x75f9,0x9589,0x655d,0x5f0a,0x5fc5,0x8f9f,0x58c1,0x81c2,0x907f, 0x965b,0x97ad,0x908a,0x7de8,0x8cb6,0x6241,0x4fbf,0x8b8a,0x535e,0x8fa8, 0x8faf,0x8fae,0x904d,0x6a19,0x5f6a,0x8198,0x8868,0x9c49,0x618b,0x522b, 0x765f,0x5f6c,0x658c,0x7015,0x6ff1,0x8cd3,0x64ef,0x5175,0x51b0,0x67c4, 0x4e19,0x79c9,0x9905,0x70b3 }, { /* ku 12 */ 0x75c5,0x5e76,0x73bb,0x83e0,0x64ad,0x64a5,0x9262,0x6ce2,0x535a,0x52c3, 0x640f,0x9251,0x7b94,0x4f2f,0x5e1b,0x8236,0x8116,0x818a,0x6e24,0x6cca, 0x99c1,0x6355,0x535c,0x54fa,0x88dc,0x57e0,0x4e0d,0x5e03,0x6b65,0x7c3f, 0x90e8,0x6016,0x64e6,0x731c,0x88c1,0x6750,0x624d,0x8ca1,0x776c,0x8e29, 0x91c7,0x5f69,0x83dc,0x8521,0x9910,0x53c3,0x8836,0x6b98,0x615a,0x6158, 0x71e6,0x84bc,0x8259,0x5009,0x6ec4,0x85cf,0x64cd,0x7cd9,0x69fd,0x66f9, 0x8349,0x53a0,0x7b56,0x5074,0x518c,0x6e2c,0x5c64,0x8e6d,0x63d2,0x53c9, 0x832c,0x8336,0x67e5,0x78b4,0x643d,0x5bdf,0x5c94,0x5dee,0x8a6b,0x62c6, 0x67f4,0x8c7a,0x6519,0x647b,0x87ec,0x995e,0x8b92,0x7e8f,0x93df,0x7523, 0x95e1,0x986b,0x660c,0x7316 }, { /* ku 13 */ 0x5834,0x5617,0x5e38,0x9577,0x511f,0x8178,0x5ee0,0x655e,0x66a2,0x5531, 0x5021,0x8d85,0x6284,0x9214,0x671d,0x5632,0x6f6e,0x5de2,0x5435,0x7092, 0x8eca,0x626f,0x64a4,0x63a3,0x5fb9,0x6f88,0x90f4,0x81e3,0x8fb0,0x5875, 0x6668,0x5ff1,0x6c89,0x9673,0x8d81,0x896f,0x6491,0x7a31,0x57ce,0x6a59, 0x6210,0x5448,0x4e58,0x7a0b,0x61f2,0x6f84,0x8aa0,0x627f,0x901e,0x9a01, 0x79e4,0x5403,0x75f4,0x6301,0x5319,0x6c60,0x9072,0x5f1b,0x99b3,0x803b, 0x9f52,0x4f88,0x5c3a,0x8d64,0x7fc5,0x65a5,0x71be,0x5145,0x885d,0x87f2, 0x5d07,0x5bf5,0x62bd,0x916c,0x7587,0x8e8a,0x7a20,0x6101,0x7c4c,0x4ec7, 0x7da2,0x7785,0x919c,0x81ed,0x521d,0x51fa,0x6a71,0x53a8,0x8e87,0x92e4, 0x96db,0x6ec1,0x9664,0x695a }, { /* ku 14 */ 0x790e,0x5132,0x77d7,0x6410,0x89f8,0x8655,0x63e3,0x5ddd,0x7a7f,0x693d, 0x50b3,0x8239,0x5598,0x4e32,0x7621,0x7a97,0x5e62,0x5e8a,0x95d6,0x5275, 0x5439,0x708a,0x6376,0x9318,0x5782,0x6625,0x693f,0x9187,0x5507,0x6df3, 0x7d14,0x8822,0x6233,0x7dbd,0x75b5,0x8328,0x78c1,0x96cc,0x8fad,0x6148, 0x74f7,0x8a5e,0x6b64,0x523a,0x8cdc,0x6b21,0x8070,0x8471,0x56f1,0x5306, 0x5f9e,0x53e2,0x51d1,0x7c97,0x918b,0x7c07,0x4fc3,0x8ea5,0x7be1,0x7ac4, 0x6467,0x5d14,0x50ac,0x8106,0x7601,0x7cb9,0x6dec,0x7fe0,0x6751,0x5b58, 0x5bf8,0x78cb,0x64ae,0x6413,0x63aa,0x632b,0x932f,0x642d,0x9054,0x7b54, 0x7629,0x6253,0x5927,0x5446,0x6b79,0x50a3,0x6234,0x5e36,0x6b86,0x4ee3, 0x8cb8,0x888b,0x5f85,0x902e }, { /* ku 15 */ 0x6020,0x803d,0x64d4,0x4e39,0x55ae,0x9132,0x64a3,0x81bd,0x65e6,0x6c2e, 0x4f46,0x619a,0x6de1,0x8a95,0x5f48,0x86cb,0x7576,0x64cb,0x9ee8,0x8569, 0x6a94,0x5200,0x6417,0x8e48,0x5012,0x5cf6,0x79b1,0x5c0e,0x5230,0x7a3b, 0x60bc,0x9053,0x76d7,0x5fb7,0x5f97,0x7684,0x8e6c,0x71c8,0x767b,0x7b49, 0x77aa,0x51f3,0x9127,0x5824,0x4f4e,0x6ef4,0x8fea,0x6575,0x7b1b,0x72c4, 0x6ecc,0x7fdf,0x5ae1,0x62b5,0x5e95,0x5730,0x8482,0x7b2c,0x5e1d,0x5f1f, 0x905e,0x7de0,0x985b,0x6382,0x6ec7,0x7898,0x9ede,0x5178,0x975b,0x588a, 0x96fb,0x4f43,0x7538,0x5e97,0x60e6,0x5960,0x6fb1,0x6bbf,0x7889,0x53fc, 0x96d5,0x51cb,0x5201,0x6389,0x540a,0x91e3,0x8abf,0x8dcc,0x7239,0x789f, 0x8776,0x8fed,0x8adc,0x758a }, { /* ku 16 */ 0x4e01,0x76ef,0x53ee,0x91d8,0x9802,0x9f0e,0x9320,0x5b9a,0x8a02,0x4e22, 0x6771,0x51ac,0x8463,0x61c2,0x52d5,0x68df,0x4f97,0x606b,0x51cd,0x6d1e, 0x515c,0x6296,0x9b25,0x9661,0x8c46,0x9017,0x75d8,0x90fd,0x7763,0x6bd2, 0x72a2,0x7368,0x8b80,0x5835,0x7779,0x8ced,0x675c,0x934d,0x809a,0x5ea6, 0x6e21,0x5992,0x7aef,0x77ed,0x935b,0x6bb5,0x65b7,0x7dde,0x5806,0x5151, 0x968a,0x5c0d,0x58a9,0x5678,0x8e72,0x6566,0x9813,0x56e4,0x920d,0x76fe, 0x9041,0x6387,0x54c6,0x591a,0x596a,0x579b,0x8eb2,0x6735,0x8dfa,0x8235, 0x5241,0x60f0,0x58ae,0x86fe,0x5ce8,0x9d5d,0x4fc4,0x984d,0x8a1b,0x5a25, 0x60e1,0x5384,0x627c,0x904f,0x9102,0x9913,0x6069,0x800c,0x5152,0x8033, 0x723e,0x990c,0x6d31,0x4e8c }, { /* ku 17 */ 0x8cb3,0x767c,0x7f70,0x7b4f,0x4f10,0x4e4f,0x95a5,0x6cd5,0x73d0,0x85e9, 0x5e06,0x756a,0x7ffb,0x6a0a,0x792c,0x91e9,0x7e41,0x51e1,0x7169,0x53cd, 0x8fd4,0x7bc4,0x8ca9,0x72af,0x98ef,0x6cdb,0x574a,0x82b3,0x65b9,0x80aa, 0x623f,0x9632,0x59a8,0x4eff,0x8a2a,0x7d21,0x653e,0x83f2,0x975e,0x5561, 0x98db,0x80a5,0x532a,0x8ab9,0x5420,0x80ba,0x5ee2,0x6cb8,0x8cbb,0x82ac, 0x915a,0x5429,0x6c1b,0x5206,0x7d1b,0x58b3,0x711a,0x6c7e,0x7c89,0x596e, 0x4efd,0x5fff,0x61a4,0x7cde,0x8c50,0x5c01,0x6953,0x8702,0x5cf0,0x92d2, 0x98a8,0x760b,0x70fd,0x9022,0x99ae,0x7e2b,0x8af7,0x5949,0x9cf3,0x4f5b, 0x5426,0x592b,0x6577,0x819a,0x5b75,0x6276,0x62c2,0x8f3b,0x5e45,0x6c1f, 0x7b26,0x4f0f,0x4fd8,0x670d }, { /* ku 18 */ 0x6d6e,0x6daa,0x798f,0x88b1,0x5f17,0x752b,0x64ab,0x8f14,0x4fef,0x91dc, 0x65a7,0x812f,0x8151,0x5e9c,0x8150,0x8d74,0x526f,0x8986,0x8ce6,0x5fa9, 0x5085,0x4ed8,0x961c,0x7236,0x8179,0x8ca0,0x5bcc,0x8a03,0x9644,0x5a66, 0x7e1b,0x5490,0x5676,0x560e,0x8a72,0x6539,0x6982,0x9223,0x84cb,0x6e89, 0x5e79,0x7518,0x6746,0x67d1,0x7aff,0x809d,0x8d95,0x611f,0x79c6,0x6562, 0x8d1b,0x5ca1,0x525b,0x92fc,0x7f38,0x809b,0x7db1,0x5d17,0x6e2f,0x6760, 0x7bd9,0x768b,0x9ad8,0x818f,0x7f94,0x7cd5,0x641e,0x93ac,0x7a3f,0x544a, 0x54e5,0x6b4c,0x64f1,0x6208,0x9d3f,0x80f3,0x7599,0x5272,0x9769,0x845b, 0x683c,0x86e4,0x95a3,0x9694,0x927b,0x500b,0x5404,0x7d66,0x6839,0x8ddf, 0x8015,0x66f4,0x5e9a,0x7fb9 }, { /* ku 19 */ 0x57c2,0x803f,0x6897,0x5de5,0x653b,0x529f,0x606d,0x9f94,0x4f9b,0x8eac, 0x516c,0x5bab,0x5f13,0x978f,0x6c5e,0x62f1,0x8ca2,0x5171,0x920e,0x52fe, 0x6e9d,0x82df,0x72d7,0x57a2,0x69cb,0x8cfc,0x591f,0x8f9c,0x83c7,0x5495, 0x7b8d,0x4f30,0x6cbd,0x5b64,0x59d1,0x9f13,0x53e4,0x8831,0x9aa8,0x8c37, 0x80a1,0x6545,0x9867,0x56fa,0x96c7,0x522e,0x74dc,0x526e,0x5be1,0x6302, 0x8902,0x4e56,0x62d0,0x602a,0x68fa,0x95dc,0x5b98,0x51a0,0x89c0,0x7ba1, 0x9928,0x7f50,0x6163,0x704c,0x8cab,0x5149,0x5ee3,0x901b,0x7470,0x898f, 0x572d,0x7845,0x6b78,0x9f9c,0x95a8,0x8ecc,0x9b3c,0x8a6d,0x7678,0x6842, 0x6ac3,0x8dea,0x8cb4,0x528a,0x8f25,0x6eda,0x68cd,0x934b,0x90ed,0x570b, 0x679c,0x88f9,0x904e,0x54c8 }, { /* ku 1a */ 0x9ab8,0x5b69,0x6d77,0x6c26,0x4ea5,0x5bb3,0x99ed,0x9163,0x61a8,0x90af, 0x97d3,0x542b,0x6db5,0x5bd2,0x51fd,0x558a,0x7f55,0x7ff0,0x64bc,0x634d, 0x65f1,0x61be,0x608d,0x710a,0x6c57,0x6f22,0x592f,0x676d,0x822a,0x58d5, 0x568e,0x8c6a,0x6beb,0x90dd,0x597d,0x8017,0x865f,0x6d69,0x5475,0x559d, 0x8377,0x83cf,0x6838,0x79be,0x548c,0x4f55,0x5408,0x76d2,0x8c89,0x95a1, 0x6cb3,0x6db8,0x8d6b,0x8910,0x9db4,0x8cc0,0x563f,0x9ed1,0x75d5,0x5f88, 0x72e0,0x6068,0x54fc,0x4ea8,0x6a2a,0x8861,0x6052,0x8f5f,0x54c4,0x70d8, 0x8679,0x9d3b,0x6d2a,0x5b8f,0x5f18,0x7d05,0x5589,0x4faf,0x7334,0x543c, 0x539a,0x5019,0x5f8c,0x547c,0x4e4e,0x5ffd,0x745a,0x58fa,0x846b,0x80e1, 0x8774,0x72d0,0x7cca,0x6e56 }, { /* ku 1b */ 0x5f27,0x864e,0x552c,0x8b77,0x4e92,0x6eec,0x6237,0x82b1,0x5629,0x83ef, 0x733e,0x6ed1,0x756b,0x5283,0x5316,0x8a71,0x69d0,0x5f8a,0x61f7,0x6dee, 0x58de,0x6b61,0x74b0,0x6853,0x9084,0x7de9,0x63db,0x60a3,0x559a,0x7613, 0x8c62,0x7165,0x6e19,0x5ba6,0x5e7b,0x8352,0x614c,0x9ec4,0x78fa,0x8757, 0x7c27,0x7687,0x51f0,0x60f6,0x714c,0x6643,0x5e4c,0x604d,0x8b0a,0x7070, 0x63ee,0x8f1d,0x5fbd,0x6062,0x86d4,0x56de,0x6bc1,0x6094,0x6167,0x5349, 0x60e0,0x6666,0x8cc4,0x7a62,0x6703,0x71f4,0x532f,0x8af1,0x8aa8,0x7e6a, 0x8477,0x660f,0x5a5a,0x9b42,0x6e3e,0x6df7,0x8c41,0x6d3b,0x4f19,0x706b, 0x7372,0x6216,0x60d1,0x970d,0x8ca8,0x798d,0x64ca,0x573e,0x57fa,0x6a5f, 0x7578,0x7a3d,0x7a4d,0x7b95 }, { /* ku 1c */ 0x808c,0x9951,0x8ff9,0x6fc0,0x8b4f,0x9dc4,0x59ec,0x7e3e,0x7ddd,0x5409, 0x6975,0x68d8,0x8f2f,0x7c4d,0x96c6,0x53ca,0x6025,0x75be,0x6c72,0x5373, 0x5ac9,0x7d1a,0x64e0,0x5e7e,0x810a,0x5df1,0x858a,0x6280,0x5180,0x5b63, 0x4f0e,0x796d,0x5291,0x60b8,0x6fdf,0x5bc4,0x5bc2,0x8a08,0x8a18,0x65e2, 0x5fcc,0x969b,0x5993,0x7e7c,0x7d00,0x5609,0x67b7,0x593e,0x4f73,0x5bb6, 0x52a0,0x83a2,0x9830,0x8cc8,0x7532,0x9240,0x5047,0x7a3c,0x50f9,0x67b6, 0x99d5,0x5ac1,0x6bb2,0x76e3,0x5805,0x5c16,0x7b8b,0x9593,0x714e,0x517c, 0x80a9,0x8271,0x5978,0x7dd8,0x7e6d,0x6aa2,0x67ec,0x78b1,0x9e7c,0x63c0, 0x64bf,0x7c21,0x5109,0x526a,0x51cf,0x85a6,0x6abb,0x9452,0x8e10,0x8ce4, 0x898b,0x9375,0x7bad,0x4ef6 }, { /* ku 1d */ 0x5065,0x8266,0x528d,0x991e,0x6f38,0x6ffa,0x6f97,0x5efa,0x50f5,0x59dc, 0x5c07,0x6f3f,0x6c5f,0x7586,0x8523,0x69f3,0x596c,0x8b1b,0x5320,0x91ac, 0x964d,0x8549,0x6912,0x7901,0x7126,0x81a0,0x4ea4,0x90ca,0x6f86,0x9a55, 0x5b0c,0x56bc,0x652a,0x9278,0x77ef,0x50e5,0x811a,0x72e1,0x89d2,0x9903, 0x7e73,0x7d5e,0x527f,0x6559,0x9175,0x8f4e,0x8f03,0x53eb,0x7a96,0x63ed, 0x63a5,0x7686,0x79f8,0x8857,0x968e,0x622a,0x52ab,0x7bc0,0x6854,0x6770, 0x6377,0x776b,0x7aed,0x6f54,0x7d50,0x89e3,0x59d0,0x6212,0x85c9,0x82a5, 0x754c,0x501f,0x4ecb,0x75a5,0x8aa1,0x5c4a,0x5dfe,0x7b4b,0x65a4,0x91d1, 0x4eca,0x6d25,0x895f,0x7dca,0x9326,0x50c5,0x8b39,0x9032,0x9773,0x6649, 0x7981,0x8fd1,0x71fc,0x6d78 }, { /* ku 1e */ 0x76e1,0x52c1,0x8346,0x5162,0x8396,0x775b,0x6676,0x9be8,0x4eac,0x9a5a, 0x7cbe,0x7cb3,0x7d93,0x4e95,0x8b66,0x666f,0x9838,0x975c,0x5883,0x656c, 0x93e1,0x5f91,0x75d9,0x9756,0x7adf,0x7af6,0x51c8,0x70af,0x7a98,0x63ea, 0x7a76,0x7cfe,0x7396,0x97ed,0x4e45,0x7078,0x4e5d,0x9152,0x53a9,0x6551, 0x820a,0x81fc,0x8205,0x548e,0x5c31,0x759a,0x97a0,0x62d8,0x72d9,0x75bd, 0x5c45,0x99d2,0x83ca,0x5c40,0x5480,0x77e9,0x8209,0x6cae,0x805a,0x62d2, 0x64da,0x5de8,0x5177,0x8ddd,0x8e1e,0x92f8,0x4ff1,0x53e5,0x61fc,0x70ac, 0x5287,0x6350,0x9d51,0x5a1f,0x5026,0x7737,0x5377,0x7d79,0x6485,0x652b, 0x6289,0x6398,0x5014,0x7235,0x89ba,0x51b3,0x8a23,0x7d76,0x5747,0x83cc, 0x921e,0x8ecd,0x541b,0x5cfb }, { /* ku 1f */ 0x4fca,0x7ae3,0x6d5a,0x90e1,0x99ff,0x5580,0x5496,0x5361,0x54af,0x958b, 0x63e9,0x6977,0x51f1,0x6168,0x520a,0x582a,0x52d8,0x574e,0x780d,0x770b, 0x5eb7,0x6177,0x7ce0,0x625b,0x6297,0x4ea2,0x7095,0x8003,0x62f7,0x70e4, 0x9760,0x5777,0x82db,0x67ef,0x68f5,0x78d5,0x9846,0x79d1,0x6bbb,0x54b3, 0x53ef,0x6e34,0x514b,0x523b,0x5ba2,0x8ab2,0x80af,0x5543,0x58be,0x61c7, 0x5751,0x542d,0x7a7a,0x6050,0x5b54,0x63a7,0x6473,0x53e3,0x6263,0x5bc7, 0x67af,0x54ed,0x7a9f,0x82e6,0x9177,0x5eab,0x8932,0x8a87,0x57ae,0x630e, 0x8de8,0x80ef,0x584a,0x7b77,0x5108,0x5feb,0x5bec,0x6b3e,0x5321,0x7b50, 0x72c2,0x6846,0x7926,0x7736,0x66e0,0x51b5,0x8667,0x76d4,0x5dcb,0x7aba, 0x8475,0x594e,0x9b41,0x5080 }, { /* ku 20 */ 0x994b,0x6127,0x6f70,0x5764,0x6606,0x6346,0x56f0,0x62ec,0x64f4,0x5ed3, 0x95ca,0x5783,0x62c9,0x5587,0x881f,0x81d8,0x8fa3,0x5566,0x840a,0x4f86, 0x8cf4,0x85cd,0x5a6a,0x6b04,0x6514,0x7c43,0x95cc,0x862d,0x703e,0x8b95, 0x652c,0x89bd,0x61f6,0x7e9c,0x721b,0x6feb,0x7405,0x6994,0x72fc,0x5eca, 0x90ce,0x6717,0x6d6a,0x6488,0x52de,0x7262,0x8001,0x4f6c,0x59e5,0x916a, 0x70d9,0x6f87,0x52d2,0x6a02,0x96f7,0x9433,0x857e,0x78ca,0x7d2f,0x5121, 0x58d8,0x64c2,0x808b,0x985e,0x6cea,0x68f1,0x695e,0x51b7,0x5398,0x68a8, 0x7281,0x9ece,0x7c6c,0x72f8,0x96e2,0x7055,0x7406,0x674e,0x88cf,0x9bc9, 0x79ae,0x8389,0x8354,0x540f,0x6817,0x9e97,0x53b2,0x52f5,0x792b,0x6b77, 0x5229,0x5088,0x4f8b,0x4fd0 }, { /* ku 21 */ 0x75e2,0x7acb,0x7c92,0x701d,0x96b8,0x529b,0x7483,0x54e9,0x5006,0x806f, 0x84ee,0x9023,0x942e,0x5ec9,0x6190,0x6f23,0x7c3e,0x6582,0x81c9,0x93c8, 0x6200,0x7149,0x7df4,0x7ce7,0x51c9,0x6881,0x7cb1,0x826f,0x5169,0x8f1b, 0x91cf,0x667e,0x4eae,0x8ad2,0x64a9,0x804a,0x50da,0x7642,0x71ce,0x5be5, 0x907c,0x6f66,0x4e86,0x6482,0x9410,0x5ed6,0x6599,0x5217,0x88c2,0x70c8, 0x52a3,0x7375,0x7433,0x6797,0x78f7,0x9716,0x81e8,0x9130,0x9c57,0x6dcb, 0x51db,0x8cc3,0x541d,0x62ce,0x73b2,0x83f1,0x96f6,0x9f61,0x9234,0x4f36, 0x7f9a,0x51cc,0x9748,0x9675,0x5dba,0x9818,0x53e6,0x4ee4,0x6e9c,0x7409, 0x69b4,0x786b,0x993e,0x7559,0x5289,0x7624,0x6d41,0x67f3,0x516d,0x9f8d, 0x807e,0x56a8,0x7c60,0x7abf }, { /* ku 22 */ 0x9686,0x58df,0x650f,0x96b4,0x6a13,0x5a41,0x645f,0x7c0d,0x6f0f,0x964b, 0x8606,0x76e7,0x9871,0x5eec,0x7210,0x64c4,0x6ef7,0x865c,0x9b6f,0x9e93, 0x788c,0x9732,0x8def,0x8cc2,0x9e7f,0x6f5e,0x7984,0x9332,0x9678,0x622e, 0x9a62,0x5415,0x92c1,0x4fa3,0x65c5,0x5c65,0x5c62,0x7e37,0x616e,0x6c2f, 0x5f8b,0x7387,0x6ffe,0x7dd1,0x5dd2,0x6523,0x5b7f,0x7064,0x5375,0x4e82, 0x63a0,0x7565,0x6384,0x8f2a,0x502b,0x4f96,0x6dea,0x7db8,0x8ad6,0x863f, 0x87ba,0x7f85,0x908f,0x947c,0x7c6e,0x9a3e,0x88f8,0x843d,0x6d1b,0x99f1, 0x7d61,0x5abd,0x9ebb,0x746a,0x78bc,0x879e,0x99ac,0x99e1,0x561b,0x55ce, 0x57cb,0x8cb7,0x9ea5,0x8ce3,0x9081,0x8109,0x779e,0x9945,0x883b,0x6eff, 0x8513,0x66fc,0x6162,0x6f2b }, { /* ku 23 */ 0x8b3e,0x8292,0x832b,0x76f2,0x6c13,0x5fd9,0x83bd,0x732b,0x8305,0x9328, 0x6bdb,0x77db,0x925a,0x536f,0x8302,0x5192,0x5e3d,0x8c8c,0x8cbf,0x9ebd, 0x73ab,0x679a,0x6885,0x9176,0x9709,0x7164,0x6ca1,0x7709,0x5a92,0x9382, 0x6bcf,0x7f8e,0x6627,0x5bd0,0x59b9,0x5a9a,0x9580,0x60b6,0x5011,0x840c, 0x8499,0x6aac,0x76df,0x9333,0x731b,0x5922,0x5b5f,0x772f,0x919a,0x9761, 0x7cdc,0x8ff7,0x8b0e,0x5f4c,0x7c73,0x79d8,0x8993,0x6ccc,0x871c,0x5bc6, 0x5e42,0x68c9,0x7720,0x7dbf,0x5195,0x514d,0x52c9,0x5a29,0x7dec,0x9762, 0x82d7,0x63cf,0x7784,0x85d0,0x79d2,0x6e3a,0x5edf,0x5999,0x8511,0x6ec5, 0x6c11,0x62bf,0x76bf,0x654f,0x61ab,0x95a9,0x660e,0x879f,0x9cf4,0x9298, 0x540d,0x547d,0x8b2c,0x6478 }, { /* ku 24 */ 0x6479,0x8611,0x6a21,0x819c,0x78e8,0x6469,0x9b54,0x62b9,0x672b,0x83ab, 0x58a8,0x9ed8,0x6cab,0x6f20,0x5bde,0x964c,0x8b00,0x725f,0x67d0,0x62c7, 0x7261,0x755d,0x59c6,0x6bcd,0x5893,0x66ae,0x5e55,0x52df,0x6155,0x6728, 0x76ee,0x7766,0x7267,0x7a46,0x62ff,0x54ea,0x5450,0x9209,0x90a3,0x5a1c, 0x7d0d,0x6c16,0x4e43,0x5976,0x8010,0x5948,0x5357,0x7537,0x96e3,0x56ca, 0x6493,0x8166,0x60f1,0x9b27,0x6dd6,0x5462,0x9912,0x5185,0x5ae9,0x80fd, 0x59ae,0x9713,0x502a,0x6ce5,0x5c3c,0x64ec,0x4f60,0x533f,0x81a9,0x9006, 0x6eba,0x852b,0x62c8,0x5e74,0x78be,0x6506,0x637b,0x5ff5,0x5a18,0x91c0, 0x9ce5,0x5c3f,0x634f,0x8076,0x5b7d,0x5699,0x9477,0x93b3,0x6d85,0x60a8, 0x6ab8,0x7370,0x51dd,0x5be7 }, { /* ku 25 */ 0x64f0,0x6fd8,0x725b,0x626d,0x9215,0x7d10,0x81bf,0x6fc3,0x8fb2,0x5f04, 0x5974,0x52aa,0x6012,0x5973,0x6696,0x8650,0x7627,0x632a,0x61e6,0x7cef, 0x8afe,0x54e6,0x6b50,0x9dd7,0x6bc6,0x85d5,0x5614,0x5076,0x6f1a,0x556a, 0x8db4,0x722c,0x5e15,0x6015,0x7436,0x62cd,0x6392,0x724c,0x5f98,0x6e43, 0x6d3e,0x6500,0x6f58,0x76e4,0x78d0,0x76fc,0x7554,0x5224,0x53db,0x4e53, 0x9f90,0x65c1,0x802a,0x80d6,0x629b,0x5486,0x5228,0x70ae,0x888d,0x8dd1, 0x6ce1,0x5478,0x80da,0x57f9,0x88f4,0x8ce0,0x966a,0x914d,0x4f69,0x6c9b, 0x5674,0x76c6,0x7830,0x62a8,0x70f9,0x6f8e,0x5f6d,0x84ec,0x68da,0x787c, 0x7bf7,0x81a8,0x670b,0x9d6c,0x6367,0x78b0,0x576f,0x7812,0x9739,0x6279, 0x62ab,0x5288,0x7435,0x6bd7 }, { /* ku 26 */ 0x5564,0x813e,0x75b2,0x76ae,0x5339,0x75de,0x50fb,0x5c41,0x8b6c,0x7bc7, 0x504f,0x7247,0x9a19,0x98c4,0x6f02,0x74e2,0x7968,0x6487,0x77a5,0x62fc, 0x983b,0x8ca7,0x54c1,0x8058,0x4e52,0x576a,0x860b,0x840d,0x5e73,0x6191, 0x74f6,0x8a55,0x5c4f,0x5761,0x6f51,0x9817,0x5a46,0x7834,0x9b44,0x8feb, 0x7c95,0x5256,0x64b2,0x92ea,0x50d5,0x8386,0x8461,0x83e9,0x84b2,0x57d4, 0x6a38,0x5703,0x666e,0x6d66,0x8b5c,0x66dd,0x7011,0x671f,0x6b3a,0x68f2, 0x621a,0x59bb,0x4e03,0x51c4,0x6f06,0x67d2,0x6c8f,0x5176,0x68cb,0x5947, 0x6b67,0x7566,0x5d0e,0x81cd,0x9f4a,0x65d7,0x7948,0x7941,0x9a0e,0x8d77, 0x8c48,0x4e5e,0x4f01,0x5553,0x5951,0x780c,0x5668,0x6c23,0x8fc4,0x68c4, 0x6c7d,0x6ce3,0x8a16,0x6390 }, { /* ku 27 */ 0x6070,0x6d3d,0x727d,0x6266,0x91fa,0x925b,0x5343,0x9077,0x7c3d,0x4edf, 0x8b19,0x4e7e,0x9ed4,0x9322,0x9257,0x524d,0x6f5b,0x9063,0x6dfa,0x8b74, 0x5879,0x5d4c,0x6b20,0x6b49,0x69cd,0x55c6,0x8154,0x7f8c,0x58bb,0x8594, 0x5f3a,0x6436,0x6a47,0x936c,0x6572,0x6084,0x6a4b,0x77a7,0x55ac,0x50d1, 0x5de7,0x9798,0x64ac,0x7ff9,0x5ced,0x4fcf,0x7ac5,0x5207,0x8304,0x4e14, 0x602f,0x7aca,0x6b3d,0x4fb5,0x89aa,0x79e6,0x7434,0x52e4,0x82b9,0x64d2, 0x79bd,0x5be2,0x6c81,0x9752,0x8f15,0x6c2b,0x50be,0x537f,0x6e05,0x64ce, 0x6674,0x6c30,0x60c5,0x9803,0x8acb,0x6176,0x74ca,0x7aae,0x79cb,0x4e18, 0x90b1,0x7403,0x6c42,0x56da,0x914b,0x6cc5,0x8da8,0x5340,0x86c6,0x66f2, 0x8ec0,0x5c48,0x9a45,0x6e20 }, { /* ku 28 */ 0x53d6,0x5a36,0x9f72,0x8da3,0x53bb,0x5708,0x9874,0x6b0a,0x919b,0x6cc9, 0x5168,0x75ca,0x62f3,0x72ac,0x5238,0x52f8,0x7f3a,0x7094,0x7638,0x5374, 0x9d72,0x69b7,0x78ba,0x96c0,0x88d9,0x7fa4,0x7136,0x71c3,0x5189,0x67d3, 0x74e4,0x58e4,0x6518,0x56b7,0x8b93,0x9952,0x64fe,0x7e5e,0x60f9,0x71b1, 0x58ec,0x4ec1,0x4eba,0x5fcd,0x97cc,0x4efb,0x8a8d,0x5203,0x598a,0x7d09, 0x6254,0x4ecd,0x65e5,0x620e,0x8338,0x84c9,0x69ae,0x878d,0x7194,0x6eb6, 0x5bb9,0x7d68,0x5197,0x63c9,0x67d4,0x8089,0x8339,0x8815,0x5112,0x5b7a, 0x5982,0x8fb1,0x4e73,0x6c5d,0x5165,0x8925,0x8edf,0x962e,0x854a,0x745e, 0x92ed,0x958f,0x6f64,0x82e5,0x5f31,0x6492,0x7051,0x85a9,0x816e,0x9c13, 0x585e,0x8cfd,0x4e09,0x53c1 }, { /* ku 29 */ 0x5098,0x6563,0x6851,0x55d3,0x55aa,0x6414,0x9a37,0x6383,0x5ac2,0x745f, 0x8272,0x6f80,0x68ee,0x50e7,0x838e,0x7802,0x6bba,0x5239,0x6c99,0x7d17, 0x50bb,0x5565,0x715e,0x7be9,0x66ec,0x73ca,0x82eb,0x6749,0x5c71,0x5220, 0x717d,0x886b,0x9583,0x965d,0x64c5,0x8d0d,0x81b3,0x5584,0x6c55,0x6247, 0x7e55,0x5892,0x50b7,0x5546,0x8cde,0x664c,0x4e0a,0x5c1a,0x88f3,0x68a2, 0x634e,0x7a0d,0x71d2,0x828d,0x52fa,0x97f6,0x5c11,0x54e8,0x90b5,0x7d39, 0x5962,0x8cd2,0x86c7,0x820c,0x6368,0x8d66,0x651d,0x5c04,0x61fe,0x6d89, 0x793e,0x8a2d,0x7837,0x7533,0x547b,0x4f38,0x8eab,0x6df1,0x5a20,0x7d33, 0x795e,0x6c88,0x5be9,0x5b38,0x751a,0x814e,0x614e,0x6ef2,0x8072,0x751f, 0x7525,0x7272,0x5347,0x7e69 }, { /* ku 2a */ 0x7701,0x76db,0x5269,0x52dd,0x8056,0x5e2b,0x5931,0x7345,0x65bd,0x6fd5, 0x8a69,0x5c38,0x8671,0x5341,0x77f3,0x62fe,0x6642,0x4ec0,0x98df,0x8755, 0x5be6,0x8b58,0x53f2,0x77e2,0x4f7f,0x5c4e,0x99db,0x59cb,0x5f0f,0x793a, 0x58eb,0x4e16,0x67ff,0x4e8b,0x62ed,0x8a93,0x901d,0x52e2,0x662f,0x55dc, 0x566c,0x9069,0x4ed5,0x4f8d,0x91cb,0x98fe,0x6c0f,0x5e02,0x6043,0x5ba4, 0x8996,0x8a66,0x6536,0x624b,0x9996,0x5b88,0x58fd,0x6388,0x552e,0x53d7, 0x7626,0x7378,0x852c,0x6a1e,0x68b3,0x6b8a,0x6292,0x8f38,0x53d4,0x8212, 0x6dd1,0x758f,0x66f8,0x8d16,0x5b70,0x719f,0x85af,0x6691,0x66d9,0x7f72, 0x8700,0x9ecd,0x9f20,0x5c6c,0x8853,0x8ff0,0x6a39,0x675f,0x620d,0x7aea, 0x5885,0x5eb6,0x6578,0x6f31 }, { /* ku 2b */ 0x6055,0x5237,0x800d,0x6454,0x8870,0x7529,0x5e25,0x6813,0x62f4,0x971c, 0x96d9,0x723d,0x8ab0,0x6c34,0x7761,0x7a0e,0x542e,0x77ac,0x9806,0x821c, 0x8aac,0x78a9,0x6714,0x720d,0x65af,0x6495,0x5636,0x601d,0x79c1,0x53f8, 0x7d72,0x6b7b,0x8086,0x5bfa,0x55e3,0x56db,0x4f3a,0x4f3c,0x98fc,0x5df3, 0x9b06,0x8073,0x616b,0x980c,0x9001,0x5b8b,0x8a1f,0x8aa6,0x641c,0x8258, 0x64fb,0x55fd,0x8607,0x9165,0x4fd7,0x7d20,0x901f,0x7c9f,0x50f3,0x5851, 0x6eaf,0x5bbf,0x8a34,0x8085,0x9178,0x849c,0x7b97,0x96d6,0x968b,0x96a8, 0x7d8f,0x9ad3,0x788e,0x6b72,0x7a57,0x9042,0x96a7,0x795f,0x5b6b,0x640d, 0x7b0b,0x84d1,0x68ad,0x5506,0x7e2e,0x7463,0x7d22,0x9396,0x6240,0x584c, 0x4ed6,0x5b83,0x5979,0x5854 }, { /* ku 2c */ 0x737a,0x64bb,0x8e4b,0x8e0f,0x80ce,0x82d4,0x62ac,0x81fa,0x6cf0,0x915e, 0x592a,0x614b,0x6c70,0x574d,0x6524,0x8caa,0x7671,0x7058,0x58c7,0x6a80, 0x75f0,0x6f6d,0x8b5a,0x8ac7,0x5766,0x6bef,0x8892,0x78b3,0x63a2,0x5606, 0x70ad,0x6e6f,0x5858,0x642a,0x5802,0x68e0,0x819b,0x5510,0x7cd6,0x5018, 0x8eba,0x6dcc,0x8d9f,0x71d9,0x638f,0x6fe4,0x6ed4,0x7e27,0x8404,0x6843, 0x9003,0x6dd8,0x9676,0x8a0e,0x5957,0x7279,0x85e4,0x9a30,0x75bc,0x8b04, 0x68af,0x5254,0x8e22,0x92bb,0x63d0,0x984c,0x8e44,0x557c,0x9ad4,0x66ff, 0x568f,0x60d5,0x6d95,0x5243,0x5c49,0x5929,0x6dfb,0x586b,0x7530,0x751c, 0x606c,0x8214,0x8146,0x6311,0x689d,0x8fe2,0x773a,0x8df3,0x8cbc,0x9435, 0x5e16,0x5ef3,0x807d,0x70f4 }, { /* ku 2d */ 0x6c40,0x5ef7,0x505c,0x4ead,0x5ead,0x633a,0x8247,0x901a,0x6850,0x916e, 0x77b3,0x540c,0x9285,0x5f64,0x7ae5,0x6876,0x6345,0x7b52,0x7d71,0x75db, 0x5077,0x6295,0x982d,0x900f,0x51f8,0x79c3,0x7a81,0x5716,0x5f92,0x9014, 0x5857,0x5c60,0x571f,0x5410,0x5154,0x6e4d,0x5718,0x63a8,0x983d,0x817f, 0x8715,0x892a,0x9000,0x541e,0x5c6f,0x81c0,0x62d6,0x6258,0x8131,0x9d15, 0x9640,0x99b1,0x99dd,0x6a62,0x59a5,0x62d3,0x553e,0x6316,0x54c7,0x86d9, 0x7aaa,0x5a03,0x74e6,0x896a,0x6b6a,0x5916,0x8c4c,0x5f4e,0x7063,0x73a9, 0x9811,0x4e38,0x70f7,0x5b8c,0x7897,0x633d,0x665a,0x7696,0x60cb,0x5b9b, 0x5a49,0x842c,0x8155,0x6c6a,0x738b,0x4ea1,0x6789,0x7db2,0x5f80,0x65fa, 0x671b,0x5fd8,0x5984,0x5a01 }, { /* ku 2e */ 0x5dcd,0x5fae,0x5371,0x97cb,0x9055,0x6845,0x570d,0x552f,0x60df,0x7232, 0x6ff0,0x7dad,0x8466,0x840e,0x59d4,0x5049,0x50de,0x5c3e,0x7def,0x672a, 0x851a,0x5473,0x754f,0x80c3,0x5582,0x9b4f,0x4f4d,0x6e2d,0x8b02,0x5c09, 0x6170,0x885b,0x761f,0x6e29,0x868a,0x6587,0x805e,0x7d0b,0x543b,0x7a69, 0x7d0a,0x554f,0x55e1,0x7fc1,0x74ee,0x64be,0x8778,0x6e26,0x7aa9,0x6211, 0x65a1,0x5367,0x63e1,0x6c83,0x5deb,0x55da,0x93a2,0x70cf,0x6c61,0x8aa3, 0x5c4b,0x7121,0x856a,0x68a7,0x543e,0x5434,0x6bcb,0x6b66,0x4e94,0x6342, 0x5348,0x821e,0x4f0d,0x4fae,0x5862,0x620a,0x9727,0x6664,0x7269,0x52ff, 0x52d9,0x609f,0x8aa4,0x6614,0x7199,0x6790,0x897f,0x7852,0x77fd,0x6670, 0x563b,0x5438,0x932b,0x72a7 }, { /* ku 2f */ 0x7a00,0x606f,0x5e0c,0x6089,0x819d,0x5915,0x60dc,0x7184,0x70ef,0x6eaa, 0x6c50,0x7280,0x6a84,0x8972,0x5e2d,0x7fd2,0x5ab3,0x559c,0x9291,0x6d17, 0x7cfb,0x9699,0x6232,0x7d30,0x778e,0x8766,0x5323,0x971e,0x8f44,0x6687, 0x5cfd,0x4fe0,0x72f9,0x4e0b,0x53a6,0x590f,0x5687,0x6380,0x9341,0x5148, 0x4ed9,0x9bae,0x7e96,0x54b8,0x8ce2,0x929c,0x8237,0x9591,0x6d8e,0x5f26, 0x5acc,0x986f,0x96aa,0x73fe,0x737b,0x7e23,0x817a,0x9921,0x7fa1,0x61b2, 0x9677,0x9650,0x7dab,0x76f8,0x53a2,0x9472,0x9999,0x7bb1,0x8944,0x6e58, 0x9109,0x7fd4,0x7965,0x8a73,0x60f3,0x97ff,0x4eab,0x9805,0x5df7,0x6a61, 0x50cf,0x5411,0x8c61,0x856d,0x785d,0x9704,0x524a,0x54ee,0x56c2,0x92b7, 0x6d88,0x5bb5,0x6dc6,0x66c9 }, { /* ku 30 */ 0x5c0f,0x5b5d,0x6821,0x8096,0x562f,0x7b11,0x6548,0x6954,0x4e9b,0x6b47, 0x874e,0x978b,0x5354,0x633e,0x643a,0x90aa,0x659c,0x8105,0x8ae7,0x5beb, 0x68b0,0x5378,0x87f9,0x61c8,0x6cc4,0x7009,0x8b1d,0x5c51,0x85aa,0x82af, 0x92c5,0x6b23,0x8f9b,0x65b0,0x5ffb,0x5fc3,0x4fe1,0x91c1,0x661f,0x8165, 0x7329,0x60fa,0x8208,0x5211,0x578b,0x5f62,0x90a2,0x884c,0x9192,0x5e78, 0x674f,0x6027,0x59d3,0x5144,0x51f6,0x80f8,0x5308,0x6c79,0x96c4,0x718a, 0x4f11,0x4fee,0x7f9e,0x673d,0x55c5,0x92b9,0x79c0,0x8896,0x7d89,0x589f, 0x620c,0x9700,0x865a,0x5618,0x9808,0x5f90,0x8a31,0x84c4,0x9157,0x53d9, 0x65ed,0x5e8f,0x755c,0x6064,0x7d6e,0x5a7f,0x7dd2,0x7e8c,0x8ed2,0x55a7, 0x5ba3,0x61f8,0x65cb,0x7384 }, { /* ku 31 */ 0x9078,0x766c,0x7729,0x7d62,0x9774,0x859b,0x5b78,0x7a74,0x96ea,0x8840, 0x52db,0x718f,0x5faa,0x65ec,0x8a62,0x5c0b,0x99b4,0x5de1,0x6b89,0x6c5b, 0x8a13,0x8a0a,0x905c,0x8fc5,0x58d3,0x62bc,0x9d09,0x9d28,0x5440,0x4e2b, 0x82bd,0x7259,0x869c,0x5d16,0x8859,0x6daf,0x96c5,0x555e,0x4e9e,0x8a1d, 0x7109,0x54bd,0x95b9,0x70df,0x6df9,0x9e7d,0x56b4,0x7814,0x8712,0x5ca9, 0x5ef6,0x8a00,0x9854,0x95bb,0x708e,0x6cbf,0x5944,0x63a9,0x773c,0x884d, 0x6f14,0x8277,0x5830,0x71d5,0x53ad,0x786f,0x96c1,0x5501,0x5f66,0x7130, 0x5bb4,0x8afa,0x9a57,0x6b83,0x592e,0x9d26,0x79e7,0x694a,0x63da,0x4f6f, 0x760d,0x7f8a,0x6d0b,0x967d,0x6c27,0x4ef0,0x7662,0x990a,0x6a23,0x6f3e, 0x9080,0x8170,0x5996,0x7476 }, { /* ku 32 */ 0x6447,0x582f,0x9065,0x7a91,0x8b21,0x59da,0x54ac,0x8200,0x85e5,0x8981, 0x8000,0x6930,0x564e,0x8036,0x723a,0x91ce,0x51b6,0x4e5f,0x9801,0x6396, 0x696d,0x8449,0x66f3,0x814b,0x591c,0x6db2,0x4e00,0x58f9,0x91ab,0x63d6, 0x92a5,0x4f9d,0x4f0a,0x8863,0x9824,0x5937,0x907a,0x79fb,0x5100,0x80f0, 0x7591,0x6c82,0x5b9c,0x59e8,0x5f5d,0x6905,0x87fb,0x501a,0x5df2,0x4e59, 0x77e3,0x4ee5,0x85dd,0x6291,0x6613,0x9091,0x5c79,0x5104,0x5f79,0x81c6, 0x9038,0x8084,0x75ab,0x4ea6,0x88d4,0x610f,0x6bc5,0x61b6,0x7fa9,0x76ca, 0x6ea2,0x8a63,0x8b70,0x8abc,0x8b6f,0x5f02,0x7ffc,0x7fcc,0x7e79,0x8335, 0x852d,0x56e0,0x6bb7,0x97f3,0x9670,0x59fb,0x541f,0x9280,0x6deb,0x5bc5, 0x98f2,0x5c39,0x5f15,0x96b1 }, { /* ku 33 */ 0x5370,0x82f1,0x6afb,0x5b30,0x9df9,0x61c9,0x7e93,0x7469,0x87a2,0x71df, 0x7192,0x8805,0x8fce,0x8d0f,0x76c8,0x5f71,0x7a4e,0x786c,0x6620,0x55b2, 0x64c1,0x50ad,0x81c3,0x7670,0x5eb8,0x96cd,0x8e34,0x86f9,0x548f,0x6cf3, 0x6d8c,0x6c38,0x607f,0x52c7,0x7528,0x5e7d,0x512a,0x60a0,0x6182,0x5c24, 0x7531,0x90f5,0x923e,0x7336,0x6cb9,0x6e38,0x9149,0x6709,0x53cb,0x53f3, 0x4f51,0x91c9,0x8a98,0x53c8,0x5e7c,0x8fc2,0x6de4,0x4e8e,0x76c2,0x6986, 0x865e,0x611a,0x8f3f,0x9918,0x4fde,0x903e,0x9b5a,0x6109,0x6e1d,0x6f01, 0x9685,0x4e88,0x5a31,0x96e8,0x8207,0x5dbc,0x79b9,0x5b87,0x8a9e,0x7fbd, 0x7389,0x57df,0x828b,0x9b31,0x5401,0x9047,0x55bb,0x5cea,0x5fa1,0x6108, 0x6b32,0x7344,0x80b2,0x8b7d }, { /* ku 34 */ 0x6d74,0x5bd3,0x88d5,0x9810,0x8c6b,0x99ad,0x9d1b,0x6df5,0x51a4,0x5143, 0x57a3,0x8881,0x539f,0x63f4,0x8f45,0x5712,0x54e1,0x5713,0x733f,0x6e90, 0x7de3,0x9060,0x82d1,0x9858,0x6028,0x9662,0x66f0,0x7d04,0x8d8a,0x8e8d, 0x9470,0x5cb3,0x7ca4,0x6708,0x60a6,0x95b2,0x8018,0x96f2,0x9116,0x5300, 0x9695,0x5141,0x904b,0x85f4,0x9196,0x6688,0x97f5,0x5b55,0x531d,0x7838, 0x96dc,0x683d,0x54c9,0x707e,0x5bb0,0x8f09,0x518d,0x5728,0x54b1,0x6522, 0x66ab,0x8d0a,0x8d1c,0x81df,0x846c,0x906d,0x7cdf,0x947f,0x85fb,0x68d7, 0x65e9,0x6fa1,0x86a4,0x8e81,0x566a,0x9020,0x7682,0x7ac8,0x71e5,0x8cac, 0x64c7,0x5247,0x6fa4,0x8cca,0x600e,0x589e,0x618e,0x66fe,0x8d08,0x624e, 0x55b3,0x6e23,0x672d,0x8ecb }, { /* ku 35 */ 0x9358,0x9598,0x7728,0x6805,0x69a8,0x548b,0x4e4d,0x70b8,0x8a50,0x6458, 0x9f4b,0x5b85,0x7a84,0x50b5,0x5be8,0x77bb,0x6c08,0x8a79,0x7c98,0x6cbe, 0x76de,0x65ac,0x8f3e,0x5d84,0x5c55,0x8638,0x68e7,0x5360,0x6230,0x7ad9, 0x6e5b,0x7dbb,0x6a1f,0x7ae0,0x5f70,0x6f33,0x5f35,0x638c,0x6f32,0x6756, 0x4e08,0x5e33,0x8cec,0x4ed7,0x8139,0x7634,0x969c,0x62db,0x662d,0x627e, 0x6cbc,0x8d99,0x7167,0x7f69,0x5146,0x8087,0x53ec,0x906e,0x6298,0x54f2, 0x87c4,0x8f4d,0x8005,0x937a,0x8517,0x9019,0x6d59,0x73cd,0x659f,0x771f, 0x7504,0x7827,0x81fb,0x8c9e,0x91dd,0x5075,0x6795,0x75b9,0x8a3a,0x9707, 0x632f,0x93ae,0x9663,0x84b8,0x6399,0x775c,0x5f81,0x7319,0x722d,0x6014, 0x6574,0x62ef,0x6b63,0x653f }, { /* ku 36 */ 0x5e40,0x7665,0x912d,0x8b49,0x829d,0x679d,0x652f,0x5431,0x8718,0x77e5, 0x80a2,0x8102,0x6c41,0x4e4b,0x7e54,0x8077,0x76f4,0x690d,0x6b96,0x57f7, 0x503c,0x4f84,0x5740,0x6307,0x6b62,0x8dbe,0x8879,0x65e8,0x7d19,0x5fd7, 0x646f,0x64f2,0x81f3,0x81f4,0x7f6e,0x5e5f,0x5cd9,0x5236,0x667a,0x79e9, 0x7a1a,0x8cea,0x7099,0x75d4,0x6eef,0x6cbb,0x7a92,0x4e2d,0x76c5,0x5fe0, 0x9418,0x8877,0x7d42,0x7a2e,0x816b,0x91cd,0x4ef2,0x8846,0x821f,0x5468, 0x5dde,0x6d32,0x8b05,0x7ca5,0x8ef8,0x8098,0x5e1a,0x5492,0x76ba,0x5b99, 0x665d,0x9a5f,0x73e0,0x682a,0x86db,0x6731,0x732a,0x8af8,0x8a85,0x9010, 0x7af9,0x71ed,0x716e,0x62c4,0x77da,0x56d1,0x4e3b,0x8457,0x67f1,0x52a9, 0x86c0,0x8caf,0x9444,0x7bc9 }, { /* ku 37 */ 0x4f4f,0x6ce8,0x795d,0x99d0,0x6293,0x722a,0x62fd,0x5c08,0x78da,0x8f49, 0x64b0,0x8cfa,0x7bc6,0x6a01,0x838a,0x88dd,0x599d,0x649e,0x58ef,0x72c0, 0x690e,0x9310,0x8ffd,0x8d05,0x589c,0x7db4,0x8ac4,0x6e96,0x6349,0x62d9, 0x5353,0x684c,0x7422,0x8301,0x914c,0x5544,0x7740,0x707c,0x6fc1,0x5179, 0x54a8,0x8cc7,0x59ff,0x6ecb,0x6dc4,0x5b5c,0x7d2b,0x4ed4,0x7c7d,0x6ed3, 0x5b50,0x81ea,0x6f2c,0x5b57,0x9b03,0x68d5,0x8e2a,0x5b97,0x7d9c,0x7e3d, 0x7e31,0x9112,0x8d70,0x594f,0x63cd,0x79df,0x8db3,0x5352,0x65cf,0x7956, 0x8a5b,0x963b,0x7d44,0x947d,0x7e82,0x5634,0x9189,0x6700,0x7f6a,0x5c0a, 0x9075,0x6628,0x5de6,0x4f50,0x67de,0x505a,0x4f5c,0x5750,0x5ea7,UBOGON, UBOGON,UBOGON,UBOGON,UBOGON }, { /* ku 38 */ 0x4e8d,0x4e0c,0x5140,0x4e10,0x5eff,0x5345,0x4e15,0x4e98,0x4e1e,0x9b32, 0x5b6c,0x5669,0x4e28,0x79ba,0x4e3f,0x5315,0x4e47,0x592d,0x723b,0x536e, 0x6c10,0x56df,0x80e4,0x9997,0x6bd3,0x777e,0x9f17,0x4e36,0x4e9f,0x9f10, 0x4e5c,0x4e69,0x4e93,0x8288,0x5b5b,0x55c7,0x560f,0x4ec4,0x5399,0x539d, 0x53b4,0x53a5,0x53ae,0x9768,0x8d0b,0x531a,0x53f5,0x532d,0x5331,0x533e, 0x8cfe,0x5366,0x5363,0x5202,0x5208,0x520e,0x5244,0x5233,0x528c,0x5274, 0x524c,0x525e,0x5261,0x525c,0x84af,0x527d,0x5282,0x5281,0x5290,0x5293, 0x5182,0x7f54,0x4ebb,0x4ec3,0x4ec9,0x4ec2,0x4ee8,0x4ee1,0x4eeb,0x4ede, 0x50b4,0x4ef3,0x4f22,0x4f64,0x4ef5,0x5000,0x5096,0x4f09,0x4f47,0x4f5e, 0x4f67,0x6538,0x4f5a,0x4f5d }, { /* ku 39 */ 0x4f5f,0x4f57,0x4f32,0x4f3d,0x4f76,0x4f74,0x4f91,0x4f89,0x4f83,0x4f8f, 0x4f7e,0x4f7b,0x5115,0x4f7c,0x5102,0x4f94,0x5114,0x513c,0x5137,0x4fc5, 0x4fda,0x4fe3,0x4fdc,0x4fd1,0x4fdf,0x4ff8,0x5029,0x504c,0x4ff3,0x502c, 0x500f,0x502e,0x502d,0x4ffe,0x501c,0x500c,0x5025,0x5028,0x50e8,0x5043, 0x5055,0x5048,0x504e,0x506c,0x50c2,0x513b,0x5110,0x513a,0x50ba,0x50d6, 0x5106,0x50ed,0x50ec,0x50e6,0x50ee,0x5107,0x510b,0x4edd,0x6c3d,0x4f58, 0x50c9,0x4fce,0x9fa0,0x6c46,0x7cf4,0x516e,0x5dfd,0x9ecc,0x9998,0x56c5, 0x5914,0x52f9,0x530d,0x8a07,0x5310,0x9cec,0x5919,0x5155,0x4ea0,0x5156, 0x4eb3,0x886e,0x88a4,0x893b,0x81e0,0x88d2,0x7980,0x5b34,0x8803,0x7fb8, 0x51ab,0x51b1,0x51bd,0x51bc }, { /* ku 3a */ 0x51c7,0x5196,0x51a2,0x51a5,0x8a01,0x8a10,0x8a0c,0x8a15,0x8b33,0x8a4e, 0x8a25,0x8a41,0x8a36,0x8a46,0x8a54,0x8a58,0x8a52,0x8a86,0x8a84,0x8a7f, 0x8a70,0x8a7c,0x8a75,0x8a6c,0x8a6e,0x8acd,0x8ae2,0x8a61,0x8a9a,0x8aa5, 0x8a91,0x8a92,0x8acf,0x8ad1,0x8ac9,0x8adb,0x8ad7,0x8ac2,0x8ab6,0x8af6, 0x8aeb,0x8b14,0x8b01,0x8ae4,0x8aed,0x8afc,0x8af3,0x8ae6,0x8aee,0x8ade, 0x8b28,0x8b9c,0x8b16,0x8b1a,0x8b10,0x8b2b,0x8b2d,0x8b56,0x8b59,0x8b4e, 0x8b9e,0x8b6b,0x8b96,0x5369,0x537a,0x961d,0x9622,0x9621,0x9631,0x962a, 0x963d,0x963c,0x9642,0x9658,0x9654,0x965f,0x9689,0x966c,0x9672,0x9674, 0x9688,0x968d,0x9697,0x96b0,0x9097,0x909b,0x913a,0x9099,0x9114,0x90a1, 0x90b4,0x90b3,0x90b6,0x9134 }, { /* ku 3b */ 0x90b8,0x90b0,0x90df,0x90c5,0x90be,0x9136,0x90c4,0x90c7,0x9106,0x9148, 0x90e2,0x90dc,0x90d7,0x90db,0x90eb,0x90ef,0x90fe,0x9104,0x9122,0x911e, 0x9123,0x9131,0x912f,0x9139,0x9143,0x9146,0x82bb,0x5950,0x52f1,0x52ac, 0x52ad,0x52be,0x54ff,0x52d0,0x52d6,0x52f0,0x53df,0x71ee,0x77cd,0x5ef4, 0x51f5,0x51fc,0x9b2f,0x53b6,0x5f01,0x755a,0x5df0,0x574c,0x580a,0x57a1, 0x587e,0x58bc,0x58c5,0x58d1,0x5729,0x572c,0x572a,0x5733,0x58d9,0x572e, 0x572f,0x58e2,0x573b,0x5742,0x5769,0x58e0,0x576b,0x58da,0x577c,0x577b, 0x5768,0x576d,0x5776,0x5773,0x57e1,0x57a4,0x578c,0x584f,0x57cf,0x57a7, 0x5816,0x5793,0x57a0,0x57d5,0x5852,0x581d,0x5864,0x57d2,0x57b8,0x57f4, 0x57ef,0x57f8,0x57e4,0x57dd }, { /* ku 3c */ 0x580b,0x580d,0x57fd,0x57ed,0x5800,0x581e,0x5819,0x5844,0x5820,0x5865, 0x586c,0x5881,0x5889,0x589a,0x5880,0x99a8,0x9f19,0x61ff,0x8279,0x827d, 0x827f,0x828f,0x828a,0x82a8,0x8284,0x828e,0x8291,0x858c,0x8299,0x82ab, 0x8553,0x82be,0x82b0,0x85f6,0x82ca,0x82e3,0x8298,0x82b7,0x82ae,0x83a7, 0x8407,0x84ef,0x82a9,0x82b4,0x82a1,0x82aa,0x829f,0x82c4,0x82e7,0x82a4, 0x82e1,0x8309,0x82f7,0x82e4,0x8622,0x8307,0x82dc,0x82f4,0x82d2,0x82d8, 0x830c,0x82fb,0x82d3,0x8526,0x831a,0x8306,0x584b,0x7162,0x82e0,0x82d5, 0x831c,0x8351,0x8558,0x84fd,0x8308,0x8392,0x833c,0x8334,0x8331,0x839b, 0x854e,0x832f,0x834f,0x8347,0x8343,0x8588,0x8340,0x8317,0x85ba,0x832d, 0x833a,0x8333,0x7296,0x6ece }, { /* ku 3d */ 0x8541,0x831b,0x85ce,0x8552,0x84c0,0x8452,0x8464,0x83b0,0x8378,0x8494, 0x8435,0x83a0,0x83aa,0x8393,0x839c,0x8385,0x837c,0x859f,0x83a9,0x837d, 0x8555,0x837b,0x8398,0x839e,0x83a8,0x9daf,0x8493,0x83c1,0x8401,0x83e5, 0x83d8,0x5807,0x8418,0x840b,0x83dd,0x83fd,0x83d6,0x841c,0x8438,0x8411, 0x8406,0x83d4,0x83df,0x840f,0x8403,0x83f8,0x83f9,0x83ea,0x83c5,0x83c0, 0x7e08,0x83f0,0x83e1,0x845c,0x8451,0x845a,0x8459,0x8473,0x8546,0x8488, 0x847a,0x8562,0x8478,0x843c,0x8446,0x8469,0x8476,0x851e,0x848e,0x8431, 0x846d,0x84c1,0x84cd,0x84d0,0x9a40,0x84bd,0x84d3,0x84ca,0x84bf,0x84ba, 0x863a,0x84a1,0x84b9,0x84b4,0x8497,0x93a3,0x8577,0x850c,0x750d,0x8538, 0x84f0,0x861e,0x851f,0x85fa }, { /* ku 3e */ 0x8556,0x853b,0x84ff,0x84fc,0x8559,0x8548,0x8568,0x8564,0x855e,0x857a, 0x77a2,0x8543,0x8604,0x857b,0x85a4,0x85a8,0x8587,0x858f,0x8579,0x85ea, 0x859c,0x8585,0x85b9,0x85b7,0x85b0,0x861a,0x85c1,0x85dc,0x85ff,0x8627, 0x8605,0x8629,0x8616,0x863c,0x5efe,0x5f08,0x593c,0x5969,0x8037,0x5955, 0x595a,0x5958,0x530f,0x5c22,0x5c25,0x5c2c,0x5c37,0x624c,0x636b,0x6476, 0x62bb,0x62ca,0x62da,0x62d7,0x62ee,0x649f,0x62f6,0x6339,0x634b,0x6343, 0x63ad,0x63f6,0x6371,0x637a,0x638e,0x6451,0x636d,0x63ac,0x638a,0x6369, 0x63ae,0x645c,0x63f2,0x63f8,0x63e0,0x64b3,0x63c4,0x63de,0x63ce,0x6452, 0x63c6,0x63be,0x6504,0x6441,0x640b,0x641b,0x6420,0x640c,0x6426,0x6421, 0x645e,0x6516,0x646d,0x6496 }, { /* ku 3f */ 0x647a,0x64f7,0x64fc,0x6499,0x651b,0x64c0,0x64d0,0x64d7,0x64e4,0x64e2, 0x6509,0x6525,0x652e,0x5f0b,0x5fd2,0x7519,0x5f11,0x535f,0x53f1,0x5630, 0x53e9,0x53e8,0x53fb,0x5412,0x5416,0x5406,0x544b,0x5638,0x56c8,0x5454, 0x56a6,0x5443,0x5421,0x5504,0x54bc,0x5423,0x5432,0x5482,0x5494,0x5477, 0x5471,0x5464,0x549a,0x5680,0x5484,0x5476,0x5466,0x565d,0x54d0,0x54ad, 0x54c2,0x54b4,0x5660,0x54a7,0x54a6,0x5635,0x55f6,0x5472,0x54a3,0x5666, 0x54bb,0x54bf,0x54cc,0x5672,0x54da,0x568c,0x54a9,0x54aa,0x54a4,0x5665, 0x54cf,0x54de,0x561c,0x54e7,0x562e,0x54fd,0x5514,0x54f3,0x55e9,0x5523, 0x550f,0x5511,0x5527,0x552a,0x5616,0x558f,0x55b5,0x5549,0x56c0,0x5541, 0x5555,0x553f,0x5550,0x553c }, { /* ku 40 */ 0x5537,0x5556,0x5575,0x5576,0x5577,0x5533,0x5530,0x555c,0x558b,0x55d2, 0x5583,0x55b1,0x55b9,0x5588,0x5581,0x559f,0x557e,0x55d6,0x5591,0x557b, 0x55df,0x560d,0x56b3,0x5594,0x5599,0x55ea,0x55f7,0x55c9,0x561f,0x55d1, 0x56c1,0x55ec,0x55d4,0x55e6,0x55dd,0x55c4,0x55ef,0x55e5,0x55f2,0x566f, 0x55cc,0x55cd,0x55e8,0x55f5,0x55e4,0x8f61,0x561e,0x5608,0x560c,0x5601, 0x56b6,0x5623,0x55fe,0x5600,0x5627,0x562d,0x5658,0x5639,0x5657,0x562c, 0x564d,0x5662,0x5659,0x5695,0x564c,0x5654,0x5686,0x5664,0x5671,0x566b, 0x567b,0x567c,0x5685,0x5693,0x56af,0x56d4,0x56d7,0x56dd,0x56e1,0x5707, 0x56eb,0x56f9,0x56ff,0x5704,0x570a,0x5709,0x571c,0x5e43,0x5e19,0x5e14, 0x5e11,0x5e6c,0x5e58,0x5e57 }, { /* ku 41 */ 0x5e37,0x5e44,0x5e54,0x5e5b,0x5e5e,0x5e61,0x5c8c,0x5c7a,0x5c8d,0x5c90, 0x5d87,0x5c88,0x5cf4,0x5c99,0x5c91,0x5d50,0x5c9c,0x5cb5,0x5ca2,0x5d2c, 0x5cac,0x5cab,0x5cb1,0x5ca3,0x5cc1,0x5cb7,0x5da7,0x5cd2,0x5da0,0x5ccb, 0x5d22,0x5d97,0x5d0d,0x5d27,0x5d26,0x5d2e,0x5d24,0x5d1e,0x5d06,0x5d1b, 0x5db8,0x5d3e,0x5d34,0x5d3d,0x5d6c,0x5d5b,0x5d6f,0x5d81,0x5d6b,0x5d4b, 0x5d4a,0x5d69,0x5d74,0x5d82,0x5d99,0x5d9d,0x8c73,0x5db7,0x5dd4,0x5f73, 0x5f77,0x5f82,0x5f87,0x5f89,0x540e,0x5fa0,0x5f99,0x5f9c,0x5fa8,0x5fad, 0x5fb5,0x5fbc,0x8862,0x5f61,0x72ad,0x72b0,0x72b4,0x7377,0x7341,0x72c3, 0x72c1,0x72ce,0x72cd,0x72d2,0x72e8,0x736a,0x72e9,0x733b,0x72f4,0x72f7, 0x7301,0x72f3,0x736b,0x72fa }, { /* ku 42 */ 0x72fb,0x7317,0x7313,0x7380,0x730a,0x731e,0x731d,0x737c,0x7322,0x7339, 0x7325,0x732c,0x7338,0x7331,0x7350,0x734d,0x7357,0x7360,0x736c,0x736f, 0x737e,0x821b,0x5925,0x98e7,0x5924,0x5902,0x98e0,0x9933,0x98e9,0x993c, 0x98ea,0x98eb,0x98ed,0x98f4,0x9909,0x9911,0x4f59,0x991b,0x9937,0x993f, 0x9943,0x9948,0x9949,0x994a,0x994c,0x9962,0x5e80,0x5ee1,0x5e8b,0x5e96, 0x5ea5,0x5ea0,0x5eb9,0x5eb5,0x5ebe,0x5eb3,0x8ce1,0x5ed2,0x5ed1,0x5edb, 0x5ee8,0x5eea,0x81ba,0x5fc4,0x5fc9,0x5fd6,0x61fa,0x61ae,0x5fee,0x616a, 0x5fe1,0x5fe4,0x613e,0x60b5,0x6134,0x5fea,0x5fed,0x5ff8,0x6019,0x6035, 0x6026,0x601b,0x600f,0x600d,0x6029,0x602b,0x600a,0x61cc,0x6021,0x615f, 0x61e8,0x60fb,0x6137,0x6042 }, { /* ku 43 */ 0x606a,0x60f2,0x6096,0x609a,0x6173,0x609d,0x6083,0x6092,0x608c,0x609b, 0x611c,0x60bb,0x60b1,0x60dd,0x60d8,0x60c6,0x60da,0x60b4,0x6120,0x6192, 0x6115,0x6123,0x60f4,0x6100,0x610e,0x612b,0x614a,0x6175,0x61ac,0x6194, 0x61a7,0x61b7,0x61d4,0x61f5,0x5fdd,0x96b3,0x9582,0x9586,0x95c8,0x958e, 0x9594,0x958c,0x95e5,0x95ad,0x95ab,0x9b2e,0x95ac,0x95be,0x95b6,0x9b29, 0x95bf,0x95bd,0x95bc,0x95c3,0x95cb,0x95d4,0x95d0,0x95d5,0x95de,0x4e2c, 0x723f,0x6215,0x6c35,0x6c54,0x6c5c,0x6c4a,0x7043,0x6c85,0x6c90,0x6c94, 0x6c8c,0x6c68,0x6c69,0x6c74,0x6c76,0x6c86,0x6f59,0x6cd0,0x6cd4,0x6cad, 0x7027,0x7018,0x6cf1,0x6cd7,0x6cb2,0x6ce0,0x6cd6,0x6ffc,0x6ceb,0x6cee, 0x6cb1,0x6cd3,0x6cef,0x6d87 }, { /* ku 44 */ 0x6d39,0x6d27,0x6d0c,0x6d79,0x6e5e,0x6d07,0x6d04,0x6d19,0x6d0e,0x6d2b, 0x6fae,0x6d2e,0x6d35,0x6d1a,0x700f,0x6ef8,0x6f6f,0x6d33,0x6d91,0x6d6f, 0x6df6,0x6f7f,0x6d5e,0x6d93,0x6d94,0x6d5c,0x6d60,0x6d7c,0x6d63,0x6e1a, 0x6dc7,0x6dc5,0x6dde,0x7006,0x6dbf,0x6de0,0x6fa0,0x6de6,0x6ddd,0x6dd9, 0x700b,0x6dab,0x6e0c,0x6dae,0x6e2b,0x6e6e,0x6e4e,0x6e6b,0x6eb2,0x6e5f, 0x6e86,0x6e53,0x6e54,0x6e32,0x6e25,0x6e44,0x7067,0x6eb1,0x6e98,0x7044, 0x6f2d,0x7005,0x6ea5,0x6ea7,0x6ebd,0x6ebb,0x6eb7,0x6f77,0x6eb4,0x6ecf, 0x6e8f,0x6ec2,0x6e9f,0x6f62,0x7020,0x701f,0x6f24,0x6f15,0x6ef9,0x6f2f, 0x6f36,0x7032,0x6f74,0x6f2a,0x6f09,0x6f29,0x6f89,0x6f8d,0x6f8c,0x6f78, 0x6f72,0x6f7c,0x6f7a,0x7028 }, { /* ku 45 */ 0x6fc9,0x6fa7,0x6fb9,0x6fb6,0x6fc2,0x6fe1,0x6fee,0x6fde,0x6fe0,0x6fef, 0x701a,0x7023,0x701b,0x7039,0x7035,0x705d,0x705e,0x5b80,0x5b84,0x5b95, 0x5b93,0x5ba5,0x5bb8,0x752f,0x9a2b,0x6434,0x5be4,0x5bee,0x8930,0x5bf0, 0x8e47,0x8b07,0x8fb6,0x8fd3,0x8fd5,0x8fe5,0x8fee,0x8fe4,0x9087,0x8fe6, 0x9015,0x8fe8,0x9005,0x9004,0x900b,0x9090,0x9011,0x900d,0x9016,0x9021, 0x9035,0x9036,0x902d,0x902f,0x9044,0x9051,0x9052,0x9050,0x9068,0x9058, 0x9062,0x905b,0x66b9,0x9074,0x907d,0x9082,0x9088,0x9083,0x908b,0x5f50, 0x5f57,0x5f56,0x5f58,0x5c3b,0x54ab,0x5c50,0x5c59,0x5b71,0x5c63,0x5c68, 0x7fbc,0x5f33,0x5f29,0x5f2d,0x8274,0x5f3c,0x9b3b,0x5c6e,0x5981,0x5983, 0x598d,0x5af5,0x5ad7,0x59a3 }, { /* ku 46 */ 0x5997,0x59ca,0x5b00,0x599e,0x59a4,0x59d2,0x59b2,0x59af,0x59d7,0x59be, 0x5a6d,0x5b08,0x59dd,0x5b4c,0x59e3,0x59d8,0x59f9,0x5a0c,0x5a09,0x5aa7, 0x5afb,0x5a11,0x5a23,0x5a13,0x5a40,0x5a67,0x5a4a,0x5a55,0x5a3c,0x5a62, 0x5b0b,0x80ec,0x5aaa,0x5a9b,0x5a77,0x5a7a,0x5abe,0x5aeb,0x5ab2,0x5b21, 0x5b2a,0x5ab8,0x5ae0,0x5ae3,0x5b19,0x5ad6,0x5ae6,0x5ad8,0x5adc,0x5b09, 0x5b17,0x5b16,0x5b32,0x5b37,0x5b40,0x5c15,0x5c1c,0x5b5a,0x5b65,0x5b73, 0x5b51,0x5b53,0x5b62,0x99d4,0x99df,0x99d9,0x9a36,0x9a5b,0x99d1,0x99d8, 0x9a4d,0x9a4a,0x99e2,0x9a6a,0x9a0f,0x9a0d,0x9a05,0x9a42,0x9a2d,0x9a16, 0x9a41,0x9a2e,0x9a38,0x9a43,0x9a44,0x9a4f,0x9a65,0x9a64,0x7cf9,0x7d06, 0x7d02,0x7d07,0x7d08,0x7e8a }, { /* ku 47 */ 0x7d1c,0x7d15,0x7d13,0x7d3a,0x7d32,0x7d31,0x7e10,0x7d3c,0x7d40,0x7d3f, 0x7d5d,0x7d4e,0x7d73,0x7d86,0x7d83,0x7d88,0x7dbe,0x7dba,0x7dcb,0x7dd4, 0x7dc4,0x7d9e,0x7dac,0x7db9,0x7da3,0x7db0,0x7dc7,0x7dd9,0x7dd7,0x7df9, 0x7df2,0x7e62,0x7de6,0x7df6,0x7df1,0x7e0b,0x7de1,0x7e09,0x7e1d,0x7e1f, 0x7e1e,0x7e2d,0x7e0a,0x7e11,0x7e7d,0x7e39,0x7e35,0x7e32,0x7e46,0x7e45, 0x7e88,0x7e5a,0x7e52,0x7e6e,0x7e7e,0x7e70,0x7e6f,0x7e98,0x5e7a,0x757f, 0x5ddb,0x753e,0x9095,0x738e,0x74a3,0x744b,0x73a2,0x739f,0x73cf,0x73c2, 0x74cf,0x73b7,0x73b3,0x73c0,0x73c9,0x73c8,0x73e5,0x73d9,0x980a,0x740a, 0x73e9,0x73e7,0x73de,0x74bd,0x743f,0x7489,0x742a,0x745b,0x7426,0x7425, 0x7428,0x7430,0x742e,0x742c }, { /* ku 48 */ 0x741b,0x741a,0x7441,0x745c,0x7457,0x7455,0x7459,0x74a6,0x746d,0x747e, 0x749c,0x74d4,0x7480,0x7481,0x7487,0x748b,0x749e,0x74a8,0x74a9,0x7490, 0x74a7,0x74da,0x74ba,0x97d9,0x97de,0x97dc,0x674c,0x6753,0x675e,0x6748, 0x69aa,0x6aea,0x6787,0x676a,0x6773,0x6798,0x6898,0x6775,0x68d6,0x6a05, 0x689f,0x678b,0x6777,0x677c,0x67f0,0x6adb,0x67d8,0x6af3,0x67e9,0x67b0, 0x6ae8,0x67d9,0x67b5,0x67da,0x67b3,0x67dd,0x6800,0x67c3,0x67b8,0x67e2, 0x6adf,0x67c1,0x6a89,0x6832,0x6833,0x690f,0x6a48,0x684e,0x6968,0x6844, 0x69bf,0x6883,0x681d,0x6855,0x6a3a,0x6841,0x6a9c,0x6840,0x6b12,0x684a, 0x6849,0x6829,0x68b5,0x688f,0x6874,0x6877,0x6893,0x686b,0x6b1e,0x696e, 0x68fc,0x6add,0x69e7,0x68f9 }, { /* ku 49 */ 0x6b0f,0x68f0,0x690b,0x6901,0x6957,0x68e3,0x6910,0x6971,0x6939,0x6960, 0x6942,0x695d,0x6b16,0x696b,0x6980,0x6998,0x6978,0x6934,0x69cc,0x6aec, 0x6ada,0x69ce,0x6af8,0x6966,0x6963,0x6979,0x699b,0x69a7,0x69bb,0x69ab, 0x69ad,0x69d4,0x69b1,0x69c1,0x69ca,0x6ab3,0x6995,0x6ae7,0x698d,0x69ff, 0x6aa3,0x69ed,0x6a17,0x6a18,0x6a65,0x69f2,0x6a44,0x6a3e,0x6aa0,0x6a50, 0x6a5b,0x6a35,0x6a8e,0x6ad3,0x6a3d,0x6a28,0x6a58,0x6ade,0x6a91,0x6a90, 0x6aa9,0x6a97,0x6aab,0x7337,0x7352,0x6b81,0x6b82,0x6ba4,0x6b84,0x6b9e, 0x6bae,0x6b8d,0x6bab,0x6b9b,0x6baf,0x6baa,0x8ed4,0x8edb,0x8ef2,0x8efb, 0x8f64,0x8ef9,0x8efc,0x8eeb,0x8ee4,0x8f62,0x8efa,0x8efe,0x8f0a,0x8f07, 0x8f05,0x8f12,0x8f26,0x8f1e }, { /* ku 4a */ 0x8f1f,0x8f1c,0x8f33,0x8f46,0x8f54,0x8ece,0x6214,0x6227,0x621b,0x621f, 0x6222,0x6221,0x6225,0x6224,0x6229,0x81e7,0x750c,0x74f4,0x74ff,0x750f, 0x7511,0x7513,0x6534,0x65ee,0x65ef,0x65f0,0x660a,0x66c7,0x6772,0x6603, 0x6615,0x6600,0x7085,0x66f7,0x661d,0x6634,0x6631,0x6636,0x6635,0x8006, 0x665f,0x66c4,0x6641,0x664f,0x6689,0x6661,0x6657,0x6677,0x6684,0x668c, 0x66d6,0x669d,0x66be,0x66db,0x66dc,0x66e6,0x66e9,0x8cc1,0x8cb0,0x8cba, 0x8cbd,0x8d04,0x8cb2,0x8cc5,0x8d10,0x8cd1,0x8cda,0x8cd5,0x8ceb,0x8ce7, 0x8cfb,0x8998,0x89ac,0x89a1,0x89bf,0x89a6,0x89af,0x89b2,0x89b7,0x726e, 0x729f,0x725d,0x7266,0x726f,0x727e,0x727f,0x7284,0x728b,0x728d,0x728f, 0x7292,0x6308,0x6332,0x63b0 }, { /* ku 4b */ 0x643f,0x64d8,0x8004,0x6bea,0x6bf3,0x6bfd,0x6bff,0x6bf9,0x6c05,0x6c0c, 0x6c06,0x6c0d,0x6c15,0x6c18,0x6c19,0x6c1a,0x6c21,0x6c2c,0x6c24,0x6c2a, 0x6c32,0x6535,0x6555,0x656b,0x7258,0x7252,0x7256,0x7230,0x8662,0x5216, 0x809f,0x809c,0x8093,0x80bc,0x670a,0x80bd,0x80b1,0x80ab,0x80ad,0x80b4, 0x80b7,0x6727,0x8156,0x80e9,0x81da,0x80db,0x80c2,0x80c4,0x80d9,0x80cd, 0x80d7,0x6710,0x80dd,0x811b,0x80f1,0x80f4,0x80ed,0x81be,0x810e,0x80f2, 0x80fc,0x6715,0x8112,0x8c5a,0x8161,0x811e,0x812c,0x8118,0x8132,0x8148, 0x814c,0x8153,0x8174,0x8159,0x815a,0x8171,0x8160,0x8169,0x817c,0x817d, 0x816d,0x8167,0x584d,0x5ab5,0x8188,0x8182,0x81cf,0x6ed5,0x81a3,0x81aa, 0x81cc,0x6726,0x81ca,0x81bb }, { /* ku 4c */ 0x81c1,0x81a6,0x6b5f,0x6b37,0x6b39,0x6b43,0x6b46,0x6b59,0x98ae,0x98af, 0x98b6,0x98bc,0x98c6,0x98c8,0x6bb3,0x5f40,0x8f42,0x89f3,0x6590,0x9f4f, 0x6595,0x65bc,0x65c6,0x65c4,0x65c3,0x65cc,0x65ce,0x65d2,0x65d6,0x716c, 0x7152,0x7096,0x7197,0x70bb,0x70c0,0x70b7,0x70ab,0x70b1,0x71c1,0x70ca, 0x7110,0x7113,0x71dc,0x712f,0x7131,0x7173,0x715c,0x7168,0x7145,0x7172, 0x714a,0x7178,0x717a,0x7198,0x71b3,0x71b5,0x71a8,0x71a0,0x71e0,0x71d4, 0x71e7,0x71f9,0x721d,0x7228,0x706c,0x71fe,0x7166,0x71b9,0x623e,0x623d, 0x6243,0x6248,0x6249,0x793b,0x7940,0x7946,0x7949,0x795b,0x795c,0x7953, 0x795a,0x79b0,0x7957,0x7960,0x798e,0x7967,0x797a,0x79aa,0x798a,0x799a, 0x79a7,0x79b3,0x5fd1,0x5fd0 }, { /* ku 4d */ 0x61df,0x605d,0x605a,0x6067,0x6041,0x6059,0x6063,0x6164,0x6106,0x610d, 0x615d,0x61a9,0x619d,0x61cb,0x61e3,0x6207,0x8080,0x807f,0x6c93,0x6fa9, 0x6dfc,0x78ef,0x77f8,0x78ad,0x7809,0x7868,0x7818,0x7811,0x65ab,0x782d, 0x78b8,0x781d,0x7839,0x792a,0x7931,0x781f,0x783c,0x7825,0x782c,0x7823, 0x7829,0x784e,0x786d,0x7864,0x78fd,0x7826,0x7850,0x7847,0x784c,0x786a, 0x78e7,0x7893,0x789a,0x7887,0x78e3,0x78a1,0x78a3,0x78b2,0x78b9,0x78a5, 0x78d4,0x78d9,0x78c9,0x78ec,0x78f2,0x7905,0x78f4,0x7913,0x7924,0x791e, 0x7934,0x9f95,0x9ef9,0x9efb,0x9efc,0x76f1,0x7704,0x7798,0x76f9,0x7707, 0x7708,0x771a,0x7722,0x7719,0x772d,0x7726,0x7735,0x7738,0x775e,0x77bc, 0x7747,0x7743,0x775a,0x7768 }, { /* ku 4e */ 0x7762,0x7765,0x777f,0x778d,0x777d,0x7780,0x778c,0x7791,0x779f,0x77a0, 0x77b0,0x77b5,0x77bd,0x753a,0x7540,0x754e,0x754b,0x7548,0x755b,0x7572, 0x7579,0x7583,0x7f58,0x7f61,0x7f5f,0x8a48,0x7f68,0x7f86,0x7f71,0x7f79, 0x7f88,0x7f7e,0x76cd,0x76e5,0x8832,0x91d2,0x91d3,0x91d4,0x91d9,0x91d7, 0x91d5,0x91f7,0x91e7,0x91e4,0x9346,0x91f5,0x91f9,0x9208,0x9226,0x9245, 0x9211,0x9210,0x9201,0x9227,0x9204,0x9225,0x9200,0x923a,0x9266,0x9237, 0x9233,0x9255,0x923d,0x9238,0x925e,0x926c,0x926d,0x923f,0x9460,0x9230, 0x9249,0x9248,0x924d,0x922e,0x9239,0x9438,0x92ac,0x92a0,0x927a,0x92aa, 0x92ee,0x92cf,0x9403,0x92e3,0x943a,0x92b1,0x92a6,0x93a7,0x9296,0x92cc, 0x92a9,0x93f5,0x9293,0x927f }, { /* ku 4f */ 0x93a9,0x929a,0x931a,0x92ab,0x9283,0x940b,0x92a8,0x92a3,0x9412,0x9338, 0x92f1,0x93d7,0x92e5,0x92f0,0x92ef,0x92e8,0x92bc,0x92dd,0x92f6,0x9426, 0x9427,0x92c3,0x92df,0x92e6,0x9312,0x9306,0x9369,0x931b,0x9340,0x9301, 0x9315,0x932e,0x9343,0x9307,0x9308,0x931f,0x9319,0x9365,0x9347,0x9376, 0x9354,0x9364,0x93aa,0x9370,0x9384,0x93e4,0x93d8,0x9428,0x9387,0x93cc, 0x9398,0x93b8,0x93bf,0x93a6,0x93b0,0x93b5,0x944c,0x93e2,0x93dc,0x93dd, 0x93cd,0x93de,0x93c3,0x93c7,0x93d1,0x9414,0x941d,0x93f7,0x9465,0x9413, 0x946d,0x9420,0x9479,0x93f9,0x9419,0x944a,0x9432,0x943f,0x9454,0x9463, 0x937e,0x77e7,0x77ec,0x96c9,0x79d5,0x79ed,0x79e3,0x79eb,0x7a06,0x5d47, 0x7a03,0x7a02,0x7a1e,0x7a14 }, { /* ku 50 */ 0x7a39,0x7a37,0x7a61,0x9ecf,0x99a5,0x7a70,0x7688,0x768e,0x7693,0x7699, 0x76a4,0x74de,0x74e0,0x752c,0x9ce9,0x9cf6,0x9d07,0x9d06,0x9d23,0x9d87, 0x9e15,0x9d1d,0x9d1f,0x9de5,0x9d2f,0x9dd9,0x9d30,0x9d42,0x9e1e,0x9d53, 0x9e1d,0x9d60,0x9d52,0x9df3,0x9d5c,0x9d61,0x9d93,0x9d6a,0x9d6f,0x9d89, 0x9d98,0x9d9a,0x9dc0,0x9da5,0x9da9,0x9dc2,0x9dbc,0x9e1a,0x9dd3,0x9dda, 0x9def,0x9de6,0x9df2,0x9df8,0x9e0c,0x9dfa,0x9e1b,0x7592,0x7594,0x7664, 0x7658,0x759d,0x7667,0x75a3,0x75b3,0x75b4,0x75b8,0x75c4,0x75b1,0x75b0, 0x75c3,0x75c2,0x7602,0x75cd,0x75e3,0x7646,0x75e6,0x75e4,0x7647,0x75e7, 0x7603,0x75f1,0x75fc,0x75ff,0x7610,0x7600,0x7649,0x760c,0x761e,0x760a, 0x7625,0x763b,0x7615,0x7619 }, { /* ku 51 */ 0x761b,0x763c,0x7622,0x7620,0x7640,0x762d,0x7630,0x766d,0x7635,0x7643, 0x766e,0x7633,0x764d,0x7669,0x7654,0x765c,0x7656,0x7672,0x766f,0x7fca, 0x7ae6,0x7a78,0x7a79,0x7a80,0x7a86,0x7a88,0x7a95,0x7ac7,0x7aa0,0x7aac, 0x7aa8,0x7ab6,0x7ab3,0x8864,0x8869,0x8872,0x887d,0x887f,0x8882,0x88a2, 0x8960,0x88b7,0x88bc,0x88c9,0x8933,0x88ce,0x895d,0x8947,0x88f1,0x891a, 0x88fc,0x88e8,0x88fe,0x88f0,0x8921,0x8919,0x8913,0x8938,0x890a,0x8964, 0x892b,0x8936,0x8941,0x8966,0x897b,0x758b,0x80e5,0x76b8,0x76b4,0x77dc, 0x8012,0x8014,0x8016,0x801c,0x8020,0x802e,0x8025,0x8026,0x802c,0x8029, 0x8028,0x8031,0x800b,0x8035,0x8043,0x8046,0x8079,0x8052,0x8075,0x8071, 0x8983,0x9807,0x980e,0x980f }, { /* ku 52 */ 0x9821,0x981c,0x6f41,0x9826,0x9837,0x984e,0x9853,0x9873,0x9862,0x9859, 0x9865,0x986c,0x9870,0x864d,0x8654,0x866c,0x87e3,0x8806,0x867a,0x867c, 0x867b,0x86a8,0x868d,0x868b,0x8706,0x869d,0x86a7,0x86a3,0x86aa,0x8693, 0x86a9,0x86b6,0x86c4,0x86b5,0x8823,0x86b0,0x86ba,0x86b1,0x86af,0x86c9, 0x87f6,0x86b4,0x86e9,0x86fa,0x87ef,0x86ed,0x8784,0x86d0,0x8713,0x86de, 0x8810,0x86df,0x86d8,0x86d1,0x8703,0x8707,0x86f8,0x8708,0x870a,0x870d, 0x8709,0x8723,0x873b,0x871e,0x8725,0x872e,0x871a,0x873e,0x87c8,0x8734, 0x8731,0x8729,0x8737,0x873f,0x8782,0x8722,0x877d,0x8811,0x877b,0x8760, 0x8770,0x874c,0x876e,0x878b,0x8753,0x8763,0x87bb,0x8764,0x8759,0x8765, 0x8793,0x87af,0x87ce,0x87d2 }, { /* ku 53 */ 0x87c6,0x8788,0x8785,0x87ad,0x8797,0x8783,0x87ab,0x87e5,0x87ac,0x87b5, 0x87b3,0x87cb,0x87d3,0x87bd,0x87d1,0x87c0,0x87ca,0x87db,0x87ea,0x87e0, 0x87ee,0x8816,0x8813,0x87fe,0x880a,0x881b,0x8821,0x8839,0x883c,0x7f36, 0x7f4c,0x7f44,0x7f45,0x8210,0x7afa,0x7afd,0x7b08,0x7be4,0x7b04,0x7b67, 0x7b0a,0x7b2b,0x7b0f,0x7b47,0x7b38,0x7b2a,0x7b19,0x7b2e,0x7b31,0x7b20, 0x7b25,0x7b24,0x7b33,0x7c69,0x7b1e,0x7b58,0x7bf3,0x7b45,0x7b75,0x7b4c, 0x7b8f,0x7b60,0x7b6e,0x7b7b,0x7b62,0x7b72,0x7b71,0x7b90,0x7c00,0x7bcb, 0x7bb8,0x7bac,0x7b9d,0x7c5c,0x7b85,0x7c1e,0x7b9c,0x7ba2,0x7c2b,0x7bb4, 0x7c23,0x7bc1,0x7bcc,0x7bdd,0x7bda,0x7be5,0x7be6,0x7bea,0x7c0c,0x7bfe, 0x7bfc,0x7c0f,0x7c6a,0x7c0b }, { /* ku 54 */ 0x7c1f,0x7c2a,0x7c26,0x7c38,0x7c5f,0x7c40,0x81fe,0x8201,0x8202,0x8204, 0x81ec,0x8844,0x8221,0x8222,0x8264,0x822d,0x822f,0x8228,0x822b,0x8238, 0x826b,0x8233,0x8234,0x823e,0x8244,0x8249,0x824b,0x824f,0x825a,0x825f, 0x8268,0x887e,0x88ca,0x8888,0x88d8,0x88df,0x895e,0x7f9d,0x7fa5,0x7fa7, 0x7faf,0x7fb0,0x7fb2,0x7c7c,0x6549,0x7c91,0x7cf2,0x7cf6,0x7c9e,0x7ca2, 0x7cb2,0x7cbc,0x7cbd,0x7cdd,0x7cc7,0x7ccc,0x7ccd,0x7cc8,0x7cc5,0x7cd7, 0x7ce8,0x826e,0x66a8,0x7fbf,0x7fce,0x7fd5,0x7fe5,0x7fe1,0x7fe6,0x7fe9, 0x7fee,0x7ff3,0x7cf8,0x7e36,0x7da6,0x7dae,0x7e47,0x7e9b,0x9ea9,0x9eb4, 0x8d73,0x8d84,0x8d94,0x8d91,0x8db2,0x8d67,0x8d6d,0x8c47,0x8c49,0x914a, 0x9150,0x914e,0x914f,0x9164 }, { /* ku 55 */ 0x9162,0x9161,0x9170,0x9169,0x916f,0x91c5,0x91c3,0x9172,0x9174,0x9179, 0x918c,0x9185,0x9190,0x918d,0x9191,0x91a2,0x91a3,0x91aa,0x91ad,0x91ae, 0x91af,0x91b5,0x91b4,0x91ba,0x8c55,0x9e7a,0x8e89,0x8deb,0x8e05,0x8e59, 0x8e69,0x8db5,0x8dbf,0x8dbc,0x8dba,0x8e4c,0x8dd6,0x8dd7,0x8dda,0x8e92, 0x8dce,0x8dcf,0x8ddb,0x8dc6,0x8dec,0x8e7a,0x8e55,0x8de3,0x8e9a,0x8e8b, 0x8de4,0x8e09,0x8dfd,0x8e14,0x8e1d,0x8e1f,0x8e93,0x8e2e,0x8e23,0x8e91, 0x8e3a,0x8e40,0x8e39,0x8e35,0x8e3d,0x8e31,0x8e49,0x8e41,0x8e42,0x8ea1, 0x8e63,0x8e4a,0x8e70,0x8e76,0x8e7c,0x8e6f,0x8e74,0x8e85,0x8eaa,0x8e94, 0x8e90,0x8ea6,0x8e9e,0x8c78,0x8c82,0x8c8a,0x8c85,0x8c98,0x8c94,0x659b, 0x89d6,0x89f4,0x89da,0x89dc }, { /* ku 56 */ 0x89e5,0x89eb,0x89f6,0x8a3e,0x8b26,0x975a,0x96e9,0x9742,0x96ef,0x9706, 0x973d,0x9708,0x970f,0x970e,0x972a,0x9744,0x9730,0x973e,0x9f54,0x9f5f, 0x9f59,0x9f60,0x9f5c,0x9f66,0x9f6c,0x9f6a,0x9f77,0x9efd,0x9eff,0x9f09, 0x96b9,0x96bc,0x96bd,0x96ce,0x96d2,0x77bf,0x8b8e,0x928e,0x947e,0x92c8, 0x93e8,0x936a,0x93ca,0x938f,0x943e,0x946b,0x9b77,0x9b74,0x9b81,0x9b83, 0x9b8e,0x9c78,0x7a4c,0x9b92,0x9c5f,0x9b90,0x9bad,0x9b9a,0x9baa,0x9b9e, 0x9c6d,0x9bab,0x9b9d,0x9c58,0x9bc1,0x9c7a,0x9c31,0x9c39,0x9c23,0x9c37, 0x9bc0,0x9bca,0x9bc7,0x9bfd,0x9bd6,0x9bea,0x9beb,0x9be1,0x9be4,0x9be7, 0x9bdd,0x9be2,0x9bf0,0x9bdb,0x9bf4,0x9bd4,0x9c5d,0x9c08,0x9c10,0x9c0d, 0x9c12,0x9c09,0x9bff,0x9c20 }, { /* ku 57 */ 0x9c32,0x9c2d,0x9c28,0x9c25,0x9c29,0x9c33,0x9c3e,0x9c48,0x9c3b,0x9c35, 0x9c45,0x9c56,0x9c54,0x9c52,0x9c67,0x977c,0x9785,0x97c3,0x97bd,0x9794, 0x97c9,0x97ab,0x97a3,0x97b2,0x97b4,0x9ab1,0x9ab0,0x9ab7,0x9dbb,0x9ab6, 0x9aba,0x9abc,0x9ac1,0x9ac0,0x9acf,0x9ac2,0x9ad6,0x9ad5,0x9ad1,0x9b45, 0x9b43,0x9b58,0x9b4e,0x9b48,0x9b4d,0x9b51,0x9957,0x995c,0x992e,0x9955, 0x9954,0x9adf,0x9ae1,0x9ae6,0x9aef,0x9aeb,0x9afb,0x9aed,0x9af9,0x9b08, 0x9b0f,0x9b22,0x9b1f,0x9b23,0x4e48,0x9ebe,0x7e3b,0x9e82,0x9e87,0x9e88, 0x9e8b,0x9e92,0x93d6,0x9e9d,0x9e9f,0x9edb,0x9edc,0x9edd,0x9ee0,0x9edf, 0x9ee2,0x9ef7,0x9ee7,0x9ee5,0x9ef2,0x9eef,0x9f22,0x9f2c,0x9f2f,0x9f39, 0x9f37,0x9f3d,0x9f3e,0x9f44 }, { /* ku 58 */ 0x896c,0x95c6,0x9336,0x5f46,0x8514,0x7e94,0x5382,0x51b2,0x4e11,0x9f63, 0x5679,0x515a,0x6dc0,0x9f15,0x6597,0x5641,0x9aee,0x8303,0x4e30,0x8907, 0x5e72,0x7a40,0x98b3,0x5e7f,0x95a4,0x9b0d,0x5212,0x8ff4,0x5f59,0x7a6b, 0x98e2,0x51e0,0x50a2,0x4ef7,0x8350,0x8591,0x5118,0x636e,0x6372,0x524b, 0x5938,0x774f,0x8721,0x814a,0x7e8d,0x91cc,0x66c6,0x5e18,0x77ad,0x9e75, 0x56c9,0x9ef4,0x6fdb,0x61de,0x77c7,0x7030,0x9eb5,0x884a,0x95e2,0x82f9, 0x51ed,0x6251,0x4ec6,0x6734,0x97c6,0x7c64,0x7e34,0x97a6,0x9eaf,0x786e, 0x820d,0x672f,0x677e,0x56cc,0x53f0,0x98b1,0x6aaf,0x7f4e,0x6d82,0x7cf0, 0x4e07,0x4fc2,0x7e6b,0x9e79,0x56ae,0x9b1a,0x846f,0x53f6,0x90c1,0x79a6, 0x7c72,0x613f,0x4e91,0x9ad2 }, { /* ku 59 */ 0x75c7,0x96bb,0x53ea,0x7dfb,0x88fd,0x79cd,0x7843,0x7b51,0x51c6,UBOGON, UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON, UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON, UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON, UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON, UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON, UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON, UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON, UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON, UBOGON,UBOGON,UBOGON,UBOGON } }; alpine-2.10+dfsg/imap/src/charset/tis_620.c0000600000175000017500000000364511512502123022043 0ustar paulproteuspaulproteus/* ======================================================================== * Copyright 1988-2006 University of Washington * * Licensed under the Apache License, Version 2.0 (the "License"); * you may not use this file except in compliance with the License. * You may obtain a copy of the License at * * http://www.apache.org/licenses/LICENSE-2.0 * * * ======================================================================== */ /* * Program: TIS 620-2529 conversion table * * Author: Mark Crispin * Networks and Distributed Computing * Computing & Communications * University of Washington * Administration Building, AG-44 * Seattle, WA 98195 * Internet: MRC@CAC.Washington.EDU * * Date: 24 October 1997 * Last Edited: 30 August 2006 */ /* TIS 620-2529 is the "Thai Industrial Standard for Thai Character Code * for Computer", published by the Thai Industrial Standards Institute, * Ministry of Industry of Thailand. */ static const unsigned short tis620tab[128] = { 0x0080,0x0081,0x0082,0x0083,0x0084,0x0085,0x0086,0x0087, 0x0088,0x0089,0x008a,0x008b,0x008c,0x008d,0x008e,0x008f, 0x0090,0x0091,0x0092,0x0093,0x0094,0x0095,0x0096,0x0097, 0x0098,0x0099,0x009a,0x009b,0x009c,0x009d,0x009e,0x009f, UBOGON,0x0e01,0x0e02,0x0e03,0x0e04,0x0e05,0x0e06,0x0e07, 0x0e08,0x0e09,0x0e0a,0x0e0b,0x0e0c,0x0e0d,0x0e0e,0x0e0f, 0x0e10,0x0e11,0x0e12,0x0e13,0x0e14,0x0e15,0x0e16,0x0e17, 0x0e18,0x0e19,0x0e1a,0x0e1b,0x0e1c,0x0e1d,0x0e1e,0x0e1f, 0x0e20,0x0e21,0x0e22,0x0e23,0x0e24,0x0e25,0x0e26,0x0e27, 0x0e28,0x0e29,0x0e2a,0x0e2b,0x0e2c,0x0e2d,0x0e2e,0x0e2f, 0x0e30,0x0e31,0x0e32,0x0e33,0x0e34,0x0e35,0x0e36,0x0e37, 0x0e38,0x0e39,0x0e3a,UBOGON,UBOGON,UBOGON,UBOGON,0x0e3f, 0x0e40,0x0e41,0x0e42,0x0e43,0x0e44,0x0e45,0x0e46,0x0e47, 0x0e48,0x0e49,0x0e4a,0x0e4b,0x0e4c,0x0e4d,0x0e4e,0x0e4f, 0x0e50,0x0e51,0x0e52,0x0e53,0x0e54,0x0e55,0x0e56,0x0e57, 0x0e58,0x0e59,0x0e5a,0x0e5b,UBOGON,UBOGON,UBOGON,UBOGON }; alpine-2.10+dfsg/imap/src/charset/ibm.c0000600000175000017500000004124111512502123021416 0ustar paulproteuspaulproteus/* ======================================================================== * Copyright 1988-2006 University of Washington * * Licensed under the Apache License, Version 2.0 (the "License"); * you may not use this file except in compliance with the License. * You may obtain a copy of the License at * * http://www.apache.org/licenses/LICENSE-2.0 * * * ======================================================================== */ /* * Program: IBM conversion tables * * Author: Mark Crispin * Networks and Distributed Computing * Computing & Communications * University of Washington * Administration Building, AG-44 * Seattle, WA 98195 * Internet: MRC@CAC.Washington.EDU * * Date: 4 November 2002 * Last Edited: 30 August 2006 */ /* IBM Latin US */ static const unsigned short ibm_437tab[128] = { 0x00c7,0x00fc,0x00e9,0x00e2,0x00e4,0x00e0,0x00e5,0x00e7, 0x00ea,0x00eb,0x00e8,0x00ef,0x00ee,0x00ec,0x00c4,0x00c5, 0x00c9,0x00e6,0x00c6,0x00f4,0x00f6,0x00f2,0x00fb,0x00f9, 0x00ff,0x00d6,0x00dc,0x00a2,0x00a3,0x00a5,0x20a7,0x0192, 0x00e1,0x00ed,0x00f3,0x00fa,0x00f1,0x00d1,0x00aa,0x00ba, 0x00bf,0x2310,0x00ac,0x00bd,0x00bc,0x00a1,0x00ab,0x00bb, 0x2591,0x2592,0x2593,0x2502,0x2524,0x2561,0x2562,0x2556, 0x2555,0x2563,0x2551,0x2557,0x255d,0x255c,0x255b,0x2510, 0x2514,0x2534,0x252c,0x251c,0x2500,0x253c,0x255e,0x255f, 0x255a,0x2554,0x2569,0x2566,0x2560,0x2550,0x256c,0x2567, 0x2568,0x2564,0x2565,0x2559,0x2558,0x2552,0x2553,0x256b, 0x256a,0x2518,0x250c,0x2588,0x2584,0x258c,0x2590,0x2580, 0x03b1,0x00df,0x0393,0x03c0,0x03a3,0x03c3,0x00b5,0x03c4, 0x03a6,0x0398,0x03a9,0x03b4,0x221e,0x03c6,0x03b5,0x2229, 0x2261,0x00b1,0x2265,0x2264,0x2320,0x2321,0x00f7,0x2248, 0x00b0,0x2219,0x00b7,0x221a,0x207f,0x00b2,0x25a0,0x00a0 }; /* IBM Greek */ static const unsigned short ibm_737tab[128] = { 0x0391,0x0392,0x0393,0x0394,0x0395,0x0396,0x0397,0x0398, 0x0399,0x039a,0x039b,0x039c,0x039d,0x039e,0x039f,0x03a0, 0x03a1,0x03a3,0x03a4,0x03a5,0x03a6,0x03a7,0x03a8,0x03a9, 0x03b1,0x03b2,0x03b3,0x03b4,0x03b5,0x03b6,0x03b7,0x03b8, 0x03b9,0x03ba,0x03bb,0x03bc,0x03bd,0x03be,0x03bf,0x03c0, 0x03c1,0x03c3,0x03c2,0x03c4,0x03c5,0x03c6,0x03c7,0x03c8, 0x2591,0x2592,0x2593,0x2502,0x2524,0x2561,0x2562,0x2556, 0x2555,0x2563,0x2551,0x2557,0x255d,0x255c,0x255b,0x2510, 0x2514,0x2534,0x252c,0x251c,0x2500,0x253c,0x255e,0x255f, 0x255a,0x2554,0x2569,0x2566,0x2560,0x2550,0x256c,0x2567, 0x2568,0x2564,0x2565,0x2559,0x2558,0x2552,0x2553,0x256b, 0x256a,0x2518,0x250c,0x2588,0x2584,0x258c,0x2590,0x2580, 0x03c9,0x03ac,0x03ad,0x03ae,0x03ca,0x03af,0x03cc,0x03cd, 0x03cb,0x03ce,0x0386,0x0388,0x0389,0x038a,0x038c,0x038e, 0x038f,0x00b1,0x2265,0x2264,0x03aa,0x03ab,0x00f7,0x2248, 0x00b0,0x2219,0x00b7,0x221a,0x207f,0x00b2,0x25a0,0x00a0 }; /* IBM Baltic Rim */ static const unsigned short ibm_775tab[128] = { 0x0106,0x00fc,0x00e9,0x0101,0x00e4,0x0123,0x00e5,0x0107, 0x0142,0x0113,0x0156,0x0157,0x012b,0x0179,0x00c4,0x00c5, 0x00c9,0x00e6,0x00c6,0x014d,0x00f6,0x0122,0x00a2,0x015a, 0x015b,0x00d6,0x00dc,0x00f8,0x00a3,0x00d8,0x00d7,0x00a4, 0x0100,0x012a,0x00f3,0x017b,0x017c,0x017a,0x201d,0x00a6, 0x00a9,0x00ae,0x00ac,0x00bd,0x00bc,0x0141,0x00ab,0x00bb, 0x2591,0x2592,0x2593,0x2502,0x2524,0x0104,0x010c,0x0118, 0x0116,0x2563,0x2551,0x2557,0x255d,0x012e,0x0160,0x2510, 0x2514,0x2534,0x252c,0x251c,0x2500,0x253c,0x0172,0x016a, 0x255a,0x2554,0x2569,0x2566,0x2560,0x2550,0x256c,0x017d, 0x0105,0x010d,0x0119,0x0117,0x012f,0x0161,0x0173,0x016b, 0x017e,0x2518,0x250c,0x2588,0x2584,0x258c,0x2590,0x2580, 0x00d3,0x00df,0x014c,0x0143,0x00f5,0x00d5,0x00b5,0x0144, 0x0136,0x0137,0x013b,0x013c,0x0146,0x0112,0x0145,0x2019, 0x00ad,0x00b1,0x201c,0x00be,0x00b6,0x00a7,0x00f7,0x201e, 0x00b0,0x2219,0x00b7,0x00b9,0x00b3,0x00b2,0x25a0,0x00a0 }; /* IBM Latin 1 */ static const unsigned short ibm_850tab[128] = { 0x00c7,0x00fc,0x00e9,0x00e2,0x00e4,0x00e0,0x00e5,0x00e7, 0x00ea,0x00eb,0x00e8,0x00ef,0x00ee,0x00ec,0x00c4,0x00c5, 0x00c9,0x00e6,0x00c6,0x00f4,0x00f6,0x00f2,0x00fb,0x00f9, 0x00ff,0x00d6,0x00dc,0x00f8,0x00a3,0x00d8,0x00d7,0x0192, 0x00e1,0x00ed,0x00f3,0x00fa,0x00f1,0x00d1,0x00aa,0x00ba, 0x00bf,0x00ae,0x00ac,0x00bd,0x00bc,0x00a1,0x00ab,0x00bb, 0x2591,0x2592,0x2593,0x2502,0x2524,0x00c1,0x00c2,0x00c0, 0x00a9,0x2563,0x2551,0x2557,0x255d,0x00a2,0x00a5,0x2510, 0x2514,0x2534,0x252c,0x251c,0x2500,0x253c,0x00e3,0x00c3, 0x255a,0x2554,0x2569,0x2566,0x2560,0x2550,0x256c,0x00a4, 0x00f0,0x00d0,0x00ca,0x00cb,0x00c8,0x0131,0x00cd,0x00ce, 0x00cf,0x2518,0x250c,0x2588,0x2584,0x00a6,0x00cc,0x2580, 0x00d3,0x00df,0x00d4,0x00d2,0x00f5,0x00d5,0x00b5,0x00fe, 0x00de,0x00da,0x00db,0x00d9,0x00fd,0x00dd,0x00af,0x00b4, 0x00ad,0x00b1,0x2017,0x00be,0x00b6,0x00a7,0x00f7,0x00b8, 0x00b0,0x00a8,0x00b7,0x00b9,0x00b3,0x00b2,0x25a0,0x00a0 }; /* IBM Latin 2 */ static const unsigned short ibm_852tab[128] = { 0x00c7,0x00fc,0x00e9,0x00e2,0x00e4,0x016f,0x0107,0x00e7, 0x0142,0x00eb,0x0150,0x0151,0x00ee,0x0179,0x00c4,0x0106, 0x00c9,0x0139,0x013a,0x00f4,0x00f6,0x013d,0x013e,0x015a, 0x015b,0x00d6,0x00dc,0x0164,0x0165,0x0141,0x00d7,0x010d, 0x00e1,0x00ed,0x00f3,0x00fa,0x0104,0x0105,0x017d,0x017e, 0x0118,0x0119,0x00ac,0x017a,0x010c,0x015f,0x00ab,0x00bb, 0x2591,0x2592,0x2593,0x2502,0x2524,0x00c1,0x00c2,0x011a, 0x015e,0x2563,0x2551,0x2557,0x255d,0x017b,0x017c,0x2510, 0x2514,0x2534,0x252c,0x251c,0x2500,0x253c,0x0102,0x0103, 0x255a,0x2554,0x2569,0x2566,0x2560,0x2550,0x256c,0x00a4, 0x0111,0x0110,0x010e,0x00cb,0x010f,0x0147,0x00cd,0x00ce, 0x011b,0x2518,0x250c,0x2588,0x2584,0x0162,0x016e,0x2580, 0x00d3,0x00df,0x00d4,0x0143,0x0144,0x0148,0x0160,0x0161, 0x0154,0x00da,0x0155,0x0170,0x00fd,0x00dd,0x0163,0x00b4, 0x00ad,0x02dd,0x02db,0x02c7,0x02d8,0x00a7,0x00f7,0x00b8, 0x00b0,0x00a8,0x02d9,0x0171,0x0158,0x0159,0x25a0,0x00a0 }; /* IBM Cyrillic */ static const unsigned short ibm_855tab[128] = { 0x0452,0x0402,0x0453,0x0403,0x0451,0x0401,0x0454,0x0404, 0x0455,0x0405,0x0456,0x0406,0x0457,0x0407,0x0458,0x0408, 0x0459,0x0409,0x045a,0x040a,0x045b,0x040b,0x045c,0x040c, 0x045e,0x040e,0x045f,0x040f,0x044e,0x042e,0x044a,0x042a, 0x0430,0x0410,0x0431,0x0411,0x0446,0x0426,0x0434,0x0414, 0x0435,0x0415,0x0444,0x0424,0x0433,0x0413,0x00ab,0x00bb, 0x2591,0x2592,0x2593,0x2502,0x2524,0x0445,0x0425,0x0438, 0x0418,0x2563,0x2551,0x2557,0x255d,0x0439,0x0419,0x2510, 0x2514,0x2534,0x252c,0x251c,0x2500,0x253c,0x043a,0x041a, 0x255a,0x2554,0x2569,0x2566,0x2560,0x2550,0x256c,0x00a4, 0x043b,0x041b,0x043c,0x041c,0x043d,0x041d,0x043e,0x041e, 0x043f,0x2518,0x250c,0x2588,0x2584,0x041f,0x044f,0x2580, 0x042f,0x0440,0x0420,0x0441,0x0421,0x0442,0x0422,0x0443, 0x0423,0x0436,0x0416,0x0432,0x0412,0x044c,0x042c,0x2116, 0x00ad,0x044b,0x042b,0x0437,0x0417,0x0448,0x0428,0x044d, 0x042d,0x0449,0x0429,0x0447,0x0427,0x00a7,0x25a0,0x00a0 }; /* IBM Turkish */ static const unsigned short ibm_857tab[128] = { 0x00c7,0x00fc,0x00e9,0x00e2,0x00e4,0x00e0,0x00e5,0x00e7, 0x00ea,0x00eb,0x00e8,0x00ef,0x00ee,0x0131,0x00c4,0x00c5, 0x00c9,0x00e6,0x00c6,0x00f4,0x00f6,0x00f2,0x00fb,0x00f9, 0x0130,0x00d6,0x00dc,0x00f8,0x00a3,0x00d8,0x015e,0x015f, 0x00e1,0x00ed,0x00f3,0x00fa,0x00f1,0x00d1,0x011e,0x011f, 0x00bf,0x00ae,0x00ac,0x00bd,0x00bc,0x00a1,0x00ab,0x00bb, 0x2591,0x2592,0x2593,0x2502,0x2524,0x00c1,0x00c2,0x00c0, 0x00a9,0x2563,0x2551,0x2557,0x255d,0x00a2,0x00a5,0x2510, 0x2514,0x2534,0x252c,0x251c,0x2500,0x253c,0x00e3,0x00c3, 0x255a,0x2554,0x2569,0x2566,0x2560,0x2550,0x256c,0x00a4, 0x00ba,0x00aa,0x00ca,0x00cb,0x00c8,UBOGON,0x00cd,0x00ce, 0x00cf,0x2518,0x250c,0x2588,0x2584,0x00a6,0x00cc,0x2580, 0x00d3,0x00df,0x00d4,0x00d2,0x00f5,0x00d5,0x00b5,UBOGON, 0x00d7,0x00da,0x00db,0x00d9,0x00ec,0x00ff,0x00af,0x00b4, 0x00ad,0x00b1,UBOGON,0x00be,0x00b6,0x00a7,0x00f7,0x00b8, 0x00b0,0x00a8,0x00b7,0x00b9,0x00b3,0x00b2,0x25a0,0x00a0 }; /* IBM Portuguese */ static const unsigned short ibm_860tab[128] = { 0x00c7,0x00fc,0x00e9,0x00e2,0x00e3,0x00e0,0x00c1,0x00e7, 0x00ea,0x00ca,0x00e8,0x00cd,0x00d4,0x00ec,0x00c3,0x00c2, 0x00c9,0x00c0,0x00c8,0x00f4,0x00f5,0x00f2,0x00da,0x00f9, 0x00cc,0x00d5,0x00dc,0x00a2,0x00a3,0x00d9,0x20a7,0x00d3, 0x00e1,0x00ed,0x00f3,0x00fa,0x00f1,0x00d1,0x00aa,0x00ba, 0x00bf,0x00d2,0x00ac,0x00bd,0x00bc,0x00a1,0x00ab,0x00bb, 0x2591,0x2592,0x2593,0x2502,0x2524,0x2561,0x2562,0x2556, 0x2555,0x2563,0x2551,0x2557,0x255d,0x255c,0x255b,0x2510, 0x2514,0x2534,0x252c,0x251c,0x2500,0x253c,0x255e,0x255f, 0x255a,0x2554,0x2569,0x2566,0x2560,0x2550,0x256c,0x2567, 0x2568,0x2564,0x2565,0x2559,0x2558,0x2552,0x2553,0x256b, 0x256a,0x2518,0x250c,0x2588,0x2584,0x258c,0x2590,0x2580, 0x03b1,0x00df,0x0393,0x03c0,0x03a3,0x03c3,0x00b5,0x03c4, 0x03a6,0x0398,0x03a9,0x03b4,0x221e,0x03c6,0x03b5,0x2229, 0x2261,0x00b1,0x2265,0x2264,0x2320,0x2321,0x00f7,0x2248, 0x00b0,0x2219,0x00b7,0x221a,0x207f,0x00b2,0x25a0,0x00a0 }; /* IBM Icelandic */ static const unsigned short ibm_861tab[128] = { 0x00c7,0x00fc,0x00e9,0x00e2,0x00e4,0x00e0,0x00e5,0x00e7, 0x00ea,0x00eb,0x00e8,0x00d0,0x00f0,0x00de,0x00c4,0x00c5, 0x00c9,0x00e6,0x00c6,0x00f4,0x00f6,0x00fe,0x00fb,0x00dd, 0x00fd,0x00d6,0x00dc,0x00f8,0x00a3,0x00d8,0x20a7,0x0192, 0x00e1,0x00ed,0x00f3,0x00fa,0x00c1,0x00cd,0x00d3,0x00da, 0x00bf,0x2310,0x00ac,0x00bd,0x00bc,0x00a1,0x00ab,0x00bb, 0x2591,0x2592,0x2593,0x2502,0x2524,0x2561,0x2562,0x2556, 0x2555,0x2563,0x2551,0x2557,0x255d,0x255c,0x255b,0x2510, 0x2514,0x2534,0x252c,0x251c,0x2500,0x253c,0x255e,0x255f, 0x255a,0x2554,0x2569,0x2566,0x2560,0x2550,0x256c,0x2567, 0x2568,0x2564,0x2565,0x2559,0x2558,0x2552,0x2553,0x256b, 0x256a,0x2518,0x250c,0x2588,0x2584,0x258c,0x2590,0x2580, 0x03b1,0x00df,0x0393,0x03c0,0x03a3,0x03c3,0x00b5,0x03c4, 0x03a6,0x0398,0x03a9,0x03b4,0x221e,0x03c6,0x03b5,0x2229, 0x2261,0x00b1,0x2265,0x2264,0x2320,0x2321,0x00f7,0x2248, 0x00b0,0x2219,0x00b7,0x221a,0x207f,0x00b2,0x25a0,0x00a0 }; /* IBM Hebrew */ static const unsigned short ibm_862tab[128] = { 0x05d0,0x05d1,0x05d2,0x05d3,0x05d4,0x05d5,0x05d6,0x05d7, 0x05d8,0x05d9,0x05da,0x05db,0x05dc,0x05dd,0x05de,0x05df, 0x05e0,0x05e1,0x05e2,0x05e3,0x05e4,0x05e5,0x05e6,0x05e7, 0x05e8,0x05e9,0x05ea,0x00a2,0x00a3,0x00a5,0x20a7,0x0192, 0x00e1,0x00ed,0x00f3,0x00fa,0x00f1,0x00d1,0x00aa,0x00ba, 0x00bf,0x2310,0x00ac,0x00bd,0x00bc,0x00a1,0x00ab,0x00bb, 0x2591,0x2592,0x2593,0x2502,0x2524,0x2561,0x2562,0x2556, 0x2555,0x2563,0x2551,0x2557,0x255d,0x255c,0x255b,0x2510, 0x2514,0x2534,0x252c,0x251c,0x2500,0x253c,0x255e,0x255f, 0x255a,0x2554,0x2569,0x2566,0x2560,0x2550,0x256c,0x2567, 0x2568,0x2564,0x2565,0x2559,0x2558,0x2552,0x2553,0x256b, 0x256a,0x2518,0x250c,0x2588,0x2584,0x258c,0x2590,0x2580, 0x03b1,0x00df,0x0393,0x03c0,0x03a3,0x03c3,0x00b5,0x03c4, 0x03a6,0x0398,0x03a9,0x03b4,0x221e,0x03c6,0x03b5,0x2229, 0x2261,0x00b1,0x2265,0x2264,0x2320,0x2321,0x00f7,0x2248, 0x00b0,0x2219,0x00b7,0x221a,0x207f,0x00b2,0x25a0,0x00a0 }; /* IBM Canada/French */ static const unsigned short ibm_863tab[128] = { 0x00c7,0x00fc,0x00e9,0x00e2,0x00c2,0x00e0,0x00b6,0x00e7, 0x00ea,0x00eb,0x00e8,0x00ef,0x00ee,0x2017,0x00c0,0x00a7, 0x00c9,0x00c8,0x00ca,0x00f4,0x00cb,0x00cf,0x00fb,0x00f9, 0x00a4,0x00d4,0x00dc,0x00a2,0x00a3,0x00d9,0x00db,0x0192, 0x00a6,0x00b4,0x00f3,0x00fa,0x00a8,0x00b8,0x00b3,0x00af, 0x00ce,0x2310,0x00ac,0x00bd,0x00bc,0x00be,0x00ab,0x00bb, 0x2591,0x2592,0x2593,0x2502,0x2524,0x2561,0x2562,0x2556, 0x2555,0x2563,0x2551,0x2557,0x255d,0x255c,0x255b,0x2510, 0x2514,0x2534,0x252c,0x251c,0x2500,0x253c,0x255e,0x255f, 0x255a,0x2554,0x2569,0x2566,0x2560,0x2550,0x256c,0x2567, 0x2568,0x2564,0x2565,0x2559,0x2558,0x2552,0x2553,0x256b, 0x256a,0x2518,0x250c,0x2588,0x2584,0x258c,0x2590,0x2580, 0x03b1,0x00df,0x0393,0x03c0,0x03a3,0x03c3,0x00b5,0x03c4, 0x03a6,0x0398,0x03a9,0x03b4,0x221e,0x03c6,0x03b5,0x2229, 0x2261,0x00b1,0x2265,0x2264,0x2320,0x2321,0x00f7,0x2248, 0x00b0,0x2219,0x00b7,0x221a,0x207f,0x00b2,0x25a0,0x00a0 }; /* IBM Arabic */ static const unsigned short ibm_864tab[128] = { 0x00b0,0x00b7,0x2219,0x221a,0x2592,0x2500,0x2502,0x253c, 0x2524,0x252c,0x251c,0x2534,0x2510,0x250c,0x2514,0x2518, 0x03b2,0x221e,0x03c6,0x00b1,0x00bd,0x00bc,0x2248,0x00ab, 0x00bb,0xfef7,0xfef8,UBOGON,UBOGON,0xfefb,0xfefc,UBOGON, 0x00a0,0x00ad,0xfe82,0x00a3,0x00a4,0xfe84,UBOGON,UBOGON, 0xfe8e,0xfe8f,0xfe95,0xfe99,0x060c,0xfe9d,0xfea1,0xfea5, 0x0660,0x0661,0x0662,0x0663,0x0664,0x0665,0x0666,0x0667, 0x0668,0x0669,0xfed1,0x061b,0xfeb1,0xfeb5,0xfeb9,0x061f, 0x00a2,0xfe80,0xfe81,0xfe83,0xfe85,0xfeca,0xfe8b,0xfe8d, 0xfe91,0xfe93,0xfe97,0xfe9b,0xfe9f,0xfea3,0xfea7,0xfea9, 0xfeab,0xfead,0xfeaf,0xfeb3,0xfeb7,0xfebb,0xfebf,0xfec1, 0xfec5,0xfecb,0xfecf,0x00a6,0x00ac,0x00f7,0x00d7,0xfec9, 0x0640,0xfed3,0xfed7,0xfedb,0xfedf,0xfee3,0xfee7,0xfeeb, 0xfeed,0xfeef,0xfef3,0xfebd,0xfecc,0xfece,0xfecd,0xfee1, 0xfe7d,0x0651,0xfee5,0xfee9,0xfeec,0xfef0,0xfef2,0xfed0, 0xfed5,0xfef5,0xfef6,0xfedd,0xfed9,0xfef1,0x25a0,UBOGON }; /* IBM Nordic */ static const unsigned short ibm_865tab[128] = { 0x00c7,0x00fc,0x00e9,0x00e2,0x00e4,0x00e0,0x00e5,0x00e7, 0x00ea,0x00eb,0x00e8,0x00ef,0x00ee,0x00ec,0x00c4,0x00c5, 0x00c9,0x00e6,0x00c6,0x00f4,0x00f6,0x00f2,0x00fb,0x00f9, 0x00ff,0x00d6,0x00dc,0x00f8,0x00a3,0x00d8,0x20a7,0x0192, 0x00e1,0x00ed,0x00f3,0x00fa,0x00f1,0x00d1,0x00aa,0x00ba, 0x00bf,0x2310,0x00ac,0x00bd,0x00bc,0x00a1,0x00ab,0x00a4, 0x2591,0x2592,0x2593,0x2502,0x2524,0x2561,0x2562,0x2556, 0x2555,0x2563,0x2551,0x2557,0x255d,0x255c,0x255b,0x2510, 0x2514,0x2534,0x252c,0x251c,0x2500,0x253c,0x255e,0x255f, 0x255a,0x2554,0x2569,0x2566,0x2560,0x2550,0x256c,0x2567, 0x2568,0x2564,0x2565,0x2559,0x2558,0x2552,0x2553,0x256b, 0x256a,0x2518,0x250c,0x2588,0x2584,0x258c,0x2590,0x2580, 0x03b1,0x00df,0x0393,0x03c0,0x03a3,0x03c3,0x00b5,0x03c4, 0x03a6,0x0398,0x03a9,0x03b4,0x221e,0x03c6,0x03b5,0x2229, 0x2261,0x00b1,0x2265,0x2264,0x2320,0x2321,0x00f7,0x2248, 0x00b0,0x2219,0x00b7,0x221a,0x207f,0x00b2,0x25a0,0x00a0 }; /* IBM Cyrillic/Russian */ static const unsigned short ibm_866tab[128] = { 0x0410,0x0411,0x0412,0x0413,0x0414,0x0415,0x0416,0x0417, 0x0418,0x0419,0x041a,0x041b,0x041c,0x041d,0x041e,0x041f, 0x0420,0x0421,0x0422,0x0423,0x0424,0x0425,0x0426,0x0427, 0x0428,0x0429,0x042a,0x042b,0x042c,0x042d,0x042e,0x042f, 0x0430,0x0431,0x0432,0x0433,0x0434,0x0435,0x0436,0x0437, 0x0438,0x0439,0x043a,0x043b,0x043c,0x043d,0x043e,0x043f, 0x2591,0x2592,0x2593,0x2502,0x2524,0x2561,0x2562,0x2556, 0x2555,0x2563,0x2551,0x2557,0x255d,0x255c,0x255b,0x2510, 0x2514,0x2534,0x252c,0x251c,0x2500,0x253c,0x255e,0x255f, 0x255a,0x2554,0x2569,0x2566,0x2560,0x2550,0x256c,0x2567, 0x2568,0x2564,0x2565,0x2559,0x2558,0x2552,0x2553,0x256b, 0x256a,0x2518,0x250c,0x2588,0x2584,0x258c,0x2590,0x2580, 0x0440,0x0441,0x0442,0x0443,0x0444,0x0445,0x0446,0x0447, 0x0448,0x0449,0x044a,0x044b,0x044c,0x044d,0x044e,0x044f, 0x0401,0x0451,0x0404,0x0454,0x0407,0x0457,0x040e,0x045e, 0x00b0,0x2219,0x00b7,0x221a,0x2116,0x00a4,0x25a0,0x00a0 }; /* IBM Greek 2 */ static const unsigned short ibm_869tab[128] = { UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,0x0386,UBOGON, 0x00b7,0x00ac,0x00a6,0x2018,0x2019,0x0388,0x2015,0x0389, 0x038a,0x03aa,0x038c,UBOGON,UBOGON,0x038e,0x03ab,0x00a9, 0x038f,0x00b2,0x00b3,0x03ac,0x00a3,0x03ad,0x03ae,0x03af, 0x03ca,0x0390,0x03cc,0x03cd,0x0391,0x0392,0x0393,0x0394, 0x0395,0x0396,0x0397,0x00bd,0x0398,0x0399,0x00ab,0x00bb, 0x2591,0x2592,0x2593,0x2502,0x2524,0x039a,0x039b,0x039c, 0x039d,0x2563,0x2551,0x2557,0x255d,0x039e,0x039f,0x2510, 0x2514,0x2534,0x252c,0x251c,0x2500,0x253c,0x03a0,0x03a1, 0x255a,0x2554,0x2569,0x2566,0x2560,0x2550,0x256c,0x03a3, 0x03a4,0x03a5,0x03a6,0x03a7,0x03a8,0x03a9,0x03b1,0x03b2, 0x03b3,0x2518,0x250c,0x2588,0x2584,0x03b4,0x03b5,0x2580, 0x03b6,0x03b7,0x03b8,0x03b9,0x03ba,0x03bb,0x03bc,0x03bd, 0x03be,0x03bf,0x03c0,0x03c1,0x03c3,0x03c2,0x03c4,0x0384, 0x00ad,0x00b1,0x03c5,0x03c6,0x03c7,0x00a7,0x03c8,0x0385, 0x00b0,0x00a8,0x03c9,0x03cb,0x03b0,0x03ce,0x25a0,0x00a0 }; /* IBM Thai */ static const unsigned short ibm_874tab[128] = { 0x20ac,UBOGON,UBOGON,UBOGON,UBOGON,0x2026,UBOGON,UBOGON, UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON, UBOGON,0x2018,0x2019,0x201c,0x201d,0x2022,0x2013,0x2014, UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON, 0x00a0,0x0e01,0x0e02,0x0e03,0x0e04,0x0e05,0x0e06,0x0e07, 0x0e08,0x0e09,0x0e0a,0x0e0b,0x0e0c,0x0e0d,0x0e0e,0x0e0f, 0x0e10,0x0e11,0x0e12,0x0e13,0x0e14,0x0e15,0x0e16,0x0e17, 0x0e18,0x0e19,0x0e1a,0x0e1b,0x0e1c,0x0e1d,0x0e1e,0x0e1f, 0x0e20,0x0e21,0x0e22,0x0e23,0x0e24,0x0e25,0x0e26,0x0e27, 0x0e28,0x0e29,0x0e2a,0x0e2b,0x0e2c,0x0e2d,0x0e2e,0x0e2f, 0x0e30,0x0e31,0x0e32,0x0e33,0x0e34,0x0e35,0x0e36,0x0e37, 0x0e38,0x0e39,0x0e3a,UBOGON,UBOGON,UBOGON,UBOGON,0x0e3f, 0x0e40,0x0e41,0x0e42,0x0e43,0x0e44,0x0e45,0x0e46,0x0e47, 0x0e48,0x0e49,0x0e4a,0x0e4b,0x0e4c,0x0e4d,0x0e4e,0x0e4f, 0x0e50,0x0e51,0x0e52,0x0e53,0x0e54,0x0e55,0x0e56,0x0e57, 0x0e58,0x0e59,0x0e5a,0x0e5b,UBOGON,UBOGON,UBOGON,UBOGON }; alpine-2.10+dfsg/imap/src/ipopd/0000700000175000017500000000000011512502151020162 5ustar paulproteuspaulproteusalpine-2.10+dfsg/imap/src/ipopd/ipop2d.c0000600000175000017500000004610111512502124021527 0ustar paulproteuspaulproteus/* ======================================================================== * Copyright 1988-2008 University of Washington * * Licensed under the Apache License, Version 2.0 (the "License"); * you may not use this file except in compliance with the License. * You may obtain a copy of the License at * * http://www.apache.org/licenses/LICENSE-2.0 * * * ======================================================================== */ /* * Program: IPOP2D - IMAP to POP2 conversion server * * Author: Mark Crispin * UW Technology * University of Washington * Seattle, WA 98195 * Internet: MRC@Washington.EDU * * Date: 28 October 1990 * Last Edited: 13 February 2008 */ /* Parameter files */ #include #include #include extern int errno; /* just in case */ #include #include #include "c-client.h" /* Autologout timer */ #define KODTIMEOUT 60*5 #define LOGINTIMEOUT 60*3 #define TIMEOUT 60*30 /* Size of temporary buffers */ #define TMPLEN 1024 /* Server states */ #define LISN 0 #define AUTH 1 #define MBOX 2 #define ITEM 3 #define NEXT 4 #define DONE 5 /* Global storage */ char *version = "75"; /* edit number of this server */ short state = LISN; /* server state */ short critical = NIL; /* non-zero if in critical code */ MAILSTREAM *stream = NIL; /* mailbox stream */ time_t idletime = 0; /* time we went idle */ unsigned long nmsgs = 0; /* number of messages */ unsigned long current = 1; /* current message number */ unsigned long size = 0; /* size of current message */ char status[MAILTMPLEN]; /* space for status string */ char *user = ""; /* user name */ char *pass = ""; /* password */ unsigned long *msg = NIL; /* message translation vector */ char *logout = "Logout"; char *goodbye = "+ Sayonara\015\012"; /* Function prototypes */ int main (int argc,char *argv[]); void sayonara (int status); void clkint (); void kodint (); void hupint (); void trmint (); short c_helo (char *t,int argc,char *argv[]); short c_fold (char *t); short c_read (char *t); short c_retr (char *t); short c_acks (char *t); short c_ackd (char *t); short c_nack (char *t); /* Main program */ int main (int argc,char *argv[]) { char *s,*t; char cmdbuf[TMPLEN]; char *pgmname = (argc && argv[0]) ? (((s = strrchr (argv[0],'/')) || (s = strrchr (argv[0],'\\'))) ? s+1 : argv[0]) : "ipop2d"; /* set service name before linkage */ mail_parameters (NIL,SET_SERVICENAME,(void *) "pop"); #include "linkage.c" if (mail_parameters (NIL,GET_DISABLEPLAINTEXT,NIL)) { goodbye = "- POP2 server disabled on this system\015\012"; sayonara (1); } /* initialize server */ server_init (pgmname,"pop",NIL,clkint,kodint,hupint,trmint,NIL); /* There are reports of POP2 clients which get upset if anything appears * between the "+" and the "POP2" in the greeting. */ printf ("+ POP2 %s %s.%s server ready\015\012",tcp_serverhost (), CCLIENTVERSION,version); fflush (stdout); /* dump output buffer */ state = AUTH; /* initial server state */ while (state != DONE) { /* command processing loop */ idletime = time (0); /* get a command under timeout */ alarm ((state != AUTH) ? TIMEOUT : LOGINTIMEOUT); clearerr (stdin); /* clear stdin errors */ while (!fgets (cmdbuf,TMPLEN-1,stdin)) { if (ferror (stdin) && (errno == EINTR)) clearerr (stdin); else { char *e = ferror (stdin) ? strerror (errno) : "Unexpected client disconnect"; alarm (0); /* disable all interrupts */ server_init (NIL,NIL,NIL,SIG_IGN,SIG_IGN,SIG_IGN,SIG_IGN,SIG_IGN); sprintf (logout = cmdbuf,"%.80s while reading line",e); state = DONE; stream = mail_close (stream); goodbye = NIL; sayonara (1); } } alarm (0); /* make sure timeout disabled */ idletime = 0; /* no longer idle */ /* find end of line */ if (!strchr (cmdbuf,'\012')) { server_init (NIL,NIL,NIL,SIG_IGN,SIG_IGN,SIG_IGN,SIG_IGN,SIG_IGN); logout = "- Command line too long\015\012"; state = DONE; } else if (!(s = strtok (cmdbuf," \015\012"))) { server_init (NIL,NIL,NIL,SIG_IGN,SIG_IGN,SIG_IGN,SIG_IGN,SIG_IGN); goodbye = "- Missing or null command\015\012"; state = DONE; } else { /* dispatch based on command */ ucase (s); /* canonicalize case */ /* snarf argument */ t = strtok (NIL,"\015\012"); if ((state == AUTH) && !strcmp (s,"HELO")) state = c_helo (t,argc,argv); else if ((state == MBOX || state == ITEM) && !strcmp (s,"FOLD")) state = c_fold (t); else if ((state == MBOX || state == ITEM) && !strcmp (s,"READ")) state = c_read (t); else if ((state == ITEM) && !strcmp (s,"RETR")) state = c_retr (t); else if ((state == NEXT) && !strcmp (s,"ACKS")) state = c_acks (t); else if ((state == NEXT) && !strcmp (s,"ACKD")) state = c_ackd (t); else if ((state == NEXT) && !strcmp (s,"NACK")) state = c_nack (t); else if ((state == AUTH || state == MBOX || state == ITEM) && !strcmp (s,"QUIT")) { server_init (NIL,NIL,NIL,SIG_IGN,SIG_IGN,SIG_IGN,SIG_IGN,SIG_IGN); state = DONE; /* done in either case */ if (t) goodbye = "- Bogus argument given to QUIT\015\012"; else { /* expunge the stream */ if (stream && nmsgs) stream = mail_close_full (stream,CL_EXPUNGE); stream = NIL; /* don't repeat it */ } } else { /* some other or inappropriate command */ server_init (NIL,NIL,NIL,SIG_IGN,SIG_IGN,SIG_IGN,SIG_IGN,SIG_IGN); goodbye = "- Bogus or out of sequence command\015\012"; state = DONE; } } fflush (stdout); /* make sure output blatted */ } /* clean up the stream */ if (stream) mail_close (stream); sayonara (0); return 0; /* stupid compilers */ } /* Say goodbye * Accepts: exit status * * Does not return */ void sayonara (int status) { logouthook_t lgoh = (logouthook_t) mail_parameters (NIL,GET_LOGOUTHOOK,NIL); if (goodbye) { /* have a goodbye message? */ fputs (goodbye,stdout); fflush (stdout); /* make sure blatted */ } syslog (LOG_INFO,"%s user=%.80s host=%.80s",logout, user ? (char *) user : "???",tcp_clienthost ()); /* do logout hook if needed */ if (lgoh) (*lgoh) (mail_parameters (NIL,GET_LOGOUTDATA,NIL)); _exit (status); /* all done */ } /* Clock interrupt */ void clkint () { alarm (0); /* disable all interrupts */ server_init (NIL,NIL,NIL,SIG_IGN,SIG_IGN,SIG_IGN,SIG_IGN,SIG_IGN); goodbye = "- Autologout; idle for too long\015\012"; logout = "Autologout"; state = DONE; /* mark state done in either case */ if (!critical) { /* badly host if in critical code */ if (stream && !stream->lock) mail_close (stream); stream = NIL; sayonara (1); /* die die die */ } } /* Kiss Of Death interrupt */ void kodint () { /* only if in command wait */ if (idletime && ((time (0) - idletime) > KODTIMEOUT)) { alarm (0); /* disable all interrupts */ server_init (NIL,NIL,NIL,SIG_IGN,SIG_IGN,SIG_IGN,SIG_IGN,SIG_IGN); goodbye = "- Killed (lost mailbox lock)\015\012"; logout = "Killed (lost mailbox lock)"; state = DONE; /* mark state done in either case */ if (!critical) { /* badly host if in critical code */ if (stream && !stream->lock) mail_close (stream); stream = NIL; sayonara (1); /* die die die */ } } } /* Hangup interrupt */ void hupint () { alarm (0); /* disable all interrupts */ server_init (NIL,NIL,NIL,SIG_IGN,SIG_IGN,SIG_IGN,SIG_IGN,SIG_IGN); goodbye = NIL; logout = "Hangup"; state = DONE; /* mark state done in either case */ if (!critical) { /* badly host if in critical code */ if (stream && !stream->lock) mail_close (stream); stream = NIL; sayonara (1); /* die die die */ } } /* Termination interrupt */ void trmint () { alarm (0); /* disable all interrupts */ server_init (NIL,NIL,NIL,SIG_IGN,SIG_IGN,SIG_IGN,SIG_IGN,SIG_IGN); goodbye = "- Killed (terminated)\015\012"; logout = "Killed (terminated)"; if (critical) state = DONE; /* mark state done in either case */ /* Make no attempt at graceful closure since a shutdown may be in * progress, and we won't have any time to do mail_close() actions. */ else sayonara (1); /* die die die */ } /* Parse HELO command * Accepts: pointer to command argument * Returns: new state */ short c_helo (char *t,int argc,char *argv[]) { char *s,*u,*p; char tmp[TMPLEN]; if ((!(t && *t && (u = strtok (t," ")) && (p = strtok (NIL,"\015\012")))) || (strlen (p) >= TMPLEN)) { /* get user name and password */ fputs ("- Missing user or password\015\012",stdout); return DONE; } /* copy password, handle quoting */ for (s = tmp; *p; p++) *s++ = (*p == '\\') ? *++p : *p; *s = '\0'; /* tie off string */ pass = cpystr (tmp); if (!(s = strchr (u,':'))) { /* want remote mailbox? */ /* no, delimit user from possible admin */ if (s = strchr (u,'*')) *s++ = '\0'; if (server_login (user = cpystr (u),pass,s,argc,argv)) { syslog (LOG_INFO,"%sLogin user=%.80s host=%.80s",s ? "Admin " : "", user,tcp_clienthost ()); return c_fold ("INBOX"); /* local; select INBOX */ } } #ifndef DISABLE_POP_PROXY /* can't do if can't log in as anonymous */ else if (anonymous_login (argc,argv)) { *s++ = '\0'; /* separate host name from user name */ user = cpystr (s); /* note user name */ syslog (LOG_INFO,"IMAP login to host=%.80s user=%.80s host=%.80s",u,user, tcp_clienthost ()); /* initially remote INBOX */ sprintf (tmp,"{%.128s/user=%.128s}INBOX",u,user); /* disable rimap just in case */ mail_parameters (NIL,SET_RSHTIMEOUT,0); return c_fold (tmp); } #endif fputs ("- Bad login\015\012",stdout); return DONE; } /* Parse FOLD command * Accepts: pointer to command argument * Returns: new state */ short c_fold (char *t) { unsigned long i,j,flags; char *s = NIL,tmp[2*TMPLEN]; NETMBX mb; if (!(t && *t)) { /* make sure there's an argument */ fputs ("- Missing mailbox name\015\012",stdout); return DONE; } myusername_full (&flags); /* get user type flags */ /* expunge old stream */ if (stream && nmsgs) mail_expunge (stream); nmsgs = 0; /* no more messages */ if (msg) fs_give ((void **) &msg); #ifndef DISABLE_POP_PROXY if (flags == MU_ANONYMOUS) { /* don't permit proxy to leave IMAP */ if (stream) { /* not first time */ if (!(stream->mailbox && (s = strchr (stream->mailbox,'}')))) fatal ("bad previous mailbox name"); strncpy (tmp,stream->mailbox,i = (++s - stream->mailbox)); if (i >= TMPLEN) fatal ("ridiculous network prefix"); strcpy (tmp+i,t); /* append mailbox to initial spec */ t = tmp; } /* must be net name first time */ else if (!mail_valid_net_parse (t,&mb)) fatal ("anonymous folder bogon"); } #endif /* open mailbox, note # of messages */ if (j = (stream = mail_open (stream,t,NIL)) ? stream->nmsgs : 0) { sprintf (tmp,"1:%lu",j); /* fetch fast information for all messages */ mail_fetch_fast (stream,tmp,NIL); msg = (unsigned long *) fs_get ((stream->nmsgs + 1) * sizeof (unsigned long)); for (i = 1; i <= j; i++) /* find undeleted messages, add to vector */ if (!mail_elt (stream,i)->deleted) msg[++nmsgs] = i; } #ifndef DISABLE_POP_PROXY if (!stream && (flags == MU_ANONYMOUS)) { fputs ("- Bad login\015\012",stdout); return DONE; } #endif printf ("#%lu messages in %s\015\012",nmsgs,stream ? stream->mailbox : ""); return MBOX; } /* Parse READ command * Accepts: pointer to command argument * Returns: new state */ short c_read (char *t) { MESSAGECACHE *elt = NIL; if (t && *t) { /* have a message number argument? */ /* validity check message number */ if (((current = strtoul (t,NIL,10)) < 1) || (current > nmsgs)) { fputs ("- Invalid message number given to READ\015\012",stdout); return DONE; } } else if (current > nmsgs) { /* at end of mailbox? */ fputs ("=0 No more messages\015\012",stdout); return MBOX; } /* set size if message valid and exists */ size = msg[current] ? (elt = mail_elt(stream,msg[current]))->rfc822_size : 0; if (elt) sprintf (status,"Status: %s%s\015\012", elt->seen ? "R" : " ",elt->recent ? " " : "O"); else status[0] = '\0'; /* no status */ size += strlen (status); /* update size to reflect status */ /* display results */ printf ("=%lu characters in message %lu\015\012",size + 2,current); return ITEM; } /* Parse RETR command * Accepts: pointer to command argument * Returns: new state */ short c_retr (char *t) { unsigned long i,j; STRING *bs; if (t) { /* disallow argument */ fputs ("- Bogus argument given to RETR\015\012",stdout); return DONE; } if (size) { /* message size valid? */ t = mail_fetch_header (stream,msg[current],NIL,NIL,&i,FT_PEEK); if (i > 2) { /* only if there is something */ i -= 2; /* lop off last two octets */ while (i) { /* blat the header */ if (!(j = fwrite (t,sizeof (char),i,stdout))) return DONE; if (i -= j) t += j; /* advance to incomplete data */ } } fputs (status,stdout); /* yes, output message */ fputs ("\015\012",stdout); /* delimit header from text */ if (t = mail_fetch_text (stream,msg[current],NIL,&i,FT_RETURNSTRINGSTRUCT)) while (i) { /* blat the text */ if (!(j = fwrite (t,sizeof (char),i,stdout))) return DONE; if (i -= j) t += j; /* advance to incomplete data */ } else for (bs = &stream->private.string; i--; ) if (putc (SNX (bs),stdout) == EOF) return DONE; fputs ("\015\012",stdout); /* trailer to coddle PCNFS' NFSMAIL */ } else return DONE; /* otherwise go away */ return NEXT; } /* Parse ACKS command * Accepts: pointer to command argument * Returns: new state */ short c_acks (char *t) { char tmp[TMPLEN]; if (t) { /* disallow argument */ fputs ("- Bogus argument given to ACKS\015\012",stdout); return DONE; } /* mark message as seen */ sprintf (tmp,"%lu",msg[current++]); mail_setflag (stream,tmp,"\\Seen"); return c_read (NIL); /* end message reading transaction */ } /* Parse ACKD command * Accepts: pointer to command argument * Returns: new state */ short c_ackd (char *t) { char tmp[TMPLEN]; if (t) { /* disallow argument */ fputs ("- Bogus argument given to ACKD\015\012",stdout); return DONE; } /* mark message as seen and deleted */ sprintf (tmp,"%lu",msg[current]); mail_setflag (stream,tmp,"\\Seen \\Deleted"); msg[current++] = 0; /* mark message as deleted */ return c_read (NIL); /* end message reading transaction */ } /* Parse NACK command * Accepts: pointer to command argument * Returns: new state */ short c_nack (char *t) { if (t) { /* disallow argument */ fputs ("- Bogus argument given to NACK\015\012",stdout); return DONE; } return c_read (NIL); /* end message reading transaction */ } /* Co-routines from MAIL library */ /* Message matches a search * Accepts: MAIL stream * message number */ void mm_searched (MAILSTREAM *stream,unsigned long msgno) { /* Never called */ } /* Message exists (i.e. there are that many messages in the mailbox) * Accepts: MAIL stream * message number */ void mm_exists (MAILSTREAM *stream,unsigned long number) { /* Can't use this mechanism. POP has no means of notifying the client of new mail during the session. */ } /* Message expunged * Accepts: MAIL stream * message number */ void mm_expunged (MAILSTREAM *stream,unsigned long number) { if (state != DONE) { /* ignore if closing */ /* someone else screwed us */ goodbye = "- Mailbox expunged from under me!\015\012"; if (stream && !stream->lock) mail_close (stream); stream = NIL; sayonara (1); } } /* Message status changed * Accepts: MAIL stream * message number */ void mm_flags (MAILSTREAM *stream,unsigned long number) { /* This isn't used */ } /* Mailbox found * Accepts: MAIL stream * hierarchy delimiter * mailbox name * mailbox attributes */ void mm_list (MAILSTREAM *stream,int delimiter,char *name,long attributes) { /* This isn't used */ } /* Subscribe mailbox found * Accepts: MAIL stream * hierarchy delimiter * mailbox name * mailbox attributes */ void mm_lsub (MAILSTREAM *stream,int delimiter,char *name,long attributes) { /* This isn't used */ } /* Mailbox status * Accepts: MAIL stream * mailbox name * mailbox status */ void mm_status (MAILSTREAM *stream,char *mailbox,MAILSTATUS *status) { /* This isn't used */ } /* Notification event * Accepts: MAIL stream * string to log * error flag */ void mm_notify (MAILSTREAM *stream,char *string,long errflg) { mm_log (string,errflg); /* just do mm_log action */ } /* Log an event for the user to see * Accepts: string to log * error flag */ void mm_log (char *string,long errflg) { switch (errflg) { case NIL: /* information message */ case PARSE: /* parse glitch */ break; /* too many of these to log */ case WARN: /* warning */ syslog (LOG_DEBUG,"%s",string); break; case BYE: /* driver broke connection */ if (state != DONE) { char tmp[MAILTMPLEN]; alarm (0); /* disable all interrupts */ server_init (NIL,NIL,NIL,SIG_IGN,SIG_IGN,SIG_IGN,SIG_IGN,SIG_IGN); sprintf (logout = tmp,"Mailbox closed (%.80s)",string); sayonara (1); } break; case ERROR: /* error that broke command */ default: /* default should never happen */ syslog (LOG_NOTICE,"%s",string); break; } } /* Log an event to debugging telemetry * Accepts: string to log */ void mm_dlog (char *string) { /* Not doing anything here for now */ } /* Get user name and password for this host * Accepts: parse of network mailbox name * where to return user name * where to return password * trial count */ void mm_login (NETMBX *mb,char *username,char *password,long trial) { /* set user name */ strncpy (username,*mb->user ? mb->user : user,NETMAXUSER-1); strncpy (password,pass,255); /* and password */ username[NETMAXUSER] = password[255] = '\0'; } /* About to enter critical code * Accepts: stream */ void mm_critical (MAILSTREAM *stream) { ++critical; } /* About to exit critical code * Accepts: stream */ void mm_nocritical (MAILSTREAM *stream) { --critical; } /* Disk error found * Accepts: stream * system error code * flag indicating that mailbox may be clobbered * Returns: abort flag */ long mm_diskerror (MAILSTREAM *stream,long errcode,long serious) { if (serious) { /* try your damnest if clobberage likely */ syslog (LOG_ALERT, "Retrying after disk error user=%.80s host=%.80s mbx=%.80s: %.80s", user,tcp_clienthost (), (stream && stream->mailbox) ? stream->mailbox : "???", strerror (errcode)); alarm (0); /* make damn sure timeout disabled */ sleep (60); /* give it some time to clear up */ return NIL; } syslog (LOG_ALERT,"Fatal disk error user=%.80s host=%.80s mbx=%.80s: %.80s", user,tcp_clienthost (), (stream && stream->mailbox) ? stream->mailbox : "???", strerror (errcode)); return T; } /* Log a fatal error event * Accepts: string to log */ void mm_fatal (char *string) { mm_log (string,ERROR); /* shouldn't happen normally */ } alpine-2.10+dfsg/imap/src/ipopd/ipopd.80000600000175000017500000000325511512502124021375 0ustar paulproteuspaulproteus.ig * ======================================================================== * Copyright 1988-2006 University of Washington * * Licensed under the Apache License, Version 2.0 (the "License"); * you may not use this file except in compliance with the License. * You may obtain a copy of the License at * * http://www.apache.org/licenses/LICENSE-2.0 * * * ======================================================================== .. .TH IPOPD 8 "August 30, 2006" .UC 5 .SH NAME IPOPd \- Post Office Protocol server .SH SYNOPSIS .B /usr/etc/ipop2d .PP .B /usr/etc/ipop3d .SH DESCRIPTION .I ipop2d and .I ipop3d are servers which support the .B POP2 and .B POP3 remote mail access protocols respectively. .I ipop2d and .I ipop3d can also be used by .B POP2 and .B POP3 clients respecitively to access mailboxes on .B IMAP servers by specifying a login user name in the form : e.g., .B SERVER.WASHINGTON.EDU:SMITH. .PP These daemons contain CRAM-MD5 and APOP support. See the md5.txt documentation file for additional information. .PP .I ipop2d and .I ipop3d are invoked by the internet server (see .IR inetd (8)), normally for requests to connect to the .B POP port as indicated by the .I /etc/services file (see .IR services (5)). .SH "SEE ALSO" imapd(8) .SH BUGS The .B POP2 and .B POP3 protocols are intrinsically less flexible than .B IMAP and do not maintain `read' vs `unread' state on the server. As a result, most .B POP based software transfers all the mail from the server to the client and deletes it from the server. This necessarily locks the user into using only a single client. .PP .B POP3 does not allow you to specify an alternate folder from the user's default. alpine-2.10+dfsg/imap/src/ipopd/makefile.ntk0000600000175000017500000000300711512502124022457 0ustar paulproteuspaulproteus# ======================================================================== # Copyright 1988-2006 University of Washington # # Licensed under the Apache License, Version 2.0 (the "License"); # you may not use this file except in compliance with the License. # You may obtain a copy of the License at # # http://www.apache.org/licenses/LICENSE-2.0 # # # ======================================================================== # Program: IPOPD Makefile for Windows 9x and Windows NT + Kerberos # # Author: Mark Crispin # Networks and Distributed Computing # Computing & Communications # University of Washington # Administration Building, AG-44 # Seattle, WA 98195 # Internet: MRC@CAC.Washington.EDU # # Date: 28 October 1990 # Last Edited: 30 August 2006 C = ..\c-client CCLIENTLIB = $C\cclient.lib K5 = \k5\lib K5LIB = $(K5)\comerr32.lib $(K5)\gssapi32.lib $(K5)\krb5_32.lib LIBS = $(CCLIENTLIB) $(K5LIB) ws2_32.lib winmm.lib advapi32.lib OSCOMPAT = /DWIN32 /D_WIN32_WINNT=0x0400 VSCOMPAT = /D_CRT_SECURE_NO_DEPRECATE /D_CRT_NONSTDC_NO_DEPRECATE CFLAGS= -I$C /MT /W3 $(OSCOMPAT) $(VSCOMPAT) -nologo $(EXTRACFLAGS) ipopd: ipop2d ipop3d ipop2d: $(CCLIENTLIB) ipop2d.obj LINK /NOLOGO ipop2d.obj $(LIBS) ipop3d: $(CCLIENTLIB) ipop3d.obj LINK /NOLOGO ipop3d.obj $(LIBS) ipop2d.obj: $C\mail.h $C\misc.h $C\osdep.h ipop3d.obj: $C\mail.h $C\misc.h $C\osdep.h $(CCLIENTLIB): @echo Make c-client first false clean: del *.obj *.exe *.lib *.exp || rem # A monument to a hack of long ago and far away... love: @echo not war? alpine-2.10+dfsg/imap/src/ipopd/Makefile0000600000175000017500000000250311512502124021624 0ustar paulproteuspaulproteus# ======================================================================== # Copyright 1988-2006 University of Washington # # Licensed under the Apache License, Version 2.0 (the "License"); # you may not use this file except in compliance with the License. # You may obtain a copy of the License at # # http://www.apache.org/licenses/LICENSE-2.0 # # # ======================================================================== # Program: IPOPD client Makefile # # Author: Mark Crispin # Networks and Distributed Computing # Computing & Communications # University of Washington # Administration Building, AG-44 # Seattle, WA 98195 # Internet: MRC@CAC.Washington.EDU # # Date: 28 October 1990 # Last Edited: 30 August 2006 C = ../c-client CCLIENTLIB = $C/c-client.a SHELL = /bin/sh # Get local definitions from c-client directory CC = `cat $C/CCTYPE` CFLAGS = -I$C `cat $C/CFLAGS` LDFLAGS = $(CCLIENTLIB) `cat $C/LDFLAGS` ipopd: ipop2d ipop3d ipop2d: $(CCLIENTLIB) ipop2d.o $(CC) $(CFLAGS) -o ipop2d ipop2d.o $(LDFLAGS) ipop3d: $(CCLIENTLIB) ipop3d.o $(CC) $(CFLAGS) -o ipop3d ipop3d.o $(LDFLAGS) ipop2d.o: $C/mail.h $C/misc.h $C/osdep.h ipop3d.o: $C/mail.h $C/misc.h $C/osdep.h $(CCLIENTLIB): cd $C;make clean: rm -f *.o ipop2d ipop3d || true # A monument to a hack of long ago and far away... love: @echo 'not war?' alpine-2.10+dfsg/imap/src/ipopd/makefile.w2k0000600000175000017500000000263611512502124022375 0ustar paulproteuspaulproteus# ======================================================================== # Copyright 1988-2006 University of Washington # # Licensed under the Apache License, Version 2.0 (the "License"); # you may not use this file except in compliance with the License. # You may obtain a copy of the License at # # http://www.apache.org/licenses/LICENSE-2.0 # # # ======================================================================== # Program: IPOPD Makefile for Windows 2000/XP # # Author: Mark Crispin # Networks and Distributed Computing # Computing & Communications # University of Washington # Administration Building, AG-44 # Seattle, WA 98195 # Internet: MRC@CAC.Washington.EDU # # Date: 28 October 1990 # Last Edited: 30 August 2006 C = ..\c-client CCLIENTLIB = $C\cclient.lib LIBS = $(CCLIENTLIB) ws2_32.lib winmm.lib advapi32.lib secur32.lib crypt32.lib OSCOMPAT = /DWIN32 VSCOMPAT = /D_CRT_SECURE_NO_DEPRECATE /D_CRT_NONSTDC_NO_DEPRECATE CFLAGS= -I$C /MT /W3 $(OSCOMPAT) $(VSCOMPAT) -nologo $(EXTRACFLAGS) ipopd: ipop2d ipop3d ipop2d: $(CCLIENTLIB) ipop2d.obj LINK /NOLOGO ipop2d.obj $(LIBS) ipop3d: $(CCLIENTLIB) ipop3d.obj LINK /NOLOGO ipop3d.obj $(LIBS) ipop2d.obj: $C\mail.h $C\misc.h $C\osdep.h ipop3d.obj: $C\mail.h $C\misc.h $C\osdep.h $(CCLIENTLIB): @echo Make c-client first false clean: del *.obj *.exe *.lib *.exp || rem # A monument to a hack of long ago and far away... love: @echo not war? alpine-2.10+dfsg/imap/src/ipopd/ipop3d.c0000600000175000017500000007745611512502124021551 0ustar paulproteuspaulproteus/* ======================================================================== * Copyright 1988-2008 University of Washington * * Licensed under the Apache License, Version 2.0 (the "License"); * you may not use this file except in compliance with the License. * You may obtain a copy of the License at * * http://www.apache.org/licenses/LICENSE-2.0 * * * ======================================================================== */ /* * Program: IPOP3D - IMAP to POP3 conversion server * * Author: Mark Crispin * UW Technology * University of Washington * Seattle, WA 98195 * Internet: MRC@Washington.EDU * * Date: 1 November 1990 * Last Edited: 19 February 2008 */ /* Parameter files */ #include #include #include extern int errno; /* just in case */ #include #include #include "c-client.h" #define CRLF PSOUT ("\015\012") /* primary output terpri */ /* Autologout timer */ #define KODTIMEOUT 60*5 #define LOGINTIMEOUT 60*3 #define TIMEOUT 60*10 /* Server states */ #define AUTHORIZATION 0 #define TRANSACTION 1 #define UPDATE 2 #define LOGOUT 3 /* Eudora food */ #define STATUS "Status: %s%s\015\012" #define SLEN (sizeof (STATUS)-3) /* Global storage */ char *version = "104"; /* edit number of this server */ short state = AUTHORIZATION; /* server state */ short critical = NIL; /* non-zero if in critical code */ MAILSTREAM *stream = NIL; /* mailbox stream */ time_t idletime = 0; /* time we went idle */ unsigned long nmsgs = 0; /* current number of messages */ unsigned long ndele = 0; /* number of deletes */ unsigned long nseen = 0; /* number of mark-seens */ unsigned long last = 0; /* highest message accessed */ unsigned long il = 0; /* initial last message */ char challenge[128]; /* challenge */ char *host = NIL; /* remote host name */ char *user = NIL; /* user name */ char *pass = NIL; /* password */ char *initial = NIL; /* initial response */ long *msg = NIL; /* message translation vector */ short *flags = NIL; /* flags */ char *logout = "Logout"; char *goodbye = "+OK Sayonara\015\012"; /* POP3 flags */ #define DELE 0x1 #define SEEN 0x2 /* Function prototypes */ int main (int argc,char *argv[]); void sayonara (int status); void clkint (); void kodint (); void hupint (); void trmint (); int pass_login (char *t,int argc,char *argv[]); char *apop_login (char *chal,char *user,char *md5,int argc,char *argv[]); char *responder (void *challenge,unsigned long clen,unsigned long *rlen); int mbxopen (char *mailbox); long blat (char *text,long lines,unsigned long size,STRING *st); void rset (); /* Main program */ int main (int argc,char *argv[]) { unsigned long i,j,k; char *s,*t; char tmp[MAILTMPLEN]; time_t autologouttime; char *pgmname = (argc && argv[0]) ? (((s = strrchr (argv[0],'/')) || (s = strrchr (argv[0],'\\'))) ? s+1 : argv[0]) : "ipop3d"; /* set service name before linkage */ mail_parameters (NIL,SET_SERVICENAME,(void *) "pop"); #include "linkage.c" /* initialize server */ server_init (pgmname,"pop3","pop3s",clkint,kodint,hupint,trmint,NIL); mail_parameters (NIL,SET_BLOCKENVINIT,VOIDT); s = myusername_full (&i); /* get user name and flags */ mail_parameters (NIL,SET_BLOCKENVINIT,NIL); if (i == MU_LOGGEDIN) { /* allow EXTERNAL if logged in already */ mail_parameters (NIL,UNHIDE_AUTHENTICATOR,(void *) "EXTERNAL"); mail_parameters (NIL,SET_EXTERNALAUTHID,(void *) s); } { /* set up MD5 challenge */ AUTHENTICATOR *auth = mail_lookup_auth (1); while (auth && compare_cstring (auth->name,"CRAM-MD5")) auth = auth->next; /* build challenge -- less than 128 chars */ if (auth && auth->server && !(auth->flags & AU_DISABLE)) sprintf (challenge,"<%lx.%lx@%.64s>",(unsigned long) getpid (), (unsigned long) time (0),tcp_serverhost ()); else challenge[0] = '\0'; /* no MD5 authentication */ } /* There are reports of POP3 clients which get upset if anything appears * between the "+OK" and the "POP3" in the greeting. */ PSOUT ("+OK POP3 "); if (!challenge[0]) { /* if no MD5 enable, output host name */ PSOUT (tcp_serverhost ()); PBOUT (' '); } PSOUT (CCLIENTVERSION); PBOUT ('.'); PSOUT (version); PSOUT (" server ready"); if (challenge[0]) { /* if MD5 enable, output challenge here */ PBOUT (' '); PSOUT (challenge); } CRLF; PFLUSH (); /* dump output buffer */ autologouttime = time (0) + LOGINTIMEOUT; /* command processing loop */ while ((state != UPDATE) && (state != LOGOUT)) { idletime = time (0); /* get a command under timeout */ alarm ((state == TRANSACTION) ? TIMEOUT : LOGINTIMEOUT); clearerr (stdin); /* clear stdin errors */ /* read command line */ while (!PSIN (tmp,MAILTMPLEN)) { /* ignore if some interrupt */ if (ferror (stdin) && (errno == EINTR)) clearerr (stdin); else { char *e = ferror (stdin) ? strerror (errno) : "Unexpected client disconnect"; alarm (0); /* disable all interrupts */ server_init (NIL,NIL,NIL,SIG_IGN,SIG_IGN,SIG_IGN,SIG_IGN,SIG_IGN); sprintf (logout = tmp,"%.80s, while reading line",e); goodbye = NIL; rset (); /* try to gracefully close the stream */ if (state == TRANSACTION) mail_close (stream); stream = NIL; state = LOGOUT; sayonara (1); } } alarm (0); /* make sure timeout disabled */ idletime = 0; /* no longer idle */ if (!strchr (tmp,'\012')) /* find end of line */ PSOUT ("-ERR Command line too long\015\012"); else if (!(s = strtok (tmp," \015\012"))) PSOUT ("-ERR Null command\015\012"); else { /* dispatch based on command */ ucase (s); /* canonicalize case */ /* snarf argument */ t = strtok (NIL,"\015\012"); /* QUIT command always valid */ if (!strcmp (s,"QUIT")) state = UPDATE; else if (!strcmp (s,"CAPA")) { AUTHENTICATOR *auth; PSOUT ("+OK Capability list follows:\015\012"); PSOUT ("TOP\015\012LOGIN-DELAY 180\015\012UIDL\015\012"); if (s = ssl_start_tls (NIL)) fs_give ((void **) &s); else PSOUT ("STLS\015\012"); if (i = !mail_parameters (NIL,GET_DISABLEPLAINTEXT,NIL)) PSOUT ("USER\015\012"); /* display secure server authenticators */ for (auth = mail_lookup_auth (1), s = "SASL"; auth; auth = auth->next) if (auth->server && !(auth->flags & AU_DISABLE) && !(auth->flags & AU_HIDE) && (i || (auth->flags & AU_SECURE))) { if (s) { PSOUT (s); s = NIL; } PBOUT (' '); PSOUT (auth->name); } PSOUT (s ? ".\015\012" : "\015\012.\015\012"); } else switch (state) { /* else dispatch based on state */ case AUTHORIZATION: /* waiting to get logged in */ if (!strcmp (s,"AUTH")) { if (t && *t) { /* mechanism given? */ if (host) fs_give ((void **) &host); if (user) fs_give ((void **) &user); if (pass) fs_give ((void **) &pass); s = strtok (t," "); /* get mechanism name */ /* get initial response */ if (initial = strtok (NIL,"\015\012")) { if ((*initial == '=') && !initial[1]) ++initial; else if (!*initial) initial = NIL; } if (!(user = cpystr (mail_auth (s,responder,argc,argv)))) { PSOUT ("-ERR Bad authentication\015\012"); syslog (LOG_INFO,"AUTHENTICATE %s failure host=%.80s",s, tcp_clienthost ()); } else if ((state = mbxopen ("INBOX")) == TRANSACTION) syslog (LOG_INFO,"Auth user=%.80s host=%.80s nmsgs=%lu/%lu", user,tcp_clienthost (),nmsgs,stream->nmsgs); else syslog (LOG_INFO,"Auth user=%.80s host=%.80s no mailbox", user,tcp_clienthost ()); } else { AUTHENTICATOR *auth; PSOUT ("+OK Supported authentication mechanisms:\015\012"); i = !mail_parameters (NIL,GET_DISABLEPLAINTEXT,NIL); for (auth = mail_lookup_auth (1); auth; auth = auth->next) if (auth->server && !(auth->flags & AU_DISABLE) && !(auth->flags & AU_HIDE) && (i || (auth->flags & AU_SECURE))) { PSOUT (auth->name); CRLF; } PBOUT ('.'); CRLF; } } else if (!strcmp (s,"APOP")) { if (challenge[0]) { /* can do it if have an MD5 challenge */ if (host) fs_give ((void **) &host); if (user) fs_give ((void **) &user); if (pass) fs_give ((void **) &pass); /* get user name */ if (!(t && *t && (s = strtok (t," ")) && (t = strtok(NIL,"\012")))) PSOUT ("-ERR Missing APOP argument\015\012"); else if (!(user = apop_login (challenge,s,t,argc,argv))) PSOUT ("-ERR Bad APOP\015\012"); else if ((state = mbxopen ("INBOX")) == TRANSACTION) syslog (LOG_INFO,"APOP user=%.80s host=%.80s nmsgs=%lu/%lu", user,tcp_clienthost (),nmsgs,stream->nmsgs); else syslog (LOG_INFO,"APOP user=%.80s host=%.80s no mailbox", user,tcp_clienthost ()); } else PSOUT ("-ERR Not supported\015\012"); } /* (chuckle) */ else if (!strcmp (s,"RPOP")) PSOUT ("-ERR Nice try, bunkie\015\012"); else if (!strcmp (s,"STLS")) { if (t = ssl_start_tls (pgmname)) { PSOUT ("-ERR STLS failed: "); PSOUT (t); CRLF; } else PSOUT ("+OK STLS completed\015\012"); } else if (!mail_parameters (NIL,GET_DISABLEPLAINTEXT,NIL) && !strcmp (s,"USER")) { if (host) fs_give ((void **) &host); if (user) fs_give ((void **) &user); if (pass) fs_give ((void **) &pass); if (t && *t) { /* if user name given */ /* skip leading whitespace (bogus clients!) */ while (*t == ' ') ++t; /* remote user name? */ if (s = strchr (t,':')) { *s++ = '\0'; /* tie off host name */ host = cpystr (t);/* copy host name */ user = cpystr (s);/* copy user name */ } /* local user name */ else user = cpystr (t); PSOUT ("+OK User name accepted, password please\015\012"); } else PSOUT ("-ERR Missing username argument\015\012"); } else if (!mail_parameters (NIL,GET_DISABLEPLAINTEXT,NIL) && user && *user && !strcmp (s,"PASS")) state = pass_login (t,argc,argv); else PSOUT ("-ERR Unknown AUTHORIZATION state command\015\012"); break; case TRANSACTION: /* logged in */ if (!strcmp (s,"STAT")) { for (i = 1,j = 0,k = 0; i <= nmsgs; i++) /* message still exists? */ if (msg[i] && !(flags[i] & DELE)) { j++; /* count one more undeleted message */ k += mail_elt (stream,msg[i])->rfc822_size + SLEN; } sprintf (tmp,"+OK %lu %lu\015\012",j,k); PSOUT (tmp); } else if (!strcmp (s,"LIST")) { if (t && *t) { /* argument do single message */ if ((i = strtoul (t,NIL,10)) && (i <= nmsgs) && msg[i] && !(flags[i] & DELE)) { sprintf (tmp,"+OK %lu %lu\015\012",i, mail_elt(stream,msg[i])->rfc822_size + SLEN); PSOUT (tmp); } else PSOUT ("-ERR No such message\015\012"); } else { /* entire mailbox */ PSOUT ("+OK Mailbox scan listing follows\015\012"); for (i = 1,j = 0,k = 0; i <= nmsgs; i++) if (msg[i] && !(flags[i] & DELE)) { sprintf (tmp,"%lu %lu\015\012",i, mail_elt (stream,msg[i])->rfc822_size + SLEN); PSOUT (tmp); } PBOUT ('.'); /* end of list */ CRLF; } } else if (!strcmp (s,"UIDL")) { if (t && *t) { /* argument do single message */ if ((i = strtoul (t,NIL,10)) && (i <= nmsgs) && msg[i] && !(flags[i] & DELE)) { sprintf (tmp,"+OK %lu %08lx%08lx\015\012",i,stream->uid_validity, mail_uid (stream,msg[i])); PSOUT (tmp); } else PSOUT ("-ERR No such message\015\012"); } else { /* entire mailbox */ PSOUT ("+OK Unique-ID listing follows\015\012"); for (i = 1,j = 0,k = 0; i <= nmsgs; i++) if (msg[i] && !(flags[i] & DELE)) { sprintf (tmp,"%lu %08lx%08lx\015\012",i,stream->uid_validity, mail_uid (stream,msg[i])); PSOUT (tmp); } PBOUT ('.'); /* end of list */ CRLF; } } else if (!strcmp (s,"RETR")) { if (t && *t) { /* must have an argument */ if ((i = strtoul (t,NIL,10)) && (i <= nmsgs) && msg[i] && !(flags[i] & DELE)) { MESSAGECACHE *elt; /* update highest message accessed */ if (i > last) last = i; sprintf (tmp,"+OK %lu octets\015\012", (elt = mail_elt (stream,msg[i]))->rfc822_size + SLEN); PSOUT (tmp); /* if not marked seen or noted to be marked */ if (!(elt->seen || (flags[i] & SEEN))) { ++nseen; /* note that we need to mark it seen */ flags[i] |= SEEN; } /* get header */ t = mail_fetch_header (stream,msg[i],NIL,NIL,&k,FT_PEEK); blat (t,-1,k,NIL);/* write up to trailing CRLF */ /* build status */ sprintf (tmp,STATUS,elt->seen ? "R" : " ", elt->recent ? " " : "O"); if (k < 4) CRLF; /* don't write Status: if no header */ /* normal header ending with CRLF CRLF? */ else if (t[k-3] == '\012') { PSOUT (tmp); /* write status */ CRLF; /* then write second CRLF */ } else { /* abnormal - no blank line at end of header */ CRLF; /* write CRLF first then */ PSOUT (tmp); } /* output text */ t = mail_fetch_text (stream,msg[i],NIL,&k, FT_RETURNSTRINGSTRUCT | FT_PEEK); if (k) { /* only if there is a text body */ blat (t,-1,k,&stream->private.string); CRLF; /* end of list */ } PBOUT ('.'); CRLF; } else PSOUT ("-ERR No such message\015\012"); } else PSOUT ("-ERR Missing message number argument\015\012"); } else if (!strcmp (s,"DELE")) { if (t && *t) { /* must have an argument */ if ((i = strtoul (t,NIL,10)) && (i <= nmsgs) && msg[i] && !(flags[i] & DELE)) { /* update highest message accessed */ if (i > last) last = i; flags[i] |= DELE; /* note that deletion is requested */ PSOUT ("+OK Message deleted\015\012"); ++ndele; /* one more message deleted */ } else PSOUT ("-ERR No such message\015\012"); } else PSOUT ("-ERR Missing message number argument\015\012"); } else if (!strcmp (s,"NOOP")) PSOUT ("+OK No-op to you too!\015\012"); else if (!strcmp (s,"LAST")) { sprintf (tmp,"+OK %lu\015\012",last); PSOUT (tmp); } else if (!strcmp (s,"RSET")) { rset (); /* reset the mailbox */ PSOUT ("+OK Reset state\015\012"); } else if (!strcmp (s,"TOP")) { if (t && *t && (i =strtoul (t,&s,10)) && (i <= nmsgs) && msg[i] && !(flags[i] & DELE)) { /* skip whitespace */ while (*s == ' ') s++; /* make sure line count argument good */ if ((*s >= '0') && (*s <= '9')) { MESSAGECACHE *elt = mail_elt (stream,msg[i]); j = strtoul (s,NIL,10); /* update highest message accessed */ if (i > last) last = i; PSOUT ("+OK Top of message follows\015\012"); /* get header */ t = mail_fetch_header (stream,msg[i],NIL,NIL,&k,FT_PEEK); blat (t,-1,k,NIL);/* write up to trailing CRLF */ /* build status */ sprintf (tmp,STATUS,elt->seen ? "R" : " ", elt->recent ? " " : "O"); if (k < 4) CRLF; /* don't write Status: if no header */ /* normal header ending with CRLF CRLF? */ else if (t[k-3] == '\012') { PSOUT (tmp); /* write status */ CRLF; /* then write second CRLF */ } else { /* abnormal - no blank line at end of header */ CRLF; /* write CRLF first then */ PSOUT (tmp); } if (j) { /* want any text lines? */ /* output text */ t = mail_fetch_text (stream,msg[i],NIL,&k, FT_PEEK | FT_RETURNSTRINGSTRUCT); /* tie off final line if full text output */ if (k && (j -= blat (t,j,k,&stream->private.string))) CRLF; } PBOUT ('.'); /* end of list */ CRLF; } else PSOUT ("-ERR Bad line count argument\015\012"); } else PSOUT ("-ERR Bad message number argument\015\012"); } else if (!strcmp (s,"XTND")) PSOUT ("-ERR Sorry I can't do that\015\012"); else PSOUT ("-ERR Unknown TRANSACTION state command\015\012"); break; default: PSOUT ("-ERR Server in unknown state\015\012"); break; } } PFLUSH (); /* make sure output finished */ if (autologouttime) { /* have an autologout in effect? */ /* cancel if no longer waiting for login */ if (state != AUTHORIZATION) autologouttime = 0; /* took too long to login */ else if (autologouttime < time (0)) { goodbye = "-ERR Autologout\015\012"; logout = "Autologout"; state = LOGOUT; /* sayonara */ } } } /* open and need to update? */ if (stream && (state == UPDATE)) { if (nseen) { /* only bother if messages need marking seen */ *(s = tmp) = '\0'; /* clear sequence */ for (i = 1; i <= nmsgs; ++i) if (flags[i] & SEEN) { for (j = i + 1, k = 0; (j <= nmsgs) && (flags[j] & SEEN); ++j) k = j; if (k) sprintf (s,",%lu:%lu",i,k); else sprintf (s,",%lu",i); s += strlen (s); /* point to end of string */ if ((s - tmp) > (MAILTMPLEN - 30)) { mail_setflag (stream,tmp + 1,"\\Seen"); *(s = tmp) = '\0'; /* restart sequence */ } i = j; /* continue after the range */ } if (tmp[0]) mail_setflag (stream,tmp + 1,"\\Seen"); } if (ndele) { /* any messages to delete? */ *(s = tmp) = '\0'; /* clear sequence */ for (i = 1; i <= nmsgs; ++i) if (flags[i] & DELE) { for (j = i + 1, k = 0; (j <= nmsgs) && (flags[j] & DELE); ++j) k = j; if (k) sprintf (s,",%lu:%lu",i,k); else sprintf (s,",%lu",i); s += strlen (s); /* point to end of string */ if ((s - tmp) > (MAILTMPLEN - 30)) { mail_setflag (stream,tmp + 1,"\\Deleted"); *(s = tmp) = '\0'; /* restart sequence */ } i = j; /* continue after the range */ } if (tmp[0]) mail_setflag (stream,tmp + 1,"\\Deleted"); mail_expunge (stream); } syslog (LOG_INFO,"Update user=%.80s host=%.80s nmsgs=%lu ndele=%lu nseen=%lu", user,tcp_clienthost (),stream->nmsgs,ndele,nseen); mail_close (stream); } sayonara (0); return 0; /* stupid compilers */ } /* Say goodbye * Accepts: exit status * * Does not return */ void sayonara (int status) { logouthook_t lgoh = (logouthook_t) mail_parameters (NIL,GET_LOGOUTHOOK,NIL); if (goodbye) { /* have a goodbye message? */ PSOUT (goodbye); PFLUSH (); /* make sure blatted */ } syslog (LOG_INFO,"%s user=%.80s host=%.80s",logout, user ? (char *) user : "???",tcp_clienthost ()); /* do logout hook if needed */ if (lgoh) (*lgoh) (mail_parameters (NIL,GET_LOGOUTDATA,NIL)); _exit (status); /* all done */ } /* Clock interrupt */ void clkint () { alarm (0); /* disable all interrupts */ server_init (NIL,NIL,NIL,SIG_IGN,SIG_IGN,SIG_IGN,SIG_IGN,SIG_IGN); goodbye = "-ERR Autologout; idle for too long\015\012"; logout = "Autologout"; if (critical) state = LOGOUT; /* badly hosed if in critical code */ else { /* try to gracefully close the stream */ if ((state == TRANSACTION) && !stream->lock) { rset (); mail_close (stream); } state = LOGOUT; stream = NIL; sayonara (1); } } /* Kiss Of Death interrupt */ void kodint () { /* only if idle */ if (idletime && ((time (0) - idletime) > KODTIMEOUT)) { alarm (0); /* disable all interrupts */ server_init (NIL,NIL,NIL,SIG_IGN,SIG_IGN,SIG_IGN,SIG_IGN,SIG_IGN); goodbye = "-ERR Received Kiss of Death\015\012"; logout = "Killed (lost mailbox lock)"; if (critical) state =LOGOUT;/* must defer if in critical code */ else { /* try to gracefully close the stream */ if ((state == TRANSACTION) && !stream->lock) { rset (); mail_close (stream); } state = LOGOUT; stream = NIL; sayonara (1); /* die die die */ } } } /* Hangup interrupt */ void hupint () { alarm (0); /* disable all interrupts */ server_init (NIL,NIL,NIL,SIG_IGN,SIG_IGN,SIG_IGN,SIG_IGN,SIG_IGN); goodbye = NIL; /* nobody left to talk to */ logout = "Hangup"; if (critical) state = LOGOUT; /* must defer if in critical code */ else { /* try to gracefully close the stream */ if ((state == TRANSACTION) && !stream->lock) { rset (); mail_close (stream); } state = LOGOUT; stream = NIL; sayonara (1); /* die die die */ } } /* Termination interrupt */ void trmint () { alarm (0); /* disable all interrupts */ server_init (NIL,NIL,NIL,SIG_IGN,SIG_IGN,SIG_IGN,SIG_IGN,SIG_IGN); goodbye = "-ERR Killed\015\012"; logout = "Killed"; if (critical) state = LOGOUT; /* must defer if in critical code */ /* Make no attempt at graceful closure since a shutdown may be in * progress, and we won't have any time to do mail_close() actions. */ else sayonara (1); /* die die die */ } /* Parse PASS command * Accepts: pointer to command argument * Returns: new state */ int pass_login (char *t,int argc,char *argv[]) { char tmp[MAILTMPLEN]; /* flush old passowrd */ if (pass) fs_give ((void **) &pass); if (!(t && *t)) { /* if no password given */ PSOUT ("-ERR Missing password argument\015\012"); return AUTHORIZATION; } pass = cpystr (t); /* copy password argument */ if (!host) { /* want remote mailbox? */ /* no, delimit user from possible admin */ if (t = strchr (user,'*')) *t++ ='\0'; /* attempt the login */ if (server_login (user,pass,t,argc,argv)) { int ret = mbxopen ("INBOX"); if (ret == TRANSACTION) /* mailbox opened OK? */ syslog (LOG_INFO,"%sLogin user=%.80s host=%.80s nmsgs=%lu/%lu", t ? "Admin " : "",user,tcp_clienthost (),nmsgs,stream->nmsgs); else syslog (LOG_INFO,"%sLogin user=%.80s host=%.80s no mailbox", t ? "Admin " : "",user,tcp_clienthost ()); return ret; } } #ifndef DISABLE_POP_PROXY /* remote; build remote INBOX */ else if (anonymous_login (argc,argv)) { syslog (LOG_INFO,"IMAP login to host=%.80s user=%.80s host=%.80s",host, user,tcp_clienthost ()); sprintf (tmp,"{%.128s/user=%.128s}INBOX",host,user); /* disable rimap just in case */ mail_parameters (NIL,SET_RSHTIMEOUT,0); return mbxopen (tmp); } #endif /* vague error message to confuse crackers */ PSOUT ("-ERR Bad login\015\012"); return AUTHORIZATION; } /* Authentication responder * Accepts: challenge * length of challenge * pointer to response length return location if non-NIL * Returns: response */ #define RESPBUFLEN 8*MAILTMPLEN char *responder (void *challenge,unsigned long clen,unsigned long *rlen) { unsigned long i,j; unsigned char *t,resp[RESPBUFLEN]; char tmp[MAILTMPLEN]; if (initial) { /* initial response given? */ if (clen) return NIL; /* not permitted */ /* set up response */ t = (unsigned char *) initial; initial = NIL; /* no more initial response */ return (char *) rfc822_base64 (t,strlen ((char *) t),rlen ? rlen : &i); } PSOUT ("+ "); for (t = rfc822_binary (challenge,clen,&i),j = 0; j < i; j++) if (t[j] > ' ') PBOUT (t[j]); fs_give ((void **) &t); CRLF; PFLUSH (); /* dump output buffer */ resp[RESPBUFLEN-1] = '\0'; /* last buffer character is guaranteed NUL */ alarm (LOGINTIMEOUT); /* get a response under timeout */ clearerr (stdin); /* clear stdin errors */ /* read buffer */ while (!PSIN ((char *) resp,RESPBUFLEN)) { /* ignore if some interrupt */ if (ferror (stdin) && (errno == EINTR)) clearerr (stdin); else { char *e = ferror (stdin) ? strerror (errno) : "Command stream end of file"; alarm (0); /* disable all interrupts */ server_init (NIL,NIL,NIL,SIG_IGN,SIG_IGN,SIG_IGN,SIG_IGN,SIG_IGN); sprintf (logout = tmp,"%.80s, while reading authentication",e); goodbye = NIL; state = LOGOUT; sayonara (1); } } if (!(t = (unsigned char *) strchr ((char *) resp,'\012'))) { int c; while ((c = PBIN ()) != '\012') if (c == EOF) { /* ignore if some interrupt */ if (ferror (stdin) && (errno == EINTR)) clearerr (stdin); else { char *e = ferror (stdin) ? strerror (errno) : "Command stream end of file"; alarm (0); /* disable all interrupts */ server_init (NIL,NIL,NIL,SIG_IGN,SIG_IGN,SIG_IGN,SIG_IGN,SIG_IGN); sprintf (logout = tmp,"%.80s, while reading auth char",e); goodbye = NIL; state = LOGOUT; sayonara (1); } } return NIL; } alarm (0); /* make sure timeout disabled */ if (t[-1] == '\015') --t; /* remove CR */ *t = '\0'; /* tie off buffer */ return (resp[0] != '*') ? (char *) rfc822_base64 (resp,t-resp,rlen ? rlen : &i) : NIL; } /* Select mailbox * Accepts: mailbox name * Returns: new state */ int mbxopen (char *mailbox) { unsigned long i,j; char tmp[MAILTMPLEN]; MESSAGECACHE *elt; if (msg) fs_give ((void **) &msg); /* open mailbox */ if (!(stream = mail_open (stream,mailbox,NIL))) goodbye = "-ERR Unable to open user's INBOX\015\012"; else if (stream->rdonly) /* make sure not readonly */ goodbye = "-ERR Can't get lock. Mailbox in use\015\012"; else { nmsgs = 0; /* no messages yet */ if (j = stream->nmsgs) { /* if mailbox non-empty */ sprintf (tmp,"1:%lu",j); /* fetch fast information for all messages */ mail_fetch_fast (stream,tmp,NIL); } /* create 1-origin tables */ msg = (long *) fs_get (++j * sizeof (long)); flags = (short *) fs_get (j * sizeof (short)); /* build map */ for (i = 1; i < j; ++i) if (!(elt = mail_elt (stream,i))->deleted) { msg[++nmsgs] = i; /* note the presence of this message */ if (elt->seen) il = nmsgs;/* and set up initial LAST */ } /* make sure unused map entries are zero */ for (i = nmsgs + 1; i < j; ++i) msg[i] = 0; rset (); /* do implicit RSET */ sprintf (tmp,"+OK Mailbox open, %lu messages\015\012",nmsgs); PSOUT (tmp); return TRANSACTION; } syslog (LOG_INFO,"Error opening or locking INBOX user=%.80s host=%.80s", user,tcp_clienthost ()); return UPDATE; } /* Blat a string with dot checking * Accepts: string * maximum number of lines if greater than zero * maximum number of bytes to output * alternative stringstruct * Returns: number of lines output * * This routine is uglier and kludgier than it should be, just to be robust * in the case of a message which doesn't end in a newline. Yes, this routine * does truncate the last two bytes from the text. Since it is normally a * newline and the main routine adds it back, it usually does not make a * difference. But if it isn't, since the newline is required and the octet * counts have to match, there's no choice but to truncate. */ long blat (char *text,long lines,unsigned long size,STRING *st) { char c,d,e; long ret = 0; /* no-op if zero lines or empty string */ if (!(lines && (size-- > 2))) return 0; if (text) { c = *text++; d = *text++; /* collect first two bytes */ if (c == '.') PBOUT ('.'); /* double string-leading dot if necessary */ while (lines && --size) { /* copy loop */ e = *text++; /* get next byte */ PBOUT (c); /* output character */ if (c == '\012') { /* end of line? */ ret++; --lines; /* count another line */ /* double leading dot as necessary */ if (lines && size && (d == '.')) PBOUT ('.'); } c = d; d = e; /* move to next character */ } } else { c = SNX (st); d = SNX (st); /* collect first two bytes */ if (c == '.') PBOUT ('.'); /* double string-leading dot if necessary */ while (lines && --size) { /* copy loop */ e = SNX (st); /* get next byte */ PBOUT (c); /* output character */ if (c == '\012') { /* end of line? */ ret++; --lines; /* count another line */ /* double leading dot as necessary */ if (lines && size && (d == '.')) PBOUT ('.'); } c = d; d = e; /* move to next character */ } } return ret; } /* Reset mailbox */ void rset () { /* clear all flags */ if (flags) memset ((void *) flags,0,(nmsgs + 1) * sizeof (short)); ndele = nseen = 0; /* no more deleted or seen messages */ last = il; /* restore previous LAST value */ } /* Co-routines from MAIL library */ /* Message matches a search * Accepts: MAIL stream * message number */ void mm_searched (MAILSTREAM *stream,unsigned long msgno) { /* Never called */ } /* Message exists (i.e. there are that many messages in the mailbox) * Accepts: MAIL stream * message number */ void mm_exists (MAILSTREAM *stream,unsigned long number) { /* Can't use this mechanism. POP has no means of notifying the client of new mail during the session. */ } /* Message expunged * Accepts: MAIL stream * message number */ void mm_expunged (MAILSTREAM *stream,unsigned long number) { unsigned long i = number + 1; msg[number] = 0; /* I bet that this will annoy someone */ while (i <= nmsgs) --msg[i++]; } /* Message flag status change * Accepts: MAIL stream * message number */ void mm_flags (MAILSTREAM *stream,unsigned long number) { /* This isn't used */ } /* Mailbox found * Accepts: MAIL stream * hierarchy delimiter * mailbox name * mailbox attributes */ void mm_list (MAILSTREAM *stream,int delimiter,char *name,long attributes) { /* This isn't used */ } /* Subscribe mailbox found * Accepts: MAIL stream * hierarchy delimiter * mailbox name * mailbox attributes */ void mm_lsub (MAILSTREAM *stream,int delimiter,char *name,long attributes) { /* This isn't used */ } /* Mailbox status * Accepts: MAIL stream * mailbox name * mailbox status */ void mm_status (MAILSTREAM *stream,char *mailbox,MAILSTATUS *status) { /* This isn't used */ } /* Notification event * Accepts: MAIL stream * string to log * error flag */ void mm_notify (MAILSTREAM *stream,char *string,long errflg) { mm_log (string,errflg); /* just do mm_log action */ } /* Log an event for the user to see * Accepts: string to log * error flag */ void mm_log (char *string,long errflg) { switch (errflg) { case NIL: /* information message */ case PARSE: /* parse glitch */ break; /* too many of these to log */ case WARN: /* warning */ syslog (LOG_DEBUG,"%s",string); break; case BYE: /* driver broke connection */ if (state != UPDATE) { char tmp[MAILTMPLEN]; alarm (0); /* disable all interrupts */ server_init (NIL,NIL,NIL,SIG_IGN,SIG_IGN,SIG_IGN,SIG_IGN,SIG_IGN); sprintf (logout = tmp,"Mailbox closed (%.80s)",string); goodbye = NIL; state = LOGOUT; sayonara (1); } break; case ERROR: /* error that broke command */ default: /* default should never happen */ syslog (LOG_NOTICE,"%s",string); break; } } /* Log an event to debugging telemetry * Accepts: string to log */ void mm_dlog (char *string) { /* Not doing anything here for now */ } /* Get user name and password for this host * Accepts: parse of network mailbox name * where to return user name * where to return password * trial count */ void mm_login (NETMBX *mb,char *username,char *password,long trial) { /* set user name */ strncpy (username,*mb->user ? mb->user : user,NETMAXUSER-1); if (pass) { strncpy (password,pass,255);/* and password */ fs_give ((void **) &pass); } else memset (password,0,256); /* no password to send, abort login */ username[NETMAXUSER] = password[255] = '\0'; } /* About to enter critical code * Accepts: stream */ void mm_critical (MAILSTREAM *stream) { ++critical; } /* About to exit critical code * Accepts: stream */ void mm_nocritical (MAILSTREAM *stream) { --critical; } /* Disk error found * Accepts: stream * system error code * flag indicating that mailbox may be clobbered * Returns: abort flag */ long mm_diskerror (MAILSTREAM *stream,long errcode,long serious) { if (serious) { /* try your damnest if clobberage likely */ syslog (LOG_ALERT, "Retrying after disk error user=%.80s host=%.80s mbx=%.80s: %.80s", user,tcp_clienthost (), (stream && stream->mailbox) ? stream->mailbox : "???", strerror (errcode)); alarm (0); /* make damn sure timeout disabled */ sleep (60); /* give it some time to clear up */ return NIL; } syslog (LOG_ALERT,"Fatal disk error user=%.80s host=%.80s mbx=%.80s: %.80s", user,tcp_clienthost (), (stream && stream->mailbox) ? stream->mailbox : "???", strerror (errcode)); return T; } /* Log a fatal error event * Accepts: string to log */ void mm_fatal (char *string) { mm_log (string,ERROR); /* shouldn't happen normally */ } alpine-2.10+dfsg/imap/src/ipopd/makefile.nt0000600000175000017500000000264711512502124022315 0ustar paulproteuspaulproteus# ======================================================================== # Copyright 1988-2006 University of Washington # # Licensed under the Apache License, Version 2.0 (the "License"); # you may not use this file except in compliance with the License. # You may obtain a copy of the License at # # http://www.apache.org/licenses/LICENSE-2.0 # # # ======================================================================== # Program: IPOPD Makefile for Windows 9x and Windows NT # # Author: Mark Crispin # Networks and Distributed Computing # Computing & Communications # University of Washington # Administration Building, AG-44 # Seattle, WA 98195 # Internet: MRC@CAC.Washington.EDU # # Date: 28 October 1990 # Last Edited: 30 August 2006 C = ..\c-client CCLIENTLIB = $C\cclient.lib LIBS = $(CCLIENTLIB) ws2_32.lib winmm.lib advapi32.lib OSCOMPAT = /DWIN32 /D_WIN32_WINNT=0x0400 VSCOMPAT = /D_CRT_SECURE_NO_DEPRECATE /D_CRT_NONSTDC_NO_DEPRECATE CFLAGS= -I$C /MT /W3 $(OSCOMPAT) $(VSCOMPAT) -nologo $(EXTRACFLAGS) ipopd: ipop2d ipop3d ipop2d: $(CCLIENTLIB) ipop2d.obj LINK /NOLOGO ipop2d.obj $(LIBS) ipop3d: $(CCLIENTLIB) ipop3d.obj LINK /NOLOGO ipop3d.obj $(LIBS) ipop2d.obj: $C\mail.h $C\misc.h $C\osdep.h ipop3d.obj: $C\mail.h $C\misc.h $C\osdep.h $(CCLIENTLIB): @echo Make c-client first false clean: del *.obj *.exe *.lib *.exp || rem # A monument to a hack of long ago and far away... love: @echo not war? alpine-2.10+dfsg/imap/makefile.ntk0000600000175000017500000000301411512502125020554 0ustar paulproteuspaulproteus# ======================================================================== # Copyright 1988-2006 University of Washington # # Licensed under the Apache License, Version 2.0 (the "License"); # you may not use this file except in compliance with the License. # You may obtain a copy of the License at # # http://www.apache.org/licenses/LICENSE-2.0 # # # ======================================================================== # Program: IMAP Toolkit Makefile for Windows 9x and Windows NT + Kerberos # # Author: Mark Crispin # Networks and Distributed Computing # Computing & Communications # University of Washington # Administration Building, AG-44 # Seattle, WA 98195 # Internet: MRC@CAC.Washington.EDU # # Date: 7 December 1989 # Last Edited: 30 August 2006 COPY=copy CD=cd MAKE=nmake /nologo /f makefile.ntk MKDIR=mkdir RD=rmdir /s /q # Make the IMAP Toolkit build: c-client mtest mailutil imapd ipopd $(CD) c-client $(MAKE) $(CD) ..\mtest $(MAKE) $(CD) ..\mailutil $(MAKE) $(CD) ..\ipopd $(MAKE) $(CD) ..\imapd $(MAKE) $(CD) .. c-client: $(MKDIR) c-client $(COPY) src\c-client\*.* c-client $(COPY) src\charset\*.* c-client $(COPY) src\osdep\nt\*.* c-client mtest: $(MKDIR) mtest $(COPY) src\mtest\*.* mtest mailutil: $(MKDIR) mailutil $(COPY) src\mailutil\*.* mailutil ipopd: $(MKDIR) ipopd $(COPY) src\ipopd\*.* ipopd imapd: $(MKDIR) imapd $(COPY) src\imapd\*.* imapd clean: $(RD) c-client mtest mailutil ipopd imapd # A monument to a hack of long ago and far away... love: @echo 'not war?' alpine-2.10+dfsg/imap/docs/0000700000175000017500000000000011512502151017210 5ustar paulproteuspaulproteusalpine-2.10+dfsg/imap/docs/Y2K0000600000175000017500000001344511512502125017552 0ustar paulproteuspaulproteus/* ======================================================================== * Copyright 1988-2006 University of Washington * * Licensed under the Apache License, Version 2.0 (the "License"); * you may not use this file except in compliance with the License. * You may obtain a copy of the License at * * http://www.apache.org/licenses/LICENSE-2.0 * * * ======================================================================== */ QUESTION: Is c-client Y2K compliant? ANSWER: There are no known Y2K issues in c-client; nor have there ever been any known Y2K issues in c-client from its inception. Some older versions of c-client don't like the two-digit year "00", although the only impact of this is that messages with that year will sort before any other messages. Nobody should be using two-digit years in email messages any more (use "2000" instead of "00"). You may wish to read the document calendar.txt for more information about the Y3.3K/Y4K, Y20K, and Y4)K issues. Assuming that c-client is still around in 2000-40,000 years, someone will have to deal with these. Within the plausible lifetimes of people today, there are three known date-related issues in c-client which will have to be addressed in the future. If I am still alive when the first problem hits, I will be nearly 82 years old, and won't be maintaining c-client any more. Y2038: c-client, like most UNIX software, has Y2038 issues. On Tuesday, January 19, 2038 at 03:14:08 Coordinated Universal Time (also known as UTC, UT, or historically GMT), the clock on 32-bit UNIX systems will wrap around to a negative number; that is, from 0x7fffffff to 0x80000000. c-client uses an unsigned long for its 32-bit time; however the C library on most UNIX systems uses a signed long and will interpret that time as being Friday, December 13, 1901 at 20:45:52 UTC. Fixing this problem will require changing the C library to use either unsigned longs or a wider (e.g. 64-bit) value for time. Lots of work will need to be done on 32-bit UNIX systems as 2038 approaches. History suggests that most of the work will be done in the autumn of 2037... ;-) It's not known if anything is necessary to do to c-client other than just rebuild it with the new C library. Going to 32-bit unsigned longs means that there will be a Y2106 bug that someone will have to fix. Hopefully nobody will even think of using 32-bit systems by then. Y2070: c-client assumes that 2-digit years with values of 70 or greater are in the 20th century, and that 2-digit years with values of 69 or less are in the 21st century. Time for UNIX began on January 1, 1970 and email on ARPAnet happened between the first TENEX systems shortly after that; consequently there is no ambiguity with email data with 2-digit years prior to the year 2070. This is used only when parsing a 2-digit year. c-client never generates one. Fixing this problem requires convincing people not to use 2-digit years. This is a lesson that people should have figured out 70 years earlier with Y2K. Consequently, this may be a "non-problem." Otherwise, look in mail_parse_date() for the comment "two digit year" and change the statement as desired. [Note: do not change the definition of BASEYEAR since the UNIX port assumes that this matches when time began in the operating system.] Y2098: On January 1, 2098, the year in per-message internal dates will expire, since a 7-bit field is allocated for the year. c-client will mistakenly think that the day is January 1, 1970. Fortunately, it is easy to fix this problem. Just increase the width of "year" in MESSAGECACHE in mail.h. If you make it 8 bits, it'll be good until January 1, 2216; 9 bits makes it good until 2482. 10 bits will push it back that you'd worry about the Y2800 question before having to increase it again. If you ignore Y2800, 11 bits will push it it back to having to worry about Y4K first. Y2800: At this year, you will need to decide whether to keep the Gregorian calendar, which is one day slow every 20,000 years, or go to the more accurate Eastern Orthodox calendar which is one day slow every 45,000 years. The Gregorian and Eastern Orthodox calendars diverge at this year. There hasn't been any statement about how the international community will deal with the situation of the Orthodox calendar being one day ahead of the Gregorian calendar between 2800 and 2900. This will happen again between 3200 and 3300, and at gradually increasing intervals until 48,300 when the shift becomes permanent (assuming no Y20K or Y40K fixes). If you wish to make the transition to the Eastern Orthodox calendar, rebuild c-client with -DUSEORTHODOXCALENDAR=1. You can then ignore Y4K and Y20K! Y3.3K/Y4K: Some time around the year 3300, the calendar has gotten one day behind. To remedy this, a little-known rule in the Gregorian calendar is that years that are evenly divisible by 4000 are not leap years. Unlike the other rules, this rule hasn't had effect yet, and won't for another 2000 years. To fix the Y4K problem, just rebuild c-client with -DY4KBUGFIX=1. Y20K: Those of you who stuck with the Gregorian calendar have a problem; the calendar is now one day slow. The Pope has not made any statement about how this problem will be fixed. Maybe they'll declare that 20,004 is also not a leap year or something. There is no fix for this problem in c-client. Y40K: Greeks, Serbs, Russians, and other Eastern Orthodox have spent the past 38,000 years laughing at westerners' increasingly futile efforts to keep the Gregorian calendar in order. The day of reckoning has come; the Orthodox calendar is now one day slow. The Patriarch of Istanbul (nee Constantinople) has not made any statement about how this will be fixed. There is no fix for this problem in c-client. alpine-2.10+dfsg/imap/docs/calendar.txt0000600000175000017500000003542211512502125021533 0ustar paulproteuspaulproteus/* ======================================================================== * Copyright 1988-2006 University of Washington * * Licensed under the Apache License, Version 2.0 (the "License"); * you may not use this file except in compliance with the License. * You may obtain a copy of the License at * * http://www.apache.org/licenses/LICENSE-2.0 * * * ======================================================================== */ ALL ABOUT CALENDARS Although one can never be sure of what will happen at some future time, there is strong historical precedent for presuming that the present Gregorian calendar will still be in effect within the useful lifetime of the IMAP toolkit. We have therefore chosen to adhere to these precedents. The purpose of a calendar is to reckon time in advance, to show how many days have to elapse until a certain event takes place in the future, such as the harvest or the release of a new version of Pine. The earliest calendars, naturally, were crude and tended to be based upon the seasons or the lunar cycle. ANCIENT CALENDARS The calendar of the Assyrians, for example, was based upon the phases of the moon. They knew that a lunation (the time from one full moon to the next) was 29 1/2 days long, so their lunar year had a duration of 354 days. This fell short of the solar year by about 11 days. (The exact time for the solar year is approximately 365 days, 5 hours, 48 minutes, and 46 seconds.) After 3 years, such a lunar calendar would be off by a whole month, so the Assyrians added an extra month from time to time to keep their calendar in synchronization with the seasons. The best approximation that was possible in antiquity was a 19-year period, with 7 of these 19 years having 13 months (leap months). This scheme was adopted as the basis for the lunar calendar used by the Hebrews. The Arabs also used this calendar until Mohammed forbade shifting from 12 months to 13 months; this causes the Muslim holy month of Ramadan to move backwards through the seasons, completing a cycle every 32 1/2 years. When Rome emerged as a world power, the difficulties of making a calendar were well known, but the Romans complicated their lives because of their superstition that even numbers were unlucky. Hence their months were 29 or 31 days long, with the exception of February, which had 28 days. Every second year, the Roman calendar included an extra month called Mercedonius of 22 or 23 days to keep up with the solar year. JULIAN CALENDAR Even this algorithm was very poor, so that in 45 BCE, Caesar, advised by the astronomer Sosigenes, ordered a sweeping reform. By imperial decree, the year 46 BCE was made 445 days long to bring the calendar back in step with the seasons. The new calendar, similar to the one we now use was called the Julian calendar (named after Julius Caesar). Months in the Julian calendar were 30 or 31 days in length and every fourth year was made a leap year (having 366 days) by adding a day to the end of the year. This leap year rule was not consistantly applied until 8 CE. The year-ending month of February, never a popular month, was presently shortened so that Julius Caesar and Emperor Augustus could each have long months named after them. Caesar also decreed that the year would start with the first of January, which since 153 BCE was the day that Roman consuls took office, and not the vernal equinox in late March. Not everyone accepted that part of his reform, as we shall see. GREGORIAN CALENDAR Caesar's year was 11 1/2 minutes short of the calculations recommended by Sosigenes and eventually the date of the vernal equinox began to drift. Roger Bacon became alarmed and sent a note to Pope Clement IV, who apparently was not impressed. Pope Sixtus IV later became convinced that another reform was needed and called the German astronomer, Regiomontanus, to Rome to advise him. Unfortunately, Regiomontanus died of the plague shortly thereafter and the plans died as well. In 1545, the Council of Trent authorized Pope Gregory XIII to reform the calendar once more. Most of the mathematical work was done by Father Christopher Clavius, S.J. The immediate correction that was adopted was that Thursday, October 4, 1582 was to be the last day of the Julian calendar. The next day was Friday, with the date of October 15. For long range accuracy, a formula suggested by the Vatican librarian Aloysius Giglio was adopted. It said that every fourth year is a leap year except for century years that are not divisible by 400. Thus 1700, 1800 and 1900 would not be leap years, but 2000 would be a leap year since 2000 is divisible by 400. This rule eliminates 3 leap years every 4 centuries, making the calendar sufficiently correct for most ordinary purposes. This calendar is known as the Gregorian calendar and is the one that we now use today. It is interesting to note that in 1582, all the Protestant princes ignored the papal decree and so many countries continued to use the Julian calendar until either 1698 or 1752. Britain and its American colonies went from Wednesday, September 2, 1752 to Thursday, September 14. Prior to the changeover, the British used March 25 as the start of the new year. In Russia, it needed the revolution to introduce the Gregorian calendar in 1918. Turkey didn't adopt it until 1927. NUMBERING OF YEARS The numbering of the year is generally done according to an "era", such as the year of a ruler's reign. In about 525, a monk named Dionysius Exiguus suggested that the calculated year of Jesus' birth be designated as year 1 in the Julian calendar. This suggestion was adopted over the next 500 years and subsequently followed in the Gregorian calendar. For the benefit of those who seek religious significance to the calendar millenium, note that year 1 is too late by at least 4 years. Herod the Great, named in the Christian Bible as having all children in Bethlehem put to death in an attempt to kill the infant Jesus, died in 4 BCE. Nothing particularly significant of an historic or religious nature happened in Gregorian year 1; however it has become a worldwide standard as the "common era." In modern times, the terms "CE" (common era) and "BCE" (before common era) are preferred over the earlier (and, as we have seen, less accurate) "AD" (anno Domini, "the year of the Lord") and "BC" (before Christ). The Hebrew lunar calendar begins at 3760 BCE, the year of creation in Jewish tradition. The Muslim lunar calendar begins on July 16, 622, when Mohammed fled from Mecca to Medina. The Japanese, Taiwanese, and North Koreans use the Gregorian calendar, but number the year by political era. In Japan, an era begins when an emperor succeeds to the throne; year 1 of the Heisei era was 1989 when Emperor Akihito ascended to the throne (the first few days of 1989 was year 64 of the Shouwa era). In Taiwan, year 1 is the first full year after the founding of the Republic of China in 1911. In North Korea, year 1 is the year of the Juche (self-reliance) ideal, corresponding to the birth year of founder Kim Il-Sung (1912). Thus, year 2000 is Heisei 12 (Japan), 89th year of the Republic (Taiwan), and Juche 89 (North Korea). FURTHER MODIFICATIONS TO THE GREGORIAN CALENDAR Despite the great accuracy of the Gregorian calendar, it still falls behind very slightly every few years. The most serious problem is that the earth's rotation is slowing gradually. If you are very concerned about this problem, we suggest that you tune in short wave radio station WWV or the Global Positioning System, which broadcasts official time signals for use in the United States. About once every 3 years, they declare a leap second at which time you should be careful to adjust your system clock. If you have trouble picking up their signals, we suggest you purchase an atomic clock (not part of the IMAP toolkit). Another problem is that the Gregorian calendar represents a year of 365.2425 days, whereas the actual time taken for the earth to rotate around the Sun is 365.2421991 days. Thus, the Gregorian calendar is actually 26 seconds slow each year, resulting in the calendar being one day behind every 3,300 or so years (a Y3.3K problem). Consequently, the Gregorian calendar has been modified with a further rule, which is that years evenly divisible by 4000 are not leap years. Thus, the year 4000 will not be a leap year. Or, at least we assume that's what will happen assuming that the calendar remains unchanged for the next 2000 years. The modified Gregorian calendar represents a year of 365.24225 days. Thus, the modified Gregorian calendar is actually 4 seconds slow each year, resulting in the calendar being one day slow every 20,000 or so years. So there will be a Y20K problem. There is some dispute whether the modified Gregorian calendar was officially adopted, or if it's just a proposal. Other options (see below) exist; fortunately no decision needs to be made for several centuries yet. There is code in c-client to support the modified Gregorian calendar, although it is currently disabled. Sometime in the next 2000 years, someone will need to enable this code so that c-client is Y4K compiliant. Then, 18,000 years from now, someone will have to tear into c-client's code to fix the Y20K bug. EASTERN ORTHODOX MODIFICATION OF THE GREGORIAN CALENDAR The Eastern Orthodox church in 1923 established its own rules to correct the Julian calendar. In their calendar, century years modulo 900 must result in value of 200 or 600 to be considered a leap year. Both the Orthodox and Gregorian calendar agree that the years 2000 and 2400 will be leap years, and the years 1900, 2100, 2200, 2300, 2500, 2600, 2700 are not. However, the year 2800 will be a leap year in the Gregorian calendar but not in the Orthodox calendar; similarly, the year 2900 will be a leap year in the Orthodox calendar but not in the Gregorian calendar. Both calendars will agree that 3000 and 3100 are leap years, but will disagree again in 3200 and 3300. There is code in c-client to support the Orthodox calendar. It can be enabled by adding -DUSEORTHODOXCALENDAR=1 to the c-client CFLAGS, e.g. make xxx EXTRACFLAGS="-DUSEORTHODOXCALENDAR=1" The Orthodox calendar represents a year of 365.24222222... days. Thus, the Orthodox calendar is actually 2 seconds slow each year, resulting in the calendar being one day slow every 40,000 or so years. The Eastern Orthodox church has not yet made any statements on how the Y40K bug will be fixed. OTHER ISSUES AFFECTING THE CALENDAR IN THE FUTURE The effect of leap seconds also needs to be considered when looking at the Y3.3K/Y4K, Y20K, and Y40K problems. Leap seconds put the clock back in line with the Earth's rotation, whereas leap years put the calendar back in line with the Earth's revolution. Since leap seconds slow down the clock (and hence the calendar), they actually bring the day of reckoning for the Gregorian and Orthodox calendars sooner. Another factor is that the next ice age (technically, the end of the current interglacial period; we are in the middle of an ice age now!) is due around Y25K. It is not known what perturbations this will cause on the Earth's rotation and revolution, nor what calendar adjustments will be necessary at that time. Hence my use of "or so" in predicting the years that the calendar will fall behind. The actual point may be anywhere from decades (in the case of Y3.3K) to millenia (in the case of Y40K) off from these predictions. MEANINGS OF DAY NAMES The names of days of the week from a combination of Roman and Germanic names for celestial bodies: . Sunday Latin "dies solis" => "Sun's day" . Monday Latin "dies lunae" => "Moon's day" . Tuesday Germanic "Tiw's day" => "Mars' day" . Wednesday Germanic "Woden's day" => "Mercury's day" . Thursday Germanic "Thor's day" => "Jupiter's day" . Friday Germanic "Frigg's day" => "Venus' day" . Saturday Latin "dies Saturni" => "Saturn's day" MEANINGS OF MONTH NAMES The names of the months are from the Roman calendar: . January Janus, protector of doorways . February Februalia, a time for sacrifice to atone for sins . March Mars, god of war . April Latin "aperire" => "to open" buds . May Maia, goddess of plant growth . June Latin "juvenis" => "youth" . July Julius Caesar . August Augustus Caesar . September Latin "septem" => "seven" . October Latin "octo" => "eight" . November Latin "novem" => "nine" . December Latin "decem" => "ten" As you'll notice, the last four months are numbered 7 to 10, which is an artifact of the time when the new year started in March. INTERESTING FORMULAE There's another reason why the historical starting of the new year is significant. Starting with March, the length of months follows a mathematical series: 31 30 31 30 31 31 30 31 30 31 31 28 This means that you can calculate the day of week for any arbitrary day/month/year of the Gregorian calendar with the following formula (note all divisions are integral): _ _ | 7 + 31*(m - 1) y y y | dow = | d + -------------- + y + - - --- + --- | MOD 7 |_ 12 4 100 400_| where d := day of month (1..31) m := month in old style (March = 1..February = 12) y := year in old style dow := day of week (Tuesday = 0..Monday = 6) To convert from new style month/year to old style: if (m > 2) m -= 2; /* Mar-Dec: subtract 2 from month */ else m += 10,y--; /* Jan-Feb: months 11 & 12 of previous year */ Here's another fun formula. To find the number of days between two days, calculate a pair of calendar days with the formula (again, all divisions are integral), using new style month/year this time: m m + - 8 y y y d + 30 * (m - 1) + ----- + y * 365 + - - --- + --- - ld 2 4 100 400 where: d := day of month (1..31) m := month in new style (January = 1..December = 12) y := year in new style ld := leap day correction factor: 0 for January and February in non-leap years 1 for January and February in leap years 2 for all other months in all years In C code, the leap day correction factor is calculated as: (m < 3) ? !(y % 4) && ((y % 100) || !(y % 400)) : 2 It's up to you to figure out how to adapt these formulas for the Y4K bugfix and the Orthodox calendar. If you're really clever, try to use these formulae to implement the C library ctime(), gmtime(), and mktime() functions. Most C library implementations use a table of the number of days in a month. You don't need it. ACKNOWLEDGEMENT: The original version is from an old Digital Equipment Corporation SPR answer for VMS. Modifications for c-client, and additional information added by Mark Crispin. alpine-2.10+dfsg/imap/docs/md5.txt0000600000175000017500000000731011512502125020442 0ustar paulproteuspaulproteus/* ======================================================================== * Copyright 1988-2006 University of Washington * * Licensed under the Apache License, Version 2.0 (the "License"); * you may not use this file except in compliance with the License. * You may obtain a copy of the License at * * http://www.apache.org/licenses/LICENSE-2.0 * * * ======================================================================== */ MD5 Based Authentication Mark Crispin 1 November 1999 The IMAP toolkit makes available two MD5 based authentication mechanisms, CRAM-MD5 and APOP. CRAM-MD5 is described in RFC 2195, and is a SASL (RFC 2222) authentication mechanism. APOP is described in RFC 1939, the standard document for the POP3 protocol. These mechanisms use the same general idea. The server issues a challenge; the client responds with an MD5 checksum of the challenge plus the password; the server in compares the client's response with its own calculated value of the checksum. If the client's response matches the server's calulated value, the client is authenticated. Unlike plaintext passwords, this form of authentication is believed to be secure against the session being monitored; "sniffing" the session will not disclose the password nor will it provide usable information to authenticate in another session without knowing the password. The key disadvantage with this form of authentication is that the server must know a plaintext form of the password. In traditional UNIX authentication, the server only knows an encrypted form of the password. Consequently, the authentication database for this form of authentication must be kept strictly confidential; a bad guy who acquires access to this database can access any account in the database. CRAM-MD5 client support is implemented unconditionally; any client application built with the IMAP toolkit will use CRAM-MD5 with any server which advertises CRAM-MD5 SASL support. CRAM-MD5 and APOP server support is implemented if, and only if, the CRAM-MD5 authentication database exists. By default, the CRAM-MD5 authentication database is in a UNIX file called /etc/cram-md5.pwd It is recommended that this file be protected 0400. NOTE: FAILURE TO PROTECT THIS FILE AGAINST UNAUTHORIZED ACCESS WILL COMPROMSE CRAM-MD5 AND APOP AUTHENTICATION FOR ALL USERS LISTED IN THIS DATABASE. If the CRAM-MD5 authentication database exists, then plaintext password authentication (e.g. the LOGIN command) will also use the CRAM-MD5 passwords instead of UNIX passwords. Alternatively, it is possible to build the IMAP toolkit so that plaintext password authentication is disabled entirely, by using PASSWDTYPE=nul, e.g. make aix PASSWDTYPE=nul The CRAM-MD5 authentication database file consists of a series of text lines, consisting of a UNIX user name, a single tab, and the password. A line starting with a "#" character is ignored, as are any lines which are not in valid format. For example: ------------------------------Sample------------------------------ # CRAM-MD5 authentication database # Entries are in form # Lines starting with "#" are comments bill hubba-hubba hillary nysenator monica beret tripp wired kenstarr inquisitor reno waco jessie thebody billgates ruleworld ------------------------------Sample------------------------------ Every entry in the CRAM-MD5 authentication database must have a corresponding entry in the /etc/passwd file. It is STRONGLY RECOMMENDED that the CRAM-MD5 password NOT be the same as the /etc/passwd password. It is permitted for the /etc/passwd password to be disabled; /etc/passwd is just used to get the UID, GID, and home directory information. alpine-2.10+dfsg/imap/docs/RELNOTES0000600000175000017500000010231011512502125020366 0ustar paulproteuspaulproteus/* ======================================================================== * Copyright 1988-2008 University of Washington * * Licensed under the Apache License, Version 2.0 (the "License"); * you may not use this file except in compliance with the License. * You may obtain a copy of the License at * * http://www.apache.org/licenses/LICENSE-2.0 * * * ======================================================================== */ Updated: 16 December 2008 imap-2007e is a maintenance release, consisting primarily of bugfixes to problems discovered in the release that affected a small number of users plus a security fix for users of the RFC822BUFFER routines. Updated: 29 October 2008 imap-2007d is a maintenance release, consisting primarily of bugfixes to problems discovered in the release that affected a small number of users plus a security fix for users of tmail or dmail. Updated: 25 March 2008 imap-2007b is a maintenance release, consisting primarily of bugfixes to problems discovered in the release that affected a small number of users. Updated: 2 January 2008 imap-2007a is a maintenance release, consisting primarily of bugfixes to problems discovered in the release that affected a small number of users. Updated: 20 December 2007 imap-2007 is a release corresponding with the release of Alpine 1.0. The primary focus of the imap-2007 release is bugfixes and reliability improvements. This includes: . fixes to problems discovered between the Alpine 0.99999 pre-release and Alpine 1.0 . fixes to the mix driver to timing race problems uncovered by Timo Sirainen's imaptest suite. imap-2007 using the mix format is believed to pass imaptest completely. A new function, utf8_csvalidmap(), has been added for the benefit of Alpine to use in examining UTF-8 text and determining efficiently whether it can be downgraded to a legacy charset. If you develop an MUA, this may be useful for you too, although you'll have to read the source code to see how to use it. The purpose of the "not-CJK" bit is to prevent messages being downgraded to a CJK charset if all they have in that charset are some special punctuation. Updated: 5 September 2007 imap-2006k is a maintenance release, consisting primarily of bugfixes to problems discovered in the release that affected a small number of users. The primary focus of this maintenance release is to correct deadlock issues. There were two major causes of the deadlocks: . a change in imap-2006i attempted to resolve a glibc mutex-based deadlock in imapd's signal handler, but ended up worsening the problem. . a bug in the mbx driver, introduced as part of the UIDPLUS work in 2006, applied an mbx-style lock briefly on a traditional UNIX format mailbox. If the traditional UNIX format mailbox was already locked by some other process, the result would be a deadlock of both processes. imapd's signal handling logic is rewritten to avoid the mutex issue, and the mbx driver is fixed so that mbx-style locks are only applied to mbx format mailboxes. imapd now supports the WITHIN extension. Updated: 14 June 2007 imap-2006j is a maintenance release, consisting primarily of bugfixes to problems discovered in the release that affected a small number of users. Updated: 5 June 2007 imap-2006i is a maintenance release, consisting primarily of bugfixes to problems discovered in the release that affected a small number of users. imapd now supports the CHILDREN and ESEARCH extensions. imapd's attempt to return COPYUID/APPENDUID information for a traditional UNIX (and MMDF) format mailbox when the mailbox is open by another process has been declared to be a failure and is now revoked. It was subject to a timing race, loss of which involved an expensive reset of the mailbox's UID regime. Any imapd COPY or APPEND to a traditional UNIX or MMDF format that is open by some other process will now no longer return COPYUID/APPEND. Although this is technically in violation of RFC 4315, there is a loophole in that document and the timing race/performance problem is worse. Updated: 4 April 2007 imap-2006h is a maintenance release, consisting primarily of bugfixes to problems discovered in the release that affected a small number of users. Updated: 30 March 2007 imap-2006g is a maintenance release, consisting primarily of bugfixes to problems discovered in the release that affected a small number of users. Updated: 30 January 2007 imap-2006f is a maintenance release, consisting primarily of bugfixes to problems discovered in the release that affected a small number of users. For the benefit of multi-threaded applications, use of strtok() has been abolished in the c-client library. imapd and ipop3d stuff use it though. The TOPS-20 and VAX/VMS ports still use strtok() since they don't use UNIX threads. This version has been test-built on Linux, Mac OS X, NeXT, Windows XP, TOPS-20, and VAX/VMS. This will probably be the last test-build on VAX/VMS since the system I use for that purpose is being shut down. I have no way to test-build on DOS, legacy Mac OS (OS 9 and earlier), OS/2, or Windows CE; and the builds on those systems are probably broken. Updated: 26 January 2007 imap-2006e is a maintenance release, consisting primarily of bugfixes to problems discovered in the release that affected a small number of users. Updated: 6 December 2006 imap-2006d is a maintenance release, consisting primarily of bugfixes to problems discovered in the release that affected a small number of users. The decomposition mapping, title-case mapping, and character widths tables have been updated to comply with the Unicode 5.0 standard. Prototypes for the utf8aux.c functions have been moved to a new utf8aux.h. The general c-client modules now include c-client.h instead of the individual files. Use of c-client.h instead of individual include files insulates against future shuffling of include files. Updated: 23 October 2006 imap-2006c is a maintenance release, consisting primarily of bugfixes to problems discovered in the release that affected a small number of users. By popular request, if a user has a mix (or other dual-use) format INBOX, it will no longer be listed as \NoInferiors. It's a bad idea to depend upon this due to the case ambiguity issue, but it's there. Updated: 26 September 2006 imap-2006b is a maintenance release, consisting entirely of bugfixes to problems discovered in the release that affected a small number of users. Updated: 15 September 2006 imap-2006a is a maintenance release, consisting entirely of bugfixes to problems discovered in the release that affected a small number of users. If it is necessary to build IPv4-only on one of the ports that has IPv6 preconfigured (ldb, lfd, lmd, lrh, lsu, osx, oxp), this can be done by using IP6=4. You can't do IP=4 in the build command directly since these ports set IP themselves; however, now instead of setting IP=6 they now set IP=$(IP6). Updated: 30 August 2006 imap-2006 is a major release. Programs written for imap-2004g should build with this version with minor or no modification. imap-2005 was not released except as development snapshots. imap-2006 contains major extensions to its Unicode support. Searching and sorting are now done with strings canonicalized to titlecase and decomposed form. Among other things, this means that Latin letters with diacriticals will now sort with the basic Latin letter, and case-independent searching of such letters (e.g., German umlauts) now works. Previously, sorting was done strictly by Unicode codepoint, and case-independence only worked with ASCII. imapd now supports the UIDPLUS extension for mailboxes in unix, mmdf, mbx, mx, and mix formats. UID EXPUNGE is fully implemented. Note that UIDPLUS is not supported in the little-used drivers (mh, mtx, tenex) in which meaningful APPENDUID/COPYUID data can not be returned. Refer to bugs.txt for more details. The new mix format is a dual-use mailbox format designed for performance and reliability with large mailboxes. mix is documented in file mixfmt.txt. SSL/TLS certificate validation on UNIX now checks the alternative names in the certificate if the CN does not match. The new /tls-sslv23 flag in a mailbox name causes a TLS session to use the (incorrect) SSLv23 client method instead of the TLSv1 client method. Some broken servers use the SSLv23 server method, and this flag works around that problem. WARNING: use of this flag will cause TLS negotiation to fail with a server which uses the proper TLSv1 server method. Additionally, there are known security risks in SSLv2; so users should be suspicious if this switch suddenly becomes necesary. The silly mailbox flag combination /ssl/tls is now rejected as an invalid remote specification. Previous versions tried to negotiate TLS over an SSL session; even if the server permitted such a thing it couldn't work. The memory management of several drivers has been redesigned to consume less memory and hopefully be faster. The private.data member of the MESSAGECACHE (elt) has been replaced with a union that contains private.spare.data and private.spare.ptr, the latter being a pointer. A new FT_RETURNSTRINGSTRUCT flag has been added for mail_fetch_body() and mail_fetch_text() calls. If this flag is set, *and* if the function returns NIL, then the requested string data is available on a stringstruct on stream->private.string. This is a special hack for the IMAP and POP servers and is subject to incompatible change. The result is a major performance improvement in the servers with the mbx driver, particularly with large messages. Updated: 15 September 2005 imap-2004g is a maintenance release, and consists solely of a bugfix to quoted string handling in the mailbox name parsing routine. Updated: 15 August 2005 imap-2004f is a maintenance release, and consists solely of a bugfix to the TCP code. Also included is a new version of the UNIX SSL/TLS routines that allows the SSL/TLS certificate validation client code to validate alternative names in server certificates. This code has not been thoroughly regression-tested but is believed to work. To use this new code instead of the old support: cd imap-2004f/src/osdep/unix mv ssl_unix.c ssl_unix.old mv ssl_unix.new ssl_unix.c Then rebuild. Updated: 21 June 2005 imap-2004e is a maintenance release, consisting entirely of bugfixes. There are no user-visible functional enhancements in this version. Updated: 20 April 2005 imap-2004d is a maintenance release, released concurrently with Pine 4.63, and consists primarily of bugfixes There is now a workaround for RedHat breaking flock(). However, since RedHat has said that they don't support flock(), there is no guarantee that they won't break it in the future. So you may want to consider some other Linux distribution or BSD instead. See: https://bugzilla.redhat.com/bugzilla/show_bug.cgi?id=123415 for the gruesome details. There are no user-visible functional enhancements in this version. Updated: 18 January 2005 imap-2004c is a maintenance release, released concurrently with Pine 4.62, including fixes to quoted-printable encoding and CRAM-MD5 authentication. NNTP proxy in imapd now supports the LIST and LSUB commands. There are no other user-visible functional enhancements in this version. Updated: 29 November 2004 imap-2004b is a maintenance release, consisting primarily of bugfixes. Programs written for imap-2004a will build with this version without modifification. There are new ports for Solaris with Blastwave Community Open Source Software (gcs) and Mandrake Linux (lmd). SET_SNARFINTERVAL now controls how frequently local drivers will move new mail from the mail spool as well as from a maildrop. Maildrops are still tied to a minimum interval of 1 minute, but there is now no minimum for the spool file. Character set conversions now map non-breaking space to space if the destination character set doesn't have nbsp. JIS Roman yen sign is now mapped to Unicode yen sign. There are no user-visible functional enhancements in this version. Updated: 8 July 2004 imap-2004a is a maintenance release, consisting primarily of critical bugfixes. Programs written for imap-2004 will build with this version without modification. imapd now has a supported NNTP proxy capability. If the file /etc/imapd.nntp exists, the contents of that file are used as the host name of an NNTP server which will be used whenever a #news. name is used. For example, if /etc/imapd.nntp contains nntp.example.com, and the IMAP client SELECTs or EXAMINEs the name #news.comp.mail.imap, what will actually be opened in imapd is {nntp.example.com/nntp}comp.mail.imap The OSF/1 port (Digital UNIX, Tru64) now uses flocksim instead of flcksafe. Some cretin decided to delete the winning flock() call and make flock() use the losing fcntl() call instead. The unix[nt] and mmdf drivers now prevent mail_append() from writing Status:, X-Status:, X-UID, X-IMAP[base]:, and X-Keywords: header lines to a traditional UNIX or MMDF format mailbox. If any such lines are in the text supplied to mail_append(), they will be quoted by prefixing with "X-Original-" (e.g. Status: will become X-Original-Status:). There are no user-visible functional enhancements in this version. Updated: 10 May 2004 imap-2004 is a major release. Programs written for imap-2002e should build with this version with minor modification. imap-2003 was not released except as development snapshots. mailutil has three new commands: delete, rename, and prune. IPv6 support now exists for UNIX and W2K. It is the default in W2K builds. On UNIX, add "IP=6" to the make command line. Windows IPv6 support is only for W2K builds. The NNTP driver now supports NNTP SASL and TLS. The ldb (Debian) and lrh (RedHat) ports now look for mlock on /usr/sbin/mlock instead of /etc/mlock. imapd now supports the LITERAL+ and SASL-IR initial-response extensions. The IMAP driver has some additional checks to reduce the amount of network traffic, including executing "silly searches" (searches of sequence numbers only) locally. The IMAP, POP, SMTP, and NNTP drivers now have diagnostic code to provide better information about servers which violate SASL's empty challenge requirements (e.g. with the PLAIN mechanism). There is a new mail_fetch_overview_sequence() function which is like mail_fetch_overview() but takes a sequence number string as an argument. There should have been a flags argument and FT_UID bit as in all the other mail_fetch_???() functions but compatibility with the past... :-( The overview_t callback (from mail_fetch_overview()) now has a fourth argument which contains the message sequence number (as opposed to the UID which is in the second argument). It turned out that some applications were calling mail_msgno() (which can be moderately expensive) to get the sequence number, and c-client already knew it. Many declarations which are completely internal to a driver have been removed from the driver .h file, and in those cases where there are no external declarations left the .h file has been eliminated entirely. As part of this, the mbox driver routines are now incorporated with the unix driver routines as opposed to being a separate file. The mbox driver still needs to be lunk in order to get the mbox functionality. Updated: 27 August 2003 imap-2002e is a minor release, released concurrently with Pine 4.58, and contains primarily bugfixes. Programs written for imap-2002d will build with this version without modification. The NNTP client code now tries to perform better with legacy NNTP servers which do not comply with the current NNTP protocol specification draft, most notably Netscape Collabra. Delivery notifications now work reliably with SMTP servers that support it. The following changes are primarily of concern to developers and power users: There is a "limited advertise" option in env_unix.c which, if set, will only advertise the user's own namespace and the #shared/ namespace. It is now possible to build the IMAP toolkit with a separate SSL KEY file from the certificate file (SSLKEYS vs. SSLCERTS). A new BODY structure element, sparep, is available for the main program to use as a pointer for its own purposes; as well as a SET_FREEBODYSPAREP function, similar to SET_FREEENVELOPESPAREP, SET_FREEELTSPAREP, etc. Updated: 28 May 2003 imap-2002d is a minor release, released concurrently with Pine 4.56, and contains primarily bugfixes. Programs written for imap-2002 should build with this version without modification, with one exception. That exception is the ngbogus envelope flag, which stopped being used in imap-2002c and is now gone for good. The NNTP newsgroup listing code now tries to use wildmats on the NNTP server, which should result in better performance especially on slow lines. It is also once again permitted to log in on NNTP servers when /loser is set. imapd now supports the UNSELECT command. A new envelope flag, imapenvonly, indicates that the envelope in a MESSAGE/RFC822 BODY structure only has the IMAP envelope components and not the additional components from c-client: Newsgroups, Followup-To, and References. Updated: 7 April 2003 imap-2002c is a minor release, released concurrently with Pine 4.55, and contains primarily bugfixes. Programs written for imap-2002 will build with this version without modification. The POP3 driver will, with new servers that support CAPA, use the LIST command to get the elt->rfc822_size and the TOP command to get the message header, instead of fetching the entire message. Note that it is a bad idea to do this with old servers, since they may misimplement LIST and TOP. The result is a substantial performance improvement. Subject extraction for comparisons in SORT and THREAD are now done in full compliance with the rules laid out in the specification. This only makes a difference if "re:" was part of a MIME quoted-word. The new experimental #move namespace allows download-and-delete from a source mailbox to a destination mailbox. Immediately following #move is a delimiter character which must not appear in the source mailbox name, then the source mailbox name, then the delimiter again, then the destination mailbox name. For example: #move+{pop3.foo.com/pop3}+INBOX will download messages from "pop3.foo.com" into your local INBOX. The NNTP driver now uses the LIST EXTENSIONS command as described in the current NNTP protocol specification draft, and will prefer to use OVER over XOVER, HDR over XHDR, etc. The SET_NNTPRANGE function of mail_parameters() can be used to limit the number of articles recognized by the NNTP driver, resulting in a substantial performance improvement with NNTP servers that may have hundreds of thousands of old articles in the spool. If set non-zero, then only the last n article numbers will be considered. If you are on a slow link, you may want to set this to 1000 or less. Besides the normally tested UNIX and 32-bit Microsoft platforms, this release has also been tested and will once build under TOPS-20 and VAX/VMS. I also fixed a bug which would keep it from building on 16-bit DOS, but I don't know if it will build on that platform or not since I no longer have a system with the old DOS C compiler. It has not been tested on Macintosh (note however that Mac OS X is a type of UNIX and should build), Amiga, or OS/2, and probably no longer builds on those platforms. Updated: 7 January 2003 imap-2002b is a maintenace release, released concurrently with Pine 4.52, and contains only bugfixes. Programs written for imap-2002 will build with this version without modification. Drivers which do not announce new mail are now indicated by the DR_NONEWMAIL driver flag. Driver which do not announce new mail when read-only are now indicated by the DR_NONEWMAILRONLY flag. There are no user-visible functional enhancements in this version. Updated: 10 December 2002 imap-2002a is a maintenance release, consisting entirely of critical bugfixes. Programs written for imap-2002 will build with this version without modification. There are no functional enhancements in this version. Updated: 28 October 2002 imap-2002 is a major release. Programs written for imap-2001 will probably build with this version without modification, with one exception. That exception is if the program uses [GS]ET_DISABLEAUTOMATICSHAREDNAMESPACES, which has been renamed to [GS]ET_DISABLEAUTOSHAREDNS in order to placate some compilers which don't like very long names. SSLTYPE=nopwd is now the default, in accordance with current IESG security requirements. In order to build the IMAP toolkit without SSL/TLS you must now use SSLTYPE=none. At initial build time, you will be told if the SSLTYPE setting is in compliance with IESG security requirements, and if it is not you will be asked to confirm to continue the build. ORDEREDSUBJECT threading has been changed in accordance with draft 12 of the IMAP threading specification. Previously, each non-root message in an ORDEREDSUBJECT thread has been a child of the message immediately preceeding it in the thread. Draft 12 changes this so that the second message in the thread is the child of the first (root) message, and all subsequent messages are siblings of the first message. This is significant in MUAs which display the thread structure graphically; the new definition is much saner than the old one since it does not nest endlessly due to parent/child relationships that may not exist. This also impacts imapd, since imapd's THREAD command will return a thread structure. RFC 1730 server support, which was disabled in imap-2001, is now fully removed from imapd. imapd still supports IMAP2bis, specifically the FIND command, since there are still a few IMAP2 clients out there. The IMAP client routines in the c-client library continue to support recognize RFC 1730 servers, but do not implement the deprecated features of RFC 1730. The Frequently Asked Questions file is now in HTML format, although a text version (generated from the HTML version with Lynx) is also provided. A new program, mailutil, is now bundled with the IMAP toolkit. mailutil replaces the old chkmail, imapcopy, imapmove, imapxfer, mbxcopy, mbxcreat, and mbxcvt programs that were distributed in the imap-utils. In addition, the tmail, dmail, and mlock programs from the imap-utils are now also bundled with the IMAP toolkit. In addition to the usual bugfixes, the following c-client functionalities are new in imap-2002: The SET_DISABLE822TZTEXT parameter allows a client to suppress generation of the "human friendly" time zone text in RFC822 dates. This placates netnews and some broken SMTP servers which think that long timezone names from Windows are an attempt at a buffer overflow attack. The restrictBox option in env_unix.c sets "restricted box" functionality, which disables access to the root (leading "/"), access to other user's directories (leading "~"), and access to superior directories via "..". Content-Location is now supported by the "location" member of the BODY structure. Note that there is a bug in the IMAP client code in older versions of the c-client library that causes it to handle BODYSTRUCTURE extension data improperly if that data is a literal. The new functionality for Content-Location may trigger this bug. The fix is either to upgrade the IMAP client program to the imap-2002 version of c-client or to remove the Content-Location support from imapd. There are now 8 spare bits for application use in both the elts and the mail streams. mail_search() now returns a value (previously it was void). If mail_search() returns NIL, then the supplied charset was invalid or the IMAP server returned NO (probably because the supplied charset was invalid). New utf8_charset() routine to look up a charset and return c-client's database about that charset if found. Among other things, this will give you the scripts supported by that charset and its Unicode conversion table. New FT_NOLOOKAHEAD flag for mail_fetch_structure() disables fetching of any envelopes other than the one specified. Otherwise, it will try to do anticipatory fetching (up to IMAPLOOKAHEAD). New GET_FETCHLOOKAHEAD allows better control of mail_fetch_structure() lookahead. Instead of looking IMAPLOOKAHEAD messages forward from the specified message, it will use a supplied SEARCHSET to generate message sequences and ranges. It will stop at IMAPLOOKAHEAD messages or at the completion of a range which exceeds IMAPLOOKAHEAD. The search set only applies to the next mail_fetch_structure() on that stream, and is cleared once it is used. Call with SEARCHSET **set = (SEARCHSET **) mail_parameters (stream,GET_FETCHLOOKAHEAD,(void *) stream); *set = pointer to desired search set New mail_shortdate() routine returns an date in the format expected by SEARCHPGMs. Updated: 2 November 2001 imap-2001a is a maintenance release, consisting primarily of bugfixes including some critical bugfixes to crash and denial of service problems. Programs written for imap-2001 will build with this version without modification. The following new facilities have also been added: The new /norsh switch in mailbox names provides a more intuitive way of disabling rsh-IMAP than the existing :143 or setting the rsh-timeout to 0. Passwords are no longer returned in mm_dlog() callbacks unless the application sets the SET_DEBUGSENSITIVE parameter. The SET_NETFSSTATBUG parameter allows an application to force the traditional UNIX mailbox driver to close and reopen the mailbox at ping time. This is EXTREMELY inefficient, and should only be used to access files stored on AFS and old NFS systems. The ISO 8859 and Windows conversion tables have been updated to comply with Unicode 3.1, and the KOI8-R table has been verified as compliant with Unicode 3.1. The SPECIALS mechanism for passing parameters to the lowest level Makefile has been updated to be more general. See the next item for why you might care. New lrh port to build on Red Hat Linux 7.2, with pre-set definitions for the places where Red Hat has placed Kerberos and SSL. It's actually just the lnp port with SPECIALS defined accordingly. You may want to use it as a model if your system needs such definitions. Note that SPECIALS is primarily for IMAP toolkit (and Pine) purposes, and that user settings should use EXTRASPECIALS instead. Updated: 22 June 2001 imap-2001 is a major release. Programs written for imap-2000 will probably build with this version without modification. The FAQ document has been significantly expanded. Be sure to read it for more information. In addition to the usual bugfixes, the following features are new in imap-2001: SSL is now fully integrated into the IMAP toolkit; the old "alt" kludges to be able to produce a "sanitized" version of the IMAP toolkit to comply with late unlamented US export regulations are now completely gone. Full client and server TLS support is also in this release. The server certificate must be signed by a trusted certificate authority and the name in the certificate match the user's entry for the server host name; this means that the user must enter a fully-qualified host name. To build with SSL/TLS on UNIX, you now use "SSLTYPE=unix" instead of the former "SPECIALAUTHENTICATORS=ssl". To build with SSL/TLS on UNIX and disable the use of plaintext passwords except when under SSL/TLS, use "SSLTYPE=nopwd" instead of "SSLTYPE=unix". RFC 1730 (IMAP4 as opposed to IMAP4rev1) support is turned off by default in imapd. No clients should still be using RFC 1730 protocol. Look at the imapd Makefile for how to re-enable RFC 1730 support. Note that this code may be removed in the future, so if you think you need it you had better let me know. There are some new options (turned off by default) which attempt to work around problems in certain clients. See the FAQ file for more details. Updated: 24 January 2001 imap-2000c is a maintenance release, consisting primarily of bugfixes. Updated: 9 January 2001 imap-2000b is a maintenance release, consisting primarily of bugfixes. Updated: 9 November 2000 imap-2000a is a maintenance release, consisting primarily of bugfixes. Updated: 19 September 2000 imap-2000 is a major release. There are major internal and external changes from earlier versions (imap-4.x and imap-3.x series). Programs written for imap-4.x will probably build with this version without modification. It is extremely unlikely that a program written for imap-3.x or earlier series will build with this version without modifications. Drivers written for earlier versions will definitely need to be rewritten. In addition to the usual bugfixes, the following features are new in imap-2000: SSL support is now available. For UNIX, it is necessary to install some version of OpenSSL; see imap-2000/docs/SSLBUILD for more information. SSL support is now automatic for the NT, NTK, and W2K ports. SSL use is indicated by the /ssl switch in the mailbox name. With SSL connections, the server certificate is validated by the client code on UNIX, and Windows 2000 unless /novalidate-cert is specified. Server certificates are currently is not validated on Windows 9x, Windows Millenium, or Windows NT 4; this is an artifact of the operating system and not the port (e.g. client code using the NT port will validate certificates if running on Windows 2000). On UNIX, the server certificate must be signed by a trusted certificate authority. On Windows 2000, the certificate must be signed by a trusted certificate authority and match the user's entry for the server host name; this means that the user must enter a fully-qualified host name. Calendar reclama for the benefit of old broken non-Y2K compliant software. Two digit years from 00 to 69 will be interpreted as 2000 through 2069. In addition, three digit years from 100 to 105 will be interpreted as 2000 through 2005. Support for REFERENCES threading (in addition to the previously-existing ORDEREDSUBJECT threading). Support for the IMAP MULTIAPPEND extension. This allows much faster uploading of multiple messages to an IMAP server. Support for the LOGINDISABLED IMAP capability. If the IMAP server sends LOGINDISABLED as a capability, the client code will never attempt to send an IMAP LOGIN command. Support for SASL authentication identity vs. authorization identity. If the authentication method does not support this concept (e.g. AUTH=CRAM-MD5, AUTH=LOGIN, LOGIN command), the "*" character in the user name may be used to indicate a separate authentication identity; for example, "fred*joe" indicates authorization identity "fred", authentication identity "joe". UNIX-specific Changes: Support for SASL authentication identity vs. authorization identity in the IMAP and POP3 servers. If the user indicated by the authentication identity is in the "mailadm" group, he may specify any authorization identity and get logged in as the authorization identity user. If the IMAP and POP3 servers are build with PASSWDTYPE=nul, it will send LOGINDISABLED as a capability and also disable the AUTH=LOGIN and AUTH=PLAIN SASL authenticators. New MAILSUBDIR build option to change the default mailbox directory from the user's home directory to a subdirectory of the user's home directory. See imap-2000/Makefile for more information. New CHROOT_SERVER build option for closed server systems only. If defined, a chroot() call to the user's home directory is done as part of the login process. See imap-2000/Makefile for more information. New ADVERTISE_THE_WORLD build option which will add an IMAP namespace that points to the root. Not for the faint of heart. UNIX format mailboxes no longer require the pseudo-message, nor will a pseudo-message be added to a mailbox that does not have one. A new X-IMAPbase: header will be written in the first message. This is rather less efficient and robust than the pseudo-message (which remains the encouraged mechanism; UNIX format mailboxes will always be created with it), but perhaps will pacify some people who get upset by the pseudo-message. When building with MIT Kerberos it will try to detect and use libk5crypto.a instead of libcrypto.a. The mbx driver is more aggressive about cleaning up expunged messages that couldn't be purged because of shared access to the mailbox at the time of expunge. Now, every checkpoint will try to purge such messages; and a checkpoint is attempted at close time. Windows-specific Changes: New W2K port for Windows 2000. In addition to supporting SSL using the official SSPI interface (the NT and NTK ports invoke SChannel.DLL directly), the W2K port also supports Microsoft Kerberos. Note that the NT and NTK ports will work on Windows 2000, but the W2K port will not work on NT4, Windows 9x, or Windows Millenium. There is now a #user namespace, equivalent to the "~" namespace on UNIX. Changes for Developers: New c-client.h file which acts as a master include. c-client based applications should now include c-client.h instead of the individual c-client files (mail.h, misc.h, etc.). It is believed that c-client.h will work in C++ applications. New GET_FREEENVELOPESPAREP/SET_FREEENVELOPESPAREP and GET_FREEELTSPAREP/SET_FREEELTSPAREP function callbacks to free the "sparep" member of the envelope and cache elements, respectively. New OP_MULNEWSRC flag to mail_open() to use multiple newsrc files, and new GET_NEWSRCQUERY/SET_NEWSRCQUERY function callbacks to get the name of the newsrc file for news access. New "secret" nntp_article() function to do the NNTP ARTICLE command; this is generally useful only when chasing news URLs. New GET_HIDEDOTFILES/SET_HIDEDOTFILES feature to suppress file names that start with "." in mail_list() results. alpine-2.10+dfsg/imap/docs/draft/0000700000175000017500000000000011512502151020310 5ustar paulproteuspaulproteusalpine-2.10+dfsg/imap/docs/draft/README0000600000175000017500000000126411512502124021175 0ustar paulproteuspaulproteusLast Updated: 6 March 2008 This directory contains Internet Drafts which, at the time of release of this software, were not yet been published as RFCs. These documents are expected to be released as RFCs in the near future. This software adheres to the specification in these documents, which are included for informational purposes. Note, however, that these documents must be considered preliminary in nature and will be superceded by the successor RFC. File Name I-D Name --------- -------- sort.txt draft-ietf-imapext-sort-20.txt ;; SORT and THREAD commands ;; Status: approved, blocked waiting for i18n i18n.txt draft-ietf-imapext-i18n-15.txt ;; internationalization in IMAP alpine-2.10+dfsg/imap/docs/draft/sort.txt0000600000175000017500000011225211512502124022045 0ustar paulproteuspaulproteusIMAP Extensions Working Group M. Crispin Internet-Draft K. Murchison Intended status: Proposed Standard March 10, 2008 Expires: September 10, 2008 Document: internet-drafts/draft-ietf-imapext-sort-20.txt INTERNET MESSAGE ACCESS PROTOCOL - SORT AND THREAD EXTENSIONS Status of this Memo By submitting this Internet-Draft, each author represents that any applicable patent or other IPR claims of which he or she is aware have been or will be disclosed, and any of which he or she becomes aware will be disclosed, in accordance with Section 6 of BCP 79. Internet-Drafts are working documents of the Internet Engineering Task Force (IETF), its areas, and its working groups. Note that other groups may also distribute working documents as Internet-Drafts. Internet-Drafts are draft documents valid for a maximum of six months and may be updated, replaced, or obsoleted by other documents at any time. It is inappropriate to use Internet-Drafts as reference material or to cite them other than as "work in progress." The list of current Internet-Drafts can be accessed at http://www.ietf.org/ietf/1id-abstracts.txt The list of Internet-Draft Shadow Directories can be accessed at http://www.ietf.org/shadow.html. A revised version of this draft document will be submitted to the RFC editor as a Proposed Standard for the Internet Community. Discussion and suggestions for improvement are requested, and should be sent to ietf-imapext@IMC.ORG. Distribution of this memo is unlimited. Abstract This document describes the base-level server-based sorting and threading extensions to the [IMAP] protocol. These extensions provide substantial performance improvements for IMAP clients which offer sorted and threaded views. 1. Introduction The SORT and THREAD extensions to the [IMAP] protocol provide a means of server-based sorting and threading of messages, without requiring that the client download the necessary data to do so itself. This is particularly useful for online clients as described in [IMAP-MODELS]. A server which supports the base-level SORT extension indicates this with a capability name which starts with "SORT". Future, upwards-compatible extensions to the SORT extension will all start with "SORT", indicating support for this base level. A server which supports the THREAD extension indicates this with one or more capability names consisting of "THREAD=" followed by a supported threading algorithm name as described in this document. This provides for future upwards-compatible extensions. A server which implements the SORT and/or THREAD extensions MUST collate strings in accordance with the requirements of I18NLEVEL=1, as described in [IMAP-I18N], and SHOULD implement and advertise the I18NLEVEL=1 extension. Alternatively, a server MAY implement I18NLEVEL=2 (or higher) and comply with the rules of that level. Discussion: the SORT and THREAD extensions predate [IMAP-I18N] by several years. At the time of this writing, all known server implementations of SORT and THREAD comply with the rules of I18NLEVEL=1, but do not necessarily advertise it. As discussed in [IMAP-I18N] section 4.5, all server implementations should eventually be updated to comply with the I18NLEVEL=2 extension. Historical note: the REFERENCES threading algorithm is based on the [THREADING] algorithm written used in "Netscape Mail and News" versions 2.0 through 3.0. 2. Terminology The key words "MUST", "MUST NOT", "REQUIRED", "SHALL", "SHALL NOT", "SHOULD", "SHOULD NOT", "RECOMMENDED", "MAY", and "OPTIONAL" in this document are to be interpreted as described in [KEYWORDS]. The word "can" (not "may") is used to refer to a possible circumstance or situation, as opposed to an optional facility of the protocol. "User" is used to refer to a human user, whereas "client" refers to the software being run by the user. In examples, "C:" and "S:" indicate lines sent by the client and server respectively. 2.1 Base Subject Subject sorting and threading use the "base subject," which has specific subject artifacts removed. Due to the complexity of these artifacts, the formal syntax for the subject extraction rules is ambiguous. The following procedure is followed to determine the "base subject", using the [ABNF] formal syntax rules described in section 5: (1) Convert any RFC 2047 encoded-words in the subject to UTF-8 as described in "internationalization considerations." Convert all tabs and continuations to space. Convert all multiple spaces to a single space. (2) Remove all trailing text of the subject that matches the subj-trailer ABNF, repeat until no more matches are possible. (3) Remove all prefix text of the subject that matches the subj-leader ABNF. (4) If there is prefix text of the subject that matches the subj-blob ABNF, and removing that prefix leaves a non-empty subj-base, then remove the prefix text. (5) Repeat (3) and (4) until no matches remain. Note: it is possible to defer step (2) until step (6), but this requires checking for subj-trailer in step (4). (6) If the resulting text begins with the subj-fwd-hdr ABNF and ends with the subj-fwd-trl ABNF, remove the subj-fwd-hdr and subj-fwd-trl and repeat from step (2). (7) The resulting text is the "base subject" used in the SORT. All servers and disconnected (as described in [IMAP-MODELS]) clients MUST use exactly this algorithm to determine the "base subject". Otherwise there is potential for a user to get inconsistent results based on whether they are running in connected or disconnected mode. 2.2 Sent Date As used in this document, the term "sent date" refers to the date and time from the Date: header, adjusted by time zone to normalize to UTC. For example, "31 Dec 2000 16:01:33 -0800" is equivalent to the UTC date and time of "1 Jan 2001 00:01:33 +0000". If the time zone is invalid, the date and time SHOULD be treated as UTC. If the time is also invalid, the time SHOULD be treated as 00:00:00. If there is no valid date or time, the date and time SHOULD be treated as 00:00:00 on the earliest possible date. This differs from the date-related criteria in the SEARCH command (described in [IMAP] section 6.4.4), which use just the date and not the time, and are not adjusted by time zone. If the sent date can not be determined (a Date: header is missing or can not be parsed), the INTERNALDATE for that message is used as the sent date. When comparing two sent dates that match exactly, the order in which the two messages appear in the mailbox (that is, by sequence number) is used as a tie-breaker to determine the order. 3. Additional Commands These commands are extension to the [IMAP] base protocol. The section headings are intended to correspond with where they would be located in the main document if they were part of the base specification. BASE.6.4.SORT. SORT Command Arguments: sort program charset specification searching criteria (one or more) Data: untagged responses: SORT Result: OK - sort completed NO - sort error: can't sort that charset or criteria BAD - command unknown or arguments invalid The SORT command is a variant of SEARCH with sorting semantics for the results. Sort has two arguments before the searching criteria argument; a parenthesized list of sort criteria, and the searching charset. The charset argument is mandatory (unlike SEARCH) and indicates the [CHARSET] of the strings that appear in the searching criteria. The US-ASCII and UTF-8 charsets MUST be implemented. All other charsets are optional. There is also a UID SORT command which returns unique identifiers instead of message sequence numbers. Note that there are separate searching criteria for message sequence numbers and UIDs; thus the arguments to UID SORT are interpreted the same as in SORT. This is analogous to the behavior of UID SEARCH, as opposed to UID COPY, UID FETCH, or UID STORE. The SORT command first searches the mailbox for messages that match the given searching criteria using the charset argument for the interpretation of strings in the searching criteria. It then returns the matching messages in an untagged SORT response, sorted according to one or more sort criteria. Sorting is in ascending order. Earlier dates sort before later dates; smaller sizes sort before larger sizes; and strings are sorted according to ascending values established by their collation algorithm (see under "Internationalization Considerations"). If two or more messages exactly match according to the sorting criteria, these messages are sorted according to the order in which they appear in the mailbox. In other words, there is an implicit sort criterion of "sequence number". When multiple sort criteria are specified, the result is sorted in the priority order that the criteria appear. For example, (SUBJECT DATE) will sort messages in order by their base subject text; and for messages with the same base subject text will sort by their sent date. Untagged EXPUNGE responses are not permitted while the server is responding to a SORT command, but are permitted during a UID SORT command. The defined sort criteria are as follows. Refer to the Formal Syntax section for the precise syntactic definitions of the arguments. If the associated RFC-822 header for a particular criterion is absent, it is treated as the empty string. The empty string always collates before non-empty strings. ARRIVAL Internal date and time of the message. This differs from the ON criteria in SEARCH, which uses just the internal date. CC [IMAP] addr-mailbox of the first "cc" address. DATE Sent date and time, as described in section 2.2. FROM [IMAP] addr-mailbox of the first "From" address. REVERSE Followed by another sort criterion, has the effect of that criterion but in reverse (descending) order. Note: REVERSE only reverses a single criterion, and does not affect the implicit "sequence number" sort criterion if all other criteria are identicial. Consequently, a sort of REVERSE SUBJECT is not the same as a reverse ordering of a SUBJECT sort. This can be avoided by use of additional criteria, e.g. SUBJECT DATE vs. REVERSE SUBJECT REVERSE DATE. In general, however, it's better (and faster, if the client has a "reverse current ordering" command) to reverse the results in the client instead of issuing a new SORT. SIZE Size of the message in octets. SUBJECT Base subject text. TO [IMAP] addr-mailbox of the first "To" address. Example: C: A282 SORT (SUBJECT) UTF-8 SINCE 1-Feb-1994 S: * SORT 2 84 882 S: A282 OK SORT completed C: A283 SORT (SUBJECT REVERSE DATE) UTF-8 ALL S: * SORT 5 3 4 1 2 S: A283 OK SORT completed C: A284 SORT (SUBJECT) US-ASCII TEXT "not in mailbox" S: * SORT S: A284 OK SORT completed BASE.6.4.THREAD. THREAD Command Arguments: threading algorithm charset specification searching criteria (one or more) Data: untagged responses: THREAD Result: OK - thread completed NO - thread error: can't thread that charset or criteria BAD - command unknown or arguments invalid The THREAD command is a variant of SEARCH with threading semantics for the results. Thread has two arguments before the searching criteria argument; a threading algorithm, and the searching charset. The charset argument is mandatory (unlike SEARCH) and indicates the [CHARSET] of the strings that appear in the searching criteria. The US-ASCII and UTF-8 charsets MUST be implemented. All other charsets are optional. There is also a UID THREAD command which returns unique identifiers instead of message sequence numbers. Note that there are separate searching criteria for message sequence numbers and UIDs; thus the arguments to UID THREAD are interpreted the same as in THREAD. This is analogous to the behavior of UID SEARCH, as opposed to UID COPY, UID FETCH, or UID STORE. The THREAD command first searches the mailbox for messages that match the given searching criteria using the charset argument for the interpretation of strings in the searching criteria. It then returns the matching messages in an untagged THREAD response, threaded according to the specified threading algorithm. All collation is in ascending order. Earlier dates collate before later dates and strings are collated according to ascending values established by their collation algorithm (see under "Internationalization Considerations"). Untagged EXPUNGE responses are not permitted while the server is responding to a THREAD command, but are permitted during a UID THREAD command. The defined threading algorithms are as follows: ORDEREDSUBJECT The ORDEREDSUBJECT threading algorithm is also referred to as "poor man's threading." The searched messages are sorted by base subject and then by the sent date. The messages are then split into separate threads, with each thread containing messages with the same base subject text. Finally, the threads are sorted by the sent date of the first message in the thread. The first message of each thread are siblings of each other (the "root"). The second message of a thread is the child of the first message, and subsequent messages of the thread are siblings of the second message and hence children of the message at the root. Hence, there are no grandchildren in ORDEREDSUBJECT threading. Children in ORDEREDSUBJECT threading do not have descendents. Client implementations SHOULD treat descendents of a child in a server response as being siblings of that child. REFERENCES The REFERENCES threading algorithm threads the searched messages by grouping them together in parent/child relationships based on which messages are replies to others. The parent/child relationships are built using two methods: reconstructing a message's ancestry using the references contained within it; and checking the original (not base) subject of a message to see if it is a reply to (or forward of) another message. Note: "Message ID" in the following description refers to a normalized form of the msg-id in [RFC-2822]. The actual text in an RFC 2822 may use quoting, resulting in multiple ways of expressing the same Message ID. Implementations of the REFERENCES threading algorithm MUST normalize any msg-id in order to avoid false non-matches due to differences in quoting. For example, the msg-id <"01KF8JCEOCBS0045PS"@xxx.yyy.com> and the msg-id <01KF8JCEOCBS0045PS@xxx.yyy.com> MUST be interpreted as being the same Message ID. The references used for reconstructing a message's ancestry are found using the following rules: If a message contains a References header line, then use the Message IDs in the References header line as the references. If a message does not contain a References header line, or the References header line does not contain any valid Message IDs, then use the first (if any) valid Message ID found in the In-Reply-To header line as the only reference (parent) for this message. Note: Although [RFC-2822] permits multiple Message IDs in the In-Reply-To header, in actual practice this discipline has not been followed. For example, In-Reply-To headers have been observed with message addresses after the Message ID, and there are no good heuristics for software to determine the difference. This is not a problem with the References header however. If a message does not contain an In-Reply-To header line, or the In-Reply-To header line does not contain a valid Message ID, then the message does not have any references (NIL). A message is considered to be a reply or forward if the base subject extraction rules, applied to the original subject, remove any of the following: a subj-refwd, a "(fwd)" subj-trailer, or a subj-fwd-hdr and subj-fwd-trl. The REFERENCES algorithm is significantly more complex than ORDEREDSUBJECT and consists of six main steps. These steps are outlined in detail below. (1) For each searched message: (A) Using the Message IDs in the message's references, link the corresponding messages (those whose Message-ID header line contains the given reference Message ID) together as parent/child. Make the first reference the parent of the second (and the second a child of the first), the second the parent of the third (and the third a child of the second), etc. The following rules govern the creation of these links: If a message does not contain a Message-ID header line, or the Message-ID header line does not contain a valid Message ID, then assign a unique Message ID to this message. If two or more messages have the same Message ID, then only use that Message ID in the first (lowest sequence number) message, and assign a unique Message ID to each of the subsequent messages with a duplicate of that Message ID. If no message can be found with a given Message ID, create a dummy message with this ID. Use this dummy message for all subsequent references to this ID. If a message already has a parent, don't change the existing link. This is done because the References header line may have been truncated by a MUA. As a result, there is no guarantee that the messages corresponding to adjacent Message IDs in the References header line are parent and child. Do not create a parent/child link if creating that link would introduce a loop. For example, before making message A the parent of B, make sure that A is not a descendent of B. Note: Message ID comparisons are case-sensitive. (B) Create a parent/child link between the last reference (or NIL if there are no references) and the current message. If the current message already has a parent, it is probably the result of a truncated References header line, so break the current parent/child link before creating the new correct one. As in step 1.A, do not create the parent/child link if creating that link would introduce a loop. Note that if this message has no references, that it will now have no parent. Note: The parent/child links created in steps 1.A and 1.B MUST be kept consistent with one another at ALL times. (2) Gather together all of the messages that have no parents and make them all children (siblings of one another) of a dummy parent (the "root"). These messages constitute the first (head) message of the threads created thus far. (3) Prune dummy messages from the thread tree. Traverse each thread under the root, and for each message: If it is a dummy message with NO children, delete it. If it is a dummy message with children, delete it, but promote its children to the current level. In other words, splice them in with the dummy's siblings. Do not promote the children if doing so would make them children of the root, unless there is only one child. (4) Sort the messages under the root (top-level siblings only) by sent date as described in section 2.2. In the case of a dummy message, sort its children by sent date and then use the first child for the top-level sort. (5) Gather together messages under the root that have the same base subject text. (A) Create a table for associating base subjects with messages, called the subject table. (B) Populate the subject table with one message per each base subject. For each child of the root: (i) Find the subject of this thread, by using the base subject from either the current message or its first child if the current message is a dummy. This is the thread subject. (ii) If the thread subject is empty, skip this message. (iii) Look up the message associated with the thread subject in the subject table. (iv) If there is no message in the subject table with the thread subject, add the current message and the thread subject to the subject table. Otherwise, if the message in the subject table is not a dummy, AND either of the following criteria are true: The current message is a dummy, OR The message in the subject table is a reply or forward and the current message is not. then replace the message in the subject table with the current message. (C) Merge threads with the same thread subject. For each child of the root: (i) Find the message's thread subject as in step 5.B.i above. (ii) If the thread subject is empty, skip this message. (iii) Lookup the message associated with this thread subject in the subject table. (iv) If the message in the subject table is the current message, skip this message. Otherwise, merge the current message with the one in the subject table using the following rules: If both messages are dummies, append the current message's children to the children of the message in the subject table (the children of both messages become siblings), and then delete the current message. If the message in the subject table is a dummy and the current message is not, make the current message a child of the message in the subject table (a sibling of its children). If the current message is a reply or forward and the message in the subject table is not, make the current message a child of the message in the subject table (a sibling of its children). Otherwise, create a new dummy message and make both the current message and the message in the subject table children of the dummy. Then replace the message in the subject table with the dummy message. Note: Subject comparisons are case-insensitive, as described under "Internationalization Considerations." (6) Traverse the messages under the root and sort each set of siblings by sent date as described in section 2.2. Traverse the messages in such a way that the "youngest" set of siblings are sorted first, and the "oldest" set of siblings are sorted last (grandchildren are sorted before children, etc). In the case of a dummy message (which can only occur with top-level siblings), use its first child for sorting. Example: C: A283 THREAD ORDEREDSUBJECT UTF-8 SINCE 5-MAR-2000 S: * THREAD (166)(167)(168)(169)(172)(170)(171) (173)(174 (175)(176)(178)(181)(180))(179)(177 (183)(182)(188)(184)(185)(186)(187)(189))(190) (191)(192)(193)(194 195)(196 (197)(198))(199) (200 202)(201)(203)(204)(205)(206 207)(208) S: A283 OK THREAD completed C: A284 THREAD ORDEREDSUBJECT US-ASCII TEXT "gewp" S: * THREAD S: A284 OK THREAD completed C: A285 THREAD REFERENCES UTF-8 SINCE 5-MAR-2000 S: * THREAD (166)(167)(168)(169)(172)((170)(179)) (171)(173)((174)(175)(176)(178)(181)(180)) ((177)(183)(182)(188 (184)(189))(185 186)(187)) (190)(191)(192)(193)((194)(195 196))(197 198) (199)(200 202)(201)(203)(204)(205 206 207)(208) S: A285 OK THREAD completed Note: The line breaks in the first and third server responses are for editorial clarity and do not appear in real THREAD responses. 4. Additional Responses These responses are extensions to the [IMAP] base protocol. The section headings of these responses are intended to correspond with where they would be located in the main document. BASE.7.2.SORT. SORT Response Data: zero or more numbers The SORT response occurs as a result of a SORT or UID SORT command. The number(s) refer to those messages that match the search criteria. For SORT, these are message sequence numbers; for UID SORT, these are unique identifiers. Each number is delimited by a space. Example: S: * SORT 2 3 6 BASE.7.2.THREAD. THREAD Response Data: zero or more threads The THREAD response occurs as a result of a THREAD or UID THREAD command. It contains zero or more threads. A thread consists of a parenthesized list of thread members. Thread members consist of zero or more message numbers, delimited by spaces, indicating successive parent and child. This continues until the thread splits into multiple sub-threads, at which point the thread nests into multiple sub-threads with the first member of each subthread being siblings at this level. There is no limit to the nesting of threads. The messages numbers refer to those messages that match the search criteria. For THREAD, these are message sequence numbers; for UID THREAD, these are unique identifiers. Example: S: * THREAD (2)(3 6 (4 23)(44 7 96)) The first thread consists only of message 2. The second thread consists of the messages 3 (parent) and 6 (child), after which it splits into two subthreads; the first of which contains messages 4 (child of 6, sibling of 44) and 23 (child of 4), and the second of which contains messages 44 (child of 6, sibling of 4), 7 (child of 44), and 96 (child of 7). Since some later messages are parents of earlier messages, the messages were probably moved from some other mailbox at different times. -- 2 -- 3 \-- 6 |-- 4 | \-- 23 | \-- 44 \-- 7 \-- 96 Example: S: * THREAD ((3)(5)) In this example, 3 and 5 are siblings of a parent which does not match the search criteria (and/or does not exist in the mailbox); however they are members of the same thread. 5. Formal Syntax of SORT and THREAD Commands and Responses The following syntax specification uses the Augmented Backus-Naur Form (ABNF) notation as specified in [ABNF]. It also uses [ABNF] rules defined in [IMAP]. sort = ["UID" SP] "SORT" SP sort-criteria SP search-criteria sort-criteria = "(" sort-criterion *(SP sort-criterion) ")" sort-criterion = ["REVERSE" SP] sort-key sort-key = "ARRIVAL" / "CC" / "DATE" / "FROM" / "SIZE" / "SUBJECT" / "TO" thread = ["UID" SP] "THREAD" SP thread-alg SP search-criteria thread-alg = "ORDEREDSUBJECT" / "REFERENCES" / thread-alg-ext thread-alg-ext = atom ; New algorithms MUST be registered with IANA search-criteria = charset 1*(SP search-key) charset = atom / quoted ; CHARSET values MUST be registered with IANA sort-data = "SORT" *(SP nz-number) thread-data = "THREAD" [SP 1*thread-list] thread-list = "(" (thread-members / thread-nested) ")" thread-members = nz-number *(SP nz-number) [SP thread-nested] thread-nested = 2*thread-list The following syntax describes base subject extraction rules (2)-(6): subject = *subj-leader [subj-middle] *subj-trailer subj-refwd = ("re" / ("fw" ["d"])) *WSP [subj-blob] ":" subj-blob = "[" *BLOBCHAR "]" *WSP subj-fwd = subj-fwd-hdr subject subj-fwd-trl subj-fwd-hdr = "[fwd:" subj-fwd-trl = "]" subj-leader = (*subj-blob subj-refwd) / WSP subj-middle = *subj-blob (subj-base / subj-fwd) ; last subj-blob is subj-base if subj-base would ; otherwise be empty subj-trailer = "(fwd)" / WSP subj-base = NONWSP *(*WSP NONWSP) ; can be a subj-blob BLOBCHAR = %x01-5a / %x5c / %x5e-ff ; any CHAR8 except '[' and ']' NONWSP = %x01-08 / %x0a-1f / %x21-ff ; any CHAR8 other than WSP 6. Security Considerations The SORT and THREAD extensions do not raise any security considerations that are not present in the base [IMAP] protocol, and these issues are discussed in [IMAP]. Nevertheless, it is important to remember that [IMAP] protocol transactions, including message data, are sent in the clear over the network unless protection from snooping is negotiated, either by the use of STARTTLS, privacy protection is negotiated in the AUTHENTICATE command, or some other protection mechanism. Although not a security consideration, it is important to recognize that sorting by REFERENCES can lead to misleading threading trees. For example, a message with false References: header data will cause a thread to be incorporated into another thread. The process of extracting the base subject may lead to incorrect collation if the extracted data was significant text as opposed to a subject artifact. 7. Internationalization Considerations As stated in the introduction, the rules of I18NLEVEL=1 as described in [IMAP-I18N] MUST be followed; that is, the SORT and THREAD extensions MUST collate strings according to the i;unicode-casemap collation described in [UNICASEMAP]. Servers SHOULD also advertise the I18NLEVEL=1 extension. Alternatively, a server MAY implement I18NLEVEL=2 (or higher) and comply with the rules of that level. As discussed in [IMAP-I18N] section 4.5, all server implementations should eventually be updated to support the [IMAP-I18N] I18NLEVEL=2 extension. Translations of the "re" or "fw"/"fwd" tokens are not specified for removal in the base subject extraction process. An attempt to add such translated tokens would result in a geometrically complex, and ultimately unimplementable, task. Instead, note that [RFC-2822] section 3.6.5 recommends that "re:" (from the Latin "res", in the matter of) be used to identify a reply. Although it is evident that, from the multiple forms of token to identify a forwarded message, there is considerable variation found in the wild, the variations are (still) manageable. Consequently, it is suggested that "re:" and one of the variations of the tokens for forward supported by the base subject extraction rules be adopted for Internet mail messages, since doing so makes it a simple display time task to localize the token language for the user. 8. IANA Considerations [IMAP] capabilities are registered by publishing a standards track or IESG approved experimental RFC. This document constitutes registration of the SORT and THREAD capabilities in the [IMAP] capabilities registry. This document creates a new [IMAP] threading algorithms registry, which registers threading algorithms by publishing a standards track or IESG approved experimental RFC. This document constitutes registration of the ORDEREDSUBJECT and REFERENCES algorithms in that registry. 9. Normative References The following documents are normative to this document: [ABNF] Crocker, D. and Overell, P. "Augmented BNF for Syntax Specifications: ABNF", RFC 5234 January 2008 [CHARSET] Freed, N. and Postel, J. "IANA Character Set Registration Procedures", RFC 2978, October 2000. [IMAP] Crispin, M. "Internet Message Access Protocol - Version 4rev1", RFC 3501, March 2003. [IMAP-I18N] Newman, C. and Gulbrandsen, A. "Internet Message Access Protocol Internationalization", Work in Progress. [KEYWORDS] Bradner, S. "Key words for use in RFCs to Indicate Requirement Levels", BCP 14, RFC 2119, March 1997. [RFC-2822] Resnick, P. "Internet Message Format", RFC 2822, April 2001. [UNICASEMAP] Crispin, M. "i;unicode-casemap - Simple Unicode Collation Algorithm", RFC 5051. 10. Informative References The following documents are informative to this document: [IMAP-MODELS] Crispin, M. "Distributed Electronic Mail Models in IMAP4", RFC 1733, December 1994. [THREADING] Zawinski, J. "Message Threading", http://www.jwz.org/doc/threading.html, 1997-2002. Appendices Author's Address Mark R. Crispin Networks and Distributed Computing University of Washington 4545 15th Avenue NE Seattle, WA 98105-4527 Phone: +1 (206) 543-5762 EMail: MRC@CAC.Washington.EDU Kenneth Murchison Carnegie Mellon University 5000 Forbes Avenue Cyert Hall 285 Pittsburgh, PA 15213 Phone: +1 (412) 268-2638 Email: murch@andrew.cmu.edu Full Copyright Statement Copyright (C) The IETF Trust (2008). This document is subject to the rights, licenses and restrictions contained in BCP 78, and except as set forth therein, the authors retain all their rights. This document and the information contained herein are provided on an "AS IS" basis and THE CONTRIBUTOR, THE ORGANIZATION HE/SHE REPRESENTS OR IS SPONSORED BY (IF ANY), THE INTERNET SOCIETY, THE IETF TRUST AND THE INTERNET ENGINEERING TASK FORCE DISCLAIM ALL WARRANTIES, EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO ANY WARRANTY THAT THE USE OF THE INFORMATION HEREIN WILL NOT INFRINGE ANY RIGHTS OR ANY IMPLIED WARRANTIES OF MERCHANTABILITY OR FITNESS FOR A PARTICULAR PURPOSE. Intellectual Property The IETF takes no position regarding the validity or scope of any Intellectual Property Rights or other rights that might be claimed to pertain to the implementation or use of the technology described in this document or the extent to which any license under such rights might or might not be available; nor does it represent that it has made any independent effort to identify any such rights. Information on the procedures with respect to rights in RFC documents can be found in BCP 78 and BCP 79. Copies of IPR disclosures made to the IETF Secretariat and any assurances of licenses to be made available, or the result of an attempt made to obtain a general license or permission for the use of such proprietary rights by implementers or users of this specification can be obtained from the IETF on-line IPR repository at http://www.ietf.org/ipr. The IETF invites any interested party to bring to its attention any copyrights, patents or patent applications, or other proprietary rights that may cover technology that may be required to implement this standard. Please address the information to the IETF at ietf- ipr@ietf.org. Acknowledgement Funding for the RFC Editor function is currently provided by the Internet Society. alpine-2.10+dfsg/imap/docs/draft/i18n.txt0000600000175000017500000012432411512502124021640 0ustar paulproteuspaulproteus Network Working Group Chris Newman Internet-Draft Sun Microsystems Intended Status: Proposed Standard Arnt Gulbrandsen Oryx Mail Systems GmhH Alexey Melnikov Isode Limited February 1, 2008 Internet Message Access Protocol Internationalization draft-ietf-imapext-i18n-15.txt Status of this Memo By submitting this Internet-Draft, each author represents that any applicable patent or other IPR claims of which he or she is aware have been or will be disclosed, and any of which he or she becomes aware will be disclosed, in accordance with Section 6 of BCP 79. Internet-Drafts are working documents of the Internet Engineering Task Force (IETF), its areas, and its working groups. Note that other groups may also distribute working documents as Internet- Drafts. Internet-Drafts are draft documents valid for a maximum of six months and may be updated, replaced, or obsoleted by other documents at any time. It is inappropriate to use Internet-Drafts as reference material or to cite them other than as "work in progress". The list of current Internet-Drafts can be accessed at http://www.ietf.org/ietf/1id-abstracts.txt. The list of Internet- Draft Shadow Directories can be accessed at http://www.ietf.org/shadow.html. This Internet-Draft expires in August 2008. Copyright Notice Copyright (C) The IETF Trust (2008). Abstract Internet Message Access Protocol (IMAP) version 4rev1 has basic support for non-ASCII characters in mailbox names and search substrings. It also supports non-ASCII message headers and content encoded as specified by Multipurpose Internet Mail Extensions (MIME). This specification defines a collection of IMAP extensions Newman & Co Expires August 2008 FF[Page 1] Internet-draft February 2008 which improve international support including comparator negotiation for search, sort and thread, language negotiation for international error text, and translations for namespace prefixes. Table of Contents 1. Conventions Used in this Document . . . . . . . . . . . . . . 2 2. Introduction . . . . . . . . . . . . . . . . . . . . . . . . 3 3. LANGUAGE Extension . . . . . . . . . . . . . . . . . . . . . 3 3.1 LANGUAGE Extension Requirements . . . . . . . . . . . . . . . 3 3.2 LANGUAGE Command . . . . . . . . . . . . . . . . . . . . . . 4 3.3 LANGUAGE Response . . . . . . . . . . . . . . . . . . . . . . 6 3.4 TRANSLATION Extension to the NAMESPACE Response . . . . . . . 6 3.5 Formal Syntax . . . . . . . . . . . . . . . . . . . . . . . . 6 4. I18NLEVEL=1 and I18NLEVEL=2 Extensions . . . . . . . . . . . 7 4.1 Introduction and Overview . . . . . . . . . . . . . . . . . . 8 4.2 Requirements common to both I18NLEVEL=1 and I18NLEVEL=2 . . . 4.3 I18NLEVEL=1 Extension Requirements . . . . . . . . . . . . . 8 4.4 I18NLEVEL=2 Extension Requirements . . . . . . . . . . . . . 8 4.5 Compatibility Notes 4.6 Comparators and Charsets . . . . . . . . . . . . . . . . . . 9 4.7 COMPARATOR Command . . . . . . . . . . . . . . . . . . . . . 9 4.8 COMPARATOR Response . . . . . . . . . . . . . . . . . . . . . 10 4.9 BADCOMPARATOR Response Code . . . . . . . . . . . . . . . . . 4.10 Formal Syntax . . . . . . . . . . . . . . . . . . . . . . . 10 5. Other IMAP Internationalization Issues . . . . . . . . . . . 11 5.1 UTF-8 Userids and Passwords . . . . . . . . . . . . . . . . . 11 5.2 UTF-8 Mailbox Names . . . . . . . . . . . . . . . . . . . . . 11 5.3 UTF-8 Domains, Addresses and Mail Headers . . . . . . . . . . 11 6. IANA Considerations . . . . . . . . . . . . . . . . . . . . . 12 7. Security Considerations . . . . . . . . . . . . . . . . . . . 12 8. Acknowledgements . . . . . . . . . . . . . . . . . . . . . . 12 9. Relevant Standards for i18n IMAP Implementations . . . . . . 13 Normative References . . . . . . . . . . . . . . . . . . . . 13 Informative References . . . . . . . . . . . . . . . . . . . 14 Authors' Addresses . . . . . . . . . . . . . . . . . . . . . 15 Intellectual Property and Copyright Statements . . . . . . . 16 Conventions Used in This Document The key words "MUST", "MUST NOT", "REQUIRED", "SHALL", "SHALL NOT", "SHOULD", "SHOULD NOT", "RECOMMENDED", "MAY", and "OPTIONAL" in this document are to be interpreted as described in [RFC2119]. The formal syntax use the Augmented Backus-Naur Form (ABNF) [RFC4234] notation including the core rules defined in Appendix A. Newman & Co Expires August 2008 FF[Page 2] Internet-draft February 2008 The UTF8-related productions are defined in [RFC3629]. In examples, "C:" and "S:" indicate lines sent by the client and server respectively. If a single "C:" or "S:" label applies to multiple lines, then the line breaks between those lines are for editorial clarity only and are not part of the actual protocol exchange. 2. Introduction This specification defines two IMAP4rev1 [RFC3501] extensions to enhance international support. These extensions can be advertised and implemented separately. The LANGUAGE extension allows the client to request a suitable language for protocol error messages and in combination with the NAMESPACE extension [RFC2342] enables namespace translations. The I18NLEVEL=2 extension allows the client to request a suitable collation which will modify the behavior of the base specification's SEARCH command as well as the SORT and THREAD extensions [SORT]. This leverages the collation registry [RFC4790]. 3. LANGUAGE Extension IMAP allows server responses to include human-readable text that in many cases needs to be presented to the user. But that text is limited to US-ASCII by the IMAP specification [RFC3501] in order to preserve backwards compatibility with deployed IMAP implementations. This section specifies a way for an IMAP client to negotiate which language the server should use when sending human-readable text. The LANGUAGE extension only provides a mechanism for altering fixed server strings such as response text and NAMESPACE folder names. Assigning localized language aliases to shared mailboxes would be done with a separate mechanism such as the proposed METADATA extension (see [METADATA]). 3.1 LANGUAGE Extension Requirements IMAP servers that support this extension MUST list the keyword LANGUAGE in their CAPABILITY response as well as in the greeting CAPABILITY data. A server that advertises this extension MUST use the language "i- Newman & Co Expires August 2008 FF[Page 3] Internet-draft February 2008 default" as described in [RFC2277] as its default language until another supported language is negotiated by the client. A server MUST include "i-default" as one of its supported languages. Clients and servers that support this extension MUST also support the NAMESPACE extension [RFC2342]. The LANGUAGE command is valid in all states. Clients are urged to issue LANGUAGE before authentication, since some servers send valuable user information as part of authentication (e.g. "password is correct, but expired"). If a security layer (such as SASL or TLS) is subsequently negotiated by the client, it MUST re-issue the LANGUAGE command in order to make sure that no previous active attack (if any) on LANGUAGE negotiation has effect on subsequent error messages. (See Section 7 for a more detailed explanation of the attack.) 3.2 LANGUAGE Command Arguments: Optional language range arguments. Response: A possible LANGUAGE response (see section 3.3). A possible NAMESPACE response (see section 3.4). Result: OK - Command completed NO - Could not complete command BAD - arguments invalid The LANGUAGE command requests that human-readable text emitted by the server be localized to a language matching one of the language range argument as described by section 2 of [RFC4647]. If the command succeeds, the server will return human-readable responses in the first supported language specified. These responses will be in UTF-8 [RFC3629]. The server MUST send a LANGUAGE response specifying the language used, and the change takes effect immediately after the LANGUAGE response. If the command fails, the server continues to return human-readable responses in the language it was previously using. The special "default" language range argument indicates a request to use a language designated as preferred by the server administrator. The preferred language MAY vary based on the currently active user. If a language range does not match a known language tag exactly but Newman & Co Expires August 2008 FF[Page 4] Internet-draft February 2008 does match a language by the rules of [RFC4647], the server MUST send an untagged LANGUAGE response indicating the language selected. If there aren't any arguments, the server SHOULD send an untagged LANGUAGE response listing the languages it supports. If the server is unable to enumerate the list of languages it supports it MAY return a tagged NO response to the enumeration request. < The server defaults to using English i-default responses until the user explicitly changes the language. > C: A001 LOGIN KAREN PASSWORD S: A001 OK LOGIN completed < Client requested MUL language, which no server supports. > C: A002 LANGUAGE MUL S: A002 NO Unsupported language MUL < A LANGUAGE command with no arguments is a request to enumerate the list of languages the server supports. > C: A003 LANGUAGE S: * LANGUAGE (EN DE IT i-default) S: A003 OK Supported languages have been enumerated C: B001 LANGUAGE S: B001 NO Server is unable to enumerate supported languages < Once the client changes the language, all responses will be in that language starting after the LANGUAGE response. Note that this includes the NAMESPACE response. Because RFCs are in US- ASCII, this document uses an ASCII transcription rather than UTF-8 text, e.g. ue in the word "ausgefuehrt" > C: C001 LANGUAGE DE S: * LANGUAGE (DE) S: * NAMESPACE (("" "/")) (("Other Users/" "/" "TRANSLATION" ("Andere Ben&APw-tzer/"))) (("Public Folders/" "/" "TRANSLATION" ("Gemeinsame Postf&AM8-cher/"))) S: C001 OK Sprachwechsel durch LANGUAGE-Befehl ausgefuehrt < If a server does not support the requested primary language, responses will continue to be returned in the current language the server is using. > C: D001 LANGUAGE FR S: D001 NO Diese Sprache ist nicht unterstuetzt Newman & Co Expires August 2008 FF[Page 5] Internet-draft February 2008 C: D002 LANGUAGE DE-IT S: * LANGUAGE (DE-IT) S: * NAMESPACE (("" "/"))(("Other Users/" "/" "TRANSLATION" ("Andere Ben&APw-tzer/"))) (("Public Folders/" "/" "TRANSLATION" ("Gemeinsame Postf&AM8-cher/"))) S: D002 OK Sprachwechsel durch LANGUAGE-Befehl ausgefuehrt C: D003 LANGUAGE "default" S: * LANGUAGE (DE) S: D003 OK Sprachwechsel durch LANGUAGE-Befehl ausgefuehrt < Server does not speak French, but does speak English. User speaks Canadian French and Canadian English. > C: E001 LANGUAGE FR-CA EN-CA S: * LANGUAGE (EN) S: E001 OK Now speaking English 3.3 LANGUAGE Response Contents: A list of one or more language tags. The LANGUAGE response occurs as a result of a LANGUAGE command. A LANGUAGE response with a list containing a single language tag indicates that the server is now using that language. A LANGUAGE response with a list containing multiple language tags indicates the server is communicating a list of available languages to the client, and no change in the active language has been made. 3.4 TRANSLATION Extension to the NAMESPACE Response If localized representations of the namespace prefixes are available in the selected language, the server SHOULD include these in the TRANSLATION extension to the NAMESPACE response. The TRANSLATION extension to the NAMESPACE response returns a single string, containing the modified UTF-7 [RFC3501] encoded translation of the namespace prefix. It is the responsibility of the client to convert between the namespace prefix and the translation of the namespace prefix when presenting mailbox names to the user. In this example a server supports the IMAP4 NAMESPACE command. It uses no prefix to the user's Personal Namespace, a prefix of "Other Users" to its Other Users' Namespace and a prefix of "Public Folders" to its only Shared Namespace. Since a client will often display these prefixes to the user, the server includes a Newman & Co Expires August 2008 FF[Page 6] Internet-draft February 2008 translation of them that can be presented to the user. C: A001 LANGUAGE DE-IT S: * NAMESPACE (("" "/")) (("Other Users/" "/" "TRANSLATION" ("Andere Ben&APw-tzer/"))) (("Public Folders/" "/" "TRANSLATION" ("Gemeinsame Postf&AM8-cher/"))) S: A001 OK LANGUAGE-Befehl ausgefuehrt 3.5 Formal Syntax The following syntax specification inherits ABNF [RFC4234] rules from IMAP4rev1 [RFC3501], IMAP4 Namespace [RFC2342], Tags for the Identifying Languages [RFC4646], UTF-8 [RFC3629] and Collected Extensions to IMAP4 ABNF [RFC4466]. command-any =/ language-cmd ; LANGUAGE command is valid in all states language-cmd = "LANGUAGE" *(SP lang-range-quoted) response-payload =/ language-data language-data = "LANGUAGE" SP "(" lang-tag-quoted *(SP lang-tag-quoted) ")" namespace-trans = SP DQUOTE "TRANSLATION" DQUOTE SP "(" string ")" ; the string is encoded in Modified UTF-7. ; this is a subset of the syntax permitted by ; the Namespace-Response-Extension rule in [RFC4466] lang-range-quoted = astring ; Once any literal wrapper or quoting is removed, this ; follows the language-range rule in [RFC4647] lang-tag-quoted = astring ; Once any literal wrapper or quoting is removed, this follows ; the Language-Tag rule in [RFC4646] resp-text = ["[" resp-text-code "]" SP ] UTF8-TEXT-CHAR *(UTF8-TEXT-CHAR / "[") ; After the server is changed to a language other than ; i-default, this resp-text rule replaces the resp-text ; rule from [RFC3501]. UTF8-TEXT-CHAR = %x20-5A / %x5C-7E / UTF8-2 / UTF8-3 / UTF8-4 ; UTF-8 excluding 7-bit control characters and "[" Newman & Co Expires August 2008 FF[Page 7] Internet-draft February 2008 4. I18NLEVEL=1 and I18NLEVEL=2 Extensions 4.1 Introduction and Overview IMAP4rev1 [RFC3501] includes the SEARCH command which can be used to locate messages matching criteria including human-readable text. The SORT extension [SORT] to IMAP allows the client to ask the server to determine the order of messages based on criteria including human-readable text. These mechanisms require the ability to support non-English search and sort functions. Section 4 defines two IMAP extensions for internationalizing IMAP SEARCH, SORT and THREAD [SORT] using the comparator framework [RFC4790]. The I18NLEVEL=1 extension updates SEARCH/SORT/THREAD to use i;unicode-casemap comparator, as defined in [UCM]. See Sections 4.2 and 4.3 for more details. The I18NLEVEL=2 extension is a superset of the I18NLEVEL=1 extension. It adds to I18NLEVEL=1 extension the ability to determine the active comparator (see definition below) and negotiate use of comparators using the COMPARATOR command. It also adds the COMPARATOR response that indicates the active comparator and possibly other available comparators. See Sections 4.2 and 4.4 for more details. 4.2 Requirements common to both I18NLEVEL=1 and I18NLEVEL=2 The term "default comparator" refers to the comparator which is used by SEARCH and SORT absent any negotiation using the COMPARATOR (see Section 4.7) command. The term "active comparator" refers to the comparator which will be used within a session e.g. by SEARCH and SORT. The COMPARATOR command is used to change the active comparator. The active comparator applies to the following SEARCH keys: "BCC", "BODY", "CC", "FROM", "SUBJECT", "TEXT", "TO" and "HEADER". If the server also advertises the "SORT" extension, then the active comparator applies to the following SORT keys: "CC", "FROM", "SUBJECT" and "TO". If the server advertises THREAD=ORDEREDSUBJECT, then the active comparator applies to the ORDEREDSUBJECT threading algorithm. If the server advertises THREAD=REFERENCES, then the active comparator applies to the subject field comparisons done by REFERENCES threading algorithm. Future extensions may choose to apply the active comparator to their SEARCH keys. Newman & Co Expires August 2008 FF[Page 8] Internet-draft February 2008 For SORT and THREAD, the pre-processing necessary to extract the base subject text from a Subject header occurs prior to the application of a comparator. A server that advertises I18NLEVEL=1 or I18NLEVEL=2 extension MUST implement the i;unicode-casemap comparator, as defined in [UCM]. A server that advertises I18NLEVEL=1 or I18NLEVEL=2 extension MUST support UTF-8 as a SEARCH charset. 4.3 I18NLEVEL=1 Extension Requirements An IMAP server that satisfies all requirements specified in sections 4.2 and 4.6 (and doesn't support/advertise any other I18NLEVEL= extension, where n > 1) MUST list the keyword I18NLEVEL=1 in its CAPABILITY data once IMAP enters the authenticated state, and MAY list that keyword in other states. 4.4 I18NLEVEL=2 Extension Requirements IMAP server that satisfies all requirements specified in sections 4.2, 4.4, 4.6-4.10 (and doesn't support/advertise any other I18NLEVEL= extension, where n > 2) MUST list the keyword I18NLEVEL=2 in its CAPABILITY data once IMAP enters the authenticated state, and MAY list that keyword in other states. A server that advertises this extension MUST implement the i;unicode-casemap comparator, as defined in [UCM]. It MAY implement other comparators from the IANA registry established by [RFC4790]. See also section 4.5 of this document. A server that advertises this extension SHOULD use i;unicode-casemap as the default comparator. (Note that i;unicode-casemap is the default comparator for I18NLEVEL=1, but not necessarily the default for I18NLEVEL=2.) The selection of the default comparator MAY be adjustable by the server administrator, and MAY be sensitive to the current user. Once the IMAP connection enters authenticated state, the default comparator MUST remain static for the remainder of that connection. Note that since SEARCH uses the substring operation, IMAP servers can only implement collations that offer the substring operation (see [RFC4790 section 4.2.2). Since SORT uses ordering operation (and by implication equality), IMAP servers which advertise the SORT extension can only implement collations that offer all three Newman & Co Expires August 2008 FF[Page 9] Internet-draft February 2008 operations (see [RFC4790] sections 4.2.2-4). If the active collation does not provide the operations needed by an IMAP command, the server MUST respond with a tagged BAD. 4.5 Compatibility Notes Several server implementations deployed prior to the publication of this specification comply with I18NLEVEL=1 (see section 4.3), but do not advertise that. Other legacy servers use the i;ascii-casemap (see [RFC4790]) comparator. There is no good way for a client to know which comparator that a legacy server uses. If the client has to assume the worst, it may end up doing expensive local operations to obtain i;unicode-casemap comparisons even though the server implements it. Legacy server implementations which comply with I18NLEVEL=1 should be updated to advertise I18NLEVEL=1. All server implementations should eventually be updated to comply with the I18NLEVEL=2 extension. 4.6 Comparators and Character Encodings RFC 3501, section 6.4.4 says: In all search keys that use strings, a message matches the key if the string is a substring of the field. The matching is case-insensitive. When performing the SEARCH operation, the active comparator is applied instead of the case-insensitive matching specified above. An IMAP server which performs collation operations (e.g., as part of commands such as SEARCH, SORT, THREAD) does so according to the following procedure: (a) MIME encoding (for example see [RFC2047] for headers and [RFC2045] for body parts) MUST be removed in the texts being collated. If MIME encoding removal fails for a message (e.g., a body part of the message has an unsupported Content-Transfer-Encoding, uses characters not allowed by the Content-Transfer-Encoding, etc.), the collation of this message is undefined by this specification, and is handled in an implementation-dependent Newman & Co Expires August 2008 FF[Page 10] Internet-draft February 2008 manner. (b) The decoded text from (a) MUST be converted to the charset expected by the active comparator. (c) For the substring operation: If step (b) failed (e.g., the text is in an unknown charset, contains a sequence which is not valid according in that charset, etc.), the original decoded text from (a) (i.e., before the charset conversion attempt) is collated using the i;octet comparator (see [RFC4790]). If step (b) was successful, the converted text from (b) is collated according to the active comparator. For the ordering operation: All strings that were successfully converted by step (b) are separated from all strings that failed step (b). Strings in each group are collated independently. All strings successfully converted by step (b) are then validated by the active comparator. Strings that pass validation are collated using the active comparator. All strings that either fail step (b) or fail the active collation's validity operation are collated (after applying step (a)) using the i;octet comparator (see [RFC4790]). The resulting sorted list is produced by appending all collated "failed" strings after all strings collated using the active comparator. Example: The following example demonstrates ordering of 4 different strings using i;unicode-casemap [UCM] comparator. Strings are represented using hexadecimal notation used by ABNF [RFC4234]. (1) %xD0 %xC0 %xD0 %xBD %xD0 %xB4 %xD1 %x80 %xD0 %xB5 %xD0 %xB9 (labeled with charset=UTF-8) (2) %xD1 %x81 %xD0 %x95 %xD0 %xA0 %xD0 %x93 %xD0 %x95 %xD0 %x99 (labeled with charset=UTF-8) (3) %xD0 %x92 %xD0 %xB0 %xD1 %x81 %xD0 %xB8 %xD0 %xBB %xD0 %xB8 %xFF %xB9 (labeled with charset=UTF-8) (4) %xE1 %xCC %xC5 %xCB %xD3 %xC5 %xCA (labeled with charset=KOI8-R) Step (b) will convert string # 4 to the following sequence of octets (in UTF-8): Newman & Co Expires August 2008 FF[Page 11] Internet-draft February 2008 %xD0 %x90 %xD0 %xBB %xD0 %xB5 %xD0 %xBA %xD1 %x81 %xD0 %xB5 %xD0 %xB9 and will reject strings (1) and (3), as they contain octets not allowed in charset=UTF-8. After that, using the i;unicode-casemap collation, string (4) will collate before string (2). Using the i;octet collation on the original strings, string (3) will collate before string (1). So the final ordering is as follows: (4) (2) (3) (1). If the substring operation (e.g., IMAP SEARCH) of the active comparator returns the "undefined" result (see section 4.2.3 of [RFC4790]) for either the text specified in the SEARCH command or the message text, then the operation is repeated on the result of step (a) using the i;octet comparator. The ordering operation (e.g., IMAP SORT and THREAD) SHOULD collate the following together: strings encoded using unknown or invalid character encodings, strings in unrecognized charsets, and invalid input (as defined by the active collation). 4.7 COMPARATOR Command Arguments: Optional comparator order arguments. Response: A possible COMPARATOR response (see Section 4.8). Result: OK - Command completed NO - No matching comparator found BAD - arguments invalid The COMPARATOR command is valid in authenticated and selected states. The COMPARATOR command is used to determine or change the active comparator. When issued with no arguments, it results in a COMPARATOR response indicating the currently active comparator. When issued with one or more comparator argument, it changes the active comparator as directed. (If more than one installed comparator is matched by an argument, the first argument wins.) The COMPARATOR response lists all matching comparators if more than one matches the specified patterns. The argument "default" refers to the server's default comparator. Newman & Co Expires August 2008 FF[Page 12] Internet-draft February 2008 Otherwise each argument is an collation specification as defined in the Internet Application Protocol Comparator Registry [RFC4790]. < The client requests activating a Czech comparator if possible, or else a generic international comparator which it considers suitable for Czech. The server picks the first supported comparator. > C: A001 COMPARATOR "cz;*" i;basic S: * COMPARATOR i;basic S: A001 OK Will use i;basic for collation 4.8 COMPARATOR Response Contents: The active comparator. An optional list of available matching comparators The COMPARATOR response occurs as a result of a COMPARATOR command. The first argument in the comparator response is the name of the active comparator. The second argument is a list of comparators which matched any of the arguments to the COMPARATOR command and is present only if more than one match is found. 4.9 BADCOMPARATOR response code This response code SHOULD be returned as a result of server failing an IMAP command (returning NO), when the server knows that none of the specified comparators match the requested comparator(s). 4.10 Formal Syntax The following syntax specification inherits ABNF [RFC4234] rules from IMAP4rev1 [RFC3501], and Internet Application Protocol Comparator Registry [RFC4790]. command-auth =/ comparator-cmd resp-text-code =/ "BADCOMPARATOR" comparator-cmd = "COMPARATOR" *(SP comp-order-quoted) response-payload =/ comparator-data comparator-data = "COMPARATOR" SP comp-sel-quoted [SP "(" comp-id-quoted *(SP comp-id-quoted) ")"] Newman & Co Expires August 2008 FF[Page 13] Internet-draft February 2008 comp-id-quoted = astring ; Once any literal wrapper or quoting is removed, this ; follows the collation-id rule from [RFC4790] comp-order-quoted = astring ; Once any literal wrapper or quoting is removed, this ; follows the collation-order rule from [RFC4790] comp-sel-quoted = astring ; Once any literal wrapper or quoting is removed, this ; follows the collation-selected rule from [RFC4790] 5. Other IMAP Internationalization Issues The following sections provide an overview of various other IMAP internationalization issues. These issues are not resolved by this specification, but could be resolved by other standards work, such as that being done by the EAI group (see [IMAP-EAI]). 5.1 Unicode Userids and Passwords IMAP4rev1 currently restricts the userid and password fields of the LOGIN command to US-ASCII. The "userid" and "password" fields of the IMAP LOGIN command are restricted to US-ASCII only until a future standards track RFC states otherwise. Servers are encouraged to validate both fields to make sure they conform to the formal syntax of UTF-8 and to reject the LOGIN command if that syntax is violated. Servers MAY reject the use of any 8-bit in the "userid" or "password" field. When AUTHENTICATE is used, some servers may support userids and passwords in Unicode [RFC3490] since SASL (see [RFC4422]) allows that. However, such userids cannot be used as part of email addresses. 5.2 UTF-8 Mailbox Names The modified UTF-7 mailbox naming convention described in section 5.1.3 of RFC 3501 is best viewed as an transition from the status quo in 1996 when modified UTF-7 was first specified. At that time, there was widespread unofficial use of local character sets such as ISO-8859-1 and Shift-JIS for non-ASCII mailbox names, with resultant non-interoperability. The requirements in section 5.1 of RFC 3501 are very important if Newman & Co Expires August 2008 FF[Page 14] Internet-draft February 2008 we're ever going to be able to deploy UTF-8 mailbox names. Servers are encouraged to enforce them. 5.3 UTF-8 Domains, Addresses and Mail Headers There is now an IETF standard for Internationalizing Domain Names in Applications [RFC3490]. While IMAP clients are free to support this standard, an argument can be made that it would be helpful to simple clients if the IMAP server could perform this conversion (the same argument would apply to MIME header encoding [RFC2047]). However, it would be unwise to move forward with such work until the work in progress to define the format of international email addresses is complete. 6. IANA Considerations The IANA is requested to add LANGUAGE, I18NLEVEL=1 and I18NLEVEL=2 to the IMAP4 Capabilities Registry. [Note to IANA: http://www.iana.org/assignments/imap4-capabilities] 7. Security Considerations The LANGUAGE extension makes a new command available in "Not Authenticated" state in IMAP. Some IMAP implementations run with root privilege when the server is in "Not Authenticated" state and do not revoke that privilege until after authentication is complete. Such implementations are particularly vulnerable to buffer overflow security errors at this stage and need to implement parsing of this command with extra care. A LANGUAGE command issued prior to activation of a security layer is subject to an active attack which suppresses or modifies the negotiation and thus makes STARTTLS or authentication error messages more difficult to interpret. This is not a new attack as the error messages themselves are subject to active attack. Clients MUST re- issue the LANGUAGE command once a security layer is active, so this does not impact subsequent protocol operations. LANGUAGE, I18NLEVEL=1 and I18NLEVEL=2 extensions use the UTF-8 charset, thus the security considerations for UTF-8 [RFC3629] are relevent. However, neither uses UTF-8 for identifiers so the most serious concerns do not apply. 8. Acknowledgements Newman & Co Expires August 2008 FF[Page 15] Internet-draft February 2008 The LANGUAGE extension is based on a previous Internet draft by Mike Gahrns, a substantial portion of the text in that section was written by him. Many people have participated in discussions about an IMAP Language extension in the various fora of the IETF and Internet working groups, so any list of contributors is bound to be incomplete. However, the authors would like to thank Andrew McCown for early work on the original proposal, John Myers for suggestions regarding the namespace issue, along with Jutta Degener, Mark Crispin, Mark Pustilnik, Larry Osterman, Cyrus Daboo, Martin Duerst, Timo Sirainen, Ben Campbell and Magnus Nystrom for their many suggestions that have been incorporated into this document. Initial discussion of the I18NLEVEL=2 extension involved input from Mark Crispin and other participants of the IMAP Extensions WG. 9. Relevant Standards for i18n IMAP Implementations This is a non-normative list of standards to consider when implementing i18n aware IMAP software. o The LANGUAGE and I18NLEVEL=2 extensions to IMAP (this specification). o The 8-bit rules for mailbox naming in section 5.1 of RFC 3501. o The Mailbox International Naming Convention in section 5.1.3 of RFC 3501. o MIME [RFC2045] for message bodies. o MIME header encoding [RFC2047] for message headers. o The IETF EAI working group. o MIME Parameter Value and Encoded Word Extensions [RFC2231] for filenames. Quality IMAP server implementations will automatically combine multipart parameters when generating the BODYSTRUCTURE. There is also some deployed non-standard use of MIME header encoding inside double-quotes for filenames. o IDNA [RFC3490] and punycode [RFC3492] for domain names (currently only relevant to IMAP clients). o The UTF-8 charset [RFC3629]. o The IETF policy on Character Sets and Languages [RFC2277]. Normative References [RFC2119] Bradner, S., "Key words for use in RFCs to Indicate Requirement Levels", BCP 14, RFC 2119, March 1997. [RFC2277] Alvestrand, "IETF Policy on Character Sets and Languages", BCP 18, RFC 2277, January 1998. Newman & Co Expires August 2008 FF[Page 16] Internet-draft February 2008 [RFC2342] Gahrns, Newman, "IMAP4 Namespace", RFC 2342, May 1998. [RFC3501] Crispin, "INTERNET MESSAGE ACCESS PROTOCOL - VERSION 4rev1", RFC 3501, March 2003. [RFC3629] Yergeau, "UTF-8, a transformation format of ISO 10646", STD 63, RFC 3629, November 2003. [RFC4234] Crocker, Overell, "Augmented BNF for Syntax Specifications: ABNF", RFC 4234, Brandenburg Internetworking, Demon Internet Ltd, October 2005. [RFC4422] Melnikov, Zeilenga, "Simple Authentication and Security Layer (SASL)", RFC 4422, June 2006. [RFC4466] Melnikov, Daboo, "Collected Extensions to IMAP4 ABNF", RFC 4466, Isode Ltd., April 2006. [RFC4646] Philips, Davis, "Tags for Identifying Languages", BCP 47, RFC 4646, September 2006. [RFC4647] Philips, Davis, "Matching of Language Tags", BCP 47, RFC 4647, September 2006. [RFC4790] Newman, Duerst, Gulbrandsen, "Internet Application Protocol Comparator Registry", RFC 4790, February 2007. [SORT] Crispin, M. and K. Murchison, "INTERNET MESSAGE ACCESS PROTOCOL - SORT AND THREAD EXTENSION", draft-ietf- imapext-sort-19 (work in progress), November 2006. [UCM] Crispin, "i;unicode-casemap - Simple Unicode Collation Algorithm", RFC 5051, October 2007. [RFC2045] Freed, Borenstein, "Multipurpose Internet Mail Extensions (MIME) Part One: Format of Internet Message Bodies", RFC 2045, November 1996. [RFC2047] Moore, "MIME (Multipurpose Internet Mail Extensions) Part Three: Message Header Extensions for Non-ASCII Text", RFC 2047, November 1996. Informative References [RFC2231] Freed, Moore, "MIME Parameter Value and Encoded Word Extensions: Character Sets, Languages, and Newman & Co Expires August 2008 FF[Page 17] Internet-draft February 2008 Continuations", RFC 2231, November 1997. [RFC3490] Faltstrom, Hoffman, Costello, "Internationalizing Domain Names in Applications (IDNA)", RFC 3490, March 2003. [RFC3492] Costello, "Punycode: A Bootstring encoding of Unicode for Internationalized Domain Names in Applications (IDNA)", RFC 3492, March 2003. [METADATA] Daboo, C., "IMAP METADATA Extension", draft-daboo-imap- annotatemore-12 (work in progress), December 2007. [IMAP-EAI] Resnick, Newman, "IMAP Support for UTF-8", draft-ietf- eai-imap-utf8 (work in progress), May 2006. Authors' Addresses Chris Newman Sun Microsystems 3401 Centrelake Dr., Suite 410 Ontario, CA 91761 US Email: chris.newman@sun.com Arnt Gulbrandsen Oryx Mail Systems GmbH Schweppermannstr. 8 D-81671 Muenchen Germany Email: arnt@oryx.com Fax: +49 89 4502 9758 Alexey Melnikov Isode Limited 5 Castle Business Village, 36 Station Road, Hampton, Middlesex, TW12 2BX, UK Email: Alexey.Melnikov@isode.com Newman & Co Expires August 2008 FF[Page 18] Internet-draft February 2008 Intellectual Property Statement The IETF takes no position regarding the validity or scope of any Intellectual Property Rights or other rights that might be claimed to pertain to the implementation or use of the technology described in this document or the extent to which any license under such rights might or might not be available; nor does it represent that it has made any independent effort to identify any such rights. Information on the procedures with respect to rights in RFC documents can be found in BCP 78 and BCP 79. Copies of IPR disclosures made to the IETF Secretariat and any assurances of licenses to be made available, or the result of an attempt made to obtain a general license or permission for the use of such proprietary rights by implementers or users of this specification can be obtained from the IETF on-line IPR repository at http://www.ietf.org/ipr. The IETF invites any interested party to bring to its attention any copyrights, patents or patent applications, or other proprietary rights that may cover technology that may be required to implement this standard. Please address the information to the IETF at ietf-ipr@ietf.org. Full Copyright Statement Copyright (C) The IETF Trust (2008). This document is subject to the rights, licenses and restrictions contained in BCP 78, and except as set forth therein, the authors retain all their rights. This document and the information contained herein are provided on an "AS IS" basis and THE CONTRIBUTOR, THE ORGANIZATION HE/SHE REPRESENTS OR IS SPONSORED BY (IF ANY), THE INTERNET SOCIETY, THE IETF TRUST AND THE INTERNET ENGINEERING TASK FORCE DISCLAIM ALL WARRANTIES, EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO ANY WARRANTY THAT THE USE OF THE INFORMATION HEREIN WILL NOT INFRINGE ANY RIGHTS OR ANY IMPLIED WARRANTIES OF MERCHANTABILITY OR FITNESS FOR A PARTICULAR PURPOSE. Acknowledgment Funding for the RFC Editor function is currently provided by the Internet Society. Newman & Co Expires August 2008 FF[Page 19] alpine-2.10+dfsg/imap/docs/IPv6.txt0000600000175000017500000001132011512502125020535 0ustar paulproteuspaulproteus/* ======================================================================== * Copyright 1988-2006 University of Washington * * Licensed under the Apache License, Version 2.0 (the "License"); * you may not use this file except in compliance with the License. * You may obtain a copy of the License at * * http://www.apache.org/licenses/LICENSE-2.0 * * * ======================================================================== */ The following information about configuring inetd and xinetd for IPv6 was contributed by a user. I have not checked it for accuracy or completeness, but have included it as-is in the hope that it may be useful: --------------------------------------------------------------------------- One thing you might consider adding to the docs are hints for setting up inetd or xinetd to simultaneously listen on BOTH IPv4 and IPv6 for different OS. Some OS want to see separate IPv4-only and IPv6-only listening sockets configured in inetd.conf or xinetd.conf. Others will accept IPv4 connections on lines configured for IPv6 and actually generate errors if you have both configured when inetd or xinetd start up. It's not clear to me whether this difference is due to how inetd or xinetd are built or whether it's due to the kernel's IP stack implementation. I suspect it's really the latter. Below are some examples: Here's a fragment of /usr/local/etc/xinetd.conf for a FreeBSD 4.9 server: service imap { socket_type = stream protocol = tcp wait = no user = root server = /usr/local/libexec/imapd } service imap { flags = IPv6 socket_type = stream protocol = tcp wait = no user = root server = /usr/local/libexec/imapd } service imaps { socket_type = stream protocol = tcp wait = no user = root server = /usr/local/libexec/imapd } service imaps { flags = IPv6 socket_type = stream protocol = tcp wait = no user = root server = /usr/local/libexec/imapd } Note that you have to specify a nearly identical paragraph for each service which differs only by the 'flags = IPv6'. An equivalent inetd.conf would look something like: imap stream tcp nowait root /usr/local/libexec/imapd imapd imap stream tcp6 nowait root /usr/local/libexec/imapd imapd imaps stream tcp nowait root /usr/local/libexec/imapd imapd imaps stream tcp6 nowait root /usr/local/libexec/imapd imapd The man pages for inetd suggest that if you use a single entry with 'tcp46' replacing either 'tcp' or 'tcp6' the system will listen on both types of addresses. At least for the case of FreeBSD this is actually incorrect. Now if you were to use the above xinetd.conf on Fedora Linux, it would complain. What does work under Linux is to create a single service paragraph for each service which will accept connections on both IPv4 and IPv6: In /etc/xinetd.d/imap: service imap { flags = IPv6 disable = no socket_type = stream wait = no user = root server = /usr/local/sbin/imapd } In /etc/xinetd.d/imaps: service imaps { flags = IPv6 disable = no socket_type = stream wait = no user = root server = /usr/local/sbin/imapd } The man page for xinetd says the IPv6 flag means xinetd will listen ONLY on IPv6. However the actual behaviour (for Fedora Linux) is to listen on both IPv4 and IPv6. All of the above also applies to ipop3d. Anyway, this might save some folks a little bit of head scratching time. --------------------------------------------------------------------------- Addendum from the original submitter: --------------------------------------------------------------------------- I've since learned that the discrepancy really is a function of the OS. It seems those systems that force you to create separate IPv4 and IPv6 listeners in inetd (or xinetd) are the same systems that also disable IPv4-mapped IPv6 addresses by default. This is a boot-time configuration option. If you enable IPv4-mapped IPv6 addresses, then the 'tcp46' option in inetd works and the simplified config would look like: imap4 stream tcp46 nowait root /usr/local/libexec/imapd imapd imaps stream tcp46 nowait root /usr/local/libexec/imapd imapd In FreeBSD, enabling IPv4-mapped addresses is done by adding ipv6_ipv4mapping="YES" to /etc/rc.conf (in addition to ipv6_enable="YES"). alpine-2.10+dfsg/imap/docs/imaprc.txt0000600000175000017500000006475711512502125021252 0ustar paulproteuspaulproteus/* ======================================================================== * Copyright 1988-2006 University of Washington * * Licensed under the Apache License, Version 2.0 (the "License"); * you may not use this file except in compliance with the License. * You may obtain a copy of the License at * * http://www.apache.org/licenses/LICENSE-2.0 * * * ======================================================================== */ .imaprc secrets revealed! Mark Crispin, June 17, 2002 The following information describes the format of the /etc/c-client.cf and ~/.imaprc file. The Columbia MM ~/.mminit file is also read by c-client; however, the only command that ~/.mminit has in common is set keywords. ********************************************************************** * DANGER! BEWARE! TAKE CARE! * ********************************************************************** * * * These files, and this documentation, are for internal UW usage * * only. This capability is for UW experimental tinkering, and most * * emphatically *not* for sorcerer's apprentices at other sites who * * feel that if a config file capability exists, they must write a * * config file whether or not there is any need for one. * * * * This information is subject to change without notice. Commands * * may be added, removed, or altered. The behavior of comamnds may * * change. Do not use any of this information without consulting me * * first. c-client's defaults have been carefully chosen to be right * * for general-purpose and most special-purpose configurations. If * * you tinker with these defaults, all hell may break loose. * * * * This is not an idle threat. There have been several instances of * * people who ignored these warnings and have gotten burned. * * * * Don't even trust this file to work. Many of the things which can * * be changed by this file can also be changed by the application, * * and it is totally unpredictable which will take precedence. It * * all depends upon how the application is coded. Not only that, you * * may cause the application to crash. * * * * In other words, keep your cotton-pickin' hands off my defaults. * * If it crashes and erases your mail, I don't want to hear about it. * * Consider 'em ``mandatory defaults''. Got a nice ring, eh? :-) If * * you must tinker with defaults, play with the .pinerc and pine.conf * * files in Pine. It's got options galore, all supported for you to * * have fun. They're also documented; so well documented, it takes * * two strong men to carry around all the documentation. ;-) ;-) * * * * Joking aside, you really shouldn't be fooling around with this * * capability. It's dangerous, and you can shoot yourself in the * * foot easily. If you need custom changes, you are better off with * * local source code modifications. Seriously. * * * * One last warning: don't believe anything that you read in this * * document. Every effort has been made to ensure that this document * * is incomplete and inaccurate, and I take no responsibility for any * * glimmers of correct information that may, by some fluke, be here. * * * ********************************************************************** The files are read in order: /etc/c-client.cf, ~/.mminit, ~/.imaprc, and an entry in a later file overrides the setting of an earlier file except as noted below. This ordering and overriding behavior may change without notice. Almost all of these facilities can also be set via the mail_parameters() call in the program. Whether the file overrides mail_parameters(), or mail_parameters() overrides the file, is indeterminate. It will vary from program to program, and it may be one way in one version and the other way in the next version. It's completely unpredictable, and so anything you do with these files has to be in complete knowledge of what the version of each program you're running is going to do. This is because the files do something for testing, but the real capability for configurability is put in the program instead. Are you getting the feeling that you shouldn't be messing with these files yet? The very first line of the file MUST start with the exact string "I accept the risk". This ensures that you have checked the file for correctness against this version of the IMAP toolkit. This enable string may change without notice in future versions, and the new string may or may not be accurately described in an updated version of this file. So any time you install software that uses the IMAP toolkit, you need to check the new version against these files (if you have insisted upon creating them in spite of all warnings). If two pieces of software use different versions of the IMAP toolkit with incompatible requirements, one of them won't work. Re-read the warning above about why you should not use these files. Subsequent lines are read from the file one at a time. Case does not matter. Unrecognized commands are ignored. 1) set new-folder-format sets what format new mailboxes are created in. This also controls default delivery via tmail and dmail. a) set new-folder-format same-as-inbox Folder is created using the same mailbox format as INBOX. If INBOX is empty, it defaults to system standard. b) set new-folder-format system-standard This is the default. Folder is created using the wired-in system standard format, which on most UNIX systems is ordinary UNIX /bin/mail format. On SCO systems, this is MMDF. c) set new-folder-format Folder is created using the given driver name, e.g. mbx, unix, mmdf, etc. There is no protection against setting this to a silly value (e.g. news, nntp, dummy) and doing so is a great way to screw things up. Setting this to mh does not do what you think it does. Setting this to tenex or mtx isn't particularly useful. 2) set empty-folder-format sets what format data is written into an empty mailbox file using mail_copy() or mail_append(). This also controls default delivery via tmail. a) set empty-folder-format same-as-inbox Data is written using the same mailbox format as INBOX. If INBOX is empty, it defaults to system standard. b) set empty-folder-format system-standard This is the default. Data is written using the wired-in system standard format, which on most UNIX systems is ordinary UNIX /bin/mail format. On SCO systems, this is MMDF. c) set-empty-folder-format Data is written using the given driver name, e.g. tenex, unix, mmdf, etc. There is no protection against setting this to a silly value (e.g. news, nntp, dummy) and doing so is a great way to screw things up. Setting this to mh, mbx, or mx does not work. 3) set keywords , , ... Sets the list of keyword flags (supported by tenex and mtx) to the given list. Up to 30 flags may be given. Since these names correspond to numeric bits, the order of the keywords can not be changed, nor can keywords be removed or inserted (you can append new keywords, up to the limit of 30). Set keywords is a deprecated command. It may not appear in future versions, or it may appear in a changed form. It exists only for compatibility with MM, and should only appear in ~/.mminit and not in the other files. It is likely to disappear entirely in IMAP4. There is no protection against setting these to silly values, and doing so is a great way to cause a crash. 4) set from-widget header-only Sets smart insertion of the > character in front of lines that begin with ``From ''. Only such lines that are also in UNIX mbox header file format will have a > character inserted. The default is to insert the > character in front of all lines which begin with ``From '', for the benefit of legacy tools that get confused otherwise. 5) set black-box-directory Sets the directory in which the user's data can be found. A user's folders can be found in a subdirectory of the black box directory named with the user's username. For example, if the blackbox directory is /usr/spool/folders/, user jones' data can be found in /usr/spool/folders/jones/. The user's black-box directory is the location of folders, .mminit, .imaprc, .newsrc, and all other files used by c-client; internally, it sets c-client's idea of the user's ``home directory'', overriding /etc/passwd. This command may not appear in ~/.mminit or ~/.imaprc In black-box mode, it is not permitted to access any folders outside of the user's personal blackbox directory. The breakouts ``/'', ``~'', and ``..'' are not permitted. In order to make this work without crashing, you must set another option which is not listed in this document. There is no protection against setting this to a silly value, and doing so is a great way to cause a crash. 6) set local-host Sets c-client's idea of the local host name. There is no protection against setting this to a silly value, and doing so is a great way to cause a crash. 7) set news-active-file Sets the location of the news active file, if it is not in the standard place. It is recommended to use a courtesy symbolic link instead. There is no protection against setting this to a silly value, and doing so is a great way to cause a crash. 8) set news-spool-directory Sets the location of the news spool, if it is not in the standard place. It is recommended to use a courtesy symbolic link instead. There is no protection against setting this to a silly value, and doing so is a great way to cause a crash. 9) set news-state-file Sets the location of the news state file (normally $(USER)/.newsrc). This is not very useful in /etc/c-client.cf because it is a file name. Setting this in /etc/c-client.cf would set all users to the same file as their newsrc, which is probably not what you want. There is no protection against setting this to a silly value, and doing so is a great way to cause a crash. 10) set system-inbox Sets the location of the "system inbox", if it is not in the standard place. This is the default location of INBOX, or the mail drop point from which mail is snarfed (e.g. in tenex, mtx, mbox, mh formats). This is not very useful in /etc/c-client.cf because it is a file name. Setting this in /etc/c-client.cf would set all users to the same file as their system inbox, which is probably not what you want. There is no protection against setting this to a silly value, and doing so is a great way to cause a crash. 11) set tcp-open-timeout Sets the number of seconds that the TCP routines will block on opening a TCP connection before timing out. If a timeout occurs, the connection attempt is aborted. The default is zero, meaning use the operating system default (75 seconds on most UNIX systems). There is no protection against setting this to an excessively small value, such as 1, and doing so is a great way to cause users extreme grief. 12) set tcp-read-timeout Sets the number of seconds that the TCP routines will block on reading data before calling the timeout routine. If no timeout routine is set by the program, the connection will be aborted on a timeout. The default is zero, meaning infinite. There is no protection against setting this to an excessively small value, such as 1, and doing so is a great way to cause users extreme grief. 13) set tcp-write-timeout Sets the number of seconds that the TCP routines will block on sending data before calling the timeout routine. If no timeout routine is set by the program, the connection will be aborted on a timeout. The default is zero, meaning infinite. There is no protection against setting this to an excessively small value, such as 1, and doing so is a great way to cause users extreme grief. 14) set rsh-timeout Sets the number of seconds that the rsh routines will block on opening an rimapd connection before timing out. If a timeout occurs, the rsh connection attempt is aborted. A zero timeout will disable rsh. The default is 15 seconds. There is no protection against setting this to an excessively small value, such as 1, and doing so is a great way to cause users extreme grief. 15) set maximum-login-trials Sets the number of iterations of asking the user, via mm_login(), for a user name and password, before cancelling the attempt. The default is 3. There is no protection against setting this to zero, and doing so is a great way to cause users extreme grief. 16) set lookahead Sets the number of envelopes that are looked ahead in IMAP, in mail_fetchstructure(). This is based on the guess that in such operations as drawing browser lines, if you get data for message n you are likely to want it for message n+1, n+2,... in short order. Lookahead preloads the c-client cache and saves unnecessary RTTs. The default is 20, a good number for a browser on a 24x80 screen, and small enough to usually have no significant real-time difference from a single message fetch. Setting it to 0 turns off lookahead. There is no protection against setting this ridiculously high and incurring performance penalties as a result. 17) set prefetch Sets the number of envelops which are automatically fetched for the messages which match in a search. This is based on the guess that in a browser that is "zoomed" on the results of a search, you are likely to want the envelope data for each of those messages in short order. Prefetching reloads the c-client cache, saves unnecessary RTTs, and avoids loading undesired envelopes due to lookahead (see above). The default is 20. Setting it to 0 turns off prefetch. There is no protection against setting this ridiculously high and incurring performance penalties as a result. 18) set close-on-error If non-zero, IMAP connections are closed if an EXAMINE or SELECT command fails. Otherwise, they are left half-open, and can be used again to select some other mailbox. The mailbox name in the stream is set to {serverhost} The default is zero (do not close on error). 19) set imap-port Set the TCP/IP contact port to use for IMAP. This overrides the wired-in setting and the setting from /etc/services, and can in turn be overridden by an explicit user specification in the mailbox name, e.g. {serverhost:143}foo The default is zero (use setting from /etc/services or the wired-in setting (143). There is no protection against setting this to a silly value, and doing so is a great way to cause users extreme grief. 20) set pop3-port Set the TCP/IP contact port to use for POP3. This overrides the wired-in setting and the setting from /etc/services, and can in turn be overridden by an explicit user specification in the mailbox name, e.g. {serverhost:110/pop3} The default is zero (use setting from /etc/services or the wired-in setting (110). There is no protection against setting this to a silly value, and doing so is a great way to cause users extreme grief. 21) set uid-lookahead Sets the number of UIDs that are looked ahead in IMAP in mail_uid(). Lookahead preloads the c-client cache and saves unnecessary RTTs. The default is 1000, small enough to usually have no significant real-time difference from a single message UID fetch. Setting it to 0 turns off lookahead. There is no protection against setting this ridiculously high and incurring performance penalties as a result. 22) set mailbox-protection Set the default protection for newly-created mailbox files. The default is 384. There is no protection against setting this to a silly value, and doing so is a great way to screw things up massively. 23) set directory-protection Set the default protection for newly-created directories. The default is 448. There is no protection against setting this to a silly value, and doing so is a great way to screw things up massively. 24) set lock-protection Set the default protection for lock files The default is 438, which is necessary if locks are to be respected by processes running as other UIDs. There is no protection against setting this to a silly value, and contrary to what you may think just about any value other than 438 turns out to be a silly value. 25) set disable-fcntl-locking This only applies to SVR4 systems. If non-zero, fnctl() locking is not attempted. In the past, this was used to avoid locking NFS files. If NFS is involved, the evil lockd/statd daemons get invoked. These daemons supposedly work over NFS, but really don't. You probably don't really want to do this, though, because now the flock() emulator (which calls fcntl()) now checks to see if the file is accessed via NFS and no-ops the lock. This is compatible with BSD. Disabling fcntl() locking loses a great deal of locking protection on local files as well as NFS files (which now never have locking protection). The default is zero (fcntl() locking is enabled). 26) set lock-EACCES-error If non-zero, a warning message is given if an attempt to create a lock file fails. Otherwise, EACCES is treated as a "silent failure", and it proceeds without trying to use the lock file. This is for the benefit of users on systems with paranoid /usr/spool/mail protections which don't let users create /usr/spool/mail/$(USER).lock files; these unfortunate users would be harassed with a flood of error messages otherwise. The problem is that on SVR4, if EACCES remains disabled and fcntl() locking is also disabled, then there is no locking at all which is doubleplus-ungood. If the site is paranoid on /usr/spool/mail protections AND if there is no fcntl() locking (SVR4) or usable flock() locking (e.g. NFS), then there is no way to win. Find a different system to use. The default is non-zero (report EACCESS as an error). 27) set list-maximum-level Sets the maximum depth of recursion that a * wildcard list will go down the directory tree. 0 means that no recursion is permitted, and * becomes like %. The default is 20. There is no protection against setting this to a ridiculously high value. Since LIST will follow symbolic links, it can effectively recurse infinitely, until the name strings get large enough that some name limit is exceeded. 28) set anonymous-home-directory Sets the location of the anonymous home directory, if it is not in the standard place. It is recommended to use a courtesy symbolic link instead. There is no protection against setting this to a silly value, and doing so is a great way to cause a crash. 29) set chroot-server This option is for closed server systems only. If defined, a chroot() call to the user's home directory is done as part of the login process. This has the effect of preventing access to any files outside of the user's home directory (including shared mailboxes). Shared mailboxes with other users can't possibly work with this option, because there is no way to export lock information to other users. This should be done ONLY on systems which do not permit users to have shell access This option should NEVER(!!) be set if users are allowed shell access. Doing so actually makes the system *less* secure, since the user could create an etc subdirectory which would be treated as real /etc by such programs as /bin/su. The default is zero (don't do chroot). This option is strongly *NOT* recommended. 30) set disable-automatic-shared-namespaces Never look up the "ftp", "imappublic", and "imapshared" users as posssible home directories for the #ftp, #public, and #shared namespaces. On some systems (reportedly including AIX 4.3.3) getpwnam() of an unknown user name is horrendously slow. Note that this does not remove the #ftp, #public, and #shared namespaces, and they can still be set up by other means. The default is zero (shared namespaces are automatic). 31) set advertise-the-world Include the UNIX root as a shared namespace. This is generally a bad idea, since certain IMAP clients (names withheld to protect the guilty) will take this as license to download the entire filesystem tree. The default is zero (don't advertise the world). 32) set mail-subdirectory Change the default connected directory from the user's home directory to the named subdirectory of the user's home directory. For example, setting MAILSUBDIR="mail" will cause the POP2 and IMAP servers to connect to the user's ~/mail subdirectory. This is equivalent to the env_unix.c edit described in Example 2 of the CONFIG file. Note that if the subdirectory does not exist, the result is undefined. It is probably an extremely bad idea to set this unless you can guarantee that the subdirectory exists for all users. If you can not guarantee this, then you should leave the default as the user's home directory and allow them to configure a personal default in their IMAP client. The default is not to use any subdirectory. 33) set allow-user-config Allow users to use ~/.imaprc and ~/.mminit files. The default is zero (don't allow user config files). 34) set allow-reverse-dns By default, the servers (ipop[23]d and imapd) will do gethostbyaddr() on the local and remote sockets so that imapd can identify itself properly (this is important when the same CPU hosts multiple virtual hosts on different IP addresss) and also includes the client's name when it writes to the syslog. There are also client gethostbyaddr() calls, used primarily by authentication mechanisms. Setting this option to zero disables all gethostbyaddr() calls. The returned "host name" string for the socket is just the bracketed [12.34.56.78] form, as if the reverse DNS lookup failed. WARNING: Some authentication mechanisms, e.g. Kerberos V, depend upon the host names being right, and if you set this option, it won't work. You should only do this if you are encountering server performance problems due to a misconfigured DNS, e.g. long startup delays or client timeouts. The default is non-zero (allow reverse DNS). 35) set disable-plaintext Disable plaintext password authentication (LOGIN command, AUTH=LOGIN, and AUTH=PLAIN). The default is zero (allow plaintext authentication). 36) set trust-dns By default, host names are canonicalized via gethostbyname() for everything except for SSL certificate validation. This can represent a security bug due to DNS spoofing, but is more likely to deliver results that users expect. It also may be necessary for SASL authentication to work right (e.g. generating a correct name for a Kerberos service principal) if the name entered by the user is a CNAME or not a fully-qualified domain name. If trust-dns is set to zero, no host name canonicalization is done. The user's actual entered name is used for SASL authentication and will appear in the mailbox name of the open stream. The default is non-zero (do DNS canonicalization). 37) set sasl-uses-ptr-name By default, if trust-dns is set, the host names used in authentication (e.g. to generate a Kerberos service principal) are canonicalized via gethostbyaddr() instead of by gethostbyname(). If gethostbyaddr() fails the gethostbyname() canonicalization is used. This represents an additional security bug due to DNS spoofing, over and above trust-dns. It also adds an additional DNS query to starting a session. It is necessary for sites which implement a server cluster with multiple A records for a cluster name (instead of a CNAME) but each cluster member has a unique PTR record which it expects for a Kerberos service principal. If sasl-uses-ptr-name is set to zero and trust-dns is set non-zero, the gethostbyname() canonicalized name is used for SASL authentication. The setting of sasl-uses-ptr-name is irrelevant if trust-dns is set to zero. The default is non-zero (use name from PTR record for SASL). 38) set network-filesystem-stat-bug By default, traditional UNIX mailbox files are only closed and reopened at checkpoint and expunge time. This ensures that, prior to rewriting the file, that any cached stat() data from a network filesystem is updated with current data. Very old versions of NFS, and reputedly also AFS, can get into a state in which the cached stat() data stays out-of-date, even across a close and reopen of the file. If network-filesystem-stat-bug is set non-zero, then the mailbox file is closed and reopened at ping time as a workaround for this bug in these network filesystems. This means that in imapd, the mailbox file is closed and reopened for every IMAP command. This is obviously something that should be avoided unless absolutely necessary. NFS and AFS are terrible ways to distribute mail. You use use IMAP servers with a local disk instead. The default is zero (only close/reopen at checkpoint and expunge time). Setting this option is a great way to ruin your system's performance. 39) set restrict-mailbox-access